aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile12
-rw-r--r--lib/asn1/doc/src/asn1ct.xml6
-rw-r--r--lib/asn1/src/asn1ct.erl29
-rw-r--r--lib/asn1/src/asn1ct_check.erl50
-rw-r--r--lib/asn1/test/asn1_SUITE.erl.src4
-rw-r--r--lib/asn1/test/test_compile_options.erl39
-rw-r--r--lib/common_test/doc/src/ct_hooks.xml2
-rw-r--r--lib/common_test/src/ct_framework.erl2
-rw-r--r--lib/compiler/src/compile.erl50
-rw-r--r--lib/compiler/src/sys_pre_expand.erl6
-rw-r--r--lib/compiler/test/error_SUITE.erl65
-rw-r--r--lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl2
-rw-r--r--lib/crypto/c_src/Makefile.in5
-rw-r--r--lib/crypto/c_src/crypto.c58
-rw-r--r--lib/crypto/doc/src/crypto.xml8
-rw-r--r--lib/crypto/src/crypto.erl13
-rw-r--r--lib/crypto/test/crypto_SUITE.erl41
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl39
-rw-r--r--lib/dialyzer/src/dialyzer_typesig.erl195
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/results/inets20
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/results/mnesia2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/common_eunit2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/comparisons153
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/failing_funs20
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/common_eunit.erl121
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/comparisons.erl322
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/failing_funs.erl250
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/list_to_bitstring.erl2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/rebar_no_return.erl19
-rw-r--r--lib/diameter/make/rules.mk.in4
-rw-r--r--lib/diameter/src/transport/diameter_sctp.erl19
-rw-r--r--lib/erl_interface/src/encode/encode_atom.c6
-rw-r--r--lib/erl_interface/src/encode/encode_string.c6
-rw-r--r--lib/gs/contribs/bonk/sounder.erl18
-rw-r--r--lib/gs/contribs/cols/cols.erl4
-rw-r--r--lib/gs/contribs/mandel/mandel.erl2
-rw-r--r--lib/gs/contribs/othello/othello_board.erl4
-rw-r--r--lib/gs/examples/calc2.erl2
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl74
-rw-r--r--lib/hipe/regalloc/hipe_node_sets.erl2
-rw-r--r--lib/hipe/rtl/hipe_rtl_lcm.erl2
-rw-r--r--lib/ic/src/ic.erl2
-rw-r--r--lib/inets/doc/src/http_server.xml2
-rw-r--r--lib/inets/doc/src/mod_auth.xml2
-rw-r--r--lib/inets/doc/src/mod_esi.xml12
-rw-r--r--lib/inets/doc/src/notes_history.xml2
-rw-r--r--lib/inets/src/http_client/httpc_cookie.erl2
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl2
-rw-r--r--lib/inets/src/http_server/httpd_conf.erl2
-rw-r--r--lib/inets/src/http_server/httpd_esi.erl2
-rw-r--r--lib/inets/src/http_server/httpd_file.erl2
-rw-r--r--lib/inets/src/http_server/mod_auth_mnesia.erl2
-rw-r--r--lib/kernel/doc/src/inet.xml10
-rw-r--r--lib/kernel/doc/src/notes.xml2
-rw-r--r--lib/kernel/examples/uds_dist/c_src/uds_drv.c6
-rw-r--r--lib/kernel/src/auth.erl2
-rw-r--r--lib/kernel/test/file_SUITE.erl2
-rw-r--r--lib/mnesia/src/Makefile4
-rw-r--r--lib/mnesia/src/mnesia_controller.erl47
-rw-r--r--lib/mnesia/src/mnesia_dumper.erl7
-rw-r--r--lib/mnesia/src/mnesia_loader.erl244
-rw-r--r--lib/mnesia/src/mnesia_monitor.erl84
-rw-r--r--lib/mnesia/src/mnesia_schema.erl505
-rw-r--r--lib/orber/include/Makefile66
-rw-r--r--lib/os_mon/c_src/cpu_sup.c19
-rw-r--r--lib/parsetools/src/leex.erl52
-rw-r--r--lib/parsetools/src/yecc.erl37
-rw-r--r--lib/parsetools/test/leex_SUITE.erl11
-rw-r--r--lib/parsetools/test/yecc_SUITE.erl10
-rw-r--r--lib/public_key/doc/src/public_key.xml2
-rw-r--r--lib/public_key/src/pubkey_cert.erl4
-rw-r--r--lib/public_key/src/public_key.erl10
-rw-r--r--lib/public_key/test/public_key_SUITE.erl5
-rw-r--r--lib/runtime_tools/doc/src/dbg.xml10
-rw-r--r--lib/sasl/doc/src/release_handler.xml28
-rw-r--r--lib/sasl/doc/src/systools.xml10
-rw-r--r--lib/sasl/src/release_handler.erl52
-rw-r--r--lib/sasl/src/release_handler_1.erl200
-rw-r--r--lib/sasl/src/systools_lib.erl7
-rw-r--r--lib/sasl/src/systools_make.erl180
-rw-r--r--lib/sasl/src/systools_relup.erl68
-rw-r--r--lib/sasl/test/release_handler_SUITE.erl330
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/Makefile.src87
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/README19
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.appup7
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/ebin/many_mods.app17
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m.erl11
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m1.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m10.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m2.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m3.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m4.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m5.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m6.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m7.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m8.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m9.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.app17
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.appup22
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m.erl11
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m1.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m10.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m2.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m3.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m4.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m5.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m6.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m7.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m8.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m9.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.app7
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.appup24
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/src/m.erl11
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/ebin/dummy.app7
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_app.erl9
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_server.erl56
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_sup.erl15
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_sup_2.erl15
-rw-r--r--lib/sasl/test/systools_SUITE.erl87
-rw-r--r--lib/snmp/test/snmp_compiler_test.erl9
-rw-r--r--lib/ssl/src/ssl.erl14
-rw-r--r--lib/ssl/src/ssl_connection.erl17
-rw-r--r--lib/ssl/src/ssl_handshake.erl4
-rw-r--r--lib/ssl/src/ssl_manager.erl12
-rw-r--r--lib/ssl/src/ssl_session.erl4
-rw-r--r--lib/ssl/src/ssl_session_cache.erl4
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl8
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl302
-rw-r--r--lib/stdlib/doc/src/ets.xml3
-rw-r--r--lib/stdlib/src/dets_v8.erl2
-rw-r--r--lib/stdlib/src/erl_compile.erl1
-rw-r--r--lib/stdlib/src/erl_expand_records.erl2
-rw-r--r--lib/stdlib/test/ets_SUITE.erl48
-rw-r--r--lib/stdlib/test/tar_SUITE.erl60
-rw-r--r--lib/test_server/src/test_server_ctrl.erl4
-rw-r--r--lib/test_server/src/ts.config2
-rw-r--r--lib/toolbar/src/toolbar_toolconfig.erl4
-rw-r--r--lib/tools/doc/src/instrument.xml4
-rw-r--r--lib/tools/emacs/erlang.el2
-rw-r--r--lib/tools/src/cover.erl4
-rw-r--r--lib/wx/api_gen/gl_gen.erl2
-rw-r--r--lib/wx/api_gen/wx_gen.erl2
-rw-r--r--lib/xmerl/src/xmerl_ucs.erl35
-rw-r--r--lib/xmerl/src/xmerl_xsd.erl4
144 files changed, 3696 insertions, 1085 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 7f4c309da9..98d746925f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -83,19 +83,15 @@ endif
ifdef BOOTSTRAP
SUB_DIRECTORIES = \
- kernel stdlib compiler orber/include
+ kernel stdlib compiler
else
ifdef SECONDARY_BOOTSTRAP
SUB_DIRECTORIES = hipe parsetools asn1/src
else
ifdef TERTIARY_BOOTSTRAP
- SUB_DIRECTORIES = snmp
- else
- ifdef FOURTH_BOOTSTRAP
- SUB_DIRECTORIES = sasl jinterface ic syntax_tools
- else # Not bootstrap build
- SUB_DIRECTORIES = $(ERTS_SUB_DIRECTORIES) $(OTHER_SUB_DIRECTORIES)
- endif
+ SUB_DIRECTORIES = snmp sasl jinterface ic syntax_tools
+ else # Not bootstrap build
+ SUB_DIRECTORIES = $(ERTS_SUB_DIRECTORIES) $(OTHER_SUB_DIRECTORIES)
endif
endif
endif
diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml
index 265f8735c2..50458b4a9a 100644
--- a/lib/asn1/doc/src/asn1ct.xml
+++ b/lib/asn1/doc/src/asn1ct.xml
@@ -53,7 +53,7 @@
<v>Option = ber_bin | per_bin | uper_bin | der | compact_bit_string |
noobj | {n2n,EnumTypeName} |{outdir,Dir} | {i,IncludeDir} | optimize |
driver | asn1config | undec_rest | {inline,OutputName} | inline |
- {macro_name_prefix, Prefix} | {record_name_prefix, Prefix} | verbose</v>
+ {macro_name_prefix, Prefix} | {record_name_prefix, Prefix} | verbose | warnings_as_errors</v>
<v>OldOption = ber | per</v>
<v>Reason = term()</v>
<v>Prefix = string()</v>
@@ -289,6 +289,10 @@ Binary = binary()
<p>Causes more verbose information from the compiler
describing what it is doing.</p>
</item>
+ <tag><c>warnings_as_errors</c></tag>
+ <item>
+ <p>Causes warnings to be treated as errors.</p>
+ </item>
</taglist>
<p>Any additional option that is applied will be passed to
the final step when the generated .erl file is compiled.
diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl
index a167d27f82..e26fadd160 100644
--- a/lib/asn1/src/asn1ct.erl
+++ b/lib/asn1/src/asn1ct.erl
@@ -39,7 +39,7 @@
add_tobe_refed_func/1,add_generated_refed_func/1,
maybe_rename_function/3,latest_sindex/0,current_sindex/0,
set_current_sindex/1,next_sindex/0,maybe_saved_sindex/2,
- parse_and_save/2,verbose/3,warning/3,error/3]).
+ parse_and_save/2,verbose/3,warning/3,warning/4,error/3]).
-include("asn1_records.hrl").
-include_lib("stdlib/include/erl_compile.hrl").
@@ -825,10 +825,13 @@ generate({true,{M,_Module,GenTOrV}},OutFile,EncodingRule,Options) ->
case catch specialized_decode_prepare(EncodingRule,M,GenTOrV,Options) of
{error, enoent} -> ok;
{error, Reason} -> warning("Error in configuration "
- "file: ~n~p~n",[Reason],Options);
+ "file: ~n~p~n",[Reason],Options,
+ "Error in configuration file");
{'EXIT',Reason} -> warning("Internal error when "
"analyzing configuration "
- "file: ~n~p~n",[Reason],Options);
+ "file: ~n~p~n",[Reason],Options,
+ "Internal error when "
+ "analyzing configuration");
_ -> ok
end,
@@ -2524,14 +2527,14 @@ type_check(#'Externaltypereference'{}) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Report functions.
%%
-%% Errors messages are controlled with the 'errors' compiler option
+%% Error messages are controlled with the 'errors' compiler option
%% Warning messages are controlled with the 'warnings' compiler option
%% Verbose messages are controlled with the 'verbose' compiler option
error(Format, Args, S) ->
case is_error(S) of
true ->
- io:format("Error: " ++ Format, Args);
+ io:format(Format, Args);
false ->
ok
end.
@@ -2544,6 +2547,17 @@ warning(Format, Args, S) ->
ok
end.
+warning(Format, Args, S, Reason) ->
+ case {is_werr(S), is_error(S), is_warning(S)} of
+ {true, true, _} ->
+ io:format(Format, Args),
+ throw({error, Reason});
+ {false, _, true} ->
+ io:format(Format, Args);
+ _ ->
+ ok
+ end.
+
verbose(Format, Args, S) ->
case is_verbose(S) of
true ->
@@ -2566,3 +2580,8 @@ is_verbose(S) when is_record(S, state) ->
is_verbose(S#state.options);
is_verbose(O) ->
lists:member(verbose, O).
+
+is_werr(S) when is_record(S, state) ->
+ is_werr(S#state.options);
+is_werr(O) ->
+ lists:member(warnings_as_errors, O).
diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl
index efd731f052..e318477234 100644
--- a/lib/asn1/src/asn1ct_check.erl
+++ b/lib/asn1/src/asn1ct_check.erl
@@ -2031,7 +2031,7 @@ get_objectset_def2(_S,T = #typedef{typespec=#'ObjectSet'{}},_CField) ->
T;
get_objectset_def2(S,T,_CField) ->
asn1ct:warning("get_objectset_def2: uncontrolled object set structure:~n~p~n",
- [T],S).
+ [T],S,"get_objectset_def2: uncontrolled object set structure").
type_name(S,#type{def=Def}) ->
CurrMod = S#state.mname,
@@ -2705,7 +2705,7 @@ normalize_value(S,Type,{'DEFAULT',Value},NameList) ->
normalize_objectclassfieldvalue(S,Value,NL);
Err ->
asn1ct:warning("could not check default value ~p~nType:~n~p~nNameList:~n~p~n",
- [Value,Type,Err],S),
+ [Value,Type,Err],S,"could not check default value"),
Value
end;
normalize_value(S,Type,Val,NameList) ->
@@ -2791,22 +2791,27 @@ normalize_bitstring(S,Value,Type)->
case catch lists:map(F,RecList) of
{error,Reason} ->
asn1ct:warning("default value not "
- "compatible with type definition ~p~n",
- [Reason],S),
+ "compatible with type definition ~p~n",
+ [Reason],S,
+ "default value not "
+ "compatible with type definition"),
Value;
NewList ->
NewList
end;
_ ->
asn1ct:warning("default value not "
- "compatible with type definition ~p~n",
- [RecList],S),
+ "compatible with type definition ~p~n",
+ [RecList],S,
+ "default value not "
+ "compatible with type definition"),
Value
end;
{Name,String} when is_atom(Name) ->
normalize_bitstring(S,String,Type);
Other ->
- asn1ct:warning("illegal default value ~p~n",[Other],S),
+ asn1ct:warning("illegal default value ~p~n",[Other],S,
+ "illegal default value"),
Value
end.
@@ -2846,12 +2851,14 @@ normalize_octetstring(S,Value,CType) ->
lists:map(fun([])-> ok;
(H)when H > 255->
asn1ct:warning("not legal octet value ~p in OCTET STRING, ~p~n",
- [H,List],S);
+ [H,List],S,
+ "not legal octet value ~p in OCTET STRING");
(_)-> ok
end, List),
List;
Other ->
- asn1ct:warning("unknown default value ~p~n",[Other],S),
+ asn1ct:warning("unknown default value ~p~n",[Other],S,
+ "unknown default value"),
Value
end.
@@ -2908,13 +2915,15 @@ normalize_enumerated(S,{Name,EnumV},CType) when is_atom(Name) ->
normalize_enumerated(S,Value,{CType1,CType2}) when is_list(CType1), is_list(CType2)->
normalize_enumerated(S,Value,CType1++CType2);
normalize_enumerated(S,V,CType) ->
- asn1ct:warning("Enumerated unknown type ~p~n",[CType],S),
+ asn1ct:warning("Enumerated unknown type ~p~n",[CType],S,
+ "Enumerated unknown type"),
V.
normalize_enumerated2(S,V,Enum) ->
case lists:keysearch(V,1,Enum) of
{value,{Val,_}} -> Val;
_ ->
- asn1ct:warning("Enumerated value is not correct ~p~n",[V],S),
+ asn1ct:warning("enumerated value is not correct ~p~n",[V],S,
+ "enumerated value is not correct"),
V
end.
@@ -2925,7 +2934,8 @@ normalize_choice(S,{'CHOICE',{C,V}},CType,NameList) when is_atom(C) ->
{C,normalize_value(S,CT,{'DEFAULT',V},
[Name|NameList])};
Other ->
- asn1ct:warning("Wrong format of type/value ~p/~p~n",[Other,V],S),
+ asn1ct:warning("Wrong format of type/value ~p/~p~n",[Other,V],S,
+ "Wrong format of type/value"),
{C,V}
end;
normalize_choice(S,{'DEFAULT',ValueList},CType,NameList) when is_list(ValueList) ->
@@ -3101,7 +3111,8 @@ normalize_s_of(SorS,S,Value,Type,NameList) when is_list(Value) ->
List when is_list(List) ->
List;
_ ->
- asn1ct:warning("~p could not handle value ~p~n",[SorS,Value],S),
+ asn1ct:warning("~p could not handle value ~p~n",[SorS,Value],S,
+ "could not handle value"),
Value
end;
normalize_s_of(SorS,S,Value,Type,NameList)
@@ -3159,7 +3170,8 @@ get_normalized_value(S,Val,Type,Func,AddArg) ->
V2 = sort_val_if_set(AddArg,NewVal,Type),
call_Func(update_state(S,ExtM),V2,Type,Func,AddArg);
_ ->
- asn1ct:warning("default value not comparable ~p~n",[Val],S),
+ asn1ct:warning("default value not comparable ~p~n",[Val],S,
+ "default value not comparable"),
Val
end.
@@ -5756,7 +5768,8 @@ ascending_order_check1(S,TypeName,
[C1 = #'ComponentType'{tags=[{_,T}|_]},
C2 = #'ComponentType'{tags=[{_,T}|_]}|Rest]) ->
asn1ct:warning("Indistinct tag ~p in SET ~p, components ~p and ~p~n",
- [T,TypeName,C1#'ComponentType'.name,C2#'ComponentType'.name],S),
+ [T,TypeName,C1#'ComponentType'.name,C2#'ComponentType'.name],S,
+ "Indistinct tag in SET"),
ascending_order_check1(S,TypeName,[C2|Rest]);
ascending_order_check1(S,TypeName,
[C1 = #'ComponentType'{tags=[{'UNIVERSAL',T1}|_]},
@@ -5764,9 +5777,10 @@ ascending_order_check1(S,TypeName,
case (decode_type(T1) == decode_type(T2)) of
true ->
asn1ct:warning("Indistinct tags ~p and ~p in"
- " SET ~p, components ~p and ~p~n",
- [T1,T2,TypeName,C1#'ComponentType'.name,
- C2#'ComponentType'.name],S),
+ " SET ~p, components ~p and ~p~n",
+ [T1,T2,TypeName,C1#'ComponentType'.name,
+ C2#'ComponentType'.name],S,
+ "Indistinct tags and in SET"),
ascending_order_check1(S,TypeName,[C2|Rest]);
_ ->
ascending_order_check1(S,TypeName,[C2|Rest])
diff --git a/lib/asn1/test/asn1_SUITE.erl.src b/lib/asn1/test/asn1_SUITE.erl.src
index 582ccd877c..e7f93a4053 100644
--- a/lib/asn1/test/asn1_SUITE.erl.src
+++ b/lib/asn1/test/asn1_SUITE.erl.src
@@ -2236,8 +2236,10 @@ test_compile_options(Config) ->
?line ok = test_compile_options:path(Config),
?line ok = test_compile_options:noobj(Config),
?line ok = test_compile_options:record_name_prefix(Config),
- ?line ok = test_compile_options:verbose(Config)
+ ?line ok = test_compile_options:verbose(Config),
+ ?line ok = test_compile_options:warnings_as_errors(Config)
end.
+
testDoubleEllipses(suite) -> [];
testDoubleEllipses(Config) ->
?line testDoubleEllipses:compile(Config,?BER,[]),
diff --git a/lib/asn1/test/test_compile_options.erl b/lib/asn1/test/test_compile_options.erl
index 5e027cdedb..5cb212eddf 100644
--- a/lib/asn1/test/test_compile_options.erl
+++ b/lib/asn1/test/test_compile_options.erl
@@ -24,7 +24,7 @@
-export([wrong_path/1,comp/2,path/1,ticket_6143/1,noobj/1,
- record_name_prefix/1,verbose/1]).
+ record_name_prefix/1,verbose/1,warnings_as_errors/1]).
%% OTP-5689
wrong_path(Config) ->
@@ -141,6 +141,43 @@ verbose(Config) when is_list(Config) ->
?line [] = test_server:capture_get(),
ok.
+warnings_as_errors(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir,Config),
+ Asn1File = filename:join([PrivDir,"WERROR.asn1"]),
+ OutFile = filename:join([PrivDir,"WERROR.erl"]),
+ Opts = [{outdir,PrivDir},noobj,verbose],
+
+ %% Generate WERR.asn to emit warning
+ %% Warning: Wrong format of type/value
+ %% false/{'Externalvaluereference',_,'WERR',noInvokeId}
+ Warn = <<"WERROR DEFINITIONS IMPLICIT TAGS ::=\n"
+ "\n"
+ "BEGIN\n"
+ "\n"
+ "InvokeId ::= CHOICE\n"
+ "{\n"
+ " present INTEGER,\n"
+ " absent NULL\n"
+ "}\n"
+ "\n"
+ "noInvokeId InvokeId ::= absent:NULL\n"
+ "\n"
+ "NoInvokeId InvokeId ::= {noInvokeId}\n"
+ "\n"
+ "END -- end of useful definitions.\n">>,
+ ?line ok = file:write_file(Asn1File, Warn),
+
+ %% Test warnings_as_errors compile
+ ?line false = filelib:is_regular(OutFile),
+ ?line {error, _} = asn1ct:compile(Asn1File, [warnings_as_errors|Opts]),
+ ?line false = filelib:is_regular(OutFile),
+
+ %% Test normal compile
+ ?line ok = asn1ct:compile(Asn1File, Opts),
+ ?line true = filelib:is_regular(OutFile),
+ ?line ok = file:delete(OutFile),
+ ok.
+
outfiles_check(OutDir) ->
outfiles_check(OutDir,outfiles1()).
diff --git a/lib/common_test/doc/src/ct_hooks.xml b/lib/common_test/doc/src/ct_hooks.xml
index 0ece3199bb..f9fc1858d0 100644
--- a/lib/common_test/doc/src/ct_hooks.xml
+++ b/lib/common_test/doc/src/ct_hooks.xml
@@ -302,7 +302,7 @@
<p>Note that it is not possible to add CTH's here right now,
that feature might be added later,
- but it would right now break backwards compatability.</p>
+ but it would right now break backwards compatibility.</p>
</desc>
</func>
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 9e597edf38..2ebc6c311a 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -437,7 +437,7 @@ try_set_default(Name,Key,Info,Where) ->
%%% @doc Test server framework callback, called by the test_server
%%% when a test case is finished.
end_tc(Mod, Fun, Args) ->
- %% Have to keep end_tc/3 for backwards compatabilty issues
+ %% Have to keep end_tc/3 for backwards compatibility issues
end_tc(Mod, Fun, Args, '$end_tc_dummy').
end_tc(?MODULE,error_in_suite,_, _) -> % bad start!
ok;
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index ce8a5bf864..e46c667e47 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -113,7 +113,7 @@ noenv_forms(Forms, Opt) when is_atom(Opt) ->
noenv_output_generated(Opts) ->
{_,Passes} = passes(file, expand_opts(Opts)),
- any(fun ({save_binary,_F}) -> true;
+ any(fun ({save_binary,_T,_F}) -> true;
(_Other) -> false
end, Passes).
@@ -122,6 +122,7 @@ noenv_output_generated(Opts) ->
%%
-define(pass(P), {P,fun P/1}).
+-define(pass(P,T), {P,fun T/1,fun P/1}).
env_default_opts() ->
Key = "ERL_COMPILER_OPTIONS",
@@ -304,7 +305,7 @@ run_tc({Name,Fun}, St) ->
Val.
comp_ret_ok(#compile{code=Code,warnings=Warn0,module=Mod,options=Opts}=St) ->
- case member(warnings_as_errors, Opts) andalso length(Warn0) > 0 of
+ case werror(St) of
true ->
case member(report_warnings, Opts) of
true ->
@@ -339,6 +340,11 @@ comp_ret_err(#compile{warnings=Warn0,errors=Err0,options=Opts}=St) ->
false -> error
end.
+not_werror(St) -> not werror(St).
+
+werror(#compile{options=Opts,warnings=Ws}) ->
+ Ws =/= [] andalso member(warnings_as_errors, Opts).
+
%% messages_per_file([{File,[Message]}]) -> [{File,[Message]}]
messages_per_file(Ms) ->
T = lists:sort([{File,M} || {File,Messages} <- Ms, M <- Messages]),
@@ -373,7 +379,7 @@ passes(Type, Opts) ->
%% insert a first pass to remove the file (unless the
%% source file is a BEAM file).
{Ext,case last(Passes) of
- {save_binary,_Fun} ->
+ {save_binary,_TestFun,_Fun} ->
case Passes of
[{read_beam_file,_}|_] ->
%% The BEAM is both input and output.
@@ -655,7 +661,7 @@ asm_passes() ->
binary_passes() ->
[{native_compile,fun test_native/1,fun native_compile/1},
- {unless,binary,?pass(save_binary)}].
+ {unless,binary,?pass(save_binary,not_werror)}].
%%%
%%% Compiler passes.
@@ -1379,28 +1385,34 @@ report_errors(#compile{options=Opts,errors=Errors}) ->
end.
report_warnings(#compile{options=Opts,warnings=Ws0}) ->
- case member(report_warnings, Opts) of
+ Werror = member(warnings_as_errors, Opts),
+ P = case Werror of
+ true -> "";
+ false -> "Warning: "
+ end,
+ ReportWerror = Werror andalso member(report_errors, Opts),
+ case member(report_warnings, Opts) orelse ReportWerror of
true ->
- Ws1 = flatmap(fun({{F,_L},Eds}) -> format_message(F, Eds);
- ({F,Eds}) -> format_message(F, Eds) end,
+ Ws1 = flatmap(fun({{F,_L},Eds}) -> format_message(F, P, Eds);
+ ({F,Eds}) -> format_message(F, P, Eds) end,
Ws0),
Ws = lists:sort(Ws1),
foreach(fun({_,Str}) -> io:put_chars(Str) end, Ws);
false -> ok
end.
-format_message(F, [{{Line,Column}=Loc,Mod,E}|Es]) ->
- M = {{F,Loc},io_lib:format("~s:~w:~w Warning: ~s\n",
- [F,Line,Column,Mod:format_error(E)])},
- [M|format_message(F, Es)];
-format_message(F, [{Line,Mod,E}|Es]) ->
- M = {{F,{Line,0}},io_lib:format("~s:~w: Warning: ~s\n",
- [F,Line,Mod:format_error(E)])},
- [M|format_message(F, Es)];
-format_message(F, [{Mod,E}|Es]) ->
- M = {none,io_lib:format("~s: Warning: ~s\n", [F,Mod:format_error(E)])},
- [M|format_message(F, Es)];
-format_message(_, []) -> [].
+format_message(F, P, [{{Line,Column}=Loc,Mod,E}|Es]) ->
+ M = {{F,Loc},io_lib:format("~s:~w:~w ~s~s\n",
+ [F,Line,Column,P,Mod:format_error(E)])},
+ [M|format_message(F, P, Es)];
+format_message(F, P, [{Line,Mod,E}|Es]) ->
+ M = {{F,{Line,0}},io_lib:format("~s:~w: ~s~s\n",
+ [F,Line,P,Mod:format_error(E)])},
+ [M|format_message(F, P, Es)];
+format_message(F, P, [{Mod,E}|Es]) ->
+ M = {none,io_lib:format("~s: ~s~s\n", [F,P,Mod:format_error(E)])},
+ [M|format_message(F, P, Es)];
+format_message(_, _, []) -> [].
%% list_errors(File, ErrorDescriptors) -> ok
diff --git a/lib/compiler/src/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl
index 480954adac..dd6f24e21f 100644
--- a/lib/compiler/src/sys_pre_expand.erl
+++ b/lib/compiler/src/sys_pre_expand.erl
@@ -223,10 +223,8 @@ attribute(export, Es, _L, St) ->
St#expand{exports=union(from_list(Es), St#expand.exports)};
attribute(import, Is, _L, St) ->
import(Is, St);
-attribute(compile, C, _L, St) when is_list(C) ->
- St#expand{compile=St#expand.compile ++ C};
-attribute(compile, C, _L, St) ->
- St#expand{compile=St#expand.compile ++ [C]};
+attribute(compile, _C, _L, St) ->
+ St;
attribute(Name, Val, Line, St) when is_list(Val) ->
St#expand{attributes=St#expand.attributes ++ [{Name,Line,Val}]};
attribute(Name, Val, Line, St) ->
diff --git a/lib/compiler/test/error_SUITE.erl b/lib/compiler/test/error_SUITE.erl
index 6e0aadf007..eb5e50818e 100644
--- a/lib/compiler/test/error_SUITE.erl
+++ b/lib/compiler/test/error_SUITE.erl
@@ -183,23 +183,47 @@ get_compilation_errors(Config, Filename) ->
E.
warnings_as_errors(Config) when is_list(Config) ->
- Ts = [{warnings_as_errors,
+ ?line TestFile = test_filename(Config),
+ ?line BeamFile = filename:rootname(TestFile, ".erl") ++ ".beam",
+ ?line OutDir = ?config(priv_dir, Config),
+
+ Ts1 = [{warnings_as_errors,
<<"
t() ->
A = unused,
ok.
">>,
- [export_all,warnings_as_errors],
- {error,
- [],
- [{3,erl_lint,{unused_var,'A'}}]} }],
- ?line [] = run(Config, Ts),
+ [warnings_as_errors, export_all, {outdir, OutDir}],
+ {error,
+ [],
+ [{3,erl_lint,{unused_var,'A'}}]} }],
+ ?line [] = run(Ts1, TestFile, write_beam),
+ ?line false = filelib:is_regular(BeamFile),
+
+ Ts2 = [{warning_unused_var,
+ <<"
+ t() ->
+ A = unused,
+ ok.
+ ">>,
+ [return_warnings, export_all, {outdir, OutDir}],
+ {warning,
+ [{3,erl_lint,{unused_var,'A'}}]} }],
+
+ ?line [] = run(Ts2, TestFile, write_beam),
+ ?line true = filelib:is_regular(BeamFile),
+ ?line ok = file:delete(BeamFile),
+
ok.
run(Config, Tests) ->
+ ?line File = test_filename(Config),
+ run(Tests, File, dont_write_beam).
+
+run(Tests, File, WriteBeam) ->
F = fun({N,P,Ws,E}, BadL) ->
- case catch run_test(Config, P, Ws) of
+ case catch run_test(P, File, Ws, WriteBeam) of
E ->
BadL;
Bad ->
@@ -211,8 +235,12 @@ run(Config, Tests) ->
lists:foldl(F, [], Tests).
run2(Config, Tests) ->
+ ?line File = test_filename(Config),
+ run2(Tests, File, dont_write_beam).
+
+run2(Tests, File, WriteBeam) ->
F = fun({N,P,Ws,E}, BadL) ->
- case catch filter(run_test(Config, P, Ws)) of
+ case catch filter(run_test(P, File, Ws, WriteBeam)) of
E ->
BadL;
Bad ->
@@ -231,12 +259,19 @@ filter(X) ->
%% Compiles a test module and returns the list of errors and warnings.
-run_test(Conf, Test0, Warnings) ->
- Filename = 'errors_test.erl',
- ?line DataDir = ?config(priv_dir, Conf),
+test_filename(Conf) ->
+ Filename = "errors_test.erl",
+ DataDir = ?config(priv_dir, Conf),
+ filename:join(DataDir, Filename).
+
+run_test(Test0, File, Warnings, WriteBeam) ->
?line Test = ["-module(errors_test). ", Test0],
- ?line File = filename:join(DataDir, Filename),
- ?line Opts = [binary,return_errors|Warnings],
+ ?line Opts = case WriteBeam of
+ dont_write_beam ->
+ [binary,return_errors|Warnings];
+ write_beam ->
+ [return_errors|Warnings]
+ end,
?line ok = file:write_file(File, Test),
%% Compile once just to print all errors and warnings.
@@ -252,6 +287,10 @@ run_test(Conf, Test0, Warnings) ->
%io:format("compile:file(~s,~p) ->~n~p~n",
% [File,Opts,Ws]),
[];
+ {ok,errors_test,[{_File,Ws}]} ->
+ {warning,Ws};
+ {ok,errors_test,[]} ->
+ [];
{error,[{XFile,Es}],Ws} = _ZZ when is_list(XFile) ->
%io:format("compile:file(~s,~p) ->~n~p~n",
% [File,Opts,_ZZ]),
diff --git a/lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl b/lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl
index e222c5b92b..5dbe6f6b2f 100644
--- a/lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl
+++ b/lib/cosFileTransfer/src/CosFileTransfer_FileTransferSession_impl.erl
@@ -792,7 +792,7 @@ target_FTS_operation(State, _SrcFile, DestFile, Op, Offset) ->
%% Delete the temporary local copy.
delete_tmp_file(TempName,
"Transfer completed but failed to remove temporary local copy."),
- %% Completed the transfer succesfully.
+ %% Completed the transfer successfully.
{reply, ok, State};
{error, epath} ->
delete_tmp_file(TempName,
diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in
index 276c84d601..c2a986c334 100644
--- a/lib/crypto/c_src/Makefile.in
+++ b/lib/crypto/c_src/Makefile.in
@@ -41,6 +41,7 @@ CFLAGS = $(DED_CFLAGS)
SSL_LIBDIR = @SSL_LIBDIR@
SSL_INCLUDE = @SSL_INCLUDE@
SSL_CRYPTO_LIBNAME = @SSL_CRYPTO_LIBNAME@
+SSL_SSL_LIBNAME = @SSL_SSL_LIBNAME@
INCLUDES = $(SSL_INCLUDE) $(DED_INCLUDES)
@@ -84,7 +85,7 @@ DYNAMIC_CRYPTO_LIB=@SSL_DYNAMIC_ONLY@
ifeq ($(DYNAMIC_CRYPTO_LIB),yes)
SSL_DED_LD_RUNTIME_LIBRARY_PATH = @SSL_DED_LD_RUNTIME_LIBRARY_PATH@
-CRYPTO_LINK_LIB=$(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) -l$(SSL_CRYPTO_LIBNAME)
+CRYPTO_LINK_LIB=$(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) -l$(SSL_CRYPTO_LIBNAME) -l$(SSL_SSL_LIBNAME)
else
SSL_DED_LD_RUNTIME_LIBRARY_PATH=
CRYPTO_LINK_LIB=$(SSL_LIBDIR)/lib$(SSL_CRYPTO_LIBNAME).a
@@ -112,7 +113,7 @@ $(LIBDIR)/crypto$(TYPEMARKER).so: $(OBJS)
$(LIBDIR)/crypto$(TYPEMARKER).dll: $(OBJS)
$(INSTALL_DIR) $(LIBDIR)
- $(LD) $(LDFLAGS) -o $@ $(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) $(OBJS) -l$(SSL_CRYPTO_LIBNAME)
+ $(LD) $(LDFLAGS) -o $@ $(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) $(OBJS) -l$(SSL_CRYPTO_LIBNAME) -l$(SSL_SSL_LIBNAME)
clean:
ifeq ($(findstring win32,$(TARGET)), win32)
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index c781ccb302..83772d9023 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -43,6 +43,7 @@
#include <openssl/aes.h>
#include <openssl/md5.h>
#include <openssl/md4.h>
+#include <openssl/md2.h>
#include <openssl/sha.h>
#include <openssl/bn.h>
#include <openssl/objects.h>
@@ -267,6 +268,7 @@ static ERL_NIF_TERM atom_true;
static ERL_NIF_TERM atom_false;
static ERL_NIF_TERM atom_sha;
static ERL_NIF_TERM atom_md5;
+static ERL_NIF_TERM atom_md2;
static ERL_NIF_TERM atom_ripemd160;
static ERL_NIF_TERM atom_error;
static ERL_NIF_TERM atom_rsa_pkcs1_padding;
@@ -337,6 +339,7 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
atom_false = enif_make_atom(env,"false");
atom_sha = enif_make_atom(env,"sha");
atom_md5 = enif_make_atom(env,"md5");
+ atom_md2 = enif_make_atom(env,"md2");
atom_ripemd160 = enif_make_atom(env,"ripemd160");
atom_error = enif_make_atom(env,"error");
atom_rsa_pkcs1_padding = enif_make_atom(env,"rsa_pkcs1_padding");
@@ -1047,16 +1050,28 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
return(i > 0) ? atom_true : atom_false;
}
+struct hash_def {
+ int type;
+ unsigned int m_len;
+ unsigned char * (*func) (const unsigned char *d, size_t n, unsigned char *md);
+};
+
+static const struct hash_def md2_hash_def = { NID_md2, MD2_DIGEST_LENGTH, &MD2};
+static const struct hash_def md5_hash_def = { NID_md5, MD5_DIGEST_LENGTH, &MD5};
+static const struct hash_def sha1_hash_def = { NID_sha1, SHA_DIGEST_LENGTH, &SHA1};
+
static ERL_NIF_TERM rsa_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Type, Data, Signature, Key=[E,N]) */
ErlNifBinary data_bin, sign_bin;
unsigned char hmacbuf[SHA_DIGEST_LENGTH];
ERL_NIF_TERM head, tail, ret;
- int i, is_sha;
+ int i;
RSA* rsa = RSA_new();
+ const struct hash_def *hash_def = NULL;
- if (argv[0] == atom_sha) is_sha = 1;
- else if (argv[0] == atom_md5) is_sha = 0;
+ if (argv[0] == atom_sha) hash_def = &sha1_hash_def;
+ else if (argv[0] == atom_md5) hash_def = &md5_hash_def;
+ else if (argv[0] == atom_md2) hash_def = &md2_hash_def;
else goto badarg;
if (!inspect_mpint(env, argv[1], &data_bin)
@@ -1070,16 +1085,9 @@ static ERL_NIF_TERM rsa_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
ret = enif_make_badarg(env);
}
else {
- if (is_sha) {
- SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
- i = RSA_verify(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH,
- sign_bin.data+4, sign_bin.size-4, rsa);
- }
- else {
- MD5(data_bin.data+4, data_bin.size-4, hmacbuf);
- i = RSA_verify(NID_md5, hmacbuf, MD5_DIGEST_LENGTH,
- sign_bin.data+4, sign_bin.size-4, rsa);
- }
+ (void) *hash_def->func(data_bin.data+4, data_bin.size-4, hmacbuf);
+ i = RSA_verify(hash_def->type, hmacbuf, hash_def->m_len,
+ sign_bin.data+4, sign_bin.size-4, rsa);
ret = (i==1 ? atom_true : atom_false);
}
RSA_free(rsa);
@@ -1221,10 +1229,12 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
unsigned char hmacbuf[SHA_DIGEST_LENGTH];
unsigned rsa_s_len;
RSA *rsa = RSA_new();
- int i, is_sha;
+ int i;
+ const struct hash_def *hash_def = NULL;
- if (argv[0] == atom_sha) is_sha = 1;
- else if (argv[0] == atom_md5) is_sha = 0;
+ if (argv[0] == atom_sha) hash_def = &sha1_hash_def;
+ else if (argv[0] == atom_md5) hash_def = &md5_hash_def;
+ else if (argv[0] == atom_md2) hash_def = &md2_hash_def;
else goto badarg;
if (!inspect_mpint(env,argv[1],&data_bin)
@@ -1240,18 +1250,10 @@ static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
return enif_make_badarg(env);
}
enif_alloc_binary(RSA_size(rsa), &ret_bin);
- if (is_sha) {
- SHA1(data_bin.data+4, data_bin.size-4, hmacbuf);
- ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, SHA_DIGEST_LENGTH);
- i = RSA_sign(NID_sha1, hmacbuf, SHA_DIGEST_LENGTH,
- ret_bin.data, &rsa_s_len, rsa);
- }
- else {
- MD5(data_bin.data+4, data_bin.size-4, hmacbuf);
- ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, MD5_DIGEST_LENGTH);
- i = RSA_sign(NID_md5, hmacbuf,MD5_DIGEST_LENGTH,
- ret_bin.data, &rsa_s_len, rsa);
- }
+ (void) *hash_def->func(data_bin.data+4, data_bin.size-4, hmacbuf);
+ ERL_VALGRIND_ASSERT_MEM_DEFINED(hmacbuf, hash_def->m_len);
+ i = RSA_sign(hash_def->type, hmacbuf, hash_def->m_len,
+ ret_bin.data, &rsa_s_len, rsa);
RSA_free(rsa);
if (i) {
ERL_VALGRIND_MAKE_MEM_DEFINED(ret_bin.data, rsa_s_len);
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 179ba4498c..b593958264 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -347,7 +347,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</func>
<func>
<name>sha_mac_96(Key, Data) -> Mac</name>
- <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary>
+ <fsummary>Compute an <c>SHA MAC</c>message authentification code</fsummary>
<type>
<v>Key = Data = iolist() | binary()</v>
<v>Mac = binary()</v>
@@ -744,7 +744,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
<p>Generate a random number <c><![CDATA[N, Lo =< N < Hi.]]></c> Uses the
<c>crypto</c> library pseudo-random number generator. The
arguments (and result) can be either erlang integers or binary
- multi-precision integers.</p>
+ multi-precision integers. <c>Hi</c> must be larger than <c>Lo</c>.</p>
</desc>
</func>
<func>
@@ -795,7 +795,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
<v>E, N, D = Mpint</v>
<d>Where <c>E</c> is the public exponent, <c>N</c> is public modulus and
<c>D</c> is the private exponent.</d>
- <v>DigestType = md5 | sha</v>
+ <v>DigestType = md2 | md5 | sha</v>
<d>The default <c>DigestType</c> is sha.</d>
<v>Mpint = binary()</v>
<v>Signature = binary()</v>
@@ -817,7 +817,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
<v>Key = [E, N]</v>
<v>E, N = Mpint</v>
<d>Where <c>E</c> is the public exponent and <c>N</c> is public modulus.</d>
- <v>DigestType = md5 | sha</v>
+ <v>DigestType = md2 | md5 | sha</v>
<d> The default <c>DigestType</c> is sha.</d>
<v>Mpint = binary()</v>
</type>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index c35dfcebab..ddad00f4b4 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -91,7 +91,7 @@
aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt,
info_lib]).
--type rsa_digest_type() :: 'md5' | 'sha'.
+-type rsa_digest_type() :: 'md2' | 'md5' | 'sha'.
-type dss_digest_type() :: 'none' | 'sha'.
-type crypto_integer() :: binary() | integer().
@@ -415,6 +415,13 @@ rand_uniform(From,To) when is_binary(From), is_binary(To) ->
Whatever
end;
rand_uniform(From,To) when is_integer(From),is_integer(To) ->
+ if From < 0 ->
+ rand_uniform_pos(0, To - From) + From;
+ true ->
+ rand_uniform_pos(From, To)
+ end.
+
+rand_uniform_pos(From,To) when From < To ->
BinFrom = mpint(From),
BinTo = mpint(To),
case rand_uniform(BinFrom, BinTo) of
@@ -422,7 +429,9 @@ rand_uniform(From,To) when is_integer(From),is_integer(To) ->
erlint(Result);
Other ->
Other
- end.
+ end;
+rand_uniform_pos(_,_) ->
+ error(badarg).
rand_uniform_nif(_From,_To) -> ?nif_stub.
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 283aadb6ea..2fa058c852 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -878,10 +878,17 @@ rand_uniform_aux_test(0) ->
rand_uniform_aux_test(N) ->
?line L = N*1000,
?line H = N*100000+1,
+ ?line crypto_rand_uniform(L, H),
+ ?line crypto_rand_uniform(-L, L),
+ ?line crypto_rand_uniform(-H, -L),
+ ?line crypto_rand_uniform(-H, L),
+ ?line rand_uniform_aux_test(N-1).
+
+crypto_rand_uniform(L,H) ->
?line R1 = crypto:rand_uniform(L, H),
?line t(R1 >= L),
- ?line t(R1 < H),
- ?line rand_uniform_aux_test(N-1).
+ ?line t(R1 < H).
+
%%
%%
@@ -1075,16 +1082,30 @@ rsa_sign_test(Config) when is_list(Config) ->
PrivKey = [crypto:mpint(PubEx), crypto:mpint(Mod), crypto:mpint(PrivEx)],
PubKey = [crypto:mpint(PubEx), crypto:mpint(Mod)],
- ?line Sig1 = crypto:rsa_sign(sized_binary(Msg), PrivKey),
- ?line m(crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig1),PubKey), true),
+ ?line Sig = crypto:rsa_sign(sized_binary(Msg), PrivKey),
+ ?line m(crypto:rsa_verify(sized_binary(Msg), sized_binary(Sig),PubKey), true),
- ?line Sig2 = crypto:rsa_sign(md5, sized_binary(Msg), PrivKey),
- ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig2),PubKey), true),
-
- ?line m(Sig1 =:= Sig2, false),
- ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig1),PubKey), false),
- ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig1),PubKey), true),
+ ?line Sig_md2 = crypto:rsa_sign(md2, sized_binary(Msg), PrivKey),
+ ?line Sig_md5 = crypto:rsa_sign(md5, sized_binary(Msg), PrivKey),
+ ?line Sig_sha = crypto:rsa_sign(sha, sized_binary(Msg), PrivKey),
+
+ ?line m(Sig =:= Sig_sha, true),
+ ?line m(Sig_md2 =:= Sig_md5, false),
+ ?line m(Sig_md2 =:= Sig_sha, false),
+ ?line m(Sig_md5 =:= Sig_sha, false),
+ ?line m(crypto:rsa_verify(md2, sized_binary(Msg), sized_binary(Sig_md2),PubKey), true),
+ ?line m(crypto:rsa_verify(md2, sized_binary(Msg), sized_binary(Sig_md5),PubKey), false),
+ ?line m(crypto:rsa_verify(md2, sized_binary(Msg), sized_binary(Sig_sha),PubKey), false),
+
+ ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig_md2),PubKey), false),
+ ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig_md5),PubKey), true),
+ ?line m(crypto:rsa_verify(md5, sized_binary(Msg), sized_binary(Sig_sha),PubKey), false),
+
+ ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig_md2),PubKey), false),
+ ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig_md5),PubKey), false),
+ ?line m(crypto:rsa_verify(sha, sized_binary(Msg), sized_binary(Sig_sha),PubKey), true),
+
ok.
dsa_sign_test(doc) ->
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index 8cb16d8f09..659297f993 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -528,7 +528,7 @@ handle_apply(Tree, Map, State) ->
{CallSitesKnown, FunList} =
case state__lookup_call_site(Tree, State2) of
error -> {false, []};
- {ok, [external]} -> {false, {}};
+ {ok, [external]} -> {false, []};
{ok, List} -> {true, List}
end,
case CallSitesKnown of
@@ -554,7 +554,13 @@ handle_apply(Tree, Map, State) ->
{State3, enter_type(Op, OpType1, Map2), t_none()};
false ->
Map3 = enter_type_lists(Args, NewArgs, Map2),
- {State2, enter_type(Op, OpType1, Map3), t_fun_range(OpType1)}
+ Range0 = t_fun_range(OpType1),
+ Range =
+ case t_is_unit(Range0) of
+ true -> t_none();
+ false -> Range0
+ end,
+ {State2, enter_type(Op, OpType1, Map3), Range}
end
end;
true ->
@@ -2946,7 +2952,7 @@ state__get_warnings(#state{tree_map = TreeMap, fun_tab = FunTab,
%% Check if the function has a contract that allows this.
Warn =
case Contract of
- none -> true;
+ none -> not parent_allows_this(FunLbl, State);
{value, C} ->
GenRet = dialyzer_contracts:get_contract_return(C),
not t_is_unit(GenRet)
@@ -3434,6 +3440,33 @@ map_pats(Pats) ->
end,
cerl_trees:map(Fun, Pats).
+parent_allows_this(FunLbl, #state{callgraph = Callgraph, plt = Plt} =State) ->
+ case state__is_escaping(FunLbl, State) of
+ false -> false; % if it isn't escaping it can't be a return value
+ true ->
+ case state__lookup_name(FunLbl, State) of
+ {_M, _F, _A} -> false; % if it has a name it is not a fun
+ _ ->
+ case dialyzer_callgraph:in_neighbours(FunLbl, Callgraph) of
+ [Parent] ->
+ case state__lookup_name(Parent, State) of
+ {_M, _F, _A} = PMFA ->
+ case dialyzer_plt:lookup_contract(Plt, PMFA) of
+ none -> false;
+ {value, C} ->
+ GenRet = dialyzer_contracts:get_contract_return(C),
+ case erl_types:t_is_fun(GenRet) of
+ false -> false; % element of structure? far-fetched...
+ true -> t_is_unit(t_fun_range(GenRet))
+ end
+ end;
+ _ -> false % parent should have a name to have a contract
+ end;
+ _ -> false % called in other funs? far-fetched...
+ end
+ end
+ end.
+
classify_returns(Tree) ->
case find_terminals(cerl:fun_body(Tree)) of
{false, false} -> no_match;
diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl
index 65c2ff76bb..06863d89a7 100644
--- a/lib/dialyzer/src/dialyzer_typesig.erl
+++ b/lib/dialyzer/src/dialyzer_typesig.erl
@@ -62,7 +62,8 @@
-type dep() :: integer(). %% type variable names used as constraint ids
-type type_var() :: erl_types:erl_type(). %% actually: {'c','var',_,_}
--record(fun_var, {'fun' :: fun((_) -> erl_types:erl_type()), deps :: [dep()]}).
+-record(fun_var, {'fun' :: fun((_) -> erl_types:erl_type()), deps :: [dep()],
+ origin :: integer()}).
-type constr_op() :: 'eq' | 'sub'.
-type fvar_or_type() :: #fun_var{} | erl_types:erl_type().
@@ -121,8 +122,10 @@
-ifdef(DEBUG).
-define(debug(__String, __Args), io:format(__String, __Args)).
+-define(mk_fun_var(Fun, Vars), mk_fun_var(?LINE, Fun, Vars)).
-else.
-define(debug(__String, __Args), ok).
+-define(mk_fun_var(Fun, Vars), mk_fun_var(Fun, Vars)).
-endif.
%% ============================================================================
@@ -218,10 +221,10 @@ traverse(Tree, DefinedVars, State) ->
binary ->
{State1, SegTypes} = traverse_list(cerl:binary_segments(Tree),
DefinedVars, State),
- Type = mk_fun_var(fun(Map) ->
- TmpSegTypes = lookup_type_list(SegTypes, Map),
- t_bitstr_concat(TmpSegTypes)
- end, SegTypes),
+ Type = ?mk_fun_var(fun(Map) ->
+ TmpSegTypes = lookup_type_list(SegTypes, Map),
+ t_bitstr_concat(TmpSegTypes)
+ end, SegTypes),
{state__store_conj(mk_var(Tree), sub, Type, State1), mk_var(Tree)};
bitstr ->
Size = cerl:bitstr_size(Tree),
@@ -236,7 +239,7 @@ traverse(Tree, DefinedVars, State) ->
N when is_integer(N) -> {State1, t_bitstr(0, N)};
any -> % Size is not a literal
{state__store_conj(SizeType, sub, t_non_neg_integer(), State1),
- mk_fun_var(bitstr_constr(SizeType, UnitVal), [SizeType])}
+ ?mk_fun_var(bitstr_constr(SizeType, UnitVal), [SizeType])}
end,
ValTypeConstr =
case cerl:concrete(cerl:bitstr_type(Tree)) of
@@ -250,8 +253,8 @@ traverse(Tree, DefinedVars, State) ->
case state__is_in_match(State1) of
true ->
Flags = cerl:concrete(cerl:bitstr_flags(Tree)),
- mk_fun_var(bitstr_val_constr(SizeType, UnitVal, Flags),
- [SizeType]);
+ ?mk_fun_var(bitstr_val_constr(SizeType, UnitVal, Flags),
+ [SizeType]);
false -> t_integer()
end;
utf8 -> t_integer();
@@ -281,24 +284,24 @@ traverse(Tree, DefinedVars, State) ->
{State, t_cons(HdVar, TlVar)};
false ->
ConsVar = mk_var(Tree),
- ConsType = mk_fun_var(fun(Map) ->
- t_cons(lookup_type(HdVar, Map),
- lookup_type(TlVar, Map))
- end, [HdVar, TlVar]),
- HdType = mk_fun_var(fun(Map) ->
- Cons = lookup_type(ConsVar, Map),
- case t_is_cons(Cons) of
- false -> t_any();
- true -> t_cons_hd(Cons)
- end
- end, [ConsVar]),
- TlType = mk_fun_var(fun(Map) ->
- Cons = lookup_type(ConsVar, Map),
- case t_is_cons(Cons) of
- false -> t_any();
- true -> t_cons_tl(Cons)
- end
- end, [ConsVar]),
+ ConsType = ?mk_fun_var(fun(Map) ->
+ t_cons(lookup_type(HdVar, Map),
+ lookup_type(TlVar, Map))
+ end, [HdVar, TlVar]),
+ HdType = ?mk_fun_var(fun(Map) ->
+ Cons = lookup_type(ConsVar, Map),
+ case t_is_cons(Cons) of
+ false -> t_any();
+ true -> t_cons_hd(Cons)
+ end
+ end, [ConsVar]),
+ TlType = ?mk_fun_var(fun(Map) ->
+ Cons = lookup_type(ConsVar, Map),
+ case t_is_cons(Cons) of
+ false -> t_any();
+ true -> t_cons_tl(Cons)
+ end
+ end, [ConsVar]),
State2 = state__store_conj_lists([HdVar, TlVar, ConsVar], sub,
[HdType, TlType, ConsType],
State1),
@@ -656,25 +659,25 @@ get_plt_constr(MFA, Dst, ArgVars, State) ->
{RetType, ArgCs} =
case PltRes of
none ->
- {mk_fun_var(fun(Map) ->
- ArgTypes = lookup_type_list(ArgVars, Map),
- dialyzer_contracts:get_contract_return(C, ArgTypes)
- end, ArgVars), GenArgs};
+ {?mk_fun_var(fun(Map) ->
+ ArgTypes = lookup_type_list(ArgVars, Map),
+ dialyzer_contracts:get_contract_return(C, ArgTypes)
+ end, ArgVars), GenArgs};
{value, {PltRetType, PltArgTypes}} ->
%% Need to combine the contract with the success typing.
- {mk_fun_var(
- fun(Map) ->
- ArgTypes0 = lookup_type_list(ArgVars, Map),
- ArgTypes = case FunModule =:= Module of
- false ->
- List = lists:zip(PltArgTypes, ArgTypes0),
- [erl_types:t_unopaque_on_mismatch(T1, T2, Opaques)
- || {T1, T2} <- List];
- true -> ArgTypes0
- end,
- CRet = dialyzer_contracts:get_contract_return(C, ArgTypes),
- t_inf(CRet, PltRetType, opaque)
- end, ArgVars),
+ {?mk_fun_var(
+ fun(Map) ->
+ ArgTypes0 = lookup_type_list(ArgVars, Map),
+ ArgTypes = case FunModule =:= Module of
+ false ->
+ List = lists:zip(PltArgTypes, ArgTypes0),
+ [erl_types:t_unopaque_on_mismatch(T1, T2, Opaques)
+ || {T1, T2} <- List];
+ true -> ArgTypes0
+ end,
+ CRet = dialyzer_contracts:get_contract_return(C, ArgTypes),
+ t_inf(CRet, PltRetType, opaque)
+ end, ArgVars),
[t_inf(X, Y, opaque) || {X, Y} <- lists:zip(GenArgs, PltArgTypes)]}
end,
state__store_conj_lists([Dst|ArgVars], sub, [RetType|ArgCs], State)
@@ -766,10 +769,10 @@ handle_clauses_1([Clause|Tail], TopVar, Arg, DefinedVars,
case SubtrTypes =:= overflow of
true -> S;
false ->
- SubtrPatVar = mk_fun_var(fun(Map) ->
- TmpType = lookup_type(Arg, Map),
- t_subtract_list(TmpType, SubtrTypes)
- end, [Arg]),
+ SubtrPatVar = ?mk_fun_var(fun(Map) ->
+ TmpType = lookup_type(Arg, Map),
+ t_subtract_list(TmpType, SubtrTypes)
+ end, [Arg]),
state__store_conj(Arg, sub, SubtrPatVar, S)
end
end,
@@ -1043,10 +1046,10 @@ handle_guard(Guard, DefinedVars, State) ->
get_bif_constr({erlang, Op, 2}, Dst, Args = [Arg1, Arg2], _State)
when Op =:= '+'; Op =:= '-'; Op =:= '*' ->
- ReturnType = mk_fun_var(fun(Map) ->
- TmpArgTypes = lookup_type_list(Args, Map),
- erl_bif_types:type(erlang, Op, 2, TmpArgTypes)
- end, Args),
+ ReturnType = ?mk_fun_var(fun(Map) ->
+ TmpArgTypes = lookup_type_list(Args, Map),
+ erl_bif_types:type(erlang, Op, 2, TmpArgTypes)
+ end, Args),
ArgFun =
fun(A, Pos) ->
F =
@@ -1074,7 +1077,7 @@ get_bif_constr({erlang, Op, 2}, Dst, Args = [Arg1, Arg2], _State)
end
end
end,
- mk_fun_var(F, [Dst, A])
+ ?mk_fun_var(F, [Dst, A])
end,
Arg1FunVar = ArgFun(Arg2, 2),
Arg2FunVar = ArgFun(Arg1, 1),
@@ -1131,12 +1134,12 @@ get_bif_constr({erlang, Op, 2}, Dst, [Arg1, Arg2] = Args, _State)
'>=' -> {ArgFun(Arg1, Arg2, '>='), ArgFun(Arg2, Arg1, '=<')}
end,
DstArgs = [Dst, Arg1, Arg2],
- Arg1Var = mk_fun_var(Arg1Fun, DstArgs),
- Arg2Var = mk_fun_var(Arg2Fun, DstArgs),
- DstVar = mk_fun_var(fun(Map) ->
- TmpArgTypes = lookup_type_list(Args, Map),
- erl_bif_types:type(erlang, Op, 2, TmpArgTypes)
- end, Args),
+ Arg1Var = ?mk_fun_var(Arg1Fun, DstArgs),
+ Arg2Var = ?mk_fun_var(Arg2Fun, DstArgs),
+ DstVar = ?mk_fun_var(fun(Map) ->
+ TmpArgTypes = lookup_type_list(Args, Map),
+ erl_bif_types:type(erlang, Op, 2, TmpArgTypes)
+ end, Args),
mk_conj_constraint_list([mk_constraint(Dst, sub, DstVar),
mk_constraint(Arg1, sub, Arg1Var),
mk_constraint(Arg2, sub, Arg2Var)]);
@@ -1172,13 +1175,13 @@ get_bif_constr({erlang, '++', 2}, Dst, [Hd, Tl] = Args, _State) ->
end
end,
DstL = [Dst],
- HdVar = mk_fun_var(HdFun, DstL),
- TlVar = mk_fun_var(TlFun, DstL),
+ HdVar = ?mk_fun_var(HdFun, DstL),
+ TlVar = ?mk_fun_var(TlFun, DstL),
ArgTypes = erl_bif_types:arg_types(erlang, '++', 2),
- ReturnType = mk_fun_var(fun(Map) ->
- TmpArgTypes = lookup_type_list(Args, Map),
- erl_bif_types:type(erlang, '++', 2, TmpArgTypes)
- end, Args),
+ ReturnType = ?mk_fun_var(fun(Map) ->
+ TmpArgTypes = lookup_type_list(Args, Map),
+ erl_bif_types:type(erlang, '++', 2, TmpArgTypes)
+ end, Args),
Cs = mk_constraints(Args, sub, ArgTypes),
mk_conj_constraint_list([mk_constraint(Dst, sub, ReturnType),
mk_constraint(Hd, sub, HdVar),
@@ -1209,7 +1212,7 @@ get_bif_constr({erlang, is_function, 2}, Dst, [Fun, Arity], _State) ->
false -> t_any()
end
end,
- ArgV = mk_fun_var(ArgFun, [Dst, Arity]),
+ ArgV = ?mk_fun_var(ArgFun, [Dst, Arity]),
mk_conj_constraint_list([mk_constraint(Dst, sub, t_boolean()),
mk_constraint(Arity, sub, t_integer()),
mk_constraint(Fun, sub, ArgV)]);
@@ -1232,12 +1235,12 @@ get_bif_constr({erlang, is_record, 2}, Dst, [Var, Tag] = Args, _State) ->
false -> t_any()
end
end,
- ArgV = mk_fun_var(ArgFun, [Dst]),
+ ArgV = ?mk_fun_var(ArgFun, [Dst]),
DstFun = fun(Map) ->
TmpArgTypes = lookup_type_list(Args, Map),
erl_bif_types:type(erlang, is_record, 2, TmpArgTypes)
end,
- DstV = mk_fun_var(DstFun, Args),
+ DstV = ?mk_fun_var(DstFun, Args),
mk_conj_constraint_list([mk_constraint(Dst, sub, DstV),
mk_constraint(Tag, sub, t_atom()),
mk_constraint(Var, sub, ArgV)]);
@@ -1280,7 +1283,7 @@ get_bif_constr({erlang, is_record, 3}, Dst, [Var, Tag, Arity] = Args, State) ->
false -> t_any()
end
end,
- ArgV = mk_fun_var(ArgFun, [Tag, Arity, Dst]),
+ ArgV = ?mk_fun_var(ArgFun, [Tag, Arity, Dst]),
DstFun = fun(Map) ->
[TmpVar, TmpTag, TmpArity] = TmpArgTypes = lookup_type_list(Args, Map),
TmpArgTypes2 =
@@ -1314,7 +1317,7 @@ get_bif_constr({erlang, is_record, 3}, Dst, [Var, Tag, Arity] = Args, State) ->
end,
erl_bif_types:type(erlang, is_record, 3, TmpArgTypes2)
end,
- DstV = mk_fun_var(DstFun, Args),
+ DstV = ?mk_fun_var(DstFun, Args),
mk_conj_constraint_list([mk_constraint(Dst, sub, DstV),
mk_constraint(Arity, sub, t_integer()),
mk_constraint(Tag, sub, t_atom()),
@@ -1359,9 +1362,9 @@ get_bif_constr({erlang, 'and', 2}, Dst, [Arg1, Arg2] = Args, _State) ->
end
end
end,
- ArgV1 = mk_fun_var(ArgFun(Arg2), [Arg2, Dst]),
- ArgV2 = mk_fun_var(ArgFun(Arg1), [Arg1, Dst]),
- DstV = mk_fun_var(DstFun, Args),
+ ArgV1 = ?mk_fun_var(ArgFun(Arg2), [Arg2, Dst]),
+ ArgV2 = ?mk_fun_var(ArgFun(Arg1), [Arg1, Dst]),
+ DstV = ?mk_fun_var(DstFun, Args),
mk_conj_constraint_list([mk_constraint(Dst, sub, DstV),
mk_constraint(Arg1, sub, ArgV1),
mk_constraint(Arg2, sub, ArgV2)]);
@@ -1403,9 +1406,9 @@ get_bif_constr({erlang, 'or', 2}, Dst, [Arg1, Arg2] = Args, _State) ->
end
end
end,
- ArgV1 = mk_fun_var(ArgFun(Arg2), [Arg2, Dst]),
- ArgV2 = mk_fun_var(ArgFun(Arg1), [Arg1, Dst]),
- DstV = mk_fun_var(DstFun, Args),
+ ArgV1 = ?mk_fun_var(ArgFun(Arg2), [Arg2, Dst]),
+ ArgV2 = ?mk_fun_var(ArgFun(Arg1), [Arg1, Dst]),
+ DstV = ?mk_fun_var(DstFun, Args),
F = fun(A) ->
try [mk_constraint(A, sub, True)]
catch throw:error -> []
@@ -1433,8 +1436,8 @@ get_bif_constr({erlang, 'not', 1}, Dst, [Arg] = Args, _State) ->
end
end
end,
- ArgV = mk_fun_var(Fun(Dst), [Dst]),
- DstV = mk_fun_var(Fun(Arg), Args),
+ ArgV = ?mk_fun_var(Fun(Dst), [Dst]),
+ DstV = ?mk_fun_var(Fun(Arg), Args),
mk_conj_constraint_list([mk_constraint(Arg, sub, ArgV),
mk_constraint(Dst, sub, DstV)]);
get_bif_constr({erlang, '=:=', 2}, Dst, [Arg1, Arg2] = Args, _State) ->
@@ -1467,9 +1470,9 @@ get_bif_constr({erlang, '=:=', 2}, Dst, [Arg1, Arg2] = Args, _State) ->
end
end,
DstArgs = [Dst, Arg1, Arg2],
- ArgV1 = mk_fun_var(ArgFun(Arg1, Arg2), DstArgs),
- ArgV2 = mk_fun_var(ArgFun(Arg2, Arg1), DstArgs),
- DstV = mk_fun_var(DstFun, Args),
+ ArgV1 = ?mk_fun_var(ArgFun(Arg1, Arg2), DstArgs),
+ ArgV2 = ?mk_fun_var(ArgFun(Arg2, Arg1), DstArgs),
+ DstV = ?mk_fun_var(DstFun, Args),
mk_conj_constraint_list([mk_constraint(Dst, sub, DstV),
mk_constraint(Arg1, sub, ArgV1),
mk_constraint(Arg2, sub, ArgV2)]);
@@ -1510,10 +1513,10 @@ get_bif_constr({erlang, '==', 2}, Dst, [Arg1, Arg2] = Args, _State) ->
end
end
end,
- DstV = mk_fun_var(DstFun, Args),
+ DstV = ?mk_fun_var(DstFun, Args),
ArgL = [Arg1, Arg2, Dst],
- ArgV1 = mk_fun_var(ArgFun(Arg2, Arg1), ArgL),
- ArgV2 = mk_fun_var(ArgFun(Arg1, Arg2), ArgL),
+ ArgV1 = ?mk_fun_var(ArgFun(Arg2, Arg1), ArgL),
+ ArgV2 = ?mk_fun_var(ArgFun(Arg1, Arg2), ArgL),
mk_conj_constraint_list([mk_constraint(Dst, sub, DstV),
mk_constraint(Arg1, sub, ArgV1),
mk_constraint(Arg2, sub, ArgV2)]);
@@ -1531,7 +1534,7 @@ get_bif_constr({erlang, element, 2} = _BIF, Dst, Args,
end,
erl_bif_types:type(erlang, element, 2, ATs2)
end,
- ReturnType = mk_fun_var(Fun, Args),
+ ReturnType = ?mk_fun_var(Fun, Args),
ArgTypes = erl_bif_types:arg_types(erlang, element, 2),
Cs = mk_constraints(Args, sub, ArgTypes),
NewCs =
@@ -1553,7 +1556,7 @@ get_bif_constr({M, F, A} = _BIF, Dst, Args, State) ->
false -> T
end
end,
- ReturnType = mk_fun_var(fun(Map) ->
+ ReturnType = ?mk_fun_var(fun(Map) ->
TmpArgTypes0 = lookup_type_list(Args, Map),
TmpArgTypes = [UnopaqueFun(T) || T<- TmpArgTypes0],
erl_bif_types:type(M, F, A, TmpArgTypes)
@@ -1608,7 +1611,7 @@ get_bif_test_constr(Dst, Arg, Type, State) ->
false -> t_any()
end
end,
- ArgV = mk_fun_var(ArgFun, [Dst]),
+ ArgV = ?mk_fun_var(ArgFun, [Dst]),
DstFun = fun(Map) ->
ArgType = lookup_type(Arg, Map),
case t_is_none(t_inf(ArgType, Type)) of
@@ -1633,7 +1636,7 @@ get_bif_test_constr(Dst, Arg, Type, State) ->
end
end
end,
- DstV = mk_fun_var(DstFun, [Arg]),
+ DstV = ?mk_fun_var(DstFun, [Arg]),
mk_conj_constraint_list([mk_constraint(Dst, sub, DstV),
mk_constraint(Arg, sub, ArgV)]).
@@ -2323,12 +2326,25 @@ mk_constraint(Lhs, Op, Rhs) ->
constraint_opnd_is_any(#fun_var{}) -> false;
constraint_opnd_is_any(Type) -> t_is_any(Type).
+-ifdef(DEBUG).
+
+-spec mk_fun_var(fun((_) -> erl_types:erl_type()), [erl_types:erl_type()],
+ integer()) -> #fun_var{}.
+
+mk_fun_var(Line, Fun, Types) ->
+ Deps = [t_var_name(Var) || Var <- t_collect_vars(t_product(Types))],
+ #fun_var{'fun' = Fun, deps = ordsets:from_list(Deps), origin = Line}.
+
+-else.
+
-spec mk_fun_var(fun((_) -> erl_types:erl_type()), [erl_types:erl_type()]) -> #fun_var{}.
mk_fun_var(Fun, Types) ->
Deps = [t_var_name(Var) || Var <- t_collect_vars(t_product(Types))],
#fun_var{'fun' = Fun, deps = ordsets:from_list(Deps)}.
+-endif.
+
-spec get_deps(constr()) -> [dep()].
get_deps(#constraint{deps = D}) -> D;
@@ -2679,8 +2695,9 @@ find_constraint(Tuple, [_|Cs]) ->
-endif.
-ifdef(DEBUG).
-format_type(#fun_var{deps = Deps}) ->
- io_lib:format("Fun(~s)", [lists:flatten([format_type(t_var(X))||X<-Deps])]);
+format_type(#fun_var{deps = Deps, origin = Origin}) ->
+ io_lib:format("Fun@L~p(~s)",
+ [Origin, lists:flatten([format_type(t_var(X))||X<-Deps])]);
format_type(Type) ->
case cerl:is_literal(Type) of
true -> io_lib:format("~w", [cerl:concrete(Type)]);
diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/inets b/lib/dialyzer/test/r9c_SUITE_data/results/inets
index 6b16dba2ff..0177dcc88c 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/results/inets
+++ b/lib/dialyzer/test/r9c_SUITE_data/results/inets
@@ -3,9 +3,14 @@ ftp.erl:1243: The pattern {'ok', {N, Bytes}} can never match the type 'eof' | {'
ftp.erl:640: The pattern {'closed', _Why} can never match the type 'perm_fname_not_allowed' | 'perm_neg_compl' | 'perm_no_space' | 'pos_compl' | 'pos_interm' | 'pos_interm_acct' | 'trans_neg_compl' | 'trans_no_space' | {'error' | 'perm_fname_not_allowed' | 'perm_neg_compl' | 'perm_no_space' | 'pos_compl' | 'pos_interm' | 'pos_interm_acct' | 'pos_prel' | 'trans_neg_compl' | 'trans_no_space',atom() | [any()] | {'invalid_server_response',[any(),...]}}
http.erl:117: The pattern {'error', Reason} can never match the type #req_headers{connection::[45 | 97 | 101 | 105 | 107 | 108 | 112 | 118,...],content_length::[48,...],other::[{_,_}]}
http.erl:138: Function close_session/2 will never be called
-http_lib.erl:286: The call http_lib:close('ip_comm' | {'ssl',_},any()) will never return since it differs in the 1st argument from the success typing arguments: ('http' | 'https',any())
-http_lib.erl:424: The variable _ can never match since previous clauses completely covered the type any()
-http_lib.erl:438: The variable _ can never match since previous clauses completely covered the type any()
+http_lib.erl:286: The call http_lib:close('ip_comm' | {'ssl',_},port() | {'sslsocket',_,_}) will never return since it differs in the 1st argument from the success typing arguments: ('http' | 'https',port() | {'sslsocket',_,pid() | {_,{'config',_,_,_,_,{_,_,_,_}}} | {'sslsocket',_,pid() | {'sslsocket',_,pid() | {_,_,_}}}})
+http_lib.erl:415: The pattern 61 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}
+http_lib.erl:417: The pattern 59 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}
+http_lib.erl:420: The pattern 13 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}
+http_lib.erl:424: The variable _ can never match since previous clauses completely covered the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}
+http_lib.erl:428: Function read_chunk_ext_val/6 will never be called
+http_lib.erl:444: The pattern 10 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}
+http_lib.erl:552: Call to missing or unexported function ssl:accept/2
http_lib.erl:99: Function getHeaderValue/2 will never be called
httpc_handler.erl:660: Function exit_session_ok/2 has no local return
httpc_manager.erl:145: The pattern {ErrorReply, State2} can never match the type {{'ok',number()},number(),#state{reqid::number()}}
@@ -21,11 +26,14 @@ httpd_manager.erl:885: The pattern {'EXIT', Reason} can never match since previo
httpd_manager.erl:919: Function auth_status/1 will never be called
httpd_manager.erl:926: Function sec_status/1 will never be called
httpd_manager.erl:933: Function acceptor_status/1 will never be called
-httpd_request_handler.erl:374: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 66 | 98 | 100 | 103 | 105 | 111 | 116 | 121,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
-httpd_request_handler.erl:378: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
-httpd_request_handler.erl:401: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
+httpd_request_handler.erl:374: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 66 | 98 | 100 | 103 | 105 | 111 | 116 | 121,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_},socket::port() | {'sslsocket',_,_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
+httpd_request_handler.erl:378: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_},socket::port() | {'sslsocket',_,_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
+httpd_request_handler.erl:401: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_},socket::port() | {'sslsocket',_,_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
+httpd_request_handler.erl:489: The variable Other can never match since previous clauses completely covered the type {'error',_} | {'ok','http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | {'http_request','DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),'*' | binary() | string() | {'abs_path',binary() | [any()]} | {'scheme',binary() | [any()],binary() | [any()]} | {'absoluteURI','http' | 'https',binary() | [any()],'undefined' | non_neg_integer(),binary() | [any()]},{non_neg_integer(),non_neg_integer()}} | {'http_response',{non_neg_integer(),non_neg_integer()},integer(),binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}}
httpd_request_handler.erl:644: The call lists:reverse(Fields0::{'error',_} | {'ok',_}) will never return since it differs in the 1st argument from the success typing arguments: ([any()])
httpd_request_handler.erl:645: Function will never be called
+httpd_socket.erl:129: Call to missing or unexported function ssl:accept/2
+httpd_socket.erl:49: The pattern {'ok', _} can never match the type {'error',_}
httpd_sup.erl:63: The variable Else can never match since previous clauses completely covered the type {'error',_} | {'ok',[any()],_,_}
httpd_sup.erl:88: The pattern {'error', Reason} can never match the type {'ok',_,_}
httpd_sup.erl:92: The variable Else can never match since previous clauses completely covered the type {'ok',_,_}
diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/mnesia b/lib/dialyzer/test/r9c_SUITE_data/results/mnesia
index b0f4d12ae5..2be71ac7d7 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/results/mnesia
+++ b/lib/dialyzer/test/r9c_SUITE_data/results/mnesia
@@ -6,8 +6,6 @@ mnesia_bup.erl:111: The created fun has no local return
mnesia_bup.erl:574: Function fallback_receiver/2 has no local return
mnesia_bup.erl:967: Function uninstall_fallback_master/2 has no local return
mnesia_checkpoint.erl:1014: The variable Error can never match since previous clauses completely covered the type {'ok',#checkpoint_args{nodes::[any()],retainers::[any(),...]}}
-mnesia_checkpoint.erl:1209: Function system_continue/3 has no local return
-mnesia_checkpoint.erl:792: Function retainer_loop/1 has no local return
mnesia_checkpoint.erl:894: The call sys:handle_system_msg(Msg::any(),From::any(),'no_parent','mnesia_checkpoint',[],Cp::#checkpoint_args{}) breaks the contract (Msg,From,Parent,Module,Debug,Misc) -> Void when is_subtype(Msg,term()), is_subtype(From,{pid(),Tag::_}), is_subtype(Parent,pid()), is_subtype(Module,module()), is_subtype(Debug,[dbg_opt()]), is_subtype(Misc,term()), is_subtype(Void,term())
mnesia_controller.erl:1666: The variable Tab can never match since previous clauses completely covered the type [any()]
mnesia_controller.erl:1679: The pattern {'stop', Reason, Reply, State2} can never match the type {'noreply',_} | {'reply',_,_} | {'stop','shutdown',#state{}}
diff --git a/lib/dialyzer/test/small_SUITE_data/results/common_eunit b/lib/dialyzer/test/small_SUITE_data/results/common_eunit
new file mode 100644
index 0000000000..bb5fd1c9ac
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/common_eunit
@@ -0,0 +1,2 @@
+
+common_eunit.erl:57: The created fun has no local return
diff --git a/lib/dialyzer/test/small_SUITE_data/results/comparisons b/lib/dialyzer/test/small_SUITE_data/results/comparisons
new file mode 100644
index 0000000000..642585d25e
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/comparisons
@@ -0,0 +1,153 @@
+
+comparisons.erl:100: The pattern 'true' can never match the type 'false'
+comparisons.erl:101: The pattern 'true' can never match the type 'false'
+comparisons.erl:102: The pattern 'false' can never match the type 'true'
+comparisons.erl:103: The pattern 'false' can never match the type 'true'
+comparisons.erl:104: The pattern 'true' can never match the type 'false'
+comparisons.erl:105: The pattern 'true' can never match the type 'false'
+comparisons.erl:107: The pattern 'true' can never match the type 'false'
+comparisons.erl:108: The pattern 'true' can never match the type 'false'
+comparisons.erl:109: The pattern 'false' can never match the type 'true'
+comparisons.erl:110: The pattern 'false' can never match the type 'true'
+comparisons.erl:111: The pattern 'true' can never match the type 'false'
+comparisons.erl:112: The pattern 'true' can never match the type 'false'
+comparisons.erl:113: The pattern 'false' can never match the type 'true'
+comparisons.erl:114: The pattern 'false' can never match the type 'true'
+comparisons.erl:115: The pattern 'true' can never match the type 'false'
+comparisons.erl:116: The pattern 'true' can never match the type 'false'
+comparisons.erl:117: The pattern 'false' can never match the type 'true'
+comparisons.erl:118: The pattern 'false' can never match the type 'true'
+comparisons.erl:123: The pattern 'false' can never match the type 'true'
+comparisons.erl:124: The pattern 'false' can never match the type 'true'
+comparisons.erl:125: The pattern 'true' can never match the type 'false'
+comparisons.erl:126: The pattern 'true' can never match the type 'false'
+comparisons.erl:127: The pattern 'false' can never match the type 'true'
+comparisons.erl:128: The pattern 'false' can never match the type 'true'
+comparisons.erl:129: The pattern 'true' can never match the type 'false'
+comparisons.erl:130: The pattern 'true' can never match the type 'false'
+comparisons.erl:132: The pattern 'true' can never match the type 'false'
+comparisons.erl:133: The pattern 'true' can never match the type 'false'
+comparisons.erl:134: The pattern 'false' can never match the type 'true'
+comparisons.erl:135: The pattern 'false' can never match the type 'true'
+comparisons.erl:136: The pattern 'true' can never match the type 'false'
+comparisons.erl:137: The pattern 'true' can never match the type 'false'
+comparisons.erl:138: The pattern 'false' can never match the type 'true'
+comparisons.erl:139: The pattern 'false' can never match the type 'true'
+comparisons.erl:140: The pattern 'true' can never match the type 'false'
+comparisons.erl:141: The pattern 'true' can never match the type 'false'
+comparisons.erl:142: The pattern 'false' can never match the type 'true'
+comparisons.erl:143: The pattern 'false' can never match the type 'true'
+comparisons.erl:144: The pattern 'true' can never match the type 'false'
+comparisons.erl:145: The pattern 'true' can never match the type 'false'
+comparisons.erl:146: The pattern 'false' can never match the type 'true'
+comparisons.erl:147: The pattern 'false' can never match the type 'true'
+comparisons.erl:152: The pattern 'false' can never match the type 'true'
+comparisons.erl:153: The pattern 'false' can never match the type 'true'
+comparisons.erl:154: The pattern 'true' can never match the type 'false'
+comparisons.erl:155: The pattern 'true' can never match the type 'false'
+comparisons.erl:157: The pattern 'true' can never match the type 'false'
+comparisons.erl:158: The pattern 'true' can never match the type 'false'
+comparisons.erl:159: The pattern 'false' can never match the type 'true'
+comparisons.erl:160: The pattern 'false' can never match the type 'true'
+comparisons.erl:161: The pattern 'true' can never match the type 'false'
+comparisons.erl:162: The pattern 'true' can never match the type 'false'
+comparisons.erl:163: The pattern 'false' can never match the type 'true'
+comparisons.erl:164: The pattern 'false' can never match the type 'true'
+comparisons.erl:165: The pattern 'true' can never match the type 'false'
+comparisons.erl:166: The pattern 'true' can never match the type 'false'
+comparisons.erl:167: The pattern 'false' can never match the type 'true'
+comparisons.erl:168: The pattern 'false' can never match the type 'true'
+comparisons.erl:169: The pattern 'true' can never match the type 'false'
+comparisons.erl:170: The pattern 'true' can never match the type 'false'
+comparisons.erl:171: The pattern 'false' can never match the type 'true'
+comparisons.erl:172: The pattern 'false' can never match the type 'true'
+comparisons.erl:173: The pattern 'true' can never match the type 'false'
+comparisons.erl:174: The pattern 'true' can never match the type 'false'
+comparisons.erl:175: The pattern 'false' can never match the type 'true'
+comparisons.erl:176: The pattern 'false' can never match the type 'true'
+comparisons.erl:186: The pattern 'false' can never match the type 'true'
+comparisons.erl:187: The pattern 'false' can never match the type 'true'
+comparisons.erl:188: The pattern 'true' can never match the type 'false'
+comparisons.erl:189: The pattern 'true' can never match the type 'false'
+comparisons.erl:190: The pattern 'false' can never match the type 'true'
+comparisons.erl:191: The pattern 'false' can never match the type 'true'
+comparisons.erl:192: The pattern 'true' can never match the type 'false'
+comparisons.erl:193: The pattern 'true' can never match the type 'false'
+comparisons.erl:203: The pattern 'false' can never match the type 'true'
+comparisons.erl:204: The pattern 'false' can never match the type 'true'
+comparisons.erl:205: The pattern 'true' can never match the type 'false'
+comparisons.erl:206: The pattern 'true' can never match the type 'false'
+comparisons.erl:208: The pattern 'true' can never match the type 'false'
+comparisons.erl:209: The pattern 'true' can never match the type 'false'
+comparisons.erl:210: The pattern 'false' can never match the type 'true'
+comparisons.erl:211: The pattern 'false' can never match the type 'true'
+comparisons.erl:221: The pattern 'true' can never match the type 'false'
+comparisons.erl:222: The pattern 'true' can never match the type 'false'
+comparisons.erl:223: The pattern 'false' can never match the type 'true'
+comparisons.erl:224: The pattern 'false' can never match the type 'true'
+comparisons.erl:225: The pattern 'true' can never match the type 'false'
+comparisons.erl:226: The pattern 'true' can never match the type 'false'
+comparisons.erl:227: The pattern 'false' can never match the type 'true'
+comparisons.erl:228: The pattern 'false' can never match the type 'true'
+comparisons.erl:242: The pattern 'false' can never match the type 'true'
+comparisons.erl:243: The pattern 'false' can never match the type 'true'
+comparisons.erl:244: The pattern 'true' can never match the type 'false'
+comparisons.erl:245: The pattern 'true' can never match the type 'false'
+comparisons.erl:246: The pattern 'false' can never match the type 'true'
+comparisons.erl:247: The pattern 'false' can never match the type 'true'
+comparisons.erl:248: The pattern 'true' can never match the type 'false'
+comparisons.erl:249: The pattern 'true' can never match the type 'false'
+comparisons.erl:251: The pattern 'true' can never match the type 'false'
+comparisons.erl:252: The pattern 'true' can never match the type 'false'
+comparisons.erl:253: The pattern 'false' can never match the type 'true'
+comparisons.erl:254: The pattern 'false' can never match the type 'true'
+comparisons.erl:263: The pattern 'false' can never match the type 'true'
+comparisons.erl:264: The pattern 'false' can never match the type 'true'
+comparisons.erl:265: The pattern 'true' can never match the type 'false'
+comparisons.erl:266: The pattern 'true' can never match the type 'false'
+comparisons.erl:268: The pattern 'true' can never match the type 'false'
+comparisons.erl:269: The pattern 'true' can never match the type 'false'
+comparisons.erl:270: The pattern 'false' can never match the type 'true'
+comparisons.erl:271: The pattern 'false' can never match the type 'true'
+comparisons.erl:272: The pattern 'true' can never match the type 'false'
+comparisons.erl:273: The pattern 'true' can never match the type 'false'
+comparisons.erl:274: The pattern 'false' can never match the type 'true'
+comparisons.erl:275: The pattern 'false' can never match the type 'true'
+comparisons.erl:293: The pattern 'false' can never match the type 'true'
+comparisons.erl:294: The pattern 'false' can never match the type 'true'
+comparisons.erl:295: The pattern 'true' can never match the type 'false'
+comparisons.erl:296: The pattern 'true' can never match the type 'false'
+comparisons.erl:311: The pattern 'true' can never match the type 'false'
+comparisons.erl:312: The pattern 'true' can never match the type 'false'
+comparisons.erl:313: The pattern 'false' can never match the type 'true'
+comparisons.erl:314: The pattern 'false' can never match the type 'true'
+comparisons.erl:44: The pattern 'false' can never match the type 'true'
+comparisons.erl:45: The pattern 'false' can never match the type 'true'
+comparisons.erl:46: The pattern 'true' can never match the type 'false'
+comparisons.erl:47: The pattern 'true' can never match the type 'false'
+comparisons.erl:48: The pattern 'false' can never match the type 'true'
+comparisons.erl:49: The pattern 'false' can never match the type 'true'
+comparisons.erl:50: The pattern 'true' can never match the type 'false'
+comparisons.erl:51: The pattern 'true' can never match the type 'false'
+comparisons.erl:52: The pattern 'false' can never match the type 'true'
+comparisons.erl:53: The pattern 'false' can never match the type 'true'
+comparisons.erl:54: The pattern 'true' can never match the type 'false'
+comparisons.erl:55: The pattern 'true' can never match the type 'false'
+comparisons.erl:69: The pattern 'false' can never match the type 'true'
+comparisons.erl:70: The pattern 'false' can never match the type 'true'
+comparisons.erl:71: The pattern 'true' can never match the type 'false'
+comparisons.erl:72: The pattern 'true' can never match the type 'false'
+comparisons.erl:73: The pattern 'false' can never match the type 'true'
+comparisons.erl:74: The pattern 'false' can never match the type 'true'
+comparisons.erl:75: The pattern 'true' can never match the type 'false'
+comparisons.erl:76: The pattern 'true' can never match the type 'false'
+comparisons.erl:77: The pattern 'false' can never match the type 'true'
+comparisons.erl:78: The pattern 'false' can never match the type 'true'
+comparisons.erl:79: The pattern 'true' can never match the type 'false'
+comparisons.erl:80: The pattern 'true' can never match the type 'false'
+comparisons.erl:94: The pattern 'false' can never match the type 'true'
+comparisons.erl:95: The pattern 'false' can never match the type 'true'
+comparisons.erl:96: The pattern 'true' can never match the type 'false'
+comparisons.erl:97: The pattern 'true' can never match the type 'false'
+comparisons.erl:98: The pattern 'false' can never match the type 'true'
+comparisons.erl:99: The pattern 'false' can never match the type 'true'
diff --git a/lib/dialyzer/test/small_SUITE_data/results/failing_funs b/lib/dialyzer/test/small_SUITE_data/results/failing_funs
new file mode 100644
index 0000000000..a1fb22cbc6
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/failing_funs
@@ -0,0 +1,20 @@
+
+failing_funs.erl:101: The created fun has no local return
+failing_funs.erl:104: The created fun has no local return
+failing_funs.erl:127: The created fun has no local return
+failing_funs.erl:135: The created fun has no local return
+failing_funs.erl:138: The created fun has no local return
+failing_funs.erl:13: Function foo3/0 has no local return
+failing_funs.erl:13: The pattern 'b' can never match the type 'a'
+failing_funs.erl:161: The created fun has no local return
+failing_funs.erl:169: The created fun has no local return
+failing_funs.erl:172: The created fun has no local return
+failing_funs.erl:17: The pattern 'b' can never match the type 'a'
+failing_funs.erl:195: The created fun has no local return
+failing_funs.erl:203: The created fun has no local return
+failing_funs.erl:206: The created fun has no local return
+failing_funs.erl:229: The created fun has no local return
+failing_funs.erl:55: The created fun has no local return
+failing_funs.erl:62: The created fun has no local return
+failing_funs.erl:69: The created fun has no local return
+failing_funs.erl:76: The created fun has no local return
diff --git a/lib/dialyzer/test/small_SUITE_data/src/common_eunit.erl b/lib/dialyzer/test/small_SUITE_data/src/common_eunit.erl
new file mode 100644
index 0000000000..bca390068e
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/common_eunit.erl
@@ -0,0 +1,121 @@
+%%=====================================================================
+%% Program with an erroneous type declaration that caused dialyzer to
+%% go into an infinite loop. There are some comments that explain the
+%% symptoms and the culprit: the return of test_fun() is erroneous and
+%% its type should read
+%% fun((config()) -> test_rep() | [test_rep()])
+%% instead. But this should not throw dialyzer into an infinite loop.
+%% This concerned dialyzer in R14B02 (and probably prior).
+%%=====================================================================
+-module(common_eunit).
+
+-export([expand_cases/2]).
+
+-type test_name() :: atom() | {'group', atom()}.
+
+-type test_rep() :: {{atom(), atom(), arity()}, fun()}
+ | {'setup', fun(), fun()}
+ | {'setup', fun(), fun(), fun()}
+ | {atom(), test_rep()}
+ | {atom(), term(), test_rep()}.
+
+-type config() :: [proplists:property()].
+
+-type control() :: tuple() | atom().
+
+%% The combination of the following type and the (erroneous) spec for
+%% expand_cases/2 is the reason for the infinite loop in dialyzer.
+-type test_fun() :: fun((config()) -> test_rep()).
+
+%% If one comments out this spec the infinite loop disappears.
+-spec expand_cases(atom(), test_name() | [test_name()]) -> test_fun().
+expand_cases(Module, Cases) ->
+ if is_list(Cases) ->
+ TestFuns = [expand_case(Module, Case) || Case <- Cases],
+ fun(Config) -> [F(Config) || F <- TestFuns] end;
+ is_atom(Cases); is_tuple(Cases) ->
+ expand_cases(Module, [Cases])
+ end.
+
+-spec expand_case(atom(), test_name()) -> test_fun().
+expand_case(Module, CaseName) when is_atom(CaseName) ->
+ TestFun = fun(Config) ->
+ {{Module, CaseName, 1},
+ fun() -> apply(Module, CaseName, [Config]) end}
+ end,
+ setup_wrapper(Module, TestFun, {init_per_testcase, [CaseName]},
+ {end_per_testcase, [CaseName]});
+expand_case(Module, {group, GroupName}) ->
+ {Control, Cases} = group_specification(Module, GroupName),
+ TestFun = control_wrapper(Control, expand_cases(Module, Cases)),
+ setup_wrapper(Module, TestFun, {init_per_group, [GroupName]},
+ {end_per_group, [GroupName]}).
+
+-spec control_wrapper([control()], test_fun()) -> test_fun().
+control_wrapper([Control|T], TestFun0) ->
+ TestFun1 = control_wrapper(T, TestFun0),
+ fun(Config) ->
+ case Control of
+ parallel ->
+ {inparallel, TestFun1(Config)};
+ sequence ->
+ {inorder, TestFun1(Config)};
+ {timetrap, Time} ->
+ Seconds = case Time of
+ {hours, Hs} -> Hs * 60 * 60;
+ {minutes, Ms} -> Ms * 60;
+ {seconds, Ss} -> Ss;
+ MSs -> MSs / 1000
+ end,
+ {timeout, Seconds, TestFun1(Config)};
+ C when is_atom(C) ->
+ {C, TestFun1(Config)};
+ {C, Arg} ->
+ {C, Arg, TestFun1(Config)}
+ end
+ end;
+control_wrapper([], TestFun) ->
+ TestFun.
+
+-spec setup_wrapper(atom(), test_fun(), Callback, Callback) -> test_fun()
+ when Callback :: {atom(), list()}.
+setup_wrapper(Module, TestFun, {Setup, SA}, {Cleanup, CA}) ->
+ case erlang:function_exported(Module, Setup, length(SA) + 1) of
+ true ->
+ case erlang:function_exported(Module, Cleanup, length(CA) + 1) of
+ true ->
+ fun(Config0) ->
+ {setup,
+ fun() ->
+ apply(Module, Setup, SA ++ [Config0])
+ end,
+ fun(Config1) ->
+ apply(Module, Cleanup, CA ++ [Config1])
+ end,
+ TestFun}
+ end;
+ false ->
+ fun(Config) ->
+ {setup,
+ fun() ->
+ apply(Module, Setup, SA ++ [Config])
+ end,
+ TestFun}
+ end
+ end;
+ false ->
+ TestFun
+ end.
+
+-spec group_specification(atom(), atom()) -> {[control()], [test_name()]}.
+group_specification(Module, GroupName) ->
+ case lists:keyfind(GroupName, 1, Module:groups()) of
+ {_, Control, Cases} when is_list(Control), is_list(Cases) ->
+ {Control, Cases};
+ {_, Cases} when is_list(Cases) ->
+ {[], Cases};
+ false ->
+ exit({missing_group, GroupName});
+ _ ->
+ exit({bad_group_spec, GroupName})
+ end.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/comparisons.erl b/lib/dialyzer/test/small_SUITE_data/src/comparisons.erl
new file mode 100644
index 0000000000..70e3cb6af4
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/comparisons.erl
@@ -0,0 +1,322 @@
+-module(comparisons).
+
+-compile(export_all).
+
+-define(r, get(r)).
+
+integer() -> integer(?r).
+integer(X) when is_integer(X) -> X.
+
+mfloat() -> float(?r).
+mfloat(X) when is_float(X) -> X.
+
+atom() -> atom(?r).
+atom(X) when is_atom(X) -> X.
+
+tuple() -> tuple(?r).
+tuple(X) when is_tuple(X) -> X.
+
+list() -> list(?r).
+list(X) when is_list(X) -> X.
+
+i() -> integer().
+f() -> mfloat().
+n() -> case ?r of 1 -> i(); 2 -> f() end.
+a() -> atom().
+t() -> tuple().
+l() -> list().
+na() -> case ?r of 1 -> n(); 2 -> a() end.
+at() -> case ?r of 1 -> t(); 2 -> a() end.
+tl() -> case ?r of 1 -> t(); 2 -> l() end.
+
+test_i_ll_i() -> case i() < i() of true -> maybe; false -> maybe_too end.
+test_i_le_i() -> case i() =< i() of true -> maybe; false -> maybe_too end.
+test_i_gg_i() -> case i() > i() of true -> maybe; false -> maybe_too end.
+test_i_ge_i() -> case i() >= i() of true -> maybe; false -> maybe_too end.
+test_i_ll_f() -> case i() < f() of true -> maybe; false -> maybe_too end.
+test_i_le_f() -> case i() =< f() of true -> maybe; false -> maybe_too end.
+test_i_gg_f() -> case i() > f() of true -> maybe; false -> maybe_too end.
+test_i_ge_f() -> case i() >= f() of true -> maybe; false -> maybe_too end.
+test_i_ll_n() -> case i() < n() of true -> maybe; false -> maybe_too end.
+test_i_le_n() -> case i() =< n() of true -> maybe; false -> maybe_too end.
+test_i_gg_n() -> case i() > n() of true -> maybe; false -> maybe_too end.
+test_i_ge_n() -> case i() >= n() of true -> maybe; false -> maybe_too end.
+test_i_ll_a() -> case i() < a() of true -> always; false -> never end.
+test_i_le_a() -> case i() =< a() of true -> always; false -> never end.
+test_i_gg_a() -> case i() > a() of true -> never; false -> always end.
+test_i_ge_a() -> case i() >= a() of true -> never; false -> always end.
+test_i_ll_t() -> case i() < t() of true -> always; false -> never end.
+test_i_le_t() -> case i() =< t() of true -> always; false -> never end.
+test_i_gg_t() -> case i() > t() of true -> never; false -> always end.
+test_i_ge_t() -> case i() >= t() of true -> never; false -> always end.
+test_i_ll_l() -> case i() < l() of true -> always; false -> never end.
+test_i_le_l() -> case i() =< l() of true -> always; false -> never end.
+test_i_gg_l() -> case i() > l() of true -> never; false -> always end.
+test_i_ge_l() -> case i() >= l() of true -> never; false -> always end.
+
+test_f_ll_i() -> case f() < i() of true -> maybe; false -> maybe_too end.
+test_f_le_i() -> case f() =< i() of true -> maybe; false -> maybe_too end.
+test_f_gg_i() -> case f() > i() of true -> maybe; false -> maybe_too end.
+test_f_ge_i() -> case f() >= i() of true -> maybe; false -> maybe_too end.
+test_f_ll_f() -> case f() < f() of true -> maybe; false -> maybe_too end.
+test_f_le_f() -> case f() =< f() of true -> maybe; false -> maybe_too end.
+test_f_gg_f() -> case f() > f() of true -> maybe; false -> maybe_too end.
+test_f_ge_f() -> case f() >= f() of true -> maybe; false -> maybe_too end.
+test_f_ll_n() -> case f() < n() of true -> maybe; false -> maybe_too end.
+test_f_le_n() -> case f() =< n() of true -> maybe; false -> maybe_too end.
+test_f_gg_n() -> case f() > n() of true -> maybe; false -> maybe_too end.
+test_f_ge_n() -> case f() >= n() of true -> maybe; false -> maybe_too end.
+test_f_ll_a() -> case f() < a() of true -> always; false -> never end.
+test_f_le_a() -> case f() =< a() of true -> always; false -> never end.
+test_f_gg_a() -> case f() > a() of true -> never; false -> always end.
+test_f_ge_a() -> case f() >= a() of true -> never; false -> always end.
+test_f_ll_t() -> case f() < t() of true -> always; false -> never end.
+test_f_le_t() -> case f() =< t() of true -> always; false -> never end.
+test_f_gg_t() -> case f() > t() of true -> never; false -> always end.
+test_f_ge_t() -> case f() >= t() of true -> never; false -> always end.
+test_f_ll_l() -> case f() < l() of true -> always; false -> never end.
+test_f_le_l() -> case f() =< l() of true -> always; false -> never end.
+test_f_gg_l() -> case f() > l() of true -> never; false -> always end.
+test_f_ge_l() -> case f() >= l() of true -> never; false -> always end.
+
+test_n_ll_i() -> case n() < i() of true -> maybe; false -> maybe_too end.
+test_n_le_i() -> case n() =< i() of true -> maybe; false -> maybe_too end.
+test_n_gg_i() -> case n() > i() of true -> maybe; false -> maybe_too end.
+test_n_ge_i() -> case n() >= i() of true -> maybe; false -> maybe_too end.
+test_n_ll_f() -> case n() < f() of true -> maybe; false -> maybe_too end.
+test_n_le_f() -> case n() =< f() of true -> maybe; false -> maybe_too end.
+test_n_gg_f() -> case n() > f() of true -> maybe; false -> maybe_too end.
+test_n_ge_f() -> case n() >= f() of true -> maybe; false -> maybe_too end.
+test_n_ll_n() -> case n() < n() of true -> maybe; false -> maybe_too end.
+test_n_le_n() -> case n() =< n() of true -> maybe; false -> maybe_too end.
+test_n_gg_n() -> case n() > n() of true -> maybe; false -> maybe_too end.
+test_n_ge_n() -> case n() >= n() of true -> maybe; false -> maybe_too end.
+test_n_ll_a() -> case n() < a() of true -> always; false -> never end.
+test_n_le_a() -> case n() =< a() of true -> always; false -> never end.
+test_n_gg_a() -> case n() > a() of true -> never; false -> always end.
+test_n_ge_a() -> case n() >= a() of true -> never; false -> always end.
+test_n_ll_t() -> case n() < t() of true -> always; false -> never end.
+test_n_le_t() -> case n() =< t() of true -> always; false -> never end.
+test_n_gg_t() -> case n() > t() of true -> never; false -> always end.
+test_n_ge_t() -> case n() >= t() of true -> never; false -> always end.
+test_n_ll_l() -> case n() < l() of true -> always; false -> never end.
+test_n_le_l() -> case n() =< l() of true -> always; false -> never end.
+test_n_gg_l() -> case n() > l() of true -> never; false -> always end.
+test_n_ge_l() -> case n() >= l() of true -> never; false -> always end.
+
+test_a_ll_i() -> case a() < i() of true -> never; false -> always end.
+test_a_le_i() -> case a() =< i() of true -> never; false -> always end.
+test_a_gg_i() -> case a() > i() of true -> always; false -> never end.
+test_a_ge_i() -> case a() >= i() of true -> always; false -> never end.
+test_a_ll_f() -> case a() < f() of true -> never; false -> always end.
+test_a_le_f() -> case a() =< f() of true -> never; false -> always end.
+test_a_gg_f() -> case a() > f() of true -> always; false -> never end.
+test_a_ge_f() -> case a() >= f() of true -> always; false -> never end.
+test_a_ll_n() -> case a() < n() of true -> never; false -> always end.
+test_a_le_n() -> case a() =< n() of true -> never; false -> always end.
+test_a_gg_n() -> case a() > n() of true -> always; false -> never end.
+test_a_ge_n() -> case a() >= n() of true -> always; false -> never end.
+test_a_ll_a() -> case a() < a() of true -> maybe; false -> maybe_too end.
+test_a_le_a() -> case a() =< a() of true -> maybe; false -> maybe_too end.
+test_a_gg_a() -> case a() > a() of true -> maybe; false -> maybe_too end.
+test_a_ge_a() -> case a() >= a() of true -> maybe; false -> maybe_too end.
+test_a_ll_t() -> case a() < t() of true -> always; false -> never end.
+test_a_le_t() -> case a() =< t() of true -> always; false -> never end.
+test_a_gg_t() -> case a() > t() of true -> never; false -> always end.
+test_a_ge_t() -> case a() >= t() of true -> never; false -> always end.
+test_a_ll_l() -> case a() < l() of true -> always; false -> never end.
+test_a_le_l() -> case a() =< l() of true -> always; false -> never end.
+test_a_gg_l() -> case a() > l() of true -> never; false -> always end.
+test_a_ge_l() -> case a() >= l() of true -> never; false -> always end.
+
+test_t_ll_i() -> case t() < i() of true -> never; false -> always end.
+test_t_le_i() -> case t() =< i() of true -> never; false -> always end.
+test_t_gg_i() -> case t() > i() of true -> always; false -> never end.
+test_t_ge_i() -> case t() >= i() of true -> always; false -> never end.
+test_t_ll_f() -> case t() < f() of true -> never; false -> always end.
+test_t_le_f() -> case t() =< f() of true -> never; false -> always end.
+test_t_gg_f() -> case t() > f() of true -> always; false -> never end.
+test_t_ge_f() -> case t() >= f() of true -> always; false -> never end.
+test_t_ll_n() -> case t() < n() of true -> never; false -> always end.
+test_t_le_n() -> case t() =< n() of true -> never; false -> always end.
+test_t_gg_n() -> case t() > n() of true -> always; false -> never end.
+test_t_ge_n() -> case t() >= n() of true -> always; false -> never end.
+test_t_ll_a() -> case t() < a() of true -> never; false -> always end.
+test_t_le_a() -> case t() =< a() of true -> never; false -> always end.
+test_t_gg_a() -> case t() > a() of true -> always; false -> never end.
+test_t_ge_a() -> case t() >= a() of true -> always; false -> never end.
+test_t_ll_t() -> case t() < t() of true -> maybe; false -> maybe_too end.
+test_t_le_t() -> case t() =< t() of true -> maybe; false -> maybe_too end.
+test_t_gg_t() -> case t() > t() of true -> maybe; false -> maybe_too end.
+test_t_ge_t() -> case t() >= t() of true -> maybe; false -> maybe_too end.
+test_t_ll_l() -> case t() < l() of true -> always; false -> never end.
+test_t_le_l() -> case t() =< l() of true -> always; false -> never end.
+test_t_gg_l() -> case t() > l() of true -> never; false -> always end.
+test_t_ge_l() -> case t() >= l() of true -> never; false -> always end.
+
+test_l_ll_i() -> case l() < i() of true -> never; false -> always end.
+test_l_le_i() -> case l() =< i() of true -> never; false -> always end.
+test_l_gg_i() -> case l() > i() of true -> always; false -> never end.
+test_l_ge_i() -> case l() >= i() of true -> always; false -> never end.
+test_l_ll_f() -> case l() < f() of true -> never; false -> always end.
+test_l_le_f() -> case l() =< f() of true -> never; false -> always end.
+test_l_gg_f() -> case l() > f() of true -> always; false -> never end.
+test_l_ge_f() -> case l() >= f() of true -> always; false -> never end.
+test_l_ll_n() -> case l() < n() of true -> never; false -> always end.
+test_l_le_n() -> case l() =< n() of true -> never; false -> always end.
+test_l_gg_n() -> case l() > n() of true -> always; false -> never end.
+test_l_ge_n() -> case l() >= n() of true -> always; false -> never end.
+test_l_ll_a() -> case l() < a() of true -> never; false -> always end.
+test_l_le_a() -> case l() =< a() of true -> never; false -> always end.
+test_l_gg_a() -> case l() > a() of true -> always; false -> never end.
+test_l_ge_a() -> case l() >= a() of true -> always; false -> never end.
+test_l_ll_t() -> case l() < t() of true -> never; false -> always end.
+test_l_le_t() -> case l() =< t() of true -> never; false -> always end.
+test_l_gg_t() -> case l() > t() of true -> always; false -> never end.
+test_l_ge_t() -> case l() >= t() of true -> always; false -> never end.
+test_l_ll_l() -> case l() < l() of true -> maybe; false -> maybe_too end.
+test_l_le_l() -> case l() =< l() of true -> maybe; false -> maybe_too end.
+test_l_gg_l() -> case l() > l() of true -> maybe; false -> maybe_too end.
+test_l_ge_l() -> case l() >= l() of true -> maybe; false -> maybe_too end.
+
+test_n_ll_na() -> case n() < na() of true -> maybe; false -> maybe_too end.
+test_n_le_na() -> case n() =< na() of true -> maybe; false -> maybe_too end.
+test_n_gg_na() -> case n() > na() of true -> maybe; false -> maybe_too end.
+test_n_ge_na() -> case n() >= na() of true -> maybe; false -> maybe_too end.
+test_n_ll_at() -> case n() < at() of true -> always; false -> never end.
+test_n_le_at() -> case n() =< at() of true -> always; false -> never end.
+test_n_gg_at() -> case n() > at() of true -> never; false -> always end.
+test_n_ge_at() -> case n() >= at() of true -> never; false -> always end.
+test_n_ll_tl() -> case n() < tl() of true -> always; false -> never end.
+test_n_le_tl() -> case n() =< tl() of true -> always; false -> never end.
+test_n_gg_tl() -> case n() > tl() of true -> never; false -> always end.
+test_n_ge_tl() -> case n() >= tl() of true -> never; false -> always end.
+
+test_a_ll_na() -> case a() < na() of true -> maybe; false -> maybe_too end.
+test_a_le_na() -> case a() =< na() of true -> maybe; false -> maybe_too end.
+test_a_gg_na() -> case a() > na() of true -> maybe; false -> maybe_too end.
+test_a_ge_na() -> case a() >= na() of true -> maybe; false -> maybe_too end.
+test_a_ll_at() -> case a() < at() of true -> maybe; false -> maybe_too end.
+test_a_le_at() -> case a() =< at() of true -> maybe; false -> maybe_too end.
+test_a_gg_at() -> case a() > at() of true -> maybe; false -> maybe_too end.
+test_a_ge_at() -> case a() >= at() of true -> maybe; false -> maybe_too end.
+test_a_ll_tl() -> case a() < tl() of true -> always; false -> never end.
+test_a_le_tl() -> case a() =< tl() of true -> always; false -> never end.
+test_a_gg_tl() -> case a() > tl() of true -> never; false -> always end.
+test_a_ge_tl() -> case a() >= tl() of true -> never; false -> always end.
+
+test_t_ll_na() -> case t() < na() of true -> never; false -> always end.
+test_t_le_na() -> case t() =< na() of true -> never; false -> always end.
+test_t_gg_na() -> case t() > na() of true -> always; false -> never end.
+test_t_ge_na() -> case t() >= na() of true -> always; false -> never end.
+test_t_ll_at() -> case t() < at() of true -> maybe; false -> maybe_too end.
+test_t_le_at() -> case t() =< at() of true -> maybe; false -> maybe_too end.
+test_t_gg_at() -> case t() > at() of true -> maybe; false -> maybe_too end.
+test_t_ge_at() -> case t() >= at() of true -> maybe; false -> maybe_too end.
+test_t_ll_tl() -> case t() < tl() of true -> maybe; false -> maybe_too end.
+test_t_le_tl() -> case t() =< tl() of true -> maybe; false -> maybe_too end.
+test_t_gg_tl() -> case t() > tl() of true -> maybe; false -> maybe_too end.
+test_t_ge_tl() -> case t() >= tl() of true -> maybe; false -> maybe_too end.
+
+test_l_ll_na() -> case l() < na() of true -> never; false -> always end.
+test_l_le_na() -> case l() =< na() of true -> never; false -> always end.
+test_l_gg_na() -> case l() > na() of true -> always; false -> never end.
+test_l_ge_na() -> case l() >= na() of true -> always; false -> never end.
+test_l_ll_at() -> case l() < at() of true -> never; false -> always end.
+test_l_le_at() -> case l() =< at() of true -> never; false -> always end.
+test_l_gg_at() -> case l() > at() of true -> always; false -> never end.
+test_l_ge_at() -> case l() >= at() of true -> always; false -> never end.
+test_l_ll_tl() -> case l() < tl() of true -> maybe; false -> maybe_too end.
+test_l_le_tl() -> case l() =< tl() of true -> maybe; false -> maybe_too end.
+test_l_gg_tl() -> case l() > tl() of true -> maybe; false -> maybe_too end.
+test_l_ge_tl() -> case l() >= tl() of true -> maybe; false -> maybe_too end.
+
+test_na_ll_n() -> case na() < n() of true -> maybe; false -> maybe_too end.
+test_na_le_n() -> case na() =< n() of true -> maybe; false -> maybe_too end.
+test_na_gg_n() -> case na() > n() of true -> maybe; false -> maybe_too end.
+test_na_ge_n() -> case na() >= n() of true -> maybe; false -> maybe_too end.
+test_na_ll_a() -> case na() < a() of true -> maybe; false -> maybe_too end.
+test_na_le_a() -> case na() =< a() of true -> maybe; false -> maybe_too end.
+test_na_gg_a() -> case na() > a() of true -> maybe; false -> maybe_too end.
+test_na_ge_a() -> case na() >= a() of true -> maybe; false -> maybe_too end.
+test_na_ll_t() -> case na() < t() of true -> always; false -> never end.
+test_na_le_t() -> case na() =< t() of true -> always; false -> never end.
+test_na_gg_t() -> case na() > t() of true -> never; false -> always end.
+test_na_ge_t() -> case na() >= t() of true -> never; false -> always end.
+test_na_ll_l() -> case na() < l() of true -> always; false -> never end.
+test_na_le_l() -> case na() =< l() of true -> always; false -> never end.
+test_na_gg_l() -> case na() > l() of true -> never; false -> always end.
+test_na_ge_l() -> case na() >= l() of true -> never; false -> always end.
+
+test_at_ll_n() -> case at() < n() of true -> never; false -> always end.
+test_at_le_n() -> case at() =< n() of true -> never; false -> always end.
+test_at_gg_n() -> case at() > n() of true -> always; false -> never end.
+test_at_ge_n() -> case at() >= n() of true -> always; false -> never end.
+test_at_ll_a() -> case at() < a() of true -> maybe; false -> maybe_too end.
+test_at_le_a() -> case at() =< a() of true -> maybe; false -> maybe_too end.
+test_at_gg_a() -> case at() > a() of true -> maybe; false -> maybe_too end.
+test_at_ge_a() -> case at() >= a() of true -> maybe; false -> maybe_too end.
+test_at_ll_t() -> case at() < t() of true -> maybe; false -> maybe_too end.
+test_at_le_t() -> case at() =< t() of true -> maybe; false -> maybe_too end.
+test_at_gg_t() -> case at() > t() of true -> maybe; false -> maybe_too end.
+test_at_ge_t() -> case at() >= t() of true -> maybe; false -> maybe_too end.
+test_at_ll_l() -> case at() < l() of true -> always; false -> never end.
+test_at_le_l() -> case at() =< l() of true -> always; false -> never end.
+test_at_gg_l() -> case at() > l() of true -> never; false -> always end.
+test_at_ge_l() -> case at() >= l() of true -> never; false -> always end.
+
+test_tl_ll_n() -> case tl() < n() of true -> never; false -> always end.
+test_tl_le_n() -> case tl() =< n() of true -> never; false -> always end.
+test_tl_gg_n() -> case tl() > n() of true -> always; false -> never end.
+test_tl_ge_n() -> case tl() >= n() of true -> always; false -> never end.
+test_tl_ll_a() -> case tl() < a() of true -> never; false -> always end.
+test_tl_le_a() -> case tl() =< a() of true -> never; false -> always end.
+test_tl_gg_a() -> case tl() > a() of true -> always; false -> never end.
+test_tl_ge_a() -> case tl() >= a() of true -> always; false -> never end.
+test_tl_ll_t() -> case tl() < t() of true -> maybe; false -> maybe_too end.
+test_tl_le_t() -> case tl() =< t() of true -> maybe; false -> maybe_too end.
+test_tl_gg_t() -> case tl() > t() of true -> maybe; false -> maybe_too end.
+test_tl_ge_t() -> case tl() >= t() of true -> maybe; false -> maybe_too end.
+test_tl_ll_l() -> case tl() < l() of true -> maybe; false -> maybe_too end.
+test_tl_le_l() -> case tl() =< l() of true -> maybe; false -> maybe_too end.
+test_tl_gg_l() -> case tl() > l() of true -> maybe; false -> maybe_too end.
+test_tl_ge_l() -> case tl() >= l() of true -> maybe; false -> maybe_too end.
+
+test_na_ll_na() -> case na() < na() of true -> maybe; false -> maybe_too end.
+test_na_le_na() -> case na() =< na() of true -> maybe; false -> maybe_too end.
+test_na_gg_na() -> case na() > na() of true -> maybe; false -> maybe_too end.
+test_na_ge_na() -> case na() >= na() of true -> maybe; false -> maybe_too end.
+test_na_ll_at() -> case na() < at() of true -> maybe; false -> maybe_too end.
+test_na_le_at() -> case na() =< at() of true -> maybe; false -> maybe_too end.
+test_na_gg_at() -> case na() > at() of true -> maybe; false -> maybe_too end.
+test_na_ge_at() -> case na() >= at() of true -> maybe; false -> maybe_too end.
+test_na_ll_tl() -> case na() < tl() of true -> always; false -> never end.
+test_na_le_tl() -> case na() =< tl() of true -> always; false -> never end.
+test_na_gg_tl() -> case na() > tl() of true -> never; false -> always end.
+test_na_ge_tl() -> case na() >= tl() of true -> never; false -> always end.
+
+test_at_ll_na() -> case at() < na() of true -> maybe; false -> maybe_too end.
+test_at_le_na() -> case at() =< na() of true -> maybe; false -> maybe_too end.
+test_at_gg_na() -> case at() > na() of true -> maybe; false -> maybe_too end.
+test_at_ge_na() -> case at() >= na() of true -> maybe; false -> maybe_too end.
+test_at_ll_at() -> case at() < at() of true -> maybe; false -> maybe_too end.
+test_at_le_at() -> case at() =< at() of true -> maybe; false -> maybe_too end.
+test_at_gg_at() -> case at() > at() of true -> maybe; false -> maybe_too end.
+test_at_ge_at() -> case at() >= at() of true -> maybe; false -> maybe_too end.
+test_at_ll_tl() -> case at() < tl() of true -> maybe; false -> maybe_too end.
+test_at_le_tl() -> case at() =< tl() of true -> maybe; false -> maybe_too end.
+test_at_gg_tl() -> case at() > tl() of true -> maybe; false -> maybe_too end.
+test_at_ge_tl() -> case at() >= tl() of true -> maybe; false -> maybe_too end.
+
+test_tl_ll_na() -> case tl() < na() of true -> never; false -> always end.
+test_tl_le_na() -> case tl() =< na() of true -> never; false -> always end.
+test_tl_gg_na() -> case tl() > na() of true -> always; false -> never end.
+test_tl_ge_na() -> case tl() >= na() of true -> always; false -> never end.
+test_tl_ll_at() -> case tl() < at() of true -> maybe; false -> maybe_too end.
+test_tl_le_at() -> case tl() =< at() of true -> maybe; false -> maybe_too end.
+test_tl_gg_at() -> case tl() > at() of true -> maybe; false -> maybe_too end.
+test_tl_ge_at() -> case tl() >= at() of true -> maybe; false -> maybe_too end.
+test_tl_ll_tl() -> case tl() < tl() of true -> maybe; false -> maybe_too end.
+test_tl_le_tl() -> case tl() =< tl() of true -> maybe; false -> maybe_too end.
+test_tl_gg_tl() -> case tl() > tl() of true -> maybe; false -> maybe_too end.
+test_tl_ge_tl() -> case tl() >= tl() of true -> maybe; false -> maybe_too end.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/failing_funs.erl b/lib/dialyzer/test/small_SUITE_data/src/failing_funs.erl
new file mode 100644
index 0000000000..1784c4a494
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/failing_funs.erl
@@ -0,0 +1,250 @@
+-module(failing_funs).
+
+-compile(export_all).
+
+% Crashes with system call. No spec.
+foo1() -> halt().
+
+% Crashes with system call. With spec.
+-spec foo2() -> no_return().
+foo2() -> halt().
+
+% Crashes on its own. No spec.
+foo3() -> case a of b -> ok end.
+
+% Crashes on its own. With spec.
+-spec foo4() -> no_return().
+foo4() -> case a of b -> ok end.
+
+% Creates fun that crashes with system call. No spec.
+foo5() -> fun() -> halt() end.
+
+% Creates fun that crashes with system call. With spec.
+-spec foo6() -> fun(() -> no_return()).
+foo6() -> fun() -> halt() end.
+
+% Creates fun from named fun that will crash. Neither have spec.
+foo7() -> fun foo1/0.
+
+% Creates fun from named fun that will crash. Has spec.
+-spec foo8() -> fun(() -> no_return()).
+foo8() -> fun foo1/0.
+
+% Creates fun from named fun that will crash. Named has spec.
+foo9() -> fun foo2/0.
+
+% Creates fun from named fun that will crash. Both have specs.
+-spec foo10() -> fun(() -> no_return()).
+foo10() -> fun foo2/0.
+
+% Creates fun from named fun that will crash. Neither have spec.
+foo11() -> fun foo3/0.
+
+% Creates fun from named fun that will crash. Has spec.
+-spec foo12() -> fun(() -> no_return()).
+foo12() -> fun foo3/0.
+
+% Creates fun from named fun that will crash. Named has spec.
+foo13() -> fun foo4/0.
+
+% Creates fun from named fun that will crash. Both have specs.
+-spec foo14() -> fun(() -> no_return()).
+foo14() -> fun foo4/0.
+
+% Creates fun calling a named fun that will crash. Neither have spec.
+foo15() -> fun() -> foo1() end.
+
+% Creates fun calling a named fun that will crash. Has spec.
+-spec foo16() -> fun(() -> no_return()).
+foo16() -> fun() -> foo1() end.
+
+% Creates fun calling a named fun that will crash. Named has spec.
+foo17() -> fun() -> foo2() end.
+
+% Creates fun calling a named fun that will crash. Both have specs.
+-spec foo18() -> fun(() -> no_return()).
+foo18() -> fun() -> foo2() end.
+
+% Creates fun calling a named fun that will crash. Neither have spec.
+foo19() -> fun() -> foo3() end.
+
+% Creates fun calling a named fun that will crash. Has spec.
+-spec foo20() -> fun(() -> no_return()).
+foo20() -> fun() -> foo3() end.
+
+% Creates fun calling a named fun that will crash. Named has spec.
+foo21() -> fun() -> foo4() end.
+
+% Creates fun calling a named fun that will crash. Both have specs.
+-spec foo22() -> fun(() -> no_return()).
+foo22() -> fun() -> foo4() end.
+
+% Creates two funs with no local return and will return one or die. No spec.
+foo23() ->
+ Bomb = fun() -> halt() end,
+ case get(42) of
+ a -> Bomb();
+ b -> fun() -> halt() end
+ end.
+
+% Creates two funs with no local return and will return one or die. With spec.
+-spec foo24() -> fun(() -> no_return()).
+foo24() ->
+ Bomb = fun() -> halt() end,
+ case get(42) of
+ a -> Bomb();
+ b -> fun() -> halt() end
+ end.
+
+% Creates two funs with no local return and will return one or die. No spec.
+foo25() ->
+ Bomb = fun() -> foo1() end,
+ case get(42) of
+ a -> Bomb();
+ b -> fun() -> foo1() end
+ end.
+
+% Creates two funs with no local return and will return one or die. With spec.
+-spec foo26() -> fun(() -> no_return()).
+foo26() ->
+ Bomb = fun foo1/0,
+ case get(42) of
+ a -> Bomb();
+ b -> fun foo1/0
+ end.
+
+% Creates two funs with no local return and will return one or die. No spec.
+foo27() ->
+ Bomb = fun foo1/0,
+ case get(42) of
+ a -> Bomb();
+ b -> fun foo1/0
+ end.
+
+% Creates two funs with no local return and will return one or die. With spec.
+-spec foo28() -> fun(() -> no_return()).
+foo28() ->
+ Bomb = fun() -> foo1() end,
+ case get(42) of
+ a -> Bomb();
+ b -> fun() -> foo1() end
+ end.
+
+% Creates two funs with no local return and will return one or die. No spec.
+foo29() ->
+ Bomb = fun() -> foo2() end,
+ case get(42) of
+ a -> Bomb();
+ b -> fun() -> foo2() end
+ end.
+
+% Creates two funs with no local return and will return one or die. With spec.
+-spec foo30() -> fun(() -> no_return()).
+foo30() ->
+ Bomb = fun foo2/0,
+ case get(42) of
+ a -> Bomb();
+ b -> fun foo2/0
+ end.
+
+% Creates two funs with no local return and will return one or die. No spec.
+foo31() ->
+ Bomb = fun foo2/0,
+ case get(42) of
+ a -> Bomb();
+ b -> fun foo2/0
+ end.
+
+% Creates two funs with no local return and will return one or die. With spec.
+-spec foo32() -> fun(() -> no_return()).
+foo32() ->
+ Bomb = fun() -> foo2() end,
+ case get(42) of
+ a -> Bomb();
+ b -> fun() -> foo2() end
+ end.
+
+% Creates two funs with no local return and will return one or die. No spec.
+foo33() ->
+ Bomb = fun() -> foo3() end,
+ case get(42) of
+ a -> Bomb();
+ b -> fun() -> foo3() end
+ end.
+
+% Creates two funs with no local return and will return one or die. With spec.
+-spec foo34() -> fun(() -> no_return()).
+foo34() ->
+ Bomb = fun foo3/0,
+ case get(42) of
+ a -> Bomb();
+ b -> fun foo3/0
+ end.
+
+% Creates two funs with no local return and will return one or die. No spec.
+foo35() ->
+ Bomb = fun foo3/0,
+ case get(42) of
+ a -> Bomb();
+ b -> fun foo3/0
+ end.
+
+% Creates two funs with no local return and will return one or die. With spec.
+-spec foo36() -> fun(() -> no_return()).
+foo36() ->
+ Bomb = fun() -> foo3() end,
+ case get(42) of
+ a -> Bomb();
+ b -> fun() -> foo3() end
+ end.
+
+% Creates two funs with no local return and will return one or die. No spec.
+foo37() ->
+ Bomb = fun() -> foo4() end,
+ case get(42) of
+ a -> Bomb();
+ b -> fun() -> foo4() end
+ end.
+
+% Creates two funs with no local return and will return one or die. With spec.
+-spec foo38() -> fun(() -> no_return()).
+foo38() ->
+ Bomb = fun foo4/0,
+ case get(42) of
+ a -> Bomb();
+ b -> fun foo4/0
+ end.
+
+% Creates two funs with no local return and will return one or die. No spec.
+foo39() ->
+ Bomb = fun foo4/0,
+ case get(42) of
+ a -> Bomb();
+ b -> fun foo4/0
+ end.
+
+% Creates two funs with no local return and will return one or die. With spec.
+-spec foo40() -> fun(() -> no_return()).
+foo40() ->
+ Bomb = fun() -> foo4() end,
+ case get(42) of
+ a -> Bomb();
+ b -> fun() -> foo4() end
+ end.
+
+% Obtains two funs with no local return and will return one or die. No spec.
+foo41() ->
+ Bomb = foo5(),
+ case get(42) of
+ a -> Bomb();
+ b -> foo5()
+ end.
+
+% Obtains two funs with no local return and will return one or die. With spec.
+-spec foo42() -> fun(() -> no_return()).
+foo42() ->
+ Bomb = foo5(),
+ case get(42) of
+ a -> Bomb();
+ b -> foo5()
+ end.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/list_to_bitstring.erl b/lib/dialyzer/test/small_SUITE_data/src/list_to_bitstring.erl
index 2da708cb15..109aa88f16 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/list_to_bitstring.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/list_to_bitstring.erl
@@ -2,7 +2,7 @@
%% From: Ken Robinson
%% Date: 28/04/2011, 17:26
%%
-%% Program that produced borus "Function has no local return" warnings
+%% Program that produced bogus "Function has no local return" warnings
%% due to erlang:list_to_bitstring/1 having erroneous hard coded type
%% information, namely accepting iolist() instead of bitstrlist().
%% Fixed 29/04/2011.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/rebar_no_return.erl b/lib/dialyzer/test/small_SUITE_data/src/rebar_no_return.erl
new file mode 100644
index 0000000000..d3b504ae04
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/rebar_no_return.erl
@@ -0,0 +1,19 @@
+-module(rebar_no_return).
+
+-export([t/0]).
+
+-spec t() -> no_return().
+t() ->
+ F = log_and_halt("baz"),
+ F("foo", 123).
+
+-spec log_and_halt(string()) -> fun((string(),integer()) -> no_return()).
+log_and_halt(Msg) ->
+ fun(_, _) ->
+ abort(Msg)
+ end.
+
+-spec abort(string()) -> no_return().
+abort(Msg) ->
+ io:format("~s~n", [Msg]),
+ halt(1).
diff --git a/lib/diameter/make/rules.mk.in b/lib/diameter/make/rules.mk.in
index 4a1a55b8d3..6318f2bc9c 100644
--- a/lib/diameter/make/rules.mk.in
+++ b/lib/diameter/make/rules.mk.in
@@ -164,7 +164,7 @@ $(MAN3DIR)/%.3:: %.xml
date=`date +"%B %e %Y"`; \
xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-# left for compatability
+# left for compatibility
$(MAN4DIR)/%.4:: %.xml
date=`date +"%B %e %Y"`; \
xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
@@ -173,7 +173,7 @@ $(MAN4DIR)/%.5:: %.xml
date=`date +"%B %e %Y"`; \
xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
-# left for compatability
+# left for compatibility
$(MAN6DIR)/%.6:: %_app.xml
date=`date +"%B %e %Y"`; \
xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $<
diff --git a/lib/diameter/src/transport/diameter_sctp.erl b/lib/diameter/src/transport/diameter_sctp.erl
index 92aa8488a0..46473e7bf1 100644
--- a/lib/diameter/src/transport/diameter_sctp.erl
+++ b/lib/diameter/src/transport/diameter_sctp.erl
@@ -525,7 +525,22 @@ recv({[#sctp_sndrcvinfo{stream = Id}], Bin}, #transport{parent = Pid})
recv({[], #sctp_shutdown_event{assoc_id = Id}},
#transport{assoc_id = Id}) ->
- stop.
+ stop;
+
+%% Note that diameter_sctp(3) documents that sctp_events cannot be
+%% specified in the list of options passed to gen_sctp and that
+%% gen_opts/1 guards against this. This is to ensure that we know what
+%% events to expect and also to ensure that we receive
+%% #sctp_sndrcvinfo{} with each incoming message (data_io_event =
+%% true). Adaptation layer events (ie. #sctp_adaptation_event{}) are
+%% disabled by default so don't handle it. We could simply disable
+%% events we don't react to but don't.
+
+recv({[], #sctp_paddr_change{}}, _) ->
+ ok;
+
+recv({[], #sctp_pdapi_event{}}, _) ->
+ ok.
%% up/1
@@ -591,7 +606,7 @@ f([], _, _) ->
%% assoc_id/1
-assoc_id(#sctp_shutdown_event{assoc_id = Id}) -> %% undocumented
+assoc_id(#sctp_shutdown_event{assoc_id = Id}) ->
Id;
assoc_id(#sctp_assoc_change{assoc_id = Id}) ->
Id;
diff --git a/lib/erl_interface/src/encode/encode_atom.c b/lib/erl_interface/src/encode/encode_atom.c
index 69f2d1451c..b1a4479034 100644
--- a/lib/erl_interface/src/encode/encode_atom.c
+++ b/lib/erl_interface/src/encode/encode_atom.c
@@ -17,13 +17,17 @@
* %CopyrightEnd%
*/
#include <string.h>
+#include <limits.h>
#include "eidef.h"
#include "eiext.h"
#include "putget.h"
int ei_encode_atom(char *buf, int *index, const char *p)
{
- return ei_encode_atom_len(buf, index, p, strlen(p));
+ size_t len = strlen(p);
+
+ if (len >= INT_MAX) return -1;
+ return ei_encode_atom_len(buf, index, p, len);
}
int ei_encode_atom_len(char *buf, int *index, const char *p, int len)
diff --git a/lib/erl_interface/src/encode/encode_string.c b/lib/erl_interface/src/encode/encode_string.c
index 1d342cb605..593bbf2b6d 100644
--- a/lib/erl_interface/src/encode/encode_string.c
+++ b/lib/erl_interface/src/encode/encode_string.c
@@ -17,6 +17,7 @@
* %CopyrightEnd%
*/
#include <string.h>
+#include <limits.h>
#include "eidef.h"
#include "eiext.h"
#include "putget.h"
@@ -24,7 +25,10 @@
int ei_encode_string(char *buf, int *index, const char *p)
{
- return ei_encode_string_len(buf, index, p, strlen(p));
+ size_t len = strlen(p);
+
+ if (len >= INT_MAX) return -1;
+ return ei_encode_string_len(buf, index, p, len);
}
int ei_encode_string_len(char *buf, int *index, const char *p, int len)
diff --git a/lib/gs/contribs/bonk/sounder.erl b/lib/gs/contribs/bonk/sounder.erl
index 11ab03d167..899f20d4e0 100644
--- a/lib/gs/contribs/bonk/sounder.erl
+++ b/lib/gs/contribs/bonk/sounder.erl
@@ -72,13 +72,13 @@ stop() ->
sounder ! {stop},
ok end.
-new(File) when list(File) -> new(list_to_atom(File));
-new(File) when atom(File) ->
+new(File) when is_list(File) -> new(list_to_atom(File));
+new(File) when is_atom(File) ->
catch begin check(),
sounder ! {new,File,self()},
wait_for_ack(sounder) end.
-play(No) when integer(No) ->
+play(No) when is_integer(No) ->
catch begin check(),
sounder ! {play, No, self()},
wait_for_ack(sounder) end.
@@ -94,14 +94,14 @@ go() ->
loop(Port) ->
receive
- {new, File, From} when atom(File) ->
+ {new, File, From} when is_atom(File) ->
Port ! {self(),{command,lists:append([0],atom_to_list(File))}},
From ! {sounder,wait_for_ack(Port)},
loop(Port);
{play,silent,From} ->
From ! {sounder,false},
loop(Port);
- {play,No,From} when integer(No) ->
+ {play,No,From} when is_integer(No) ->
Port ! {self(),{command,[No]}},
From ! {sounder,wait_for_ack(Port)},
loop(Port);
@@ -118,13 +118,13 @@ loop(Port) ->
nosound() ->
receive
- {new,File,From} when atom(File) ->
+ {new,File,From} when is_atom(File) ->
From ! {sounder,{ok,silent}},
nosound();
{play,silent,From} ->
From ! {sounder,true},
nosound();
- {play,No,From} when integer(No) ->
+ {play,No,From} when is_integer(No) ->
From ! {sounder,{error,no_audio_cap}},
nosound();
{stop} ->
@@ -135,7 +135,7 @@ nosound() ->
wait_for_ack(sounder) ->
receive {sounder,Res} -> Res end;
-wait_for_ack(Port) when port(Port) ->
+wait_for_ack(Port) when is_port(Port) ->
receive
{Port,{data,"ok"}} ->
ok;
@@ -149,7 +149,7 @@ wait_for_ack(Port) when port(Port) ->
check() ->
case whereis(sounder) of
- Pid when pid(Pid) ->
+ Pid when is_pid(Pid) ->
ok;
undefined ->
throw({error,sounder_not_started})
diff --git a/lib/gs/contribs/cols/cols.erl b/lib/gs/contribs/cols/cols.erl
index 67b46d0dfb..439eb717f7 100644
--- a/lib/gs/contribs/cols/cols.erl
+++ b/lib/gs/contribs/cols/cols.erl
@@ -278,7 +278,7 @@ fall_column([], _X, _Y, ColumnAcc, ChecksAcc) ->
fall_column([black|Colors], X, Y, ColumnAcc, ChecksAcc) ->
case find_box(Colors) of
false -> {ColumnAcc, ChecksAcc};
- NewColors when list(NewColors) ->
+ NewColors when is_list(NewColors) ->
fall_one_step(NewColors, X, Y, ColumnAcc, ChecksAcc)
end;
fall_column([Color|Colors], X, Y, ColumnAcc, ChecksAcc) ->
@@ -330,7 +330,7 @@ new_column_list([], _, _) -> [].
%%----------------------------------------------------------------------
%% Returns: a reversed list of colors.
%%----------------------------------------------------------------------
-columntuple_to_list(ColumnTuple) when tuple(ColumnTuple) ->
+columntuple_to_list(ColumnTuple) when is_tuple(ColumnTuple) ->
columntuple_to_list(tuple_to_list(ColumnTuple),[]).
columntuple_to_list([],Acc) -> Acc;
diff --git a/lib/gs/contribs/mandel/mandel.erl b/lib/gs/contribs/mandel/mandel.erl
index d4d2452463..579f8e487b 100644
--- a/lib/gs/contribs/mandel/mandel.erl
+++ b/lib/gs/contribs/mandel/mandel.erl
@@ -119,7 +119,7 @@ start_client(Opts,Nodes) ->
try_random(random,Low,High) ->
random:uniform()*(High-Low)+Low;
-try_random(Float,_Low,_High) when number(Float) -> Float.
+try_random(Float,_Low,_High) when is_number(Float) -> Float.
%%-----------------------------------------------------------------
diff --git a/lib/gs/contribs/othello/othello_board.erl b/lib/gs/contribs/othello/othello_board.erl
index 0206ba2ded..6ccb79b7e4 100644
--- a/lib/gs/contribs/othello/othello_board.erl
+++ b/lib/gs/contribs/othello/othello_board.erl
@@ -147,7 +147,7 @@ but_pressed("Help",_ButtId,_User,GamePid,_Shell,_Wids,_Op) ->
but_pressed("Newgame",_ButtId,_User,GamePid,_Shell,Wids,Options) ->
new_game(GamePid,Wids,Options);
but_pressed([],ButtId,User,GamePid,_Shell,_Wids,_Op)
- when pid(GamePid),User == player ->
+ when is_pid(GamePid),User == player ->
[C,R] = atom_to_list(ButtId),
GamePid ! {self(),position,othello_adt:pos(C-96,translate(R-48))},
GamePid;
@@ -243,7 +243,7 @@ game_msg(Msg,User,GamePid,Shell,Wids,Options) ->
end.
-new_game(GamePid,Wids,Options) when pid(GamePid) ->
+new_game(GamePid,Wids,Options) when is_pid(GamePid) ->
exit(GamePid,kill),
new_game(Wids,Options);
new_game(_,Wids,Options) ->
diff --git a/lib/gs/examples/calc2.erl b/lib/gs/examples/calc2.erl
index d28780de01..9969a6c40f 100644
--- a/lib/gs/examples/calc2.erl
+++ b/lib/gs/examples/calc2.erl
@@ -54,7 +54,7 @@ calc() ->
calc_loop(Lbl,M,V,Op) ->
receive
- {gs,_,click,D,_} when integer(D) ->
+ {gs,_,click,D,_} when is_integer(D) ->
digit_press(Lbl,M,V*10+D,Op);
{gs,_,click,'C',_} ->
c(Lbl,M,V,Op);
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index 82e3675938..827fa79ec5 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -366,7 +366,7 @@ type(erlang, '>', 2, Xs = [Lhs, Rhs]) ->
is_integer(LhsMax), is_integer(RhsMin), RhsMin >= LhsMax -> F;
true -> t_boolean()
end;
- false -> t_boolean()
+ false -> compare('>', Lhs, Rhs)
end,
strict(Xs, Ans);
type(erlang, '>=', 2, Xs = [Lhs, Rhs]) ->
@@ -384,7 +384,7 @@ type(erlang, '>=', 2, Xs = [Lhs, Rhs]) ->
is_integer(LhsMax), is_integer(RhsMin), RhsMin > LhsMax -> F;
true -> t_boolean()
end;
- false -> t_boolean()
+ false -> compare('>=', Lhs, Rhs)
end,
strict(Xs, Ans);
type(erlang, '<', 2, Xs = [Lhs, Rhs]) ->
@@ -402,7 +402,7 @@ type(erlang, '<', 2, Xs = [Lhs, Rhs]) ->
is_integer(LhsMin), is_integer(RhsMax), RhsMax =< LhsMin -> F;
true -> t_boolean()
end;
- false -> t_boolean()
+ false -> compare('<', Lhs, Rhs)
end,
strict(Xs, Ans);
type(erlang, '=<', 2, Xs = [Lhs, Rhs]) ->
@@ -420,7 +420,7 @@ type(erlang, '=<', 2, Xs = [Lhs, Rhs]) ->
is_integer(LhsMin), is_integer(RhsMax), RhsMax < LhsMin -> F;
true -> t_boolean()
end;
- false -> t_boolean()
+ false -> compare('=<', Lhs, Rhs)
end,
strict(Xs, Ans);
type(erlang, '+', 1, Xs) ->
@@ -739,6 +739,7 @@ type(erlang, element, 2, Xs) ->
type(erlang, erase, 0, _) -> t_any();
type(erlang, erase, 1, _) -> t_any();
type(erlang, external_size, 1, _) -> t_integer();
+type(erlang, external_size, 2, _) -> t_integer();
type(erlang, finish_after_on_load, 2, Xs) ->
%% Internal BIF used by on_load.
strict(arg_types(erlang, finish_after_on_load, 2), Xs,
@@ -1202,6 +1203,7 @@ type(erlang, process_flag, 2, Xs) ->
case t_atom_vals(Flag) of
['error_handler'] -> t_atom();
['min_heap_size'] -> t_non_neg_integer();
+ ['scheduler'] -> t_non_neg_integer();
['monitor_nodes'] -> t_boolean();
['priority'] -> t_process_priority_level();
['save_calls'] -> t_non_neg_integer();
@@ -1902,7 +1904,7 @@ type(prim_file, internal_native2name, 1, Xs) ->
fun (_) -> t_prim_file_name() end);
type(prim_file, internal_normalize_utf8, 1, Xs) ->
strict(arg_types(prim_file, internal_normalize_utf8, 1), Xs,
- fun (_) -> t_binary() end);
+ fun (_) -> t_unicode_string() end);
%%-- gen_tcp ------------------------------------------------------------------
%% NOTE: All type information for this module added to avoid loss of precision
type(gen_tcp, accept, 1, Xs) ->
@@ -3178,6 +3180,50 @@ arith(Op, X1, X2) ->
end.
%%=============================================================================
+%% Comparison of terms
+%%=============================================================================
+
+compare(Op, Lhs, Rhs) ->
+ case t_is_none(t_inf(Lhs, Rhs)) of
+ false -> t_boolean();
+ true ->
+ case Op of
+ '<' -> always_smaller(Lhs, Rhs);
+ '>' -> always_smaller(Rhs, Lhs);
+ '=<' -> always_smaller(Lhs, Rhs);
+ '>=' -> always_smaller(Rhs, Lhs)
+ end
+ end.
+
+always_smaller(Type1, Type2) ->
+ {Min1, Max1} = type_ranks(Type1),
+ {Min2, Max2} = type_ranks(Type2),
+ if Max1 < Min2 -> t_atom('true');
+ Min1 > Max2 -> t_atom('false');
+ true -> t_boolean()
+ end.
+
+type_ranks(Type) ->
+ type_ranks(Type, 1, 0, 0, type_order()).
+
+type_ranks(_Type, _I, Min, Max, []) -> {Min, Max};
+type_ranks(Type, I, Min, Max, [TypeClass|Rest]) ->
+ {NewMin, NewMax} =
+ case t_is_none(t_inf(Type, TypeClass)) of
+ true -> {Min, Max};
+ false -> case Min of
+ 0 -> {I, I};
+ _ -> {Min, I}
+ end
+ end,
+ type_ranks(Type, I+1, NewMin, NewMax, Rest).
+
+type_order() ->
+ [t_number(), t_atom(), t_reference(), t_fun(), t_port(), t_pid(), t_tuple(),
+ t_list(), t_binary()].
+
+
+%%=============================================================================
-spec arg_types(atom(), atom(), arity()) -> [erl_types:erl_type()] | 'unknown'.
@@ -3446,6 +3492,8 @@ arg_types(erlang, exit, 2) ->
[t_sup(t_pid(), t_port()), t_any()];
arg_types(erlang, external_size, 1) ->
[t_any()]; % takes any term as input
+arg_types(erlang, external_size, 2) ->
+ [t_any(), t_list()]; % takes any term as input and a list of options
arg_types(erlang, finish_after_on_load, 2) ->
[t_atom(), t_boolean()];
arg_types(erlang, float, 1) ->
@@ -3700,6 +3748,7 @@ arg_types(erlang, process_display, 2) ->
arg_types(erlang, process_flag, 2) ->
[t_sup([t_atom('trap_exit'), t_atom('error_handler'),
t_atom('min_heap_size'), t_atom('priority'), t_atom('save_calls'),
+ t_atom('scheduler'), % undocumented
t_atom('monitor_nodes'), % undocumented
t_tuple([t_atom('monitor_nodes'), t_list()])]), % undocumented
t_sup([t_boolean(), t_atom(), t_non_neg_integer()])];
@@ -3738,7 +3787,7 @@ arg_types(erlang, send, 3) ->
arg_types(erlang, send_after, 3) ->
[t_non_neg_integer(), t_sup(t_pid(), t_atom()), t_any()];
arg_types(erlang, seq_trace, 2) ->
- [t_atom(), t_sup([t_boolean(), t_tuple([t_fixnum(), t_fixnum()]), t_nil()])];
+ [t_atom(), t_sup([t_boolean(), t_tuple([t_fixnum(), t_fixnum()]), t_fixnum(), t_nil()])];
arg_types(erlang, seq_trace_info, 1) ->
[t_seq_trace_info()];
arg_types(erlang, seq_trace_print, 1) ->
@@ -3987,7 +4036,7 @@ arg_types(ets, match_object, 3) ->
arg_types(ets, match_spec_compile, 1) ->
[t_matchspecs()];
arg_types(ets, match_spec_run_r, 3) ->
- [t_matchspecs(), t_any(), t_list()];
+ [t_list(t_tuple()),t_matchspecs(), t_list()];
arg_types(ets, member, 2) ->
[t_tab(), t_any()];
arg_types(ets, new, 2) ->
@@ -4019,8 +4068,12 @@ arg_types(ets, select_reverse, 3) ->
arg_types(ets, slot, 2) ->
[t_tab(), t_non_neg_fixnum()]; % 2nd arg can be 0
arg_types(ets, setopts, 2) ->
- Opt = t_sup(t_tuple([t_atom('heir'), t_pid(), t_any()]),
- t_tuple([t_atom('heir'), t_atom('none')])),
+ Opt = t_sup([t_tuple([t_atom('heir'), t_pid(), t_any()]),
+ t_tuple([t_atom('heir'), t_atom('none')]),
+ t_tuple([t_atom('protection'),
+ t_sup([t_atom('protected'),
+ t_atom('private'),
+ t_atom('public')])])]),
[t_tab(), t_sup(Opt, t_list(Opt))];
arg_types(ets, update_counter, 3) ->
Int = t_integer(),
@@ -4812,6 +4865,9 @@ t_ets_info_items() ->
t_atom('owner'),
t_atom('protection'),
t_atom('size'),
+ t_atom('compressed'),
+ t_atom('heir'),
+ t_atom('stats'),
t_atom('type')]).
%% =====================================================================
diff --git a/lib/hipe/regalloc/hipe_node_sets.erl b/lib/hipe/regalloc/hipe_node_sets.erl
index b5e2971c4d..0bb21d7506 100644
--- a/lib/hipe/regalloc/hipe_node_sets.erl
+++ b/lib/hipe/regalloc/hipe_node_sets.erl
@@ -29,7 +29,7 @@
-record(node_sets,
{spilled, % Nodes marked for spilling
- colored % Nodes succesfully colored
+ colored % Nodes successfully colored
}).
spilled(Node_sets) -> Node_sets#node_sets.spilled.
diff --git a/lib/hipe/rtl/hipe_rtl_lcm.erl b/lib/hipe/rtl/hipe_rtl_lcm.erl
index 5d65389d48..d45ab4ed46 100644
--- a/lib/hipe/rtl/hipe_rtl_lcm.erl
+++ b/lib/hipe/rtl/hipe_rtl_lcm.erl
@@ -269,7 +269,7 @@ insert_expr_last(CFG0, Label, Instr) ->
%% is a branch operation).
insert_expr_last_work(_, Instr, []) ->
%% This case should not happen since this means that block was completely
- %% empty when the function was called. For compability we insert it last.
+ %% empty when the function was called. For compatibility we insert it last.
[Instr];
insert_expr_last_work(_, Instr, [Code1]) ->
%% We insert the code next to last.
diff --git a/lib/ic/src/ic.erl b/lib/ic/src/ic.erl
index 3c6ce3d9d6..e22179fe42 100644
--- a/lib/ic/src/ic.erl
+++ b/lib/ic/src/ic.erl
@@ -320,7 +320,7 @@ pragma(G, File, T) ->
time,
time("pragma registration ", ic_pragma, pragma_reg, [G,T]),
ic_pragma:pragma_reg(G,T)) of
- %% All pragmas were succesfully applied
+ %% All pragmas were successfully applied
{ok,Clean} ->
typing(G, File, Clean);
diff --git a/lib/inets/doc/src/http_server.xml b/lib/inets/doc/src/http_server.xml
index 599a939913..f29b505bc7 100644
--- a/lib/inets/doc/src/http_server.xml
+++ b/lib/inets/doc/src/http_server.xml
@@ -406,7 +406,7 @@ http://your.server.org/***/Module[:/]Function(?QueryString|/PathInfo)
phase instead of first generating the whole web page and
then sending it to the client. The option to implement a
function with arity two is only kept for
- backwardcompatibilty reasons.
+ backwards compatibility reasons.
See <seealso marker="mod_esi">mod_esi(3)</seealso> for
implementation details of the esi callback function.</p>
</section>
diff --git a/lib/inets/doc/src/mod_auth.xml b/lib/inets/doc/src/mod_auth.xml
index 42c49e9c35..2134ebeeae 100644
--- a/lib/inets/doc/src/mod_auth.xml
+++ b/lib/inets/doc/src/mod_auth.xml
@@ -80,7 +80,7 @@
<marker id="delete_user"></marker>
<p><c>delete_user/2, delete_user/3</c> and <c>delete_user/4</c>
deletes a user
- from the user database. If the operation is succesfull, this
+ from the user database. If the operation is successful, this
function returns <c>true</c>. If an error occurs,
<c>{error,Reason}</c> is returned. When <c>delete_user/2</c> is
called the Port and Dir options are mandatory.</p>
diff --git a/lib/inets/doc/src/mod_esi.xml b/lib/inets/doc/src/mod_esi.xml
index 9674cd9a88..9906ae0895 100644
--- a/lib/inets/doc/src/mod_esi.xml
+++ b/lib/inets/doc/src/mod_esi.xml
@@ -31,8 +31,8 @@
<module>mod_esi</module>
<modulesummary>Erlang Server Interface </modulesummary>
<description>
- <p>This module defines the API - Erlang Server Interface (ESI).
- Which is a more efficient way of writing erlang scripts
+ <p>This module defines the Erlang Server Interface (ESI) API.
+ It is a more efficient way of writing erlang scripts
for your Inets web server than writing them as common CGI scripts.</p>
<marker id="deliver"></marker>
@@ -95,12 +95,12 @@
the server uses when <c>deliver/2</c> is called; do not
assume anything about the datatype.</p>
<p>Use this callback function to dynamically generate dynamic web
- content. when a part of the page is generated send the
+ content. When a part of the page is generated send the
data back to the client through <c>deliver/2</c>. Note
that the first chunk of data sent to the client must at
least contain all HTTP header fields that the response
will generate. If the first chunk does not contain the
- <em>End of HTTP the header</em>, that is <c>"\r\n\r\n",</c>
+ <em>End of HTTP header</em>, that is <c>"\r\n\r\n",</c>
the server will
assume that no HTTP header fields will be generated.</p>
</desc>
@@ -118,8 +118,8 @@
<desc>
<p>This callback format consumes a lot of memory since the
whole response must be generated before it is sent to the
- user. This functions is deprecated and only keept for backwards
- compatibility.
+ user. This function is deprecated and only kept for backwards
+ compatibility.
For new development Module:Function/3 should be used.</p>
</desc>
</func>
diff --git a/lib/inets/doc/src/notes_history.xml b/lib/inets/doc/src/notes_history.xml
index 6480bad758..f70ce5cf46 100644
--- a/lib/inets/doc/src/notes_history.xml
+++ b/lib/inets/doc/src/notes_history.xml
@@ -123,7 +123,7 @@
re-receive of acknowledgments. If multiple copies of the
same acknowledgments is received the spurious ones are
silently ignored. This fix was intended for inets-4.7.14
- but accidentaly it was not included in that release.</p>
+ but accidentally it was not included in that release.</p>
<p>Own Id: OTP-6706 Aux Id: OTP-6691 </p>
</item>
</list>
diff --git a/lib/inets/src/http_client/httpc_cookie.erl b/lib/inets/src/http_client/httpc_cookie.erl
index 4d61f82b5a..d1f46c0b0b 100644
--- a/lib/inets/src/http_client/httpc_cookie.erl
+++ b/lib/inets/src/http_client/httpc_cookie.erl
@@ -404,7 +404,7 @@ path_default(#http_cookie{path = undefined} = Cookie, DefaultPath) ->
path_default(Cookie, _) ->
Cookie.
-%% Note: if the path is only / that / will be keept
+%% Note: if the path is only / that / will be kept
skip_right_most_slash("/") ->
"/";
skip_right_most_slash(Str) ->
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index 9ac9ee6f7b..587e24cc8d 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -1157,7 +1157,7 @@ handle_cookies(Headers, Request, #options{cookies = enabled}, ProfileName) ->
httpc_manager:store_cookies(Cookies, Request#request.address,
ProfileName).
-%% This request could not be pipelined or used as sequential keept alive
+%% This request could not be pipelined or used as sequential keep alive
%% queue
handle_queue(#state{status = close} = State, _) ->
{stop, normal, State};
diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl
index f4d8a6c09f..d1b1ea0e14 100644
--- a/lib/inets/src/http_server/httpd_conf.erl
+++ b/lib/inets/src/http_server/httpd_conf.erl
@@ -305,7 +305,7 @@ load("MaxKeepAliveRequests " ++ MaxRequests, []) ->
" is an invalid MaxKeepAliveRequests")}
end;
-%% This clause is keept for backwards compability
+%% This clause is kept for backwards compatibility
load("MaxKeepAliveRequest " ++ MaxRequests, []) ->
case make_integer(MaxRequests) of
{ok, Integer} ->
diff --git a/lib/inets/src/http_server/httpd_esi.erl b/lib/inets/src/http_server/httpd_esi.erl
index 026ec9a5fe..aac5645282 100644
--- a/lib/inets/src/http_server/httpd_esi.erl
+++ b/lib/inets/src/http_server/httpd_esi.erl
@@ -39,7 +39,7 @@
%% body part. Note that it is presumed that <Data> starts with a
%% string including "\r\n\r\n" if there is any header information
%% present. The returned headers will not contain the HTTP header body
-%% delimiter \r\n. (All header, header delimiters are keept.)
+%% delimiter \r\n. (All header, header delimiters are kept.)
%% Ex: ["Content-Type : text/html\r\n Connection : closing \r\n\r\n" |
%% io_list()] --> {"Content-Type : text/html\r\n Connection : closing \r\n",
%% io_list()}
diff --git a/lib/inets/src/http_server/httpd_file.erl b/lib/inets/src/http_server/httpd_file.erl
index ccc1f7874a..e8a8ab6411 100644
--- a/lib/inets/src/http_server/httpd_file.erl
+++ b/lib/inets/src/http_server/httpd_file.erl
@@ -33,7 +33,7 @@ handle_error(enotdir, Op, ModData, Path) ->
handle_error(404, Op, ModData, Path,
": A component of the file name is not a directory");
handle_error(emfile, Op, _ModData, Path) ->
- handle_error(500, Op, none, Path, ": To many open files");
+ handle_error(500, Op, none, Path, ": Too many open files");
handle_error({enfile,_}, Op, _ModData, Path) ->
handle_error(500, Op, none, Path, ": File table overflow");
handle_error(_Reason, Op, ModData, Path) ->
diff --git a/lib/inets/src/http_server/mod_auth_mnesia.erl b/lib/inets/src/http_server/mod_auth_mnesia.erl
index ffe028617b..b7b9520649 100644
--- a/lib/inets/src/http_server/mod_auth_mnesia.erl
+++ b/lib/inets/src/http_server/mod_auth_mnesia.erl
@@ -55,7 +55,7 @@ store_directory_data(_Directory, _DirData, _Server_root) ->
%% API
%%
-%% Compability API
+%% Compatibility API
store_user(UserName, Password, Port, Dir, _AccessPassword) ->
%% AccessPassword is ignored - was not used in previous version
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index b36c28e027..fad5af85bb 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -555,8 +555,14 @@ fe80::204:acff:fe17:bf38
mode will return <c>{ok, HttpPacket}</c> from <c>gen_tcp:recv</c>
while an active socket will send messages like <c>{http,
Socket, HttpPacket}</c>.</p>
- <p>Note that the packet type <c>httph</c> is not
- needed when reading from a socket.</p>
+ </item>
+ <tag><c>httph | httph_bin</c></tag>
+ <item>
+ <p>These two types are often not needed as the socket will
+ automatically switch from <c>http</c>/<c>http_bin</c> to
+ <c>httph</c>/<c>httph_bin</c> internally after the first line
+ has been read. There might be occasions however when they are
+ useful, such as parsing trailers from chunked encoding.</p>
</item>
</taglist>
</item>
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index e325443f6c..fc8360b3d1 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -2535,7 +2535,7 @@
<c>badarg</c> if a process is already registered. As it
turns out there is no check in <c>global</c> if a process is
registered under more than one name. If some process is
- accidentaly or by design given several names, it is
+ accidentally or by design given several names, it is
possible that the name registry becomes inconsistent due
to the way the resolve function is called when name
clashes are discovered (see <c>register_name/3</c> in
diff --git a/lib/kernel/examples/uds_dist/c_src/uds_drv.c b/lib/kernel/examples/uds_dist/c_src/uds_drv.c
index fb10a375f4..9327ab19dc 100644
--- a/lib/kernel/examples/uds_dist/c_src/uds_drv.c
+++ b/lib/kernel/examples/uds_dist/c_src/uds_drv.c
@@ -111,7 +111,7 @@ do { \
typedef enum {
portTypeUnknown, /* An uninitialized port */
portTypeListener, /* A listening port/socket */
- portTypeAcceptor, /* An intermidiate stage when accepting
+ portTypeAcceptor, /* An intermediate stage when accepting
on a listen port */
portTypeConnector, /* An intermediate stage when connecting */
portTypeCommand, /* A connected open port in command mode */
@@ -401,7 +401,7 @@ static void uds_finish(void)
/*
** Protocol to control:
** 'C': Set port in command mode.
-** 'I': Set port in intermidiate mode
+** 'I': Set port in intermediate mode
** 'D': Set port in data mode
** 'N': Get identification number for listen port
** 'S': Get statistics
@@ -1000,7 +1000,7 @@ static int ensure_dir(char *path)
/*
** Try to open a lock file and lock the first byte write-only (advisory)
-** return the file descriptor if succesful, otherwise -1 (<0).
+** return the file descriptor if successful, otherwise -1 (<0).
*/
static int try_lock(char *sockname, Byte *p_creation)
{
diff --git a/lib/kernel/src/auth.erl b/lib/kernel/src/auth.erl
index ac25ab958c..c329a5652a 100644
--- a/lib/kernel/src/auth.erl
+++ b/lib/kernel/src/auth.erl
@@ -212,7 +212,7 @@ handle_info({From,badcookie,net_kernel,{From,spawn_link,_M,_F,_A,_Gleader}}, O)
{noreply, O};
handle_info({_From,badcookie,ddd_server,_Mess}, O) ->
%% Ignore bad messages to the ddd server, they will be resent
- %% If the authentication is succesful
+ %% If the authentication is successful
{noreply, O};
handle_info({From,badcookie,rex,_Msg}, O) ->
auth:print(getnode(From),
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index fdab2eb02b..77fc7e73f9 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -2165,7 +2165,7 @@ write_compressed(Config) when is_list(Config) ->
?line Second = io:get_line(Fd1, ''),
?line ok = ?FILE_MODULE:close(Fd1),
- %% Verify succesful compression by uncompressing the file
+ %% Verify successful compression by uncompressing the file
%% using zlib:gunzip/1.
?line {ok,Contents} = file:read_file(MyFile),
diff --git a/lib/mnesia/src/Makefile b/lib/mnesia/src/Makefile
index e032f563fa..1c8ec54605 100644
--- a/lib/mnesia/src/Makefile
+++ b/lib/mnesia/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2009. All Rights Reserved.
+# Copyright Ericsson AB 1996-2011. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -113,6 +113,8 @@ clean:
docs:
+$(TARGET_FILES): $(HRL_FILES)
+
# ----------------------------------------------------
# Special Build Targets
# ----------------------------------------------------
diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl
index d4b2c7b5cc..1d3bd55b48 100644
--- a/lib/mnesia/src/mnesia_controller.erl
+++ b/lib/mnesia/src/mnesia_controller.erl
@@ -57,7 +57,8 @@
release_schema_commit_lock/0,
create_table/1,
get_disc_copy/1,
- get_cstructs/0,
+ get_remote_cstructs/0, % new function
+ get_cstructs/0, % old function
sync_and_block_table_whereabouts/4,
sync_del_table_copy_whereabouts/2,
block_table/1,
@@ -278,9 +279,51 @@ rec_tabs([], _, _, Init) ->
unlink(Init),
ok.
-get_cstructs() ->
+%% New function that does exactly what get_cstructs() used to do.
+%% When this function is called, we know that the calling node knows
+%% how to convert cstructs on the receiving end (should they differ).
+get_remote_cstructs() ->
call(get_cstructs).
+%% Old function kept for backwards compatibility; converts cstructs before sending.
+get_cstructs() ->
+ {cstructs, Cstructs, Running} = call(get_cstructs),
+ Node = node(group_leader()),
+ {cstructs, normalize_cstructs(Cstructs, Node), Running}.
+
+normalize_cstructs(Cstructs, Node) ->
+ %% backward-compatibility hack; normalize before returning
+ case rpc:call(Node, mnesia_lib, val, [{schema,cstruct}]) of
+ {badrpc, _} ->
+ %% assume it's not a schema merge
+ Cstructs;
+ #cstruct{} ->
+ %% same format
+ Cstructs;
+ Cstruct ->
+ %% some other format
+ RemoteFields = [F || {F,_} <- rpc:call(Node, mnesia_schema, cs2list, [Cstruct])],
+ [convert_cs(Cs, RemoteFields) || Cs <- Cstructs]
+ end.
+
+convert_cs(Cs, Fields) ->
+ MyFields = record_info(fields, cstruct),
+ convert(tl(tuple_to_list(Cs)), MyFields, Fields, []).
+
+convert([H|T], [F|FsL], [F|FsR], Acc) ->
+ convert(T, FsL, FsR, [H|Acc]);
+convert([H|T], [Fl|FsL] = L, [Fr|FsR] = R, Acc) ->
+ case {lists:member(Fl, FsR), lists:member(Fr, FsL)} of
+ {true, false} ->
+ convert(T, L, FsR, [H|Acc]);
+ {false, true} ->
+ %% Field Fl doesn't exist on receiver side; skip.
+ convert(T, FsL, R, Acc)
+ end;
+convert([], _, _, Acc) ->
+ list_to_tuple([cstruct|lists:reverse(Acc)]).
+
+
update(Fun) ->
call({update,Fun}).
diff --git a/lib/mnesia/src/mnesia_dumper.erl b/lib/mnesia/src/mnesia_dumper.erl
index 92fd9dfade..daa9e6aff2 100644
--- a/lib/mnesia/src/mnesia_dumper.erl
+++ b/lib/mnesia/src/mnesia_dumper.erl
@@ -214,7 +214,12 @@ insert_rec(Rec, InPlace, InitBy, LogV) when is_record(Rec, commit) ->
{Tid, committed} ->
do_insert_rec(Tid, Rec, InPlace, InitBy, LogV);
{Tid, aborted} ->
- mnesia_schema:undo_prepare_commit(Tid, Rec)
+ case InitBy of
+ startup ->
+ mnesia_schema:undo_prepare_commit(Tid, Rec);
+ _ ->
+ ok
+ end
end;
insert_rec(H, _InPlace, _InitBy, _LogV) when is_record(H, log_header) ->
CurrentVersion = mnesia_log:version(),
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index e785b795d1..eb83168498 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -27,7 +27,6 @@
net_load_table/4,
send_table/3]).
--export([old_node_init_table/6]). %% Spawned old node protocol conversion hack
-export([spawned_receiver/8]). %% Spawned lock taking process
-import(mnesia_lib, [set/2, fatal/2, verbose/2, dbg_out/2]).
@@ -36,7 +35,7 @@
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason);
+ {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason);
Value -> Value
end.
@@ -51,7 +50,7 @@ disc_load_table(Tab, Reason) ->
?eval_debug_fun({?MODULE, do_get_disc_copy},
[{tab, Tab},
{reason, Reason},
- {storage, Storage},
+ {storage, Storage},
{type, Type}]),
do_get_disc_copy2(Tab, Reason, Storage, Type).
@@ -63,19 +62,19 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_copies ->
%% NOW we create the actual table
Repair = mnesia_monitor:get_env(auto_repair),
Args = [{keypos, 2}, public, named_table, Type],
- case Reason of
+ case Reason of
{dumper, _} -> %% Resources allready allocated
ignore;
_ ->
mnesia_monitor:mktab(Tab, Args),
- Count = mnesia_log:dcd2ets(Tab, Repair),
+ Count = mnesia_log:dcd2ets(Tab, Repair),
case ets:info(Tab, size) of
X when X < Count * 4 ->
- ok = mnesia_log:ets2dcd(Tab);
+ ok = mnesia_log:ets2dcd(Tab);
_ ->
ignore
end
- end,
+ end,
mnesia_index:init_index(Tab, Storage),
snmpify(Tab, Storage),
set({Tab, load_node}, node()),
@@ -84,7 +83,7 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_copies ->
do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == ram_copies ->
Args = [{keypos, 2}, public, named_table, Type],
- case Reason of
+ case Reason of
{dumper, _} -> %% Resources allready allocated
ignore;
_ ->
@@ -94,12 +93,12 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == ram_copies ->
Repair = mnesia_monitor:get_env(auto_repair),
case mnesia_monitor:use_dir() of
true ->
- case mnesia_lib:exists(Fname) of
+ case mnesia_lib:exists(Fname) of
true -> mnesia_log:dcd2ets(Tab, Repair);
false ->
case mnesia_lib:exists(Datname) of
true ->
- mnesia_lib:dets_to_ets(Tab, Tab, Datname,
+ mnesia_lib:dets_to_ets(Tab, Tab, Datname,
Type, Repair, no);
false ->
false
@@ -154,11 +153,11 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_only_copies -
%% Disable rehashing of table
%% Release read lock on table
%% Send table to receiver in chunks
-%%
+%%
%% Grab read lock on table
%% Block dirty updates
%% Update wherabouts
-%%
+%%
%% Cancel the update subscription
%% Process the subscription events
%% Optionally dump to disc
@@ -166,7 +165,7 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_only_copies -
%% Release read lock on table
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--define(MAX_TRANSFER_SIZE, 7500).
+-define(MAX_TRANSFER_SIZE, 7500).
-define(MAX_RAM_FILE_SIZE, 1000000).
-define(MAX_RAM_TRANSFERS, (?MAX_RAM_FILE_SIZE div ?MAX_TRANSFER_SIZE) + 1).
-define(MAX_NOPACKETS, 20).
@@ -187,14 +186,14 @@ try_net_load_table(Tab, Reason, Ns, Cs) ->
do_get_network_copy(Tab, _Reason, _Ns, unknown, _Cs) ->
verbose("Local table copy of ~p has recently been deleted, ignored.~n", [Tab]),
{not_loaded, storage_unknown};
-do_get_network_copy(Tab, Reason, Ns, Storage, Cs) ->
+do_get_network_copy(Tab, Reason, Ns, Storage, Cs) ->
[Node | Tail] = Ns,
case lists:member(Node,val({current, db_nodes})) of
true ->
dbg_out("Getting table ~p (~p) from node ~p: ~p~n",
[Tab, Storage, Node, Reason]),
?eval_debug_fun({?MODULE, do_get_network_copy},
- [{tab, Tab}, {reason, Reason},
+ [{tab, Tab}, {reason, Reason},
{nodes, Ns}, {storage, Storage}]),
case init_receiver(Node, Tab, Storage, Cs, Reason) of
ok ->
@@ -208,7 +207,7 @@ do_get_network_copy(Tab, Reason, Ns, Storage, Cs) ->
restart ->
try_net_load_table(Tab, Reason, Tail ++ [Node], Cs);
down ->
- try_net_load_table(Tab, Reason, Tail, Cs)
+ try_net_load_table(Tab, Reason, Tail, Cs)
end;
false ->
try_net_load_table(Tab, Reason, Tail, Cs)
@@ -223,10 +222,10 @@ do_snmpify(Tab, Us, Storage) ->
Snmp = mnesia_snmp_hook:create_table(Us, Tab, Storage),
set({Tab, {index, snmp}}, Snmp).
-%% Start the recieiver
+%% Start the recieiver
init_receiver(Node, Tab, Storage, Cs, Reas={dumper,add_table_copy}) ->
case start_remote_sender(Node, Tab, Storage) of
- {SenderPid, TabSize, DetsData} ->
+ {SenderPid, TabSize, DetsData} ->
start_receiver(Tab,Storage,Cs,SenderPid,TabSize,DetsData,Reas);
Else ->
Else
@@ -234,21 +233,21 @@ init_receiver(Node, Tab, Storage, Cs, Reas={dumper,add_table_copy}) ->
init_receiver(Node, Tab,Storage,Cs,Reason) ->
%% Grab a schema lock to avoid deadlock between table_loader and schema_commit dumping.
%% Both may grab tables-locks in different order.
- Load =
- fun() ->
- {_,Tid,Ts} = get(mnesia_activity_state),
+ Load =
+ fun() ->
+ {_,Tid,Ts} = get(mnesia_activity_state),
mnesia_locker:rlock(Tid, Ts#tidstore.store, {schema, Tab}),
- %% Check that table still exists
+ %% Check that table still exists
Active = val({Tab, active_replicas}),
%% Check that we havn't loaded it already
case val({Tab,where_to_read}) == node() of
true -> ok;
_ ->
- %% And that sender still got a copy
- %% (something might have happend while
+ %% And that sender still got a copy
+ %% (something might have happend while
%% we where waiting for the lock)
true = lists:member(Node, Active),
- {SenderPid, TabSize, DetsData} =
+ {SenderPid, TabSize, DetsData} =
start_remote_sender(Node,Tab,Storage),
Init = table_init_fun(SenderPid),
Args = [self(),Tab,Storage,Cs,SenderPid,
@@ -258,18 +257,18 @@ init_receiver(Node, Tab,Storage,Cs,Reason) ->
wait_on_load_complete(Pid)
end
end,
- Res =
+ Res =
case mnesia:transaction(Load, 20) of
- {atomic, {error,Result}} when
- element(1,Reason) == dumper ->
+ {atomic, {error,Result}} when
+ element(1,Reason) == dumper ->
{error,Result};
- {atomic, {error,Result}} ->
+ {atomic, {error,Result}} ->
fatal("Cannot create table ~p: ~p~n",
[[Tab, Storage], Result]);
{atomic, Result} -> Result;
{aborted, nomore} -> restart;
- {aborted, _Reas} ->
- verbose("Receiver failed on ~p from ~p:~nReason: ~p~n",
+ {aborted, _Reas} ->
+ verbose("Receiver failed on ~p from ~p:~nReason: ~p~n",
[Tab,Node,_Reas]),
down %% either this node or sender is dying
end,
@@ -279,7 +278,7 @@ init_receiver(Node, Tab,Storage,Cs,Reason) ->
start_remote_sender(Node,Tab,Storage) ->
mnesia_controller:start_remote_sender(Node, Tab, self(), Storage),
put(mnesia_table_sender_node, {Tab, Node}),
- receive
+ receive
{SenderPid, {first, TabSize}} ->
{SenderPid, TabSize, false};
{SenderPid, {first, TabSize, DetsData}} ->
@@ -291,22 +290,14 @@ start_remote_sender(Node,Tab,Storage) ->
end.
table_init_fun(SenderPid) ->
- PConv = mnesia_monitor:needs_protocol_conversion(node(SenderPid)),
- MeMyselfAndI = self(),
fun(read) ->
- Receiver =
- if
- PConv == true ->
- MeMyselfAndI ! {actual_tabrec, self()},
- MeMyselfAndI; %% Old mnesia
- PConv == false -> self()
- end,
+ Receiver = self(),
SenderPid ! {Receiver, more},
get_data(SenderPid, Receiver)
end.
%% Add_table_copy get's it's own locks.
-start_receiver(Tab,Storage,Cs,SenderPid,TabSize,DetsData,{dumper,add_table_copy}) ->
+start_receiver(Tab,Storage,Cs,SenderPid,TabSize,DetsData,{dumper,add_table_copy}) ->
Init = table_init_fun(SenderPid),
case do_init_table(Tab,Storage,Cs,SenderPid,TabSize,DetsData,self(), Init) of
Err = {error, _} ->
@@ -317,8 +308,8 @@ start_receiver(Tab,Storage,Cs,SenderPid,TabSize,DetsData,{dumper,add_table_copy}
end.
spawned_receiver(ReplyTo,Tab,Storage,Cs, SenderPid,TabSize,DetsData, Init) ->
- process_flag(trap_exit, true),
- Done = do_init_table(Tab,Storage,Cs,
+ process_flag(trap_exit, true),
+ Done = do_init_table(Tab,Storage,Cs,
SenderPid,TabSize,DetsData,
ReplyTo, Init),
ReplyTo ! {self(),Done},
@@ -327,17 +318,17 @@ spawned_receiver(ReplyTo,Tab,Storage,Cs, SenderPid,TabSize,DetsData, Init) ->
exit(normal).
wait_on_load_complete(Pid) ->
- receive
- {Pid, Res} ->
+ receive
+ {Pid, Res} ->
Res;
- {'EXIT', Pid, Reason} ->
+ {'EXIT', Pid, Reason} ->
exit(Reason);
- Else ->
+ Else ->
Pid ! Else,
wait_on_load_complete(Pid)
end.
-do_init_table(Tab,Storage,Cs,SenderPid,
+do_init_table(Tab,Storage,Cs,SenderPid,
TabSize,DetsInfo,OrigTabRec,Init) ->
case create_table(Tab, TabSize, Storage, Cs) of
{Storage,Tab} ->
@@ -345,11 +336,9 @@ do_init_table(Tab,Storage,Cs,SenderPid,
Node = node(SenderPid),
put(mnesia_table_receiver, {Tab, Node, SenderPid}),
mnesia_tm:block_tab(Tab),
- PConv = mnesia_monitor:needs_protocol_conversion(Node),
-
- case init_table(Tab,Storage,Init,PConv,DetsInfo,SenderPid) of
- ok ->
- tab_receiver(Node,Tab,Storage,Cs,PConv,OrigTabRec);
+ case init_table(Tab,Storage,Init,DetsInfo,SenderPid) of
+ ok ->
+ tab_receiver(Node,Tab,Storage,Cs,OrigTabRec);
Reason ->
Msg = "[d]ets:init table failed",
verbose("~s: ~p: ~p~n", [Msg, Tab, Reason]),
@@ -360,7 +349,7 @@ do_init_table(Tab,Storage,Cs,SenderPid,
end.
create_table(Tab, TabSize, Storage, Cs) ->
- if
+ if
Storage == disc_only_copies ->
mnesia_lib:lock_table(Tab),
Tmp = mnesia_lib:tab2tmp(Tab),
@@ -390,54 +379,30 @@ create_table(Tab, TabSize, Storage, Cs) ->
end
end.
-tab_receiver(Node, Tab, Storage, Cs, PConv, OrigTabRec) ->
+tab_receiver(Node, Tab, Storage, Cs, OrigTabRec) ->
receive
- {SenderPid, {no_more, DatBin}} when PConv == false ->
+ {SenderPid, {no_more, DatBin}} ->
finish_copy(Storage,Tab,Cs,SenderPid,DatBin,OrigTabRec);
-
- %% Protocol conversion hack
- {SenderPid, {no_more, DatBin}} when is_pid(PConv) ->
- PConv ! {SenderPid, no_more},
- receive
- {old_init_table_complete, ok} ->
- finish_copy(Storage, Tab, Cs, SenderPid, DatBin,OrigTabRec);
- {old_init_table_complete, Reason} ->
- Msg = "OLD: [d]ets:init table failed",
- verbose("~s: ~p: ~p~n", [Msg, Tab, Reason]),
- down(Tab, Storage)
- end;
-
- {actual_tabrec, Pid} ->
- tab_receiver(Node, Tab, Storage, Cs, Pid,OrigTabRec);
-
- {SenderPid, {more, [Recs]}} when is_pid(PConv) ->
- PConv ! {SenderPid, {more, Recs}}, %% Forward Msg to OldNodes
- tab_receiver(Node, Tab, Storage, Cs, PConv,OrigTabRec);
- {'EXIT', PConv, Reason} -> %% [d]ets:init process crashed
- Msg = "Receiver crashed",
- verbose("~s: ~p: ~p~n", [Msg, Tab, Reason]),
- down(Tab, Storage);
-
%% Protocol conversion hack
{copier_done, Node} ->
verbose("Sender of table ~p crashed on node ~p ~n", [Tab, Node]),
down(Tab, Storage);
-
+
{'EXIT', Pid, Reason} ->
handle_exit(Pid, Reason),
- tab_receiver(Node, Tab, Storage, Cs, PConv,OrigTabRec)
+ tab_receiver(Node, Tab, Storage, Cs, OrigTabRec)
end.
make_table_fun(Pid, TabRec) ->
fun(close) ->
ok;
(read) ->
- get_data(Pid, TabRec)
+ get_data(Pid, TabRec)
end.
get_data(Pid, TabRec) ->
- receive
+ receive
{Pid, {more_z, CompressedRecs}} when is_binary(CompressedRecs) ->
Pid ! {TabRec, more},
{zlib_uncompress(CompressedRecs), make_table_fun(Pid,TabRec)};
@@ -448,7 +413,7 @@ get_data(Pid, TabRec) ->
end_of_input;
{copier_done, Node} ->
case node(Pid) of
- Node ->
+ Node ->
{copier_done, Node};
_ ->
get_data(Pid, TabRec)
@@ -458,10 +423,10 @@ get_data(Pid, TabRec) ->
get_data(Pid, TabRec)
end.
-init_table(Tab, disc_only_copies, Fun, false, DetsInfo,Sender) ->
+init_table(Tab, disc_only_copies, Fun, DetsInfo,Sender) ->
ErtsVer = erlang:system_info(version),
case DetsInfo of
- {ErtsVer, DetsData} ->
+ {ErtsVer, DetsData} ->
Res = (catch dets:is_compatible_bchunk_format(Tab, DetsData)),
case Res of
{'EXIT',{undef,[{dets,_,_}|_]}} ->
@@ -481,28 +446,19 @@ init_table(Tab, disc_only_copies, Fun, false, DetsInfo,Sender) ->
_ ->
dets:init_table(Tab, Fun)
end;
-init_table(Tab, _, Fun, false, _DetsInfo,_) ->
+init_table(Tab, _, Fun, _DetsInfo,_) ->
case catch ets:init_table(Tab, Fun) of
true ->
ok;
{'EXIT', Else} -> Else
- end;
-init_table(Tab, Storage, Fun, true, _DetsInfo, Sender) -> %% Old Nodes
- spawn_link(?MODULE, old_node_init_table,
- [Tab, Storage, Fun, self(), false, Sender]),
- ok.
+ end.
-old_node_init_table(Tab, Storage, Fun, TabReceiver, DetsInfo,Sender) ->
- Res = init_table(Tab, Storage, Fun, false, DetsInfo,Sender),
- TabReceiver ! {old_init_table_complete, Res},
- unlink(TabReceiver),
- ok.
finish_copy(Storage,Tab,Cs,SenderPid,DatBin,OrigTabRec) ->
TabRef = {Storage, Tab},
subscr_receiver(TabRef, Cs#cstruct.record_name),
case handle_last(TabRef, Cs#cstruct.type, DatBin) of
- ok ->
+ ok ->
mnesia_index:init_index(Tab, Storage),
snmpify(Tab, Storage),
%% OrigTabRec must not be the spawned tab-receiver
@@ -534,7 +490,7 @@ subscr_receiver(TabRef = {_, Tab}, RecName) ->
ok
end.
-handle_event(TabRef, write, Rec) ->
+handle_event(TabRef, write, Rec) ->
db_put(TabRef, Rec);
handle_event(TabRef, delete, {_Tab, Key}) ->
db_erase(TabRef, Key);
@@ -545,8 +501,8 @@ handle_event(TabRef, clear_table, {_Tab, _Key}) ->
handle_last({disc_copies, Tab}, _Type, nobin) ->
Ret = mnesia_log:ets2dcd(Tab),
- Fname = mnesia_lib:tab2dat(Tab),
- case mnesia_lib:exists(Fname) of
+ Fname = mnesia_lib:tab2dat(Tab),
+ case mnesia_lib:exists(Fname) of
true -> %% Remove old .DAT files.
file:delete(Fname);
false ->
@@ -653,31 +609,29 @@ send_table(Pid, Tab, RemoteS) ->
{error, {no_exists, Tab}};
Storage ->
%% Send first
- TabSize = mnesia:table_info(Tab, size),
- Pconvert = mnesia_monitor:needs_protocol_conversion(node(Pid)),
+ TabSize = mnesia:table_info(Tab, size),
KeysPerTransfer = calc_nokeys(Storage, Tab),
ChunkData = dets:info(Tab, bchunk_format),
- UseDetsChunk =
- Storage == RemoteS andalso
- Storage == disc_only_copies andalso
- ChunkData /= undefined andalso
- Pconvert == false,
- if
+ UseDetsChunk =
+ Storage == RemoteS andalso
+ Storage == disc_only_copies andalso
+ ChunkData /= undefined,
+ if
UseDetsChunk == true ->
DetsInfo = erlang:system_info(version),
Pid ! {self(), {first, TabSize, {DetsInfo, ChunkData}}};
true ->
Pid ! {self(), {first, TabSize}}
end,
-
+
%% Debug info
put(mnesia_table_sender, {Tab, node(Pid), Pid}),
{Init, Chunk} = reader_funcs(UseDetsChunk, Tab, Storage, KeysPerTransfer),
-
+
SendIt = fun() ->
prepare_copy(Pid, Tab, Storage),
- send_more(Pid, 1, Chunk, Init(), Tab, Pconvert),
+ send_more(Pid, 1, Chunk, Init(), Tab),
finish_copy(Pid, Tab, Storage, RemoteS)
end,
@@ -698,7 +652,7 @@ send_table(Pid, Tab, RemoteS) ->
{error, Reason}
end
end.
-
+
prepare_copy(Pid, Tab, Storage) ->
Trans =
fun() ->
@@ -717,11 +671,11 @@ prepare_copy(Pid, Tab, Storage) ->
update_where_to_write(Tab, Node) ->
case val({Tab, access_mode}) of
- read_only ->
+ read_only ->
ignore;
- read_write ->
+ read_write ->
Current = val({current, db_nodes}),
- Ns =
+ Ns =
case lists:member(Node, Current) of
true -> Current;
false -> [Node | Current]
@@ -729,27 +683,27 @@ update_where_to_write(Tab, Node) ->
update_where_to_write(Ns, Tab, Node)
end.
-update_where_to_write([], _, _) ->
+update_where_to_write([], _, _) ->
ok;
update_where_to_write([H|T], Tab, AddNode) ->
- rpc:call(H, mnesia_controller, call,
+ rpc:call(H, mnesia_controller, call,
[{update_where_to_write, [add, Tab, AddNode], self()}]),
update_where_to_write(T, Tab, AddNode).
-send_more(Pid, N, Chunk, DataState, Tab, OldNode) ->
+send_more(Pid, N, Chunk, DataState, Tab) ->
receive
{NewPid, more} ->
- case send_packet(N - 1, NewPid, Chunk, DataState, OldNode) of
- New when is_integer(New) ->
+ case send_packet(N - 1, NewPid, Chunk, DataState) of
+ New when is_integer(New) ->
New - 1;
NewData ->
- send_more(NewPid, ?MAX_NOPACKETS, Chunk, NewData, Tab, OldNode)
+ send_more(NewPid, ?MAX_NOPACKETS, Chunk, NewData, Tab)
end;
{_NewPid, {old_protocol, Tab}} ->
Storage = val({Tab, storage_type}),
- {Init, NewChunk} =
+ {Init, NewChunk} =
reader_funcs(false, Tab, Storage, calc_nokeys(Storage, Tab)),
- send_more(Pid, 1, NewChunk, Init(), Tab, OldNode);
+ send_more(Pid, 1, NewChunk, Init(), Tab);
{copier_done, Node} when Node == node(Pid)->
verbose("Receiver of table ~p crashed on ~p (more)~n", [Tab, Node]),
@@ -770,7 +724,7 @@ dets_bchunk(Tab, Chunk) -> %% Arrg
case dets:bchunk(Tab, Chunk) of
{Cont, Data} -> {Data, Cont};
Else -> Else
- end.
+ end.
zlib_compress(Data, Level) ->
BinData = term_to_binary(Data),
@@ -793,28 +747,20 @@ compression_level() ->
Val -> Val
end.
-send_packet(N, Pid, _Chunk, '$end_of_table', OldNode) ->
- case OldNode of
- true -> ignore; %% Old nodes can't handle the new no_more
- false -> Pid ! {self(), no_more}
- end,
+send_packet(N, Pid, _Chunk, '$end_of_table') ->
+ Pid ! {self(), no_more},
N;
-send_packet(N, Pid, Chunk, {[], Cont}, OldNode) ->
- send_packet(N, Pid, Chunk, Chunk(Cont), OldNode);
-send_packet(N, Pid, Chunk, {Recs, Cont}, OldNode) when N < ?MAX_NOPACKETS ->
- case OldNode of
- true ->
- Pid ! {self(), {more, [Recs]}}; %% Old need's wrapping list
- false ->
- case compression_level() of
- 0 ->
- Pid ! {self(), {more, Recs}};
- Level ->
- Pid ! {self(), {more_z, zlib_compress(Recs, Level)}}
- end
+send_packet(N, Pid, Chunk, {[], Cont}) ->
+ send_packet(N, Pid, Chunk, Chunk(Cont));
+send_packet(N, Pid, Chunk, {Recs, Cont}) when N < ?MAX_NOPACKETS ->
+ case compression_level() of
+ 0 ->
+ Pid ! {self(), {more, Recs}};
+ Level ->
+ Pid ! {self(), {more_z, zlib_compress(Recs, Level)}}
end,
- send_packet(N+1, Pid, Chunk, Chunk(Cont), OldNode);
-send_packet(_N, _Pid, _Chunk, DataState, _OldNode) ->
+ send_packet(N+1, Pid, Chunk, Chunk(Cont));
+send_packet(_N, _Pid, _Chunk, DataState) ->
DataState.
finish_copy(Pid, Tab, Storage, RemoteS) ->
@@ -855,5 +801,5 @@ dat2bin(_Tab, _LocalS, _RemoteS) ->
handle_exit(Pid, Reason) when node(Pid) == node() ->
exit(Reason);
-handle_exit(_Pid, _Reason) -> %% Not from our node, this will be handled by
+handle_exit(_Pid, _Reason) -> %% Not from our node, this will be handled by
ignore. %% mnesia_down soon.
diff --git a/lib/mnesia/src/mnesia_monitor.erl b/lib/mnesia/src/mnesia_monitor.erl
index b6eda9ad3a..e110ad3241 100644
--- a/lib/mnesia/src/mnesia_monitor.erl
+++ b/lib/mnesia/src/mnesia_monitor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -76,13 +76,13 @@
-include("mnesia.hrl").
--record(state, {supervisor, pending_negotiators = [],
+-record(state, {supervisor, pending_negotiators = [],
going_down = [], tm_started = false, early_connects = [],
connecting, mq = []}).
--define(current_protocol_version, {7,6}).
+-define(current_protocol_version, {8,0}).
--define(previous_protocol_version, {7,5}).
+-define(previous_protocol_version, {7,6}).
start() ->
gen_server:start_link({local, ?MODULE}, ?MODULE,
@@ -151,12 +151,12 @@ check_protocol([{Node, {accept, Mon, Version, Protocol}} | Tail], Protocols) ->
case lists:member(Protocol, Protocols) of
true ->
case Protocol == protocol_version() of
- true ->
+ true ->
set({protocol, Node}, {Protocol, false});
false ->
set({protocol, Node}, {Protocol, true})
end,
- [node(Mon) | check_protocol(Tail, Protocols)];
+ [node(Mon) | check_protocol(Tail, Protocols)];
false ->
verbose("Failed to connect with ~p. ~p protocols rejected. "
"expected version = ~p, expected protocol = ~p~n",
@@ -179,7 +179,7 @@ check_protocol([], [Protocol | _Protocols]) ->
set(protocol_version, Protocol),
[].
-protocol_version() ->
+protocol_version() ->
case ?catch_val(protocol_version) of
{'EXIT', _} -> ?current_protocol_version;
Version -> Version
@@ -189,14 +189,14 @@ protocol_version() ->
%% preferred protocols are first in the list
acceptable_protocol_versions() ->
[protocol_version(), ?previous_protocol_version].
-
+
needs_protocol_conversion(Node) ->
case {?catch_val({protocol, Node}), protocol_version()} of
{{'EXIT', _}, _} ->
false;
- {{_, Bool}, ?current_protocol_version} ->
+ {{_, Bool}, ?current_protocol_version} ->
Bool;
- {{_, Bool}, _} ->
+ {{_, Bool}, _} ->
not Bool
end.
@@ -255,15 +255,15 @@ terminate_proc(Who, Reason, _State) ->
%%----------------------------------------------------------------------
init([Parent]) ->
process_flag(trap_exit, true),
- ?ets_new_table(mnesia_gvar, [set, public, named_table]),
- ?ets_new_table(mnesia_stats, [set, public, named_table]),
+ ?ets_new_table(mnesia_gvar, [set, public, named_table]),
+ ?ets_new_table(mnesia_stats, [set, public, named_table]),
set(subscribers, []),
set(activity_subscribers, []),
mnesia_lib:verbose("~p starting: ~p~n", [?MODULE, self()]),
Version = mnesia:system_info(version),
set(version, Version),
dbg_out("Version: ~p~n", [Version]),
-
+
case catch process_config_args(env()) of
ok ->
mnesia_lib:set({'$$$_report', current_pos}, 0),
@@ -283,7 +283,7 @@ init([Parent]) ->
set(checkpoints, []),
set(pending_checkpoints, []),
set(pending_checkpoint_pids, []),
-
+
{ok, #state{supervisor = Parent}};
{'EXIT', Reason} ->
mnesia_lib:report_fatal("Bad configuration: ~p~n", [Reason]),
@@ -398,9 +398,9 @@ handle_call({unsafe_close_log, Name}, _From, State) ->
disk_log:close(Name),
{reply, ok, State};
-handle_call({negotiate_protocol, Mon, _Version, _Protocols}, _From, State)
+handle_call({negotiate_protocol, Mon, _Version, _Protocols}, _From, State)
when State#state.tm_started == false ->
- State2 = State#state{early_connects = [node(Mon) | State#state.early_connects]},
+ State2 = State#state{early_connects = [node(Mon) | State#state.early_connects]},
{reply, {node(), {reject, self(), uninitialized, uninitialized}}, State2};
%% From remote monitor..
@@ -412,7 +412,7 @@ handle_call({negotiate_protocol, Mon, Version, Protocols}, From, State)
true ->
accept_protocol(Mon, MyVersion, Protocol, From, State);
false ->
- %% in this release we should be able to handle the previous
+ %% in this release we should be able to handle the previous
%% protocol
case hd(Protocols) of
?previous_protocol_version ->
@@ -427,7 +427,7 @@ handle_call({negotiate_protocol, Mon, Version, Protocols}, From, State)
end;
%% Local request to negotiate with other monitors (nodes).
-handle_call({negotiate_protocol, Nodes}, From, State) ->
+handle_call({negotiate_protocol, Nodes}, From, State) ->
case mnesia_lib:intersect(State#state.going_down, Nodes) of
[] ->
spawn_link(?MODULE, negotiate_protocol_impl, [Nodes, From]),
@@ -461,7 +461,7 @@ accept_protocol(Mon, Version, Protocol, From, State) ->
%% No need for wait
link(Mon), %% link to remote Monitor
case Protocol == protocol_version() of
- true ->
+ true ->
set({protocol, Node}, {Protocol, false});
false ->
set({protocol, Node}, {Protocol, true})
@@ -509,7 +509,7 @@ handle_cast({disconnect, Node}, State) ->
ignore;
undefined ->
ignore;
- RemoteMon when is_pid(RemoteMon) ->
+ RemoteMon when is_pid(RemoteMon) ->
unlink(RemoteMon)
end,
{noreply, State};
@@ -534,7 +534,7 @@ handle_info({'EXIT', Pid, R}, State) when Pid == State#state.supervisor ->
dbg_out("~p was ~p by supervisor~n",[?MODULE, R]),
{stop, R, State};
-handle_info({'EXIT', Pid, fatal}, State) when node(Pid) == node() ->
+handle_info({'EXIT', Pid, fatal}, State) when node(Pid) == node() ->
dbg_out("~p got FATAL ERROR from: ~p~n",[?MODULE, Pid]),
exit(State#state.supervisor, shutdown),
{noreply, State};
@@ -550,7 +550,7 @@ handle_info(Msg = {'EXIT',Pid,_}, State) ->
Node /= node() ->
{noreply, State#state{mq = State#state.mq ++ [{info, Msg}]}};
true ->
- %% We have probably got an exit signal from
+ %% We have probably got an exit signal from
%% disk_log or dets
Hint = "Hint: check that the disk still is writable",
fatal("~p got unexpected info: ~p; ~p~n",
@@ -567,10 +567,10 @@ handle_info({nodeup, Node}, State) ->
%% Let's check if Mnesia is running there in order
%% to detect if the network has been partitioned
%% due to communication failure.
-
+
HasDown = mnesia_recover:has_mnesia_down(Node),
ImRunning = mnesia_lib:is_running(),
-
+
if
%% If I'm not running the test will be made later.
HasDown == true, ImRunning == yes ->
@@ -589,7 +589,7 @@ handle_info({disk_log, _Node, Log, Info}, State) ->
{truncated, _No} ->
ok;
_ ->
- mnesia_lib:important("Warning Log file ~p error reason ~s~n",
+ mnesia_lib:important("Warning Log file ~p error reason ~s~n",
[Log, disk_log:format_error(Info)])
end,
{noreply, State};
@@ -681,38 +681,38 @@ env() ->
send_compressed
].
-default_env(access_module) ->
+default_env(access_module) ->
mnesia;
-default_env(auto_repair) ->
+default_env(auto_repair) ->
true;
-default_env(backup_module) ->
+default_env(backup_module) ->
mnesia_backup;
-default_env(debug) ->
+default_env(debug) ->
none;
default_env(dir) ->
Name = lists:concat(["Mnesia.", node()]),
filename:absname(Name);
-default_env(dump_log_load_regulation) ->
+default_env(dump_log_load_regulation) ->
false;
-default_env(dump_log_time_threshold) ->
+default_env(dump_log_time_threshold) ->
timer:minutes(3);
-default_env(dump_log_update_in_place) ->
+default_env(dump_log_update_in_place) ->
true;
default_env(dump_log_write_threshold) ->
1000;
-default_env(embedded_mnemosyne) ->
+default_env(embedded_mnemosyne) ->
false;
-default_env(event_module) ->
+default_env(event_module) ->
mnesia_event;
-default_env(extra_db_nodes) ->
+default_env(extra_db_nodes) ->
[];
-default_env(ignore_fallback_at_startup) ->
+default_env(ignore_fallback_at_startup) ->
false;
default_env(fallback_error_function) ->
{mnesia, lkill};
-default_env(max_wait_for_decision) ->
+default_env(max_wait_for_decision) ->
infinity;
-default_env(schema_location) ->
+default_env(schema_location) ->
opt_disc;
default_env(core_dir) ->
false;
@@ -732,7 +732,7 @@ check_type(Env, Val) ->
NewVal ->
NewVal
end.
-
+
do_check_type(access_module, A) when is_atom(A) -> A;
do_check_type(auto_repair, B) -> bool(B);
do_check_type(backup_module, B) when is_atom(B) -> B;
@@ -749,7 +749,7 @@ do_check_type(dump_log_update_in_place, B) -> bool(B);
do_check_type(dump_log_write_threshold, I) when is_integer(I), I > 0 -> I;
do_check_type(event_module, A) when is_atom(A) -> A;
do_check_type(ignore_fallback_at_startup, B) -> bool(B);
-do_check_type(fallback_error_function, {Mod, Func})
+do_check_type(fallback_error_function, {Mod, Func})
when is_atom(Mod), is_atom(Func) -> {Mod, Func};
do_check_type(embedded_mnemosyne, B) -> bool(B);
do_check_type(extra_db_nodes, L) when is_list(L) ->
@@ -804,8 +804,8 @@ detect_inconcistency(Nodes, Context) ->
has_remote_mnesia_down(Node) ->
HasDown = mnesia_recover:has_mnesia_down(Node),
Master = mnesia_recover:get_master_nodes(schema),
- if
- HasDown == true, Master == [] ->
+ if
+ HasDown == true, Master == [] ->
{true, node()};
true ->
{false, node()}
diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl
index fef72ad39c..05be474aea 100644
--- a/lib/mnesia/src/mnesia_schema.erl
+++ b/lib/mnesia/src/mnesia_schema.erl
@@ -100,7 +100,7 @@
]).
%% Needed outside to be able to use/set table_properties
-%% from user (not supported)
+%% from user (not supported)
-export([schema_transaction/1,
insert_schema_ops/2,
do_create_table/1,
@@ -118,9 +118,9 @@
%% Here comes the init function which also resides in
%% this module, it is called upon by the trans server
%% at startup of the system
-%%
+%%
%% We have a meta table which looks like
-%% {table, schema,
+%% {table, schema,
%% {type, set},
%% {disc_copies, all},
%% {arity, 2}
@@ -149,14 +149,14 @@ exit_on_error(GoodRes) ->
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason);
- Value -> Value
+ {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason);
+ Value -> Value
end.
%% This function traverses all cstructs in the schema and
%% sets all values in mnesia_gvar accordingly for each table/cstruct
-set_schema('$end_of_table') ->
+set_schema('$end_of_table') ->
[];
set_schema(Tab) ->
do_set_schema(Tab),
@@ -253,8 +253,8 @@ version() ->
incr_version(Cs) ->
{{Major, Minor}, _} = Cs#cstruct.version,
Nodes = mnesia_lib:intersect(val({schema, disc_copies}),
- mnesia_lib:cs_to_nodes(Cs)),
- V =
+ mnesia_lib:cs_to_nodes(Cs)),
+ V =
case Nodes -- val({Cs#cstruct.name, active_replicas}) of
[] -> {Major + 1, 0}; % All replicas are active
_ -> {Major, Minor + 1} % Some replicas are inactive
@@ -359,7 +359,7 @@ delete_schema2() ->
{error, Reason} ->
{error, Reason}
end.
-
+
ensure_no_schema([H|T]) when is_atom(H) ->
case rpc:call(H, ?MODULE, remote_read_schema, []) of
{badrpc, Reason} ->
@@ -407,7 +407,7 @@ opt_create_dir(UseDir, Dir) when UseDir == true->
check_can_write(Dir);
false ->
case file:make_dir(Dir) of
- ok ->
+ ok ->
verbose("Create Directory ~p~n", [Dir]),
ok;
{error, Reason} ->
@@ -417,7 +417,7 @@ opt_create_dir(UseDir, Dir) when UseDir == true->
end;
opt_create_dir(false, _) ->
{error, {has_no_disc, node()}}.
-
+
check_can_write(Dir) ->
case file:read_file_info(Dir) of
{ok, FI} when FI#file_info.type == directory,
@@ -450,7 +450,7 @@ read_schema(Keep) ->
read_schema(Keep, IgnoreFallback) ->
lock_schema(),
- Res =
+ Res =
case mnesia:system_info(is_running) of
yes ->
{ok, ram, get_create_list(schema)};
@@ -477,7 +477,7 @@ read_disc_schema(Keep, IgnoreFallback) ->
case mnesia_bup:fallback_exists() of
true when IgnoreFallback == false, Running /= yes ->
mnesia_bup:fallback_to_schema();
- _ ->
+ _ ->
%% If we're running, we read the schema file even
%% if fallback exists
Dat = mnesia_lib:tab2dat(schema),
@@ -499,7 +499,7 @@ read_disc_schema(Keep, IgnoreFallback) ->
end.
do_read_disc_schema(Fname, Keep) ->
- T =
+ T =
case Keep of
false ->
Args = [{keypos, 2}, public, set],
@@ -523,7 +523,7 @@ do_read_disc_schema(Fname, Keep) ->
get_initial_schema(SchemaStorage, Nodes) ->
Cs = #cstruct{name = schema,
record_name = schema,
- attributes = [table, cstruct]},
+ attributes = [table, cstruct]},
Cs2 =
case SchemaStorage of
ram_copies -> Cs#cstruct{ram_copies = Nodes};
@@ -532,7 +532,7 @@ get_initial_schema(SchemaStorage, Nodes) ->
cs2list(Cs2).
read_cstructs_from_disc() ->
- %% Assumptions:
+ %% Assumptions:
%% - local schema lock in global
%% - use_dir is true
%% - Mnesia is not running
@@ -552,14 +552,14 @@ read_cstructs_from_disc() ->
end,
Cstructs = dets:traverse(Tab, Fun),
dets:close(Tab),
- {ok, Cstructs};
+ {ok, Cstructs};
{error, Reason} ->
{error, Reason}
end;
false ->
{error, "No schema file exists"}
end.
-
+
%% We run a very special type of transactions when we
%% we want to manipulate the schema.
@@ -593,20 +593,20 @@ schema_transaction(Fun) ->
%% This process may dump the transaction log, and should
%% therefore not be run in an application process
-%%
+%%
schema_coordinator(Client, _Fun, undefined) ->
Res = {aborted, {node_not_running, node()}},
Client ! {transaction_done, Res, self()},
unlink(Client);
-
+
schema_coordinator(Client, Fun, Controller) when is_pid(Controller) ->
%% Do not trap exit in order to automatically die
%% when the controller dies
link(Controller),
unlink(Client),
-
- %% Fulfull the transaction even if the client dies
+
+ %% Fulfull the transaction even if the client dies
Res = mnesia:transaction(Fun),
Client ! {transaction_done, Res, self()},
unlink(Controller), % Avoids spurious exit message
@@ -619,7 +619,7 @@ schema_coordinator(Client, Fun, Controller) when is_pid(Controller) ->
insert_schema_ops({_Mod, _Tid, Ts}, SchemaIOps) ->
do_insert_schema_ops(Ts#tidstore.store, SchemaIOps).
-
+
do_insert_schema_ops(Store, [Head | Tail]) ->
?ets_insert(Store, Head),
do_insert_schema_ops(Store, Tail);
@@ -628,15 +628,56 @@ do_insert_schema_ops(_Store, []) ->
cs2list(Cs) when is_record(Cs, cstruct) ->
Tags = record_info(fields, cstruct),
- rec2list(Tags, 2, Cs);
+ rec2list(Tags, Tags, 2, Cs);
cs2list(CreateList) when is_list(CreateList) ->
- CreateList.
-
-rec2list([Tag | Tags], Pos, Rec) ->
+ CreateList;
+%% 4.4.19
+cs2list(Cs) when element(1, Cs) == cstruct, tuple_size(Cs) == 18 ->
+ Tags = [name,type,ram_copies,disc_copies,disc_only_copies,
+ load_order,access_mode,majority,index,snmp,local_content,
+ record_name,attributes,user_properties,frag_properties,
+ cookie,version],
+ rec2list(Tags, Tags, 2, Cs);
+%% 4.4.18 and earlier
+cs2list(Cs) when element(1, Cs) == cstruct, tuple_size(Cs) == 17 ->
+ Tags = [name,type,ram_copies,disc_copies,disc_only_copies,
+ load_order,access_mode,index,snmp,local_content,
+ record_name,attributes,user_properties,frag_properties,
+ cookie,version],
+ rec2list(Tags, Tags, 2, Cs).
+
+cs2list(false, Cs) ->
+ cs2list(Cs);
+cs2list(ver4_4_18, Cs) ->
+ Orig = record_info(fields, cstruct),
+ Tags = [name,type,ram_copies,disc_copies,disc_only_copies,
+ load_order,access_mode,index,snmp,local_content,
+ record_name,attributes,user_properties,frag_properties,
+ cookie,version],
+ rec2list(Tags, Orig, 2, Cs);
+cs2list(ver4_4_19, Cs) ->
+ Orig = record_info(fields, cstruct),
+ Tags = [name,type,ram_copies,disc_copies,disc_only_copies,
+ load_order,access_mode,majority,index,snmp,local_content,
+ record_name,attributes,user_properties,frag_properties,
+ cookie,version],
+ rec2list(Tags, Orig, 2, Cs).
+
+rec2list([Tag | Tags], [Tag | Orig], Pos, Rec) ->
Val = element(Pos, Rec),
- [{Tag, Val} | rec2list(Tags, Pos + 1, Rec)];
-rec2list([], _Pos, _Rec) ->
- [].
+ [{Tag, Val} | rec2list(Tags, Orig, Pos + 1, Rec)];
+rec2list([], _, _Pos, _Rec) ->
+ [];
+rec2list(Tags, [_|Orig], Pos, Rec) ->
+ rec2list(Tags, Orig, Pos+1, Rec).
+
+api_list2cs(List) when is_list(List) ->
+ Name = pick(unknown, name, List, must),
+ Keys = check_keys(Name, List, record_info(fields, cstruct)),
+ check_duplicates(Name, Keys),
+ list2cs(List);
+api_list2cs(Other) ->
+ mnesia:abort({badarg, Other}).
list2cs(List) when is_list(List) ->
Name = pick(unknown, name, List, must),
@@ -667,10 +708,7 @@ list2cs(List) when is_list(List) ->
Frag = pick(Name, frag_properties, List, []),
verify({alt, [nil, list]}, mnesia_lib:etype(Frag),
- {badarg, Name, {frag_properties, Frag}}),
-
- Keys = check_keys(Name, List, record_info(fields, cstruct)),
- check_duplicates(Name, Keys),
+ {badarg, Name, {frag_properties, Frag}}),
#cstruct{name = Name,
ram_copies = Rc,
disc_copies = Dc,
@@ -687,9 +725,7 @@ list2cs(List) when is_list(List) ->
user_properties = lists:sort(UserProps),
frag_properties = lists:sort(Frag),
cookie = Cookie,
- version = Version};
-list2cs(Other) ->
- mnesia:abort({badarg, Other}).
+ version = Version}.
pick(Tab, Key, List, Default) ->
case lists:keysearch(Key, 1, List) of
@@ -708,7 +744,7 @@ attr_tab_to_pos(_Tab, Pos) when is_integer(Pos) ->
Pos;
attr_tab_to_pos(Tab, Attr) ->
attr_to_pos(Attr, val({Tab, attributes})).
-
+
%% Convert attribute name to integer if neccessary
attr_to_pos(Pos, _Attrs) when is_integer(Pos) ->
Pos;
@@ -723,7 +759,7 @@ attr_to_pos(Attr, [_ | Attrs], Pos) ->
attr_to_pos(Attr, Attrs, Pos + 1);
attr_to_pos(Attr, _, _) ->
mnesia:abort({bad_type, Attr}).
-
+
check_keys(Tab, [{Key, _Val} | Tail], Items) ->
case lists:member(Key, Items) of
true -> [Key | check_keys(Tab, Tail, Items)];
@@ -759,7 +795,7 @@ verify_cstruct(Cs) when is_record(Cs, cstruct) ->
{bad_type, Tab, {type, Type}}),
%% Currently ordered_set is not supported for disk_only_copies.
- if
+ if
Type == ordered_set, Cs#cstruct.disc_only_copies /= [] ->
mnesia:abort({bad_type, Tab, {not_supported, Type, disc_only_copies}});
true ->
@@ -776,10 +812,10 @@ verify_cstruct(Cs) when is_record(Cs, cstruct) ->
Arity = length(Attrs) + 1,
verify(true, Arity > 2, {bad_type, Tab, {attributes, Attrs}}),
-
+
lists:foldl(fun(Attr,_Other) when Attr == snmp ->
mnesia:abort({bad_type, Tab, {attributes, [Attr]}});
- (Attr,Other) ->
+ (Attr,Other) ->
verify(atom, mnesia_lib:etype(Attr),
{bad_type, Tab, {attributes, [Attr]}}),
verify(false, lists:member(Attr, Other),
@@ -792,7 +828,7 @@ verify_cstruct(Cs) when is_record(Cs, cstruct) ->
Index = Cs#cstruct.index,
verify({alt, [nil, list]}, mnesia_lib:etype(Index),
{bad_type, Tab, {index, Index}}),
-
+
IxFun =
fun(Pos) ->
verify(true, fun() ->
@@ -807,7 +843,7 @@ verify_cstruct(Cs) when is_record(Cs, cstruct) ->
{bad_type, Tab, {index, [Pos]}})
end,
lists:foreach(IxFun, Index),
-
+
LC = Cs#cstruct.local_content,
verify({alt, [true, false]}, LC,
{bad_type, Tab, {local_content, LC}}),
@@ -834,7 +870,7 @@ verify_cstruct(Cs) when is_record(Cs, cstruct) ->
lists:foreach(CheckProp, Cs#cstruct.user_properties),
case Cs#cstruct.cookie of
- {{MegaSecs, Secs, MicroSecs}, _Node}
+ {{MegaSecs, Secs, MicroSecs}, _Node}
when is_integer(MegaSecs), is_integer(Secs),
is_integer(MicroSecs), is_atom(node) ->
ok;
@@ -870,15 +906,15 @@ verify_nodes(Cs) ->
end,
verify(integer, mnesia_lib:etype(LoadOrder),
{bad_type, Tab, {load_order, LoadOrder}}),
-
+
Nodes = Ram ++ Disc ++ DiscOnly,
verify(list, mnesia_lib:etype(Nodes),
{combine_error, Tab,
[{ram_copies, []}, {disc_copies, []}, {disc_only_copies, []}]}),
verify(false, has_duplicates(Nodes), {combine_error, Tab, Nodes}),
- AtomCheck = fun(N) -> verify(atom, mnesia_lib:etype(N), {bad_type, Tab, N}) end,
+ AtomCheck = fun(N) -> verify(atom, mnesia_lib:etype(N), {bad_type, Tab, N}) end,
lists:foreach(AtomCheck, Nodes).
-
+
verify(Expected, Fun, Error) when is_function(Fun) ->
do_verify(Expected, catch Fun(), Error);
verify(Expected, Actual, Error) ->
@@ -909,7 +945,7 @@ ensure_active(Cs, What) ->
W = {Tab, What},
ensure_non_empty(W),
Nodes = mnesia_lib:intersect(val({schema, disc_copies}),
- mnesia_lib:cs_to_nodes(Cs)),
+ mnesia_lib:cs_to_nodes(Cs)),
case Nodes -- val(W) of
[] ->
ok;
@@ -936,7 +972,7 @@ ensure_non_empty({Tab, Vhat}) ->
ensure_not_active(Tab = schema, Node) ->
Active = val({Tab, active_replicas}),
- case lists:member(Node, Active) of
+ case lists:member(Node, Active) of
false when Active =/= [] ->
ok;
false ->
@@ -970,7 +1006,7 @@ create_table(TabDef) ->
do_multi_create_table(TabDef) ->
get_tid_ts_and_lock(schema, write),
ensure_writable(schema),
- Cs = list2cs(TabDef),
+ Cs = api_list2cs(TabDef),
case Cs#cstruct.frag_properties of
[] ->
do_create_table(Cs);
@@ -999,7 +1035,7 @@ unsafe_make_create_table(Cs) ->
{_Mod, Tid, Ts} = get_tid_ts_and_lock(schema, none),
verify_cstruct(Cs),
Tab = Cs#cstruct.name,
-
+
%% Check that we have all disc replica nodes running
DiscNodes = Cs#cstruct.disc_copies ++ Cs#cstruct.disc_only_copies,
RunningNodes = val({current, db_nodes}),
@@ -1017,7 +1053,7 @@ unsafe_make_create_table(Cs) ->
check_if_exists(Tab) ->
TidTs = get_tid_ts_and_lock(schema, write),
{_, _, Ts} = TidTs,
- Store = Ts#tidstore.store,
+ Store = Ts#tidstore.store,
ets:foldl(
fun({op, create_table, [{name, T}|_]}, _Acc) when T==Tab ->
true;
@@ -1054,7 +1090,7 @@ make_delete_table(Tab, Mode) ->
%% nodes etc.
TidTs = get_tid_ts_and_lock(schema, write),
{_, _, Ts} = TidTs,
- Store = Ts#tidstore.store,
+ Store = Ts#tidstore.store,
Deleted = ets:select_delete(
Store, [{{op,'$1',[{name,Tab}|'_']},
[{'or',
@@ -1077,9 +1113,9 @@ make_delete_table(Tab, Mode) ->
[] ->
[make_delete_table2(Tab)];
_Props ->
- %% Check if it is a base table
- mnesia_frag:lookup_frag_hash(Tab),
-
+ %% Check if it is a base table
+ mnesia_frag:lookup_frag_hash(Tab),
+
%% Check for foreigners
F = mnesia_frag:lookup_foreigners(Tab),
verify([], F, {combine_error,
@@ -1101,7 +1137,7 @@ make_delete_table2(Tab) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Change fragmentation of a table
-
+
change_table_frag(Tab, Change) ->
schema_transaction(fun() -> do_change_table_frag(Tab, Change) end).
@@ -1112,7 +1148,7 @@ do_change_table_frag(Tab, Change) when is_atom(Tab), Tab /= schema ->
ok;
do_change_table_frag(Tab, _Change) ->
mnesia:abort({bad_type, Tab}).
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Clear a table
@@ -1150,7 +1186,7 @@ make_add_table_copy(Tab, Node, Storage) ->
verify(false, lists:member(Node, Ns), {already_exists, Tab, Node}),
Cs2 = new_cs(Cs, Node, Storage, add),
verify_cstruct(Cs2),
-
+
%% Check storage and if node is running
IsRunning = lists:member(Node, val({current, db_nodes})),
if
@@ -1177,21 +1213,21 @@ del_table_copy(Tab, Node) ->
do_del_table_copy(Tab, Node) when is_atom(Node) ->
TidTs = get_tid_ts_and_lock(schema, write),
-%% get_tid_ts_and_lock(Tab, write),
+%% get_tid_ts_and_lock(Tab, write),
insert_schema_ops(TidTs, make_del_table_copy(Tab, Node));
do_del_table_copy(Tab, Node) ->
mnesia:abort({badarg, Tab, Node}).
-
+
make_del_table_copy(Tab, Node) ->
ensure_writable(schema),
Cs = incr_version(val({Tab, cstruct})),
Storage = mnesia_lib:schema_cs_to_storage_type(Node, Cs),
- Cs2 = new_cs(Cs, Node, Storage, del),
+ Cs2 = new_cs(Cs, Node, Storage, del),
case mnesia_lib:cs_to_nodes(Cs2) of
[] when Tab == schema ->
mnesia:abort({combine_error, Tab, "Last replica"});
[] ->
- ensure_active(Cs),
+ ensure_active(Cs),
dbg_out("Last replica deleted in table ~p~n", [Tab]),
make_delete_table(Tab, whole_table);
_ when Tab == schema ->
@@ -1210,14 +1246,14 @@ remove_node_from_tabs([], _Node) ->
[];
remove_node_from_tabs([schema|Rest], Node) ->
remove_node_from_tabs(Rest, Node);
-remove_node_from_tabs([Tab|Rest], Node) ->
- {Cs, IsFragModified} =
+remove_node_from_tabs([Tab|Rest], Node) ->
+ {Cs, IsFragModified} =
mnesia_frag:remove_node(Node, incr_version(val({Tab, cstruct}))),
case mnesia_lib:schema_cs_to_storage_type(Node, Cs) of
unknown ->
case IsFragModified of
true ->
- [{op, change_table_frag, {del_node, Node}, cs2list(Cs)} |
+ [{op, change_table_frag, {del_node, Node}, cs2list(Cs)} |
remove_node_from_tabs(Rest, Node)];
false ->
remove_node_from_tabs(Rest, Node)
@@ -1246,7 +1282,7 @@ new_cs(Cs, Node, ram_copies, del) ->
new_cs(Cs, Node, disc_copies, del) ->
Cs#cstruct{disc_copies = lists:delete(Node , Cs#cstruct.disc_copies)};
new_cs(Cs, Node, disc_only_copies, del) ->
- Cs#cstruct{disc_only_copies =
+ Cs#cstruct{disc_only_copies =
lists:delete(Node , Cs#cstruct.disc_only_copies)};
new_cs(Cs, _Node, Storage, _Op) ->
mnesia:abort({badarg, Cs#cstruct.name, Storage}).
@@ -1278,7 +1314,7 @@ make_move_table(Tab, FromNode, ToNode) ->
Running = val({current, db_nodes}),
Storage = mnesia_lib:schema_cs_to_storage_type(FromNode, Cs),
verify(true, lists:member(ToNode, Running), {not_active, schema, ToNode}),
-
+
Cs2 = new_cs(Cs, ToNode, Storage, add),
Cs3 = new_cs(Cs2, FromNode, Storage, del),
verify_cstruct(Cs3),
@@ -1306,7 +1342,7 @@ make_change_table_copy_type(Tab, Node, unknown) ->
make_change_table_copy_type(Tab, Node, ToS) ->
ensure_writable(schema),
Cs = incr_version(val({Tab, cstruct})),
- FromS = mnesia_lib:storage_type_at_node(Node, Tab),
+ FromS = mnesia_lib:storage_type_at_node(Node, Tab),
case compare_storage_type(false, FromS, ToS) of
{same, _} ->
@@ -1320,12 +1356,12 @@ make_change_table_copy_type(Tab, Node, ToS) ->
Cs2 = new_cs(Cs, Node, FromS, del),
Cs3 = new_cs(Cs2, Node, ToS, add),
verify_cstruct(Cs3),
-
+
[{op, change_table_copy_type, Node, FromS, ToS, cs2list(Cs3)}].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% change index functions ....
-%% Pos is allready added by 1 in both of these functions
+%% Pos is allready added by 1 in both of these functions
add_table_index(Tab, Pos) ->
schema_transaction(fun() -> do_add_table_index(Tab, Pos) end).
@@ -1412,14 +1448,14 @@ make_del_snmp(Tab) ->
[{op, del_snmp, cs2list(Cs2)}].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
+%%
-transform_table(Tab, Fun, NewAttrs, NewRecName)
- when is_function(Fun), is_list(NewAttrs), is_atom(NewRecName) ->
+transform_table(Tab, Fun, NewAttrs, NewRecName)
+ when is_function(Fun), is_list(NewAttrs), is_atom(NewRecName) ->
schema_transaction(fun() -> do_transform_table(Tab, Fun, NewAttrs, NewRecName) end);
-transform_table(Tab, ignore, NewAttrs, NewRecName)
- when is_list(NewAttrs), is_atom(NewRecName) ->
+transform_table(Tab, ignore, NewAttrs, NewRecName)
+ when is_list(NewAttrs), is_atom(NewRecName) ->
schema_transaction(fun() -> do_transform_table(Tab, ignore, NewAttrs, NewRecName) end);
transform_table(Tab, Fun, NewAttrs, NewRecName) ->
@@ -1438,7 +1474,7 @@ make_transform(Tab, Fun, NewAttrs, NewRecName) ->
ensure_active(Cs),
ensure_writable(Tab),
case mnesia_lib:val({Tab, index}) of
- [] ->
+ [] ->
Cs2 = Cs#cstruct{attributes = NewAttrs, record_name = NewRecName},
verify_cstruct(Cs2),
[{op, transform, Fun, cs2list(Cs2)}];
@@ -1464,7 +1500,7 @@ make_transform(Tab, Fun, NewAttrs, NewRecName) ->
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%
+%%
change_table_access_mode(Tab, Mode) ->
schema_transaction(fun() -> do_change_table_access_mode(Tab, Mode) end).
@@ -1598,9 +1634,9 @@ change_prop_in_existing_op(Tab, Prop, How, Store) ->
false ->
false
end.
-
-update_existing_op([{op, Op, L = [{name,Tab}|_], _OldProp}|Ops],
- Tab, Prop, How, Acc) when Op == write_property;
+
+update_existing_op([{op, Op, L = [{name,Tab}|_], _OldProp}|Ops],
+ Tab, Prop, How, Acc) when Op == write_property;
Op == delete_property ->
%% Apparently, mnesia_dumper doesn't care about OldProp here -- just L,
%% so we will throw away OldProp (not that it matters...) and insert Prop.
@@ -1625,7 +1661,7 @@ update_existing_op([], _, _, _, _) ->
do_read_table_property(Tab, Key) ->
TidTs = get_tid_ts_and_lock(schema, read),
{_, _, Ts} = TidTs,
- Store = Ts#tidstore.store,
+ Store = Ts#tidstore.store,
Props = ets:foldl(
fun({op, create_table, [{name, T}|Opts]}, _Acc)
when T==Tab ->
@@ -1689,7 +1725,7 @@ do_delete_table_property(Tab, PropKey) ->
[Tab,PropKey]),
%% this must be an existing table
get_tid_ts_and_lock(Tab, none),
- insert_schema_ops(TidTs,
+ insert_schema_ops(TidTs,
make_delete_table_properties(Tab, [PropKey]))
end.
@@ -1711,17 +1747,17 @@ make_delete_table_properties(_Tab, [], _Cs) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Ensure that the transaction can be committed even
+%% Ensure that the transaction can be committed even
%% if the node crashes and Mnesia is restarted
prepare_commit(Tid, Commit, WaitFor) ->
case Commit#commit.schema_ops of
[] ->
{false, Commit, optional};
OrigOps ->
- {Modified, Ops, DumperMode} =
+ {Modified, Ops, DumperMode} =
prepare_ops(Tid, OrigOps, WaitFor, false, [], optional),
InitBy = schema_prepare,
- GoodRes = {Modified,
+ GoodRes = {Modified,
Commit#commit{schema_ops = lists:reverse(Ops)},
DumperMode},
case DumperMode of
@@ -1737,7 +1773,7 @@ prepare_commit(Tid, Commit, WaitFor) ->
end
end,
case Ops of
- [] ->
+ [] ->
ignore;
_ ->
%% We need to grab a dumper lock here, the log may not
@@ -1749,20 +1785,20 @@ prepare_commit(Tid, Commit, WaitFor) ->
prepare_ops(Tid, [Op | Ops], WaitFor, Changed, Acc, DumperMode) ->
case prepare_op(Tid, Op, WaitFor) of
- {true, mandatory} ->
+ {true, mandatory} ->
prepare_ops(Tid, Ops, WaitFor, Changed, [Op | Acc], mandatory);
- {true, optional} ->
+ {true, optional} ->
prepare_ops(Tid, Ops, WaitFor, Changed, [Op | Acc], DumperMode);
- {true, Ops2, mandatory} ->
+ {true, Ops2, mandatory} ->
prepare_ops(Tid, Ops, WaitFor, true, Ops2 ++ Acc, mandatory);
- {true, Ops2, optional} ->
+ {true, Ops2, optional} ->
prepare_ops(Tid, Ops, WaitFor, true, Ops2 ++ Acc, DumperMode);
- {false, optional} ->
+ {false, optional} ->
prepare_ops(Tid, Ops, WaitFor, true, Acc, DumperMode)
end;
prepare_ops(_Tid, [], _WaitFor, Changed, Acc, DumperMode) ->
{Changed, Acc, DumperMode}.
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Prepare for commit
%% returns true if Op should be included, i.e. unmodified
@@ -1781,8 +1817,8 @@ prepare_op(_Tid, {op, rec, unknown, Rec}, _WaitFor) ->
prepare_op(_Tid, {op, announce_im_running, Node, SchemaDef, Running, RemoteRunning}, _WaitFor) ->
SchemaCs = list2cs(SchemaDef),
- if
- Node == node() -> %% Announce has already run on local node
+ if
+ Node == node() -> %% Announce has already run on local node
ignore; %% from do_merge_schema
true ->
%% If a node has restarted it may still linger in db_nodes,
@@ -1794,9 +1830,9 @@ prepare_op(_Tid, {op, announce_im_running, Node, SchemaDef, Running, RemoteRunni
end,
{false, optional};
-prepare_op(_Tid, {op, sync_trans}, {part, CoordPid}) ->
+prepare_op(_Tid, {op, sync_trans}, {part, CoordPid}) ->
CoordPid ! {sync_trans, self()},
- receive
+ receive
{sync_trans, CoordPid} ->
{false, optional};
{mnesia_down, _Node} = Else ->
@@ -1807,7 +1843,7 @@ prepare_op(_Tid, {op, sync_trans}, {part, CoordPid}) ->
mnesia:abort(Else)
end;
-prepare_op(_Tid, {op, sync_trans}, {coord, Nodes}) ->
+prepare_op(_Tid, {op, sync_trans}, {coord, Nodes}) ->
case receive_sync(Nodes, []) of
{abort, Reason} ->
mnesia_lib:verbose("sync_op terminated due to ~p~n", [Reason]),
@@ -1838,7 +1874,7 @@ prepare_op(Tid, {op, create_table, TabDef}, _WaitFor) ->
create_ram_table(Tab, Cs#cstruct.type),
create_disc_table(Tab),
insert_cstruct(Tid, Cs, false),
- {true, optional};
+ {true, optional};
disc_only_copies ->
mnesia_lib:set({Tab, create_table},true),
create_disc_only_table(Tab,Cs#cstruct.type),
@@ -1857,15 +1893,15 @@ prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}, _WaitFor) ->
if
Tab == schema ->
{true, optional};
-
+
Node == node() ->
- case mnesia_lib:val({schema, storage_type}) of
- ram_copies when Storage /= ram_copies ->
+ case mnesia_lib:val({schema, storage_type}) of
+ ram_copies when Storage /= ram_copies ->
Error = {combine_error, Tab, "has no disc", Node},
mnesia:abort(Error);
_ ->
ok
- end,
+ end,
%% Tables are created by mnesia_loader get_network code
insert_cstruct(Tid, Cs, true),
case mnesia_controller:get_network_copy(Tab, Cs) of
@@ -1902,22 +1938,22 @@ prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}, _WaitFor) ->
prepare_op(Tid, {op, del_table_copy, _Storage, Node, TabDef}, _WaitFor) ->
Cs = list2cs(TabDef),
Tab = Cs#cstruct.name,
-
+
if
%% Schema table lock is always required to run a schema op.
%% No need to look it.
- node(Tid#tid.pid) == node(), Tab /= schema ->
+ node(Tid#tid.pid) == node(), Tab /= schema ->
Self = self(),
Pid = spawn_link(fun() -> lock_del_table(Tab, Node, Cs, Self) end),
put(mnesia_lock, Pid),
- receive
- {Pid, updated} ->
+ receive
+ {Pid, updated} ->
{true, optional};
{Pid, FailReason} ->
mnesia:abort(FailReason);
{'EXIT', Pid, Reason} ->
mnesia:abort(Reason)
- end;
+ end;
true ->
{true, optional}
end;
@@ -1928,12 +1964,12 @@ prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef}, _WaitFor)
Tab = Cs#cstruct.name,
NotActive = mnesia_lib:not_active_here(Tab),
-
- if
+
+ if
NotActive == true ->
mnesia:abort({not_active, Tab, node()});
-
- Tab == schema ->
+
+ Tab == schema ->
case {FromS, ToS} of
{ram_copies, disc_copies} ->
case mnesia:system_info(schema_location) of
@@ -1943,7 +1979,7 @@ prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef}, _WaitFor)
mnesia:abort({combine_error, Tab, node(),
"schema_location must be opt_disc"})
end,
- Dir = mnesia_lib:dir(),
+ Dir = mnesia_lib:dir(),
case opt_create_dir(true, Dir) of
ok ->
purge_dir(Dir, []),
@@ -1967,18 +2003,18 @@ prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef}, _WaitFor)
_ ->
mnesia:abort({combine_error, Tab, ToS})
end;
-
- FromS == ram_copies ->
+
+ FromS == ram_copies ->
case mnesia_monitor:use_dir() of
- true ->
+ true ->
Dat = mnesia_lib:tab2dcd(Tab),
case mnesia_lib:exists(Dat) of
true ->
mnesia:abort({combine_error, Tab, node(),
"Table dump exists"});
false ->
- case ToS of
- disc_copies ->
+ case ToS of
+ disc_copies ->
mnesia_log:ets2dcd(Tab, dmp);
disc_only_copies ->
mnesia_dumper:raw_named_dump_table(Tab, dmp)
@@ -1988,7 +2024,7 @@ prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef}, _WaitFor)
false ->
mnesia:abort({has_no_disc, node()})
end;
-
+
FromS == disc_copies, ToS == disc_only_copies ->
mnesia_dumper:raw_named_dump_table(Tab, dmp);
FromS == disc_only_copies ->
@@ -2020,7 +2056,7 @@ prepare_op(_Tid, {op, dump_table, unknown, TabDef}, _WaitFor) ->
case lists:member(node(), Cs#cstruct.ram_copies) of
true ->
case mnesia_monitor:use_dir() of
- true ->
+ true ->
mnesia_log:ets2dcd(Tab, dmp),
Size = mnesia:table_info(Tab, size),
{true, [{op, dump_table, Size, TabDef}], optional};
@@ -2058,7 +2094,7 @@ prepare_op(_Tid, {op, transform, Fun, TabDef}, _WaitFor) ->
mnesia_lib:db_fixtable(Storage, Tab, true),
Key = mnesia_lib:db_first(Tab),
Op = {op, transform, Fun, TabDef},
- case catch transform_objs(Fun, Tab, RecName,
+ case catch transform_objs(Fun, Tab, RecName,
Key, NewArity, Storage, Type, [Op]) of
{'EXIT', Reason} ->
mnesia_lib:db_fixtable(Storage, Tab, false),
@@ -2072,7 +2108,7 @@ prepare_op(_Tid, {op, transform, Fun, TabDef}, _WaitFor) ->
prepare_op(_Tid, {op, merge_schema, TabDef}, _WaitFor) ->
Cs = list2cs(TabDef),
case verify_merge(Cs) of
- ok ->
+ ok ->
{true, optional};
Error ->
verbose("Merge_Schema ~p failed on ~p: ~p~n", [_Tid,node(),Error]),
@@ -2093,7 +2129,7 @@ create_ram_table(Tab, Type) ->
create_disc_table(Tab) ->
File = mnesia_lib:tab2dcd(Tab),
file:delete(File),
- FArg = [{file, File}, {name, {mnesia,create}},
+ FArg = [{file, File}, {name, {mnesia,create}},
{repair, false}, {mode, read_write}],
case mnesia_monitor:open_log(FArg) of
{ok,Log} ->
@@ -2124,7 +2160,7 @@ receive_sync([], Pids) ->
receive_sync(Nodes, Pids) ->
receive
{sync_trans, Pid} ->
- Node = node(Pid),
+ Node = node(Pid),
receive_sync(lists:delete(Node, Nodes), [Pid | Pids]);
Else ->
{abort, Else}
@@ -2140,16 +2176,16 @@ lock_del_table(Tab, Node, Cs, Father) ->
false;
({badrpc, {'EXIT', {undef, _}}}) ->
%% This will be the case we talks with elder nodes
- %% than 3.8.2, they will set where_to_read without
- %% getting a lock.
+ %% than 3.8.2, they will set where_to_read without
+ %% getting a lock.
false;
(_) ->
true
end,
case lists:filter(Filter, Res) of
- [] ->
+ [] ->
Father ! {self(), updated},
- %% When transaction is commited the process dies
+ %% When transaction is commited the process dies
%% and the lock is released.
receive _ -> ok end;
Err ->
@@ -2166,7 +2202,7 @@ lock_del_table(Tab, Node, Cs, Father) ->
exit(normal).
set_where_to_read(Tab, Node, Cs) ->
- case mnesia_lib:val({Tab, where_to_read}) of
+ case mnesia_lib:val({Tab, where_to_read}) of
Node ->
case Cs#cstruct.local_content of
true ->
@@ -2185,16 +2221,16 @@ transform_objs(_Fun, _Tab, _RT, '$end_of_table', _NewArity, _Storage, _Type, Acc
transform_objs(Fun, Tab, RecName, Key, A, Storage, Type, Acc) ->
Objs = mnesia_lib:db_get(Tab, Key),
NextKey = mnesia_lib:db_next_key(Tab, Key),
- Oid = {Tab, Key},
+ Oid = {Tab, Key},
NewObjs = {Ws, Ds} = transform_obj(Tab, RecName, Key, Fun, Objs, A, Type, [], []),
- if
- NewObjs == {[], []} ->
+ if
+ NewObjs == {[], []} ->
transform_objs(Fun, Tab, RecName, NextKey, A, Storage, Type, Acc);
- Type == bag ->
+ Type == bag ->
transform_objs(Fun, Tab, RecName, NextKey, A, Storage, Type,
[{op, rec, Storage, {Oid, Ws, write}},
{op, rec, Storage, {Oid, [Oid], delete}} | Acc]);
- Ds == [] ->
+ Ds == [] ->
%% Type is set or ordered_set, no need to delete the record first
transform_objs(Fun, Tab, RecName, NextKey, A, Storage, Type,
[{op, rec, Storage, {Oid, Ws, write}} | Acc]);
@@ -2215,15 +2251,15 @@ transform_obj(Tab, RecName, Key, Fun, [Obj|Rest], NewArity, Type, Ws, Ds) ->
NewObj == Obj ->
transform_obj(Tab, RecName, Key, Fun, Rest, NewArity, Type, Ws, Ds);
RecName == element(1, NewObj), Key == element(2, NewObj) ->
- transform_obj(Tab, RecName, Key, Fun, Rest, NewArity,
+ transform_obj(Tab, RecName, Key, Fun, Rest, NewArity,
Type, [NewObj | Ws], Ds);
- NewObj == delete ->
- case Type of
+ NewObj == delete ->
+ case Type of
bag -> %% Just don't write that object
- transform_obj(Tab, RecName, Key, Fun, Rest,
- NewArity, Type, Ws, Ds);
+ transform_obj(Tab, RecName, Key, Fun, Rest,
+ NewArity, Type, Ws, Ds);
_ ->
- transform_obj(Tab, RecName, Key, Fun, Rest, NewArity,
+ transform_obj(Tab, RecName, Key, Fun, Rest, NewArity,
Type, Ws, [NewObj | Ds])
end;
true ->
@@ -2247,7 +2283,7 @@ undo_prepare_commit(Tid, Commit) ->
%% Undo in reverse order
undo_prepare_ops(Tid, [Op | Ops]) ->
- case element(1, Op) of
+ case element(1, Op) of
TheOp when TheOp /= op, TheOp /= restore_op ->
undo_prepare_ops(Tid, Ops);
_ ->
@@ -2274,7 +2310,7 @@ undo_prepare_op(Tid, {op, create_table, TabDef}) ->
mnesia_lib:unset({Tab, create_table}),
delete_cstruct(Tid, Cs),
case mnesia_lib:cs_to_storage_type(node(), Cs) of
- unknown ->
+ unknown ->
ok;
ram_copies ->
ram_delete_table(Tab, ram_copies);
@@ -2289,7 +2325,7 @@ undo_prepare_op(Tid, {op, create_table, TabDef}) ->
%% disc_delete_table(Tab, Storage),
file:delete(Dat)
end;
-
+
undo_prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}) ->
Cs = list2cs(TabDef),
Tab = Cs#cstruct.name,
@@ -2314,21 +2350,21 @@ undo_prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}) ->
Cs2 = new_cs(Cs, Node, Storage, del),
insert_cstruct(Tid, Cs2, true) % Don't care about the version
end;
-
-undo_prepare_op(_Tid, {op, del_table_copy, _, Node, TabDef})
+
+undo_prepare_op(_Tid, {op, del_table_copy, _, Node, TabDef})
when Node == node() ->
Cs = list2cs(TabDef),
Tab = Cs#cstruct.name,
mnesia_lib:set({Tab, where_to_read}, Node);
-undo_prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef})
+undo_prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef})
when N == node() ->
Cs = list2cs(TabDef),
Tab = Cs#cstruct.name,
mnesia_checkpoint:tm_change_table_copy_type(Tab, ToS, FromS),
Dmp = mnesia_lib:tab2dmp(Tab),
-
+
case {FromS, ToS} of
{ram_copies, disc_copies} when Tab == schema ->
file:delete(Dmp),
@@ -2382,9 +2418,9 @@ ram_delete_table(Tab, Storage) ->
ignore;
disc_only_copies ->
ignore;
- _Else ->
+ _Else ->
%% delete possible index files and data .....
- %% Got to catch this since if no info has been set in the
+ %% Got to catch this since if no info has been set in the
%% mnesia_gvar it will crash
catch mnesia_index:del_transient(Tab, Storage),
case ?catch_val({Tab, {index, snmp}}) of
@@ -2454,7 +2490,7 @@ has_known_suffix(File, [Suffix | Tail], false) ->
has_known_suffix(File, Tail, lists:suffix(Suffix, File));
has_known_suffix(_File, [], Bool) ->
Bool.
-
+
known_suffixes() -> real_suffixes() ++ tmp_suffixes().
real_suffixes() -> [".DAT", ".LOG", ".BUP", ".DCL", ".DCD"].
@@ -2477,11 +2513,11 @@ info2(Tab, [{frag_hash, _V} | Tail]) -> % Ignore frag_hash
info2(Tab, [{P, V} | Tail]) ->
io:format("~-20w -> ~p~n",[P,V]),
info2(Tab, Tail);
-info2(_, []) ->
+info2(_, []) ->
io:format("~n", []).
get_table_properties(Tab) ->
- case catch mnesia_lib:db_match_object(ram_copies,
+ case catch mnesia_lib:db_match_object(ram_copies,
mnesia_gvar, {{Tab, '_'}, '_'}) of
{'EXIT', _} ->
mnesia:abort({no_exists, Tab, all});
@@ -2509,9 +2545,9 @@ get_table_properties(Tab) ->
recs = error_recs
}).
-restore(Opaque) ->
+restore(Opaque) ->
restore(Opaque, [], mnesia_monitor:get_env(backup_module)).
-restore(Opaque, Args) when is_list(Args) ->
+restore(Opaque, Args) when is_list(Args) ->
restore(Opaque, Args, mnesia_monitor:get_env(backup_module));
restore(_Opaque, BadArg) ->
{aborted, {badarg, BadArg}}.
@@ -2522,7 +2558,7 @@ restore(Opaque, Args, Module) when is_list(Args), is_atom(Module) ->
case mnesia_bup:read_schema(R#r.module, Opaque) of
{error, Reason} ->
{aborted, Reason};
- BupSchema ->
+ BupSchema ->
schema_transaction(fun() -> do_restore(R, BupSchema) end)
end;
{'EXIT', Reason} ->
@@ -2556,8 +2592,8 @@ check_restore_arg({keep_tables, List}, R) when is_list(List) ->
check_restore_arg({skip_tables, List}, R) when is_list(List) ->
TableList = [{Tab, skip_tables} || Tab <- List],
R#r{table_options = R#r.table_options ++ TableList};
-check_restore_arg({default_op, Op}, R) ->
- case Op of
+check_restore_arg({default_op, Op}, R) ->
+ case Op of
clear_tables -> ok;
recreate_tables -> ok;
keep_tables -> ok;
@@ -2588,12 +2624,12 @@ restore_items([Rec | Recs], Header, Schema, R) ->
case lists:keysearch(Tab, 1, R#r.tables) of
{value, {Tab, Where0, Snmp, RecName}} ->
Where = case Where0 of
- undefined ->
+ undefined ->
val({Tab, where_to_commit});
_ ->
Where0
end,
- {Rest, NRecs} = restore_tab_items([Rec | Recs], Tab,
+ {Rest, NRecs} = restore_tab_items([Rec | Recs], Tab,
RecName, Where, Snmp,
R#r.recs, R#r.insert_op),
restore_items(Rest, Header, Schema, R#r{recs = NRecs});
@@ -2601,12 +2637,12 @@ restore_items([Rec | Recs], Header, Schema, R) ->
Rest = skip_tab_items(Recs, Tab),
restore_items(Rest, Header, Schema, R)
end;
-
+
restore_items([], _Header, _Schema, R) ->
R.
restore_func(Tab, R) ->
- case lists:keysearch(Tab, 1, R#r.table_options) of
+ case lists:keysearch(Tab, 1, R#r.table_options) of
{value, {Tab, OP}} ->
OP;
false ->
@@ -2618,24 +2654,24 @@ where_to_commit(Tab, CsList) ->
Disc = [{N, disc_copies} || N <- pick(Tab, disc_copies, CsList, [])],
DiscO = [{N, disc_only_copies} || N <- pick(Tab, disc_only_copies, CsList, [])],
Ram ++ Disc ++ DiscO.
-
+
%% Changes of the Meta info of schema itself is not allowed
restore_schema([{schema, schema, _List} | Schema], R) ->
restore_schema(Schema, R);
restore_schema([{schema, Tab, List} | Schema], R) ->
case restore_func(Tab, R) of
- clear_tables ->
+ clear_tables ->
do_clear_table(Tab),
- Snmp = val({Tab, snmp}),
- RecName = val({Tab, record_name}),
+ Snmp = val({Tab, snmp}),
+ RecName = val({Tab, record_name}),
R2 = R#r{tables = [{Tab, undefined, Snmp, RecName} | R#r.tables]},
restore_schema(Schema, R2);
- recreate_tables ->
+ recreate_tables ->
case ?catch_val({Tab, cstruct}) of
- {'EXIT', _} ->
+ {'EXIT', _} ->
TidTs = {_Mod, Tid, Ts} = get(mnesia_activity_state),
RunningNodes = val({current, db_nodes}),
- Nodes = mnesia_lib:intersect(mnesia_lib:cs_to_nodes(list2cs(List)),
+ Nodes = mnesia_lib:intersect(mnesia_lib:cs_to_nodes(list2cs(List)),
RunningNodes),
mnesia_locker:wlock_no_exist(Tid, Ts#tidstore.store, Tab, Nodes),
TidTs;
@@ -2643,20 +2679,20 @@ restore_schema([{schema, Tab, List} | Schema], R) ->
TidTs = get_tid_ts_and_lock(Tab, write)
end,
NC = {cookie, ?unique_cookie},
- List2 = lists:keyreplace(cookie, 1, List, NC),
+ List2 = lists:keyreplace(cookie, 1, List, NC),
Where = where_to_commit(Tab, List2),
Snmp = pick(Tab, snmp, List2, []),
RecName = pick(Tab, record_name, List2, Tab),
insert_schema_ops(TidTs, [{op, restore_recreate, List2}]),
R2 = R#r{tables = [{Tab, Where, Snmp, RecName} | R#r.tables]},
restore_schema(Schema, R2);
- keep_tables ->
+ keep_tables ->
get_tid_ts_and_lock(Tab, write),
Snmp = val({Tab, snmp}),
- RecName = val({Tab, record_name}),
+ RecName = val({Tab, record_name}),
R2 = R#r{tables = [{Tab, undefined, Snmp, RecName} | R#r.tables]},
restore_schema(Schema, R2);
- skip_tables ->
+ skip_tables ->
restore_schema(Schema, R)
end;
@@ -2667,7 +2703,7 @@ restore_schema([{schema, Tab} | Schema], R) ->
restore_schema([], R) ->
R.
-restore_tab_items([Rec | Rest], Tab, RecName, Where, Snmp, Recs, Op)
+restore_tab_items([Rec | Rest], Tab, RecName, Where, Snmp, Recs, Op)
when element(1, Rec) == Tab ->
NewRecs = Op(Rec, Recs, RecName, Where, Snmp),
restore_tab_items(Rest, Tab, RecName, Where, Snmp, NewRecs, Op);
@@ -2675,7 +2711,7 @@ restore_tab_items([Rec | Rest], Tab, RecName, Where, Snmp, Recs, Op)
restore_tab_items(Rest, _Tab, _RecName, _Where, _Snmp, Recs, _Op) ->
{Rest, Recs}.
-skip_tab_items([Rec| Rest], Tab)
+skip_tab_items([Rec| Rest], Tab)
when element(1, Rec) == Tab ->
skip_tab_items(Rest, Tab);
skip_tab_items(Recs, _) ->
@@ -2710,7 +2746,6 @@ merge_schema() ->
merge_schema(UserFun) ->
schema_transaction(fun() -> UserFun(fun(Arg) -> do_merge_schema(Arg) end) end).
-
do_merge_schema(LockTabs0) ->
{_Mod, Tid, Ts} = get_tid_ts_and_lock(schema, write),
LockTabs = [{T, tab_to_nodes(T)} || T <- LockTabs0],
@@ -2732,14 +2767,14 @@ do_merge_schema(LockTabs0) ->
[mnesia_locker:wlock_no_exist(
Tid, Store, T, mnesia_lib:intersect(Ns, OtherNodes))
|| {T,Ns} <- LockTabs],
- case rpc:call(Node, mnesia_controller, get_cstructs, []) of
+ case fetch_cstructs(Node) of
{cstructs, Cstructs, RemoteRunning1} ->
LockedAlready = Running ++ [Node],
{New, Old} = mnesia_recover:connect_nodes(RemoteRunning1),
RemoteRunning = mnesia_lib:intersect(New ++ Old, RemoteRunning1),
- if
+ if
RemoteRunning /= RemoteRunning1 ->
- mnesia_lib:error("Mnesia on ~p could not connect to node(s) ~p~n",
+ mnesia_lib:error("Mnesia on ~p could not connect to node(s) ~p~n",
[node(), RemoteRunning1 -- RemoteRunning]),
mnesia:abort({node_not_running, RemoteRunning1 -- RemoteRunning});
true -> ok
@@ -2749,24 +2784,24 @@ do_merge_schema(LockTabs0) ->
[mnesia_locker:wlock_no_exist(Tid, Store, T,
mnesia_lib:intersect(Ns,NeedsLock))
|| {T,Ns} <- LockTabs],
- {value, SchemaCs} =
- lists:keysearch(schema, #cstruct.name, Cstructs),
+ NeedsConversion = need_old_cstructs(NeedsLock ++ LockedAlready),
+ {value, SchemaCs} = lists:keysearch(schema, #cstruct.name, Cstructs),
+ SchemaDef = cs2list(NeedsConversion, SchemaCs),
%% Announce that Node is running
- A = [{op, announce_im_running, node(),
- cs2list(SchemaCs), Running, RemoteRunning}],
+ A = [{op, announce_im_running, node(), SchemaDef, Running, RemoteRunning}],
do_insert_schema_ops(Store, A),
-
+
%% Introduce remote tables to local node
- do_insert_schema_ops(Store, make_merge_schema(Node, Cstructs)),
-
+ do_insert_schema_ops(Store, make_merge_schema(Node, NeedsConversion, Cstructs)),
+
%% Introduce local tables to remote nodes
Tabs = val({schema, tables}),
Ops = [{op, merge_schema, get_create_list(T)}
|| T <- Tabs,
not lists:keymember(T, #cstruct.name, Cstructs)],
do_insert_schema_ops(Store, Ops),
-
+
%% Ensure that the txn will be committed on all nodes
NewNodes = RemoteRunning -- Running,
mnesia_lib:set(prepare_op, {announce_im_running,NewNodes}),
@@ -2782,19 +2817,49 @@ do_merge_schema(LockTabs0) ->
not_merged
end.
+fetch_cstructs(Node) ->
+ case mnesia_monitor:needs_protocol_conversion(Node) of
+ true ->
+ case rpc:call(Node, mnesia_controller, get_cstructs, []) of
+ {cstructs, Cs0, RR} ->
+ {cstructs, [list2cs(cs2list(Cs)) || Cs <- Cs0], RR};
+ Err -> Err
+ end;
+ false ->
+ rpc:call(Node, mnesia_controller, get_remote_cstructs, [])
+ end.
+
+need_old_cstructs(Nodes) ->
+ Filter = fun(Node) -> not mnesia_monitor:needs_protocol_conversion(Node) end,
+ case lists:dropwhile(Filter, Nodes) of
+ [] -> false;
+ [Node|_] ->
+ case rpc:call(Node, mnesia_lib, val, [{schema,cstruct}]) of
+ #cstruct{} ->
+ %% mnesia_lib:warning("Mnesia on ~p do not need to convert cstruct (~p)~n",
+ %% [node(), Node]),
+ false;
+ {badrpc, _} ->
+ need_old_cstructs(lists:delete(Node,Nodes));
+ Cs when element(1, Cs) == cstruct, tuple_size(Cs) == 17 ->
+ ver4_4_18; % Without majority
+ Cs when element(1, Cs) == cstruct, tuple_size(Cs) == 18 ->
+ ver4_4_19 % With majority
+ end
+ end.
+
tab_to_nodes(Tab) when is_atom(Tab) ->
Cs = val({Tab, cstruct}),
mnesia_lib:cs_to_nodes(Cs).
-make_merge_schema(Node, [Cs | Cstructs]) ->
- Ops = do_make_merge_schema(Node, Cs),
- Ops ++ make_merge_schema(Node, Cstructs);
-make_merge_schema(_Node, []) ->
+make_merge_schema(Node, NeedsConv, [Cs | Cstructs]) ->
+ Ops = do_make_merge_schema(Node, NeedsConv, Cs),
+ Ops ++ make_merge_schema(Node, NeedsConv, Cstructs);
+make_merge_schema(_Node, _, []) ->
[].
%% Merge definitions of schema table
-do_make_merge_schema(Node, RemoteCs)
- when RemoteCs#cstruct.name == schema ->
+do_make_merge_schema(Node, NeedsConv, RemoteCs = #cstruct{name = schema}) ->
Cs = val({schema, cstruct}),
Masters = mnesia_recover:get_master_nodes(schema),
HasRemoteMaster = lists:member(Node, Masters),
@@ -2804,15 +2869,15 @@ do_make_merge_schema(Node, RemoteCs)
StCsLocal = mnesia_lib:cs_to_storage_type(node(), Cs),
StRcsLocal = mnesia_lib:cs_to_storage_type(node(), RemoteCs),
StCsRemote = mnesia_lib:cs_to_storage_type(Node, Cs),
- StRcsRemote = mnesia_lib:cs_to_storage_type(Node, RemoteCs),
-
+ StRcsRemote = mnesia_lib:cs_to_storage_type(Node, RemoteCs),
+
if
Cs#cstruct.cookie == RemoteCs#cstruct.cookie,
Cs#cstruct.version == RemoteCs#cstruct.version ->
%% Great, we have the same cookie and version
%% and do not need to merge cstructs
[];
-
+
Cs#cstruct.cookie /= RemoteCs#cstruct.cookie,
Cs#cstruct.disc_copies /= [],
RemoteCs#cstruct.disc_copies /= [] ->
@@ -2823,14 +2888,14 @@ do_make_merge_schema(Node, RemoteCs)
HasRemoteMaster == false ->
%% Choose local cstruct,
%% since it's the master
- [{op, merge_schema, cs2list(Cs)}];
+ [{op, merge_schema, cs2list(NeedsConv, Cs)}];
HasRemoteMaster == true,
HasLocalMaster == false ->
%% Choose remote cstruct,
%% since it's the master
- [{op, merge_schema, cs2list(RemoteCs)}];
-
+ [{op, merge_schema, cs2list(NeedsConv, RemoteCs)}];
+
true ->
Str = io_lib:format("Incompatible schema cookies. "
"Please, restart from old backup."
@@ -2838,12 +2903,12 @@ do_make_merge_schema(Node, RemoteCs)
[Node, cs2list(RemoteCs), node(), cs2list(Cs)]),
throw(Str)
end;
-
+
StCsLocal /= StRcsLocal, StRcsLocal /= unknown, StCsLocal /= ram_copies ->
Str = io_lib:format("Incompatible schema storage types (local). "
"on ~w storage ~w, on ~w storage ~w~n",
[node(), StCsLocal, Node, StRcsLocal]),
- throw(Str);
+ throw(Str);
StCsRemote /= StRcsRemote, StCsRemote /= unknown, StRcsRemote /= ram_copies ->
Str = io_lib:format("Incompatible schema storage types (remote). "
"on ~w cs ~w, on ~w rcs ~w~n",
@@ -2854,27 +2919,27 @@ do_make_merge_schema(Node, RemoteCs)
%% Choose local cstruct,
%% since it involves disc nodes
MergedCs = merge_cstructs(Cs, RemoteCs, Force),
- [{op, merge_schema, cs2list(MergedCs)}];
-
+ [{op, merge_schema, cs2list(NeedsConv, MergedCs)}];
+
RemoteCs#cstruct.disc_copies /= [] ->
%% Choose remote cstruct,
%% since it involves disc nodes
MergedCs = merge_cstructs(RemoteCs, Cs, Force),
- [{op, merge_schema, cs2list(MergedCs)}];
+ [{op, merge_schema, cs2list(NeedsConv, MergedCs)}];
Cs > RemoteCs ->
%% Choose remote cstruct
MergedCs = merge_cstructs(RemoteCs, Cs, Force),
- [{op, merge_schema, cs2list(MergedCs)}];
-
+ [{op, merge_schema, cs2list(NeedsConv, MergedCs)}];
+
true ->
%% Choose local cstruct
MergedCs = merge_cstructs(Cs, RemoteCs, Force),
- [{op, merge_schema, cs2list(MergedCs)}]
+ [{op, merge_schema, cs2list(NeedsConv, MergedCs)}]
end;
%% Merge definitions of normal table
-do_make_merge_schema(Node, RemoteCs) ->
+do_make_merge_schema(Node, NeedsConv, RemoteCs = #cstruct{}) ->
Tab = RemoteCs#cstruct.name,
Masters = mnesia_recover:get_master_nodes(schema),
HasRemoteMaster = lists:member(Node, Masters),
@@ -2883,27 +2948,27 @@ do_make_merge_schema(Node, RemoteCs) ->
case ?catch_val({Tab, cstruct}) of
{'EXIT', _} ->
%% A completely new table, created while Node was down
- [{op, merge_schema, cs2list(RemoteCs)}];
+ [{op, merge_schema, cs2list(NeedsConv, RemoteCs)}];
Cs when Cs#cstruct.cookie == RemoteCs#cstruct.cookie ->
if
Cs#cstruct.version == RemoteCs#cstruct.version ->
%% We have exactly the same version of the
%% table def
[];
-
+
Cs#cstruct.version > RemoteCs#cstruct.version ->
%% Oops, we have different versions
%% of the table def, lets merge them.
%% The only changes that may have occurred
%% is that new replicas may have been added.
MergedCs = merge_cstructs(Cs, RemoteCs, Force),
- [{op, merge_schema, cs2list(MergedCs)}];
-
+ [{op, merge_schema, cs2list(NeedsConv, MergedCs)}];
+
Cs#cstruct.version < RemoteCs#cstruct.version ->
%% Oops, we have different versions
%% of the table def, lets merge them
MergedCs = merge_cstructs(RemoteCs, Cs, Force),
- [{op, merge_schema, cs2list(MergedCs)}]
+ [{op, merge_schema, cs2list(NeedsConv, MergedCs)}]
end;
Cs ->
%% Different cookies, not possible to merge
@@ -2912,14 +2977,14 @@ do_make_merge_schema(Node, RemoteCs) ->
HasRemoteMaster == false ->
%% Choose local cstruct,
%% since it's the master
- [{op, merge_schema, cs2list(Cs)}];
+ [{op, merge_schema, cs2list(NeedsConv, Cs)}];
HasRemoteMaster == true,
HasLocalMaster == false ->
%% Choose remote cstruct,
%% since it's the master
- [{op, merge_schema, cs2list(RemoteCs)}];
-
+ [{op, merge_schema, cs2list(NeedsConv, RemoteCs)}];
+
true ->
Str = io_lib:format("Bad cookie in table definition"
" ~w: ~w = ~w, ~w = ~w~n",
@@ -2989,7 +3054,7 @@ compare_storage_type(true, One, Another) ->
compare_storage_type(false, Another, One);
compare_storage_type(false, _One, _Another) ->
incompatible.
-
+
change_storage_type(N, ram_copies, Cs) ->
Nodes = [N | Cs#cstruct.ram_copies],
Cs#cstruct{ram_copies = mnesia_lib:uniq(Nodes)};
@@ -3071,14 +3136,14 @@ verify_merge(RemoteCs) ->
if
StCsLocal == StRcsLocal -> ok;
StCsLocal == unknown -> ok;
- (StRcsLocal == unknown), (HasRemoteMaster == false) ->
+ (StRcsLocal == unknown), (HasRemoteMaster == false) ->
{merge_error, Cs, RemoteCs};
%% Trust the merger
true -> ok
end
end.
-announce_im_running([N | Ns], SchemaCs) ->
+announce_im_running([N | Ns], SchemaCs) ->
{L1, L2} = mnesia_recover:connect_nodes([N]),
case lists:member(N, L1) or lists:member(N, L2) of
true ->
@@ -3095,7 +3160,7 @@ announce_im_running([], _) ->
unannounce_im_running([N | Ns]) ->
mnesia_lib:del({current, db_nodes}, N),
- mnesia_controller:del_active_replica(schema, N),
+ mnesia_controller:del_active_replica(schema, N),
unannounce_im_running(Ns);
unannounce_im_running([]) ->
ok.
diff --git a/lib/orber/include/Makefile b/lib/orber/include/Makefile
deleted file mode 100644
index 219b7085e6..0000000000
--- a/lib/orber/include/Makefile
+++ /dev/null
@@ -1,66 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1998-2009. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-#
-#
-include $(ERL_TOP)/make/target.mk
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(ORBER_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/orber-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-EXTERNAL_HRL_FILES= ../include/corba.hrl \
- ../include/ifr_types.hrl \
- ../include/orber_pi.hrl
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-debug opt clean docs:
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-
-release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) $(RELSYSDIR)/include
-
-
-release_docs_spec:
-
-
diff --git a/lib/os_mon/c_src/cpu_sup.c b/lib/os_mon/c_src/cpu_sup.c
index fbf318c614..e3bdbd1489 100644
--- a/lib/os_mon/c_src/cpu_sup.c
+++ b/lib/os_mon/c_src/cpu_sup.c
@@ -191,7 +191,10 @@ int main(int argc, char** argv) {
static cpu_t *read_procstat(FILE *fp, cpu_t *cpu) {
char buffer[BUFFERSIZE];
- fgets(buffer, BUFFERSIZE, fp);
+ if (fgets(buffer, BUFFERSIZE, fp) == NULL) {
+ memset(cpu, 0, sizeof(cpu_t));
+ return cpu;
+ }
sscanf(buffer, "cpu%u %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu",
&(cpu->id),
&(cpu->user),
@@ -223,7 +226,11 @@ static void util_measure(unsigned int **result_vec, int *result_sz) {
return;
}
- fgets(buffer, BUFFERSIZE, fp); /*ignore read*/
+ /*ignore read*/
+ if (fgets(buffer, BUFFERSIZE, fp) == NULL) {
+ *result_sz = 0;
+ return;
+ }
rv = *result_vec;
rv[0] = no_of_cpus;
rv[1] = CU_VALUES;
@@ -447,8 +454,12 @@ static void sendv(unsigned int data[], int ints) {
}
static void error(char* err_msg) {
- write(FD_ERR, err_msg, strlen(err_msg));
- write(FD_ERR, "\n", 1);
+ /*
+ * if we get error here we have trouble,
+ * silence unnecessary warnings
+ */
+ if(write(FD_ERR, err_msg, strlen(err_msg)));
+ if(write(FD_ERR, "\n", 1));
exit(-1);
}
diff --git a/lib/parsetools/src/leex.erl b/lib/parsetools/src/leex.erl
index 942e9928b1..cdf20461d9 100644
--- a/lib/parsetools/src/leex.erl
+++ b/lib/parsetools/src/leex.erl
@@ -73,12 +73,15 @@
%%% Interface to erl_compile.
compile(Input0, Output0,
- #options{warning = WarnLevel, verbose=Verbose, includes=Includes}) ->
+ #options{warning = WarnLevel, verbose=Verbose, includes=Includes,
+ specific=Specific}) ->
Input = assure_extension(shorten_filename(Input0), ".xrl"),
Output = assure_extension(shorten_filename(Output0), ".erl"),
Includefile = lists:sublist(Includes, 1),
+ Werror = proplists:get_bool(warnings_as_errors, Specific),
Opts = [{scannerfile,Output},{includefile,Includefile},{verbose,Verbose},
- {report_errors,true},{report_warnings,WarnLevel > 0}],
+ {report_errors,true},{report_warnings,WarnLevel > 0},
+ {warnings_as_errors, Werror}],
case file(Input, Opts) of
{ok, _} ->
ok;
@@ -107,7 +110,7 @@ file(File, Opts0) ->
St = try
{ok,REAs,Actions,Code,St2} = parse_file(St1),
{DFA,DF} = make_dfa(REAs, St2),
- case werr(St2) of
+ case werror(St2) of
false ->
St3 = out_file(St2, DFA, DF, Actions, Code),
case lists:member(dfa_graph, St3#leex.opts) of
@@ -259,9 +262,9 @@ leex_ret(St) ->
report_warnings(St),
Es = pack_errors(St#leex.errors),
Ws = pack_warnings(St#leex.warnings),
- Werr = werr(St),
+ Werror = werror(St),
if
- Werr ->
+ Werror ->
do_error_return(St, Es, Ws);
Es =:= [] ->
case member(return_warnings, St#leex.opts) of
@@ -278,9 +281,9 @@ do_error_return(St, Es, Ws) ->
false -> error
end.
-werr(St) ->
- member(warnings_as_errors, St#leex.opts)
- andalso length(St#leex.warnings) > 0.
+werror(St) ->
+ St#leex.warnings =/= []
+ andalso member(warnings_as_errors, St#leex.opts).
pack_errors([{File,_} | _] = Es) ->
[{File, flatmap(fun({_,E}) -> [E] end, sort(Es))}];
@@ -304,15 +307,24 @@ report_errors(St) ->
end, report_errors, St#leex.opts).
report_warnings(St) ->
- when_opt(fun () ->
- foreach(fun({File,{none,Mod,W}}) ->
- io:fwrite("~s: Warning: ~s\n",
- [File,Mod:format_error(W)]);
- ({File,{Line,Mod,W}}) ->
- io:fwrite("~s:~w: Warning: ~s\n",
- [File,Line,Mod:format_error(W)])
- end, sort(St#leex.warnings))
- end, report_warnings, St#leex.opts).
+ Werror = member(warnings_as_errors, St#leex.opts),
+ Prefix = case Werror of
+ true -> "";
+ false -> "Warning: "
+ end,
+ ReportWerror = Werror andalso member(report_errors, St#leex.opts),
+ ShouldReport = member(report_warnings, St#leex.opts) orelse ReportWerror,
+ when_bool(fun () ->
+ foreach(fun({File,{none,Mod,W}}) ->
+ io:fwrite("~s: ~s~s\n",
+ [File,Prefix,
+ Mod:format_error(W)]);
+ ({File,{Line,Mod,W}}) ->
+ io:fwrite("~s:~w: ~s~s\n",
+ [File,Line,Prefix,
+ Mod:format_error(W)])
+ end, sort(St#leex.warnings))
+ end, ShouldReport).
-spec add_error(_, #leex{}) -> no_return().
add_error(E, St) ->
@@ -360,6 +372,12 @@ when_opt(Do, Opt, Opts) ->
false -> ok
end.
+when_bool(Do, Bool) ->
+ case Bool of
+ true -> Do();
+ false -> ok
+ end.
+
verbose_print(St, Format, Args) ->
when_opt(fun () -> io:fwrite(Format, Args) end, verbose, St#leex.opts).
diff --git a/lib/parsetools/src/yecc.erl b/lib/parsetools/src/yecc.erl
index 72cff3af92..354d56527d 100644
--- a/lib/parsetools/src/yecc.erl
+++ b/lib/parsetools/src/yecc.erl
@@ -133,12 +133,15 @@
%%% Interface to erl_compile.
compile(Input0, Output0,
- #options{warning = WarnLevel, verbose=Verbose, includes=Includes}) ->
+ #options{warning = WarnLevel, verbose=Verbose, includes=Includes,
+ specific=Specific}) ->
Input = shorten_filename(Input0),
Output = shorten_filename(Output0),
Includefile = lists:sublist(Includes, 1),
+ Werror = proplists:get_bool(warnings_as_errors, Specific),
Opts = [{parserfile,Output}, {includefile,Includefile}, {verbose,Verbose},
- {report_errors, true}, {report_warnings, WarnLevel > 0}],
+ {report_errors, true}, {report_warnings, WarnLevel > 0},
+ {warnings_as_errors, Werror}],
case file(Input, Opts) of
{ok, _OutFile} ->
ok;
@@ -411,15 +414,15 @@ infile(Parent, Infilex, Options) ->
{error, Reason} ->
add_error(St0#yecc.infile, none, {file_error, Reason}, St0)
end,
- case {St#yecc.errors, werr(St)} of
+ case {St#yecc.errors, werror(St)} of
{[], false} -> ok;
_ -> _ = file:delete(St#yecc.outfile)
end,
Parent ! {self(), yecc_ret(St)}.
-werr(St) ->
- member(warnings_as_errors, St#yecc.options)
- andalso length(St#yecc.warnings) > 0.
+werror(St) ->
+ St#yecc.warnings =/= []
+ andalso member(warnings_as_errors, St#yecc.options).
outfile(St0) ->
case file:open(St0#yecc.outfile, [write, delayed_write]) of
@@ -783,9 +786,9 @@ yecc_ret(St0) ->
report_warnings(St),
Es = pack_errors(St#yecc.errors),
Ws = pack_warnings(St#yecc.warnings),
- Werr = werr(St),
+ Werror = werror(St),
if
- Werr ->
+ Werror ->
do_error_return(St, Es, Ws);
Es =:= [] ->
case member(return_warnings, St#yecc.options) of
@@ -849,14 +852,22 @@ report_errors(St) ->
end.
report_warnings(St) ->
- case member(report_warnings, St#yecc.options) of
+ Werror = member(warnings_as_errors, St#yecc.options),
+ Prefix = case Werror of
+ true -> "";
+ false -> "Warning: "
+ end,
+ ReportWerror = Werror andalso member(report_errors, St#yecc.options),
+ case member(report_warnings, St#yecc.options) orelse ReportWerror of
true ->
foreach(fun({File,{none,Mod,W}}) ->
- io:fwrite(<<"~s: Warning: ~s\n">>,
- [File,Mod:format_error(W)]);
+ io:fwrite(<<"~s: ~s~s\n">>,
+ [File,Prefix,
+ Mod:format_error(W)]);
({File,{Line,Mod,W}}) ->
- io:fwrite(<<"~s:~w: Warning: ~s\n">>,
- [File,Line,Mod:format_error(W)])
+ io:fwrite(<<"~s:~w: ~s~s\n">>,
+ [File,Line,Prefix,
+ Mod:format_error(W)])
end, sort(St#yecc.warnings));
false ->
ok
diff --git a/lib/parsetools/test/leex_SUITE.erl b/lib/parsetools/test/leex_SUITE.erl
index 48312445ef..1e50aedf07 100644
--- a/lib/parsetools/test/leex_SUITE.erl
+++ b/lib/parsetools/test/leex_SUITE.erl
@@ -152,6 +152,7 @@ file(Config) when is_list(Config) ->
?line writable(Dotfile),
file:delete(Dotfile),
+ ok = file:delete(Scannerfile),
Warn = <<"Definitions.1998\n"
"D = [0-9]\n"
"Rules.\n"
@@ -159,11 +160,15 @@ file(Config) when is_list(Config) ->
"Erlang code.\n">>,
ok = file:write_file(Filename, Warn),
error = leex:file(Filename, [warnings_as_errors]),
+ false = filelib:is_regular(Scannerfile),
error = leex:file(Filename, [return_warnings,warnings_as_errors]),
- {ok,Scannerfile,[{Filename,[{1,leex,ignored_characters}]}]} =
- leex:file(Filename, [return_warnings]),
+ false = filelib:is_regular(Scannerfile),
{error,_,[{Filename,[{1,leex,ignored_characters}]}]} =
- leex:file(Filename, [return_errors,warnings_as_errors]),
+ leex:file(Filename, [return_errors,warnings_as_errors]),
+ false = filelib:is_regular(Scannerfile),
+ {ok,Scannerfile,[{Filename,[{1,leex,ignored_characters}]}]} =
+ leex:file(Filename, [return_warnings]),
+ true = filelib:is_regular(Scannerfile),
file:delete(Filename),
ok.
diff --git a/lib/parsetools/test/yecc_SUITE.erl b/lib/parsetools/test/yecc_SUITE.erl
index 0133524950..a5f66b48e9 100644
--- a/lib/parsetools/test/yecc_SUITE.erl
+++ b/lib/parsetools/test/yecc_SUITE.erl
@@ -173,6 +173,7 @@ syntax(Config) when is_list(Config) ->
%% Report errors. Very simple test of format_error/1.
Ret = [return, {report, true}],
Filename = filename:join(Dir, "file.yrl"),
+ Parserfile = filename:join(Dir, "file.erl"),
Parserfile1 = filename:join(Dir, "a file"),
?line ok = file:write_file(Filename, <<"">>),
@@ -248,12 +249,17 @@ syntax(Config) when is_list(Config) ->
yecc:file(Filename, Ret),
%% Bad declaration with warnings_as_errors.
+ ok = file:delete(Parserfile),
error = yecc:file(Filename, [warnings_as_errors]),
+ false = filelib:is_regular(Parserfile),
error = yecc:file(Filename, [return_warnings,warnings_as_errors]),
- {ok,_,[{_,[{2,yecc,bad_declaration}]}]} =
- yecc:file(Filename, [return_warnings]),
+ false = filelib:is_regular(Parserfile),
{error,_,[{_,[{2,yecc,bad_declaration}]}]} =
yecc:file(Filename, [return_errors,warnings_as_errors]),
+ false = filelib:is_regular(Parserfile),
+ {ok,_,[{_,[{2,yecc,bad_declaration}]}]} =
+ yecc:file(Filename, [return_warnings]),
+ true = filelib:is_regular(Parserfile),
%% Bad declaration.
?line ok = file:write_file(Filename,
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 9a3832c68b..b3ce49e2ca 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -79,7 +79,7 @@
<p><code> rsa_padding() = 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding'
| 'rsa_no_padding'</code></p>
- <p><code> rsa_digest_type() = 'md5' | 'sha' </code></p>
+ <p><code> rsa_digest_type() = 'md2' | 'md5' | 'sha' </code></p>
<p><code> dss_digest_type() = 'none' | 'sha' </code></p>
diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl
index 5ab9642279..61082a1ec5 100644
--- a/lib/public_key/src/pubkey_cert.erl
+++ b/lib/public_key/src/pubkey_cert.erl
@@ -38,7 +38,7 @@
%%====================================================================
%%--------------------------------------------------------------------
--spec verify_data(DER::binary()) -> {md5 | sha, binary(), binary()}.
+-spec verify_data(DER::binary()) -> {md2 | md5 | sha, binary(), binary()}.
%%
%% Description: Extracts data from DerCert needed to call public_key:verify/4.
%%--------------------------------------------------------------------
@@ -378,6 +378,8 @@ digest_type(?sha1WithRSAEncryption) ->
sha;
digest_type(?md5WithRSAEncryption) ->
md5;
+digest_type(?md2WithRSAEncryption) ->
+ md2;
digest_type(?'id-dsa-with-sha1') ->
sha.
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 33fcce2c44..940efffcd0 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -55,7 +55,7 @@
-type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding'
| 'rsa_no_padding'.
-type public_crypt_options() :: [{rsa_pad, rsa_padding()}].
--type rsa_digest_type() :: 'md5' | 'sha'.
+-type rsa_digest_type() :: 'md2' | 'md5' | 'sha'.
-type dss_digest_type() :: 'none' | 'sha'.
-define(UINT32(X), X:32/unsigned-big-integer).
@@ -307,7 +307,8 @@ encrypt_private(PlainText, #'RSAPrivateKey'{modulus = N,
sign(PlainText, DigestType, #'RSAPrivateKey'{modulus = N, publicExponent = E,
privateExponent = D})
when is_binary(PlainText),
- (DigestType == md5 orelse
+ (DigestType == md2 orelse
+ DigestType == md5 orelse
DigestType == sha) ->
crypto:rsa_sign(DigestType, sized_binary(PlainText), [crypto:mpint(E),
@@ -335,7 +336,10 @@ sign(PlainText, sha, #'DSAPrivateKey'{p = P, q = Q, g = G, x = X})
%%--------------------------------------------------------------------
verify(PlainText, DigestType, Signature,
#'RSAPublicKey'{modulus = Mod, publicExponent = Exp})
- when is_binary (PlainText), DigestType == sha; DigestType == md5 ->
+ when is_binary(PlainText),
+ (DigestType == md2 orelse
+ DigestType == md5 orelse
+ DigestType == sha) ->
crypto:rsa_verify(DigestType,
sized_binary(PlainText),
sized_binary(Signature),
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index b11e4d092a..a9c198c581 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -537,7 +537,10 @@ rsa_sign_verify(Config) when is_list(Config) ->
false = public_key:verify(Msg, sha, <<1:8, RSASign/binary>>, PublicRSA),
RSASign1 = public_key:sign(Msg, md5, PrivateRSA),
- true = public_key:verify(Msg, md5, RSASign1, PublicRSA).
+ true = public_key:verify(Msg, md5, RSASign1, PublicRSA),
+
+ RSASign2 = public_key:sign(Msg, md2, PrivateRSA),
+ true = public_key:verify(Msg, md2, RSASign2, PublicRSA).
%%--------------------------------------------------------------------
diff --git a/lib/runtime_tools/doc/src/dbg.xml b/lib/runtime_tools/doc/src/dbg.xml
index 0e63649c09..4e32bd5c0d 100644
--- a/lib/runtime_tools/doc/src/dbg.xml
+++ b/lib/runtime_tools/doc/src/dbg.xml
@@ -706,7 +706,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard) c
value from the last invocation of the fun. The initial value
of the second parameter is specified in the <c>InitialData</c>
part of the <c>HandlerSpec</c>. The <c>HandlerFun</c> may
- chose any appropriate action to take when invoked, and can
+ choose any appropriate action to take when invoked, and can
save a state for the next invocation by returning it.
</p>
<p>If <c>Type</c> is a port, then the second parameter should
@@ -766,7 +766,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard) c
<p>This function creates a trace port generating <em>fun</em>.
The <em>fun</em> takes no arguments and returns a newly opened
trace port. The return value from this function is suitable as
- a second parameter to tracer/2, i. e. <c>dbg:tracer(port, dbg:trace_port(ip, 4711))</c>. </p>
+ a second parameter to tracer/2, i.e. <c>dbg:tracer(port, dbg:trace_port(ip, 4711))</c>. </p>
<p>A trace port is an
Erlang port to a dynamically linked in driver that handles
trace messages directly, without the overhead of sending them
@@ -852,9 +852,9 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard) c
<desc>
<p>This function is used to do a control operation on the
active trace port driver on the given node
- (<c>Nodename</c>). Which operations that are allowed as well
- as their return values are depending on which trace driver
- that is used.</p>
+ (<c>Nodename</c>). Which operations are allowed as well
+ as their return values depend on which trace driver
+ is used.</p>
<p>Returns either <c>ok</c> or <c>{ok, Result}</c>
if the operation was successful, or <c>{error, Reason}</c>
if the current tracer is a process
diff --git a/lib/sasl/doc/src/release_handler.xml b/lib/sasl/doc/src/release_handler.xml
index 4a973bc5ed..5ac0dc1acc 100644
--- a/lib/sasl/doc/src/release_handler.xml
+++ b/lib/sasl/doc/src/release_handler.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2009</year>
+ <year>1996</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -159,9 +159,12 @@ old reboot_old permanent
<funcs>
<func>
<name>check_install_release(Vsn) -> {ok, OtherVsn, Descr} | {error, Reason}</name>
+ <name>check_install_release(Vsn,Opts) -> {ok, OtherVsn, Descr} | {error, Reason}</name>
<fsummary>Check installation of a release in the system.</fsummary>
<type>
<v>Vsn = OtherVsn = string()</v>
+ <v>Opts = [Opt]</v>
+ <v>Opt = purge</v>
<v>Descr = term()</v>
<v>Reason = term()</v>
</type>
@@ -179,6 +182,11 @@ old reboot_old permanent
upgrade script.</p>
<p>Returns the same as <c>install_release/1</c>. <c>Descr</c>
defaults to "" if no <c>relup</c> file is found.</p>
+ <p>If the option <c>purge</c> is given, all old code that can
+ be soft purged will be purged after all other checks are
+ successfully completed. This can be useful in order to
+ reduce the time needed by <seealso
+ marker="#install_release/1">install_release</seealso>.</p>
</desc>
</func>
<func>
@@ -299,6 +307,24 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
<c>{update_paths,true}</c>, afterwards
<c>code:lib_dir(myapp)</c> will return
<c>/home/user/myapp-1.0</c>.</p>
+ <note>
+ <p>Installing a new release might be quite time consuming if
+ there are many processes in the system. The reason is that
+ each process must be checked for references to old code
+ before a module can be purged. This check might lead to
+ garbage collections and copying of data.</p>
+ <p>If you wish to speed up the execution of
+ <c>install_release</c>, then you may call <seealso
+ marker="#check_install_release/1">check_install_release</seealso>
+ first, using the option <c>purge</c>. This will do the same
+ check for old code, and then purge all modules that can be
+ soft purged. The purged modules will then no longer have any
+ old code, and <c>install_release</c> will not need to do the
+ checks.</p>
+ <p>Obviously, this will not reduce the overall time for the
+ upgrade, but it will allow checks and purge to be executed
+ in the background before the real upgrade is started.</p>
+ </note>
</desc>
</func>
<func>
diff --git a/lib/sasl/doc/src/systools.xml b/lib/sasl/doc/src/systools.xml
index 883c9c372b..8c1c327d74 100644
--- a/lib/sasl/doc/src/systools.xml
+++ b/lib/sasl/doc/src/systools.xml
@@ -45,7 +45,8 @@
<v>Name = string()</v>
<v>UpFrom = DownTo = [Name | {Name,Descr}]</v>
<v>&nbsp;Descr = term()</v>
- <v>Opt = {path,[Dir]} | restart_emulator | silent | noexec | {outdir,Dir}</v>
+ <v>Opt = {path,[Dir]} | restart_emulator | silent | noexec | {outdir,Dir}
+ | warnings_as_errors</v>
<v>&nbsp;Dir = string()</v>
<v>Result = ok | error | {ok,Relup,Module,Warnings} | {error,Module,Error}</v>
<v>&nbsp;Relup - see relup(4)</v>
@@ -122,6 +123,8 @@
<p>If the option <c>noexec</c> is provided, the function returns
the same values as for <c>silent</c> but no <c>relup</c> file
is created.</p>
+ <p>If the option <c>warnings_as_errors</c> is provided, warnings
+ are treated as errors.</p>
</desc>
</func>
<func>
@@ -130,7 +133,8 @@
<fsummary>Generate a boot script <c>.script/.boot</c>.</fsummary>
<type>
<v>Name = string()</v>
- <v>Opt = src_tests | {path,[Dir]} | local | {variables,[Var]} | exref | {exref,[App]}] | silent | {outdir,Dir}</v>
+ <v>Opt = src_tests | {path,[Dir]} | local | {variables,[Var]} | exref | {exref,[App]}]
+ | silent | {outdir,Dir} | warnings_as_errors</v>
<v>&nbsp;Dir = string()</v>
<v>&nbsp;Var = {VarName,Prefix}</v>
<v>&nbsp;&nbsp;VarName = Prefix = string()</v>
@@ -232,6 +236,8 @@
Warnings and errors can be converted to strings by calling
<c>Module:format_warning(Warnings)</c> or
<c>Module:format_error(Error)</c>.</p>
+ <p>If the option <c>warnings_as_errors</c> is provided, warnings
+ are treated as errors.</p>
</desc>
</func>
<func>
diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl
index ab54b1d00b..bc08f94dff 100644
--- a/lib/sasl/src/release_handler.erl
+++ b/lib/sasl/src/release_handler.erl
@@ -25,8 +25,8 @@
-export([start_link/0,
create_RELEASES/1, create_RELEASES/2, create_RELEASES/4,
unpack_release/1,
- check_install_release/1, install_release/1, install_release/2,
- remove_release/1,
+ check_install_release/1, check_install_release/2,
+ install_release/1, install_release/2, remove_release/1,
which_releases/0, make_permanent/1, reboot_old_release/1,
set_unpacked/2, set_removed/1, install_file/2]).
-export([upgrade_app/2, downgrade_app/2, downgrade_app/3,
@@ -149,15 +149,35 @@ unpack_release(ReleaseName) ->
%%-----------------------------------------------------------------
%% Purpose: Checks the relup script for the specified version.
%% The release must be unpacked.
+%% Options = [purge] - all old code that can be soft purged
+%% will be purged if all checks succeeds. This can be usefull
+%% in order to reduce time needed in the following call to
+%% install_release.
%% Returns: {ok, FromVsn, Descr} | {error, Reason}
-%% Reason = {already_installed, Vsn} |
+%% Reason = {illegal_option, IllegalOpt} |
+%% {already_installed, Vsn} |
%% {bad_relup_file, RelFile} |
%% {no_such_release, Vsn} |
%% {no_such_from_vsn, Vsn} |
%% exit_reason()
%%-----------------------------------------------------------------
check_install_release(Vsn) ->
- call({check_install_release, Vsn}).
+ check_install_release(Vsn, []).
+
+check_install_release(Vsn, Opts) ->
+ case check_check_install_options(Opts, false) of
+ {ok,Purge} ->
+ call({check_install_release, Vsn, Purge});
+ Error ->
+ Error
+ end.
+
+check_check_install_options([purge|Opts], _) ->
+ check_check_install_options(Opts, true);
+check_check_install_options([Illegal|_],_Purge) ->
+ {error,{illegal_option,Illegal}};
+check_check_install_options([],Purge) ->
+ {ok,Purge}.
%%-----------------------------------------------------------------
@@ -541,11 +561,12 @@ handle_call({unpack_release, ReleaseName}, _From, S)
handle_call({unpack_release, _ReleaseName}, _From, S) ->
{reply, {error, client_node}, S};
-handle_call({check_install_release, Vsn}, _From, S) ->
+handle_call({check_install_release, Vsn, Purge}, _From, S) ->
case catch do_check_install_release(S#state.rel_dir,
Vsn,
S#state.releases,
- S#state.masters) of
+ S#state.masters,
+ Purge) of
{ok, CurrentVsn, Descr} ->
{reply, {ok, CurrentVsn, Descr}, S};
{error, Reason} ->
@@ -855,7 +876,7 @@ check_path_response(Path, {ok, _Info}) ->
check_path_response(Path, {error, _Reason}) ->
throw({error, {no_such_directory, Path}}).
-do_check_install_release(RelDir, Vsn, Releases, Masters) ->
+do_check_install_release(RelDir, Vsn, Releases, Masters, Purge) ->
case lists:keysearch(Vsn, #release.vsn, Releases) of
{value, #release{status = current}} ->
{error, {already_installed, Vsn}};
@@ -880,7 +901,20 @@ do_check_install_release(RelDir, Vsn, Releases, Masters) ->
case get_rh_script(LatestRelease, Release, RelDir, Masters) of
{ok, {CurrentVsn, Descr, Script}} ->
case catch check_script(Script, Libs) of
- ok ->
+ {ok,SoftPurgeMods} when Purge=:=true ->
+ %% Get modules with brutal_purge
+ %% instructions, but that can be
+ %% soft purged
+ {ok,BrutalPurgeMods} =
+ release_handler_1:check_old_processes(
+ Script,brutal_purge),
+ lists:foreach(
+ fun(Mod) ->
+ catch erlang:purge_module(Mod)
+ end,
+ SoftPurgeMods ++ BrutalPurgeMods),
+ {ok, CurrentVsn, Descr};
+ {ok,_} ->
{ok, CurrentVsn, Descr};
Else ->
Else
@@ -1967,7 +2001,7 @@ safe_write_file_m(File, Data, Masters) ->
%% 'update_paths' option to release_handler:install_release/2 if the
%% code path shall be updated then.
%% -----------------------------------------------------------------
-get_new_libs([{App,Vsn,LibDir}|CurrentLibs], NewLibs) ->
+get_new_libs([{App,Vsn,_LibDir}|CurrentLibs], NewLibs) ->
case lists:keyfind(App,1,NewLibs) of
{App,NewVsn,_} = LibInfo when NewVsn =/= Vsn ->
[LibInfo | get_new_libs(CurrentLibs,NewLibs)];
diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl
index ff62f847ac..8d0baf3ab1 100644
--- a/lib/sasl/src/release_handler_1.erl
+++ b/lib/sasl/src/release_handler_1.erl
@@ -19,8 +19,9 @@
-module(release_handler_1).
%% External exports
--export([eval_script/1, eval_script/5, check_script/2]).
--export([get_current_vsn/1]). %% exported because used in a test case
+-export([eval_script/1, eval_script/5,
+ check_script/2, check_old_processes/2]).
+-export([get_current_vsn/1, get_supervised_procs/0]). %% exported because used in a test case
-record(eval_state, {bins = [], stopped = [], suspended = [], apps = [],
libdirs, unpurged = [], vsns = [], newlibs = [],
@@ -47,17 +48,20 @@
%%% This is a low-level release handler.
%%%-----------------------------------------------------------------
check_script(Script, LibDirs) ->
- case catch check_old_processes(Script) of
- ok ->
+ case catch check_old_processes(Script,soft_purge) of
+ {ok, PurgeMods} ->
{Before, _After} = split_instructions(Script),
case catch lists:foldl(fun(Instruction, EvalState1) ->
eval(Instruction, EvalState1)
end,
#eval_state{libdirs = LibDirs},
Before) of
- EvalState2 when is_record(EvalState2, eval_state) -> ok;
- {error, Error} -> {error, Error};
- Other -> {error, Other}
+ EvalState2 when is_record(EvalState2, eval_state) ->
+ {ok,PurgeMods};
+ {error, Error} ->
+ {error, Error};
+ Other ->
+ {error, Other}
end;
{error, Mod} ->
{error, {old_processes, Mod}}
@@ -68,8 +72,8 @@ eval_script(Script) ->
eval_script(Script, [], [], [], []).
eval_script(Script, Apps, LibDirs, NewLibs, Opts) ->
- case catch check_old_processes(Script) of
- ok ->
+ case catch check_old_processes(Script,soft_purge) of
+ {ok,_} ->
{Before, After} = split_instructions(Script),
case catch lists:foldl(fun(Instruction, EvalState1) ->
eval(Instruction, EvalState1)
@@ -112,32 +116,63 @@ split_instructions([], Before) ->
{[], lists:reverse(Before)}.
%%-----------------------------------------------------------------
-%% Func: check_old_processes/1
+%% Func: check_old_processes/2
%% Args: Script = [instruction()]
+%% PrePurgeMethod = soft_purge | brutal_purge
%% Purpose: Check if there is any process that runs an old version
-%% of a module that should be soft_purged, (i.e. not purged
-%% at all if there is any such process). Returns {error, Mod}
-%% if so, ok otherwise.
-%% Returns: ok | {error, Mod}
+%% of a module that should be purged according to PrePurgeMethod.
+%% Returns a list of modules that can be soft_purged.
+%%
+%% If PrePurgeMethod == soft_purge, the function will succeed
+%% only if there is no process running old code of any of the
+%% modules. Else it will throw {error,Mod}, where Mod is the
+%% first module found that can not be soft_purged.
+%%
+%% If PrePurgeMethod == brutal_purge, the function will
+%% always succeed and return a list of all modules that are
+%% specified in the script with PrePurgeMethod brutal_purge,
+%% but that can be soft_purged.
+%%
+%% Returns: {ok,PurgeMods} | {error, Mod}
+%% PurgeMods = [Mod]
%% Mod = atom()
%%-----------------------------------------------------------------
-check_old_processes(Script) ->
- lists:foreach(fun({load, {Mod, soft_purge, _PostPurgeMethod}}) ->
- check_old_code(Mod);
- ({remove, {Mod, soft_purge, _PostPurgeMethod}}) ->
- check_old_code(Mod);
- (_) -> ok
- end,
- Script).
+check_old_processes(Script,PrePurgeMethod) ->
+ Procs = erlang:processes(),
+ {ok,lists:flatmap(
+ fun({load, {Mod, PPM, _PostPurgeMethod}}) when PPM==PrePurgeMethod ->
+ check_old_code(Mod,Procs,PrePurgeMethod);
+ ({remove, {Mod, PPM, _PostPurgeMethod}}) when PPM==PrePurgeMethod ->
+ check_old_code(Mod,Procs,PrePurgeMethod);
+ (_) -> []
+ end,
+ Script)}.
+
+check_old_code(Mod,Procs,PrePurgeMethod) ->
+ case erlang:check_old_code(Mod) of
+ true when PrePurgeMethod==soft_purge ->
+ do_check_old_code(Mod,Procs);
+ true when PrePurgeMethod==brutal_purge ->
+ case catch do_check_old_code(Mod,Procs) of
+ {error,Mod} -> [];
+ R -> R
+ end;
+ false ->
+ []
+ end.
+
+
+do_check_old_code(Mod,Procs) ->
+ lists:foreach(
+ fun(Pid) ->
+ case erlang:check_process_code(Pid, Mod) of
+ false -> ok;
+ true -> throw({error, Mod})
+ end
+ end,
+ Procs),
+ [Mod].
-check_old_code(Mod) ->
- lists:foreach(fun(Pid) ->
- case erlang:check_process_code(Pid, Mod) of
- false -> ok;
- true -> throw({error, Mod})
- end
- end,
- erlang:processes()).
%%-----------------------------------------------------------------
%% An unpurged module is a module for which there exist an old
@@ -458,6 +493,19 @@ start(Procs) ->
%% supervisor module, we should load the new version, and then
%% delete the old. Then we should perform the start changes
%% manually, by adding/deleting children.
+%%
+%% Recent changes to this code cause the upgrade error out and
+%% log the case where a suspended supervisor has which_children
+%% called against it. This retains the behavior of causing a VM
+%% restart to the *old* version of a release but has the
+%% advantage of logging the pid and supervisor that had the
+%% issue.
+%%
+%% A second case where this can occur is if a child spec is
+%% incorrect and get_modules is called against a process that
+%% can't respond to the gen:call. Again an error is logged,
+%% an error returned and a VM restart is issued.
+%%
%% Returns: [{SuperPid, ChildName, ChildPid, Mods}]
%%-----------------------------------------------------------------
%% OTP-3452. For each application the first item contains the pid
@@ -467,49 +515,81 @@ start(Procs) ->
get_supervised_procs() ->
lists:foldl(
fun(Application, Procs) ->
- case application_controller:get_master(Application) of
- Pid when is_pid(Pid) ->
- {Root, _AppMod} = application_master:get_child(Pid),
- case get_supervisor_module(Root) of
- {ok, SupMod} ->
- get_procs(supervisor:which_children(Root),
- Root) ++
- [{undefined, undefined, Root, [SupMod]} |
- Procs];
- {error, _} ->
- error_logger:error_msg("release_handler: "
- "cannot find top "
- "supervisor for "
- "application ~w~n",
- [Application]),
- get_procs(supervisor:which_children(Root),
- Root) ++ Procs
- end;
- _ -> Procs
- end
+ get_master_procs(Application,
+ Procs,
+ application_controller:get_master(Application))
end,
[],
- lists:map(fun({Application, _Name, _Vsn}) ->
- Application
- end,
- application:which_applications())).
+ get_application_names()).
+
+get_supervised_procs(_, Root, Procs, {ok, SupMod}) ->
+ get_procs(maybe_supervisor_which_children(get_proc_state(Root), SupMod, Root), Root) ++
+ [{undefined, undefined, Root, [SupMod]} | Procs];
+get_supervised_procs(Application, Root, Procs, {error, _}) ->
+ error_logger:error_msg("release_handler: cannot find top supervisor for "
+ "application ~w~n", [Application]),
+ get_procs(maybe_supervisor_which_children(get_proc_state(Root), Application, Root), Root) ++ Procs.
+
+get_application_names() ->
+ lists:map(fun({Application, _Name, _Vsn}) ->
+ Application
+ end,
+ application:which_applications()).
+
+get_master_procs(Application, Procs, Pid) when is_pid(Pid) ->
+ {Root, _AppMod} = application_master:get_child(Pid),
+ get_supervised_procs(Application, Root, Procs, get_supervisor_module(Root));
+get_master_procs(_, Procs, _) ->
+ Procs.
get_procs([{Name, Pid, worker, dynamic} | T], Sup) when is_pid(Pid) ->
- Mods = get_dynamic_mods(Pid),
+ Mods = maybe_get_dynamic_mods(Name, Pid),
[{Sup, Name, Pid, Mods} | get_procs(T, Sup)];
get_procs([{Name, Pid, worker, Mods} | T], Sup) when is_pid(Pid), is_list(Mods) ->
[{Sup, Name, Pid, Mods} | get_procs(T, Sup)];
get_procs([{Name, Pid, supervisor, Mods} | T], Sup) when is_pid(Pid) ->
- [{Sup, Name, Pid, Mods} | get_procs(T, Sup)] ++
- get_procs(supervisor:which_children(Pid), Pid);
+ [{Sup, Name, Pid, Mods} | get_procs(T, Sup)] ++
+ get_procs(maybe_supervisor_which_children(get_proc_state(Pid), Name, Pid), Pid);
get_procs([_H | T], Sup) ->
get_procs(T, Sup);
get_procs(_, _Sup) ->
[].
-get_dynamic_mods(Pid) ->
- {ok,Res} = gen:call(Pid, self(), get_modules),
- Res.
+get_proc_state(Proc) ->
+ {status, _, {module, _}, [_, State, _, _, _]} = sys:get_status(Proc),
+ State.
+
+maybe_supervisor_which_children(suspended, Name, Pid) ->
+ error_logger:error_msg("release_handler: a which_children call"
+ " to ~p (~p) was avoided. This supervisor"
+ " is suspended and should likely be upgraded"
+ " differently. Exiting ...~n", [Name, Pid]),
+ error(suspended_supervisor);
+
+maybe_supervisor_which_children(State, Name, Pid) ->
+ case catch supervisor:which_children(Pid) of
+ Res when is_list(Res) ->
+ Res;
+ Other ->
+ error_logger:error_msg("release_handler: ~p~nerror during"
+ " a which_children call to ~p (~p)."
+ " [State: ~p] Exiting ... ~n",
+ [Other, Name, Pid, State]),
+ error(which_children_failed)
+ end.
+
+maybe_get_dynamic_mods(Name, Pid) ->
+ case catch gen:call(Pid, self(), get_modules) of
+ {ok, Res} ->
+ Res;
+ Other ->
+ error_logger:error_msg("release_handler: ~p~nerror during a"
+ " get_modules call to ~p (~p),"
+ " there may be an error in it's"
+ " childspec. Exiting ...~n",
+ [Other, Name, Pid]),
+ error(get_modules_failed)
+ end.
%% XXXX
%% Note: The following is a terrible hack done in order to resolve the
diff --git a/lib/sasl/src/systools_lib.erl b/lib/sasl/src/systools_lib.erl
index f951647b79..1b6ea125d9 100644
--- a/lib/sasl/src/systools_lib.erl
+++ b/lib/sasl/src/systools_lib.erl
@@ -24,7 +24,7 @@
%%
-export([file_term2binary/2, read_term/1, read_term_from_stream/2,
- get_dirs/1, get_path/1]).
+ get_dirs/1, get_path/1, werror/2]).
-include_lib("kernel/include/file.hrl").
@@ -219,6 +219,7 @@ flat([H|T], Ack) ->
flat(T, [H|Ack]);
flat([], Ack) ->
lists:reverse(Ack).
-
-
+
+werror(Options, Warnings) ->
+ lists:member(warnings_as_errors, Options) andalso Warnings =/= [].
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index 7489ee58d2..7f400f5cce 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -44,10 +44,12 @@
%%-----------------------------------------------------------------
%% Create a boot script from a release file.
-%% Options is a list of {path, Path} | silent | local where path sets
-%% the search path, silent supresses error message printing on console,
-%% local generates a script with references to the directories there
-%% the applications are found.
+%% Options is a list of {path, Path} | silent | local
+%% | warnings_as_errors
+%% where path sets the search path, silent supresses error message
+%% printing on console, local generates a script with references
+%% to the directories there the applications are found,
+%% and warnings_as_errors treats warnings as errors.
%%
%% New options: {path,Path} can contain wildcards
%% src_tests
@@ -85,11 +87,16 @@ make_script(RelName, Output, Flags) when is_list(RelName),
ModTestP = {member(src_tests, Flags),xref_p(Flags)},
case get_release(RelName, Path, ModTestP, machine(Flags)) of
{ok, Release, Appls, Warnings} ->
- case generate_script(Output,Release,Appls,Flags) of
- ok ->
+ case systools_lib:werror(Flags, Warnings) of
+ true ->
return(ok,Warnings,Flags);
- Error ->
- return(Error,Warnings,Flags)
+ false ->
+ case generate_script(Output,Release,Appls,Flags) of
+ ok ->
+ return(ok,Warnings,Flags);
+ Error ->
+ return(Error,Warnings,Flags)
+ end
end;
Error ->
return(Error,[],Flags)
@@ -130,10 +137,21 @@ get_outdir(Flags) ->
return(ok,Warnings,Flags) ->
case member(silent,Flags) of
true ->
- {ok,?MODULE,Warnings};
+ case systools_lib:werror(Flags, Warnings) of
+ true ->
+ error;
+ false ->
+ {ok,?MODULE,Warnings}
+ end;
_ ->
- io:format("~s",[format_warning(Warnings)]),
- ok
+ case member(warnings_as_errors,Flags) of
+ true ->
+ io:format("~s",[format_warning(Warnings, true)]),
+ error;
+ false ->
+ io:format("~s",[format_warning(Warnings)]),
+ ok
+ end
end;
return({error,Mod,Error},_,Flags) ->
case member(silent,Flags) of
@@ -1612,9 +1630,9 @@ var_dir(_Dir, _, _, []) ->
false.
appDir(AppDir) ->
- case reverse(filename:split(AppDir)) of
- ["ebin"|Dir] -> filename:join(reverse(Dir));
- _ -> AppDir
+ case filename:basename(AppDir) of
+ "ebin" -> filename:dirname(AppDir);
+ _ -> AppDir
end.
add_modules(Modules, Tar, AppDir, ToDir, Ext) ->
@@ -1833,78 +1851,89 @@ get_flag(_,_) -> false.
%% Check Options for make_script
check_args_script(Args) ->
cas(Args,
- {undef, undef, undef, undef, undef, undef, undef, undef, []}).
+ {undef, undef, undef, undef, undef, undef, undef, undef,
+ undef, []}).
-cas([], {_Path,_Sil,_Loc,_Test,_Var,_Mach,_Xref,_XrefApps, X}) ->
+cas([], {_Path,_Sil,_Loc,_Test,_Var,_Mach,_Xref,_XrefApps,_Werror, X}) ->
X;
%%% path ---------------------------------------------------------------
-cas([{path, P} | Args], {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X}) when is_list(P) ->
+cas([{path, P} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) when is_list(P) ->
case check_path(P) of
ok ->
- cas(Args, {P, Sil, Loc, Test, Var, Mach, Xref, XrefApps,X});
+ cas(Args, {P, Sil, Loc, Test, Var, Mach, Xref, XrefApps,
+ Werror, X});
error ->
cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,
- X++[{path,P}]})
+ Werror, X++[{path,P}]})
end;
%%% silent -------------------------------------------------------------
-cas([silent | Args], {Path, _Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X}) ->
- cas(Args, {Path, silent, Loc, Test, Var, Mach, Xref, XrefApps, X});
+cas([silent | Args], {Path, _Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) ->
+ cas(Args, {Path, silent, Loc, Test, Var, Mach, Xref, XrefApps,
+ Werror, X});
%%% local --------------------------------------------------------------
-cas([local | Args], {Path, Sil, _Loc, Test, Var, Mach,
- Xref, XrefApps, X}) ->
- cas(Args, {Path, Sil, local, Test, Var, Mach, Xref, XrefApps, X});
+cas([local | Args], {Path, Sil, _Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) ->
+ cas(Args, {Path, Sil, local, Test, Var, Mach, Xref, XrefApps,
+ Werror, X});
%%% src_tests -------------------------------------------------------
-cas([src_tests | Args], {Path, Sil, Loc, _Test, Var, Mach,
- Xref, XrefApps, X}) ->
+cas([src_tests | Args], {Path, Sil, Loc, _Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) ->
cas(Args,
- {Path, Sil, Loc, src_tests, Var, Mach, Xref, XrefApps,X});
+ {Path, Sil, Loc, src_tests, Var, Mach, Xref, Werror, XrefApps,X});
%%% variables ----------------------------------------------------------
-cas([{variables, V} | Args], {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X}) when is_list(V) ->
+cas([{variables, V} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) when is_list(V) ->
case check_vars(V) of
ok ->
cas(Args,
- {Path, Sil, Loc, Test, V, Mach, Xref, XrefApps, X});
+ {Path, Sil, Loc, Test, V, Mach, Xref, XrefApps, Werror, X});
error ->
cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,
- X++[{variables, V}]})
+ Werror, X++[{variables, V}]})
end;
%%% machine ------------------------------------------------------------
-cas([{machine, M} | Args], {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X}) when is_atom(M) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, X});
+cas([{machine, M} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) when is_atom(M) ->
+ cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X});
%%% exref --------------------------------------------------------------
-cas([exref | Args], {Path, Sil, Loc, Test, Var, Mach,
- _Xref, XrefApps, X}) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, exref, XrefApps, X});
+cas([exref | Args], {Path, Sil, Loc, Test, Var, Mach, _Xref,
+ XrefApps, Werror, X}) ->
+ cas(Args, {Path, Sil, Loc, Test, Var, Mach, exref, XrefApps, Werror, X});
%%% exref Apps ---------------------------------------------------------
-cas([{exref, Apps} | Args], {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X}) when is_list(Apps) ->
+cas([{exref, Apps} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) when is_list(Apps) ->
case check_apps(Apps) of
ok ->
cas(Args, {Path, Sil, Loc, Test, Var, Mach,
- Xref, Apps, X});
+ Xref, Apps, Werror, X});
error ->
cas(Args, {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X++[{exref, Apps}]})
+ Xref, XrefApps, Werror, X++[{exref, Apps}]})
end;
%%% outdir Dir ---------------------------------------------------------
-cas([{outdir, Dir} | Args], {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X}) when is_list(Dir) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, X});
+cas([{outdir, Dir} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) when is_list(Dir) ->
+ cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X});
%%% otp_build (secret, not documented) ---------------------------------
-cas([otp_build | Args], {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X}) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, X});
+cas([otp_build | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) ->
+ cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X});
%%% no_module_tests (kept for backwards compatibility, but ignored) ----
-cas([no_module_tests | Args], {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, X}) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,X});
+cas([no_module_tests | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, Werror, X}) ->
+ cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X});
+%%% warnings_as_errors (kept for backwards compatibility, but ignored) ----
+cas([warnings_as_errors | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
+ XrefApps, _Werror, X}) ->
+ cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,
+ warnings_as_errors, X});
%%% ERROR --------------------------------------------------------------
-cas([Y | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, X}) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,X++[Y]}).
+cas([Y | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,
+ Werror, X}) ->
+ cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror,
+ X++[Y]}).
@@ -2030,7 +2059,6 @@ check_apps([H|T]) when is_atom(H) ->
check_apps(_) ->
error.
-
%% Format error
format_error(badly_formatted_release) ->
@@ -2144,21 +2172,31 @@ form_tar_err({add, File, Error}) ->
%% Format warning
format_warning(Warnings) ->
- map(fun({warning,W}) -> form_warn(W) end, Warnings).
-
-form_warn({source_not_found,{Mod,_,App,_,_}}) ->
- io_lib:format("*WARNING* ~p: Source code not found: ~p.erl~n",
- [App,Mod]);
-form_warn({{parse_error, File},{_,_,App,_,_}}) ->
- io_lib:format("*WARNING* ~p: Parse error: ~p~n",
- [App,File]);
-form_warn({obj_out_of_date,{Mod,_,App,_,_}}) ->
- io_lib:format("*WARNING* ~p: Object code (~p) out of date~n",[App,Mod]);
-form_warn({exref_undef, Undef}) ->
- F = fun({M,F,A}) ->
- io_lib:format("*WARNING* Undefined function ~p:~p/~p~n",
- [M,F,A])
+ format_warning(Warnings, false).
+
+format_warning(Warnings, Werror) ->
+ Prefix = case Werror of
+ true ->
+ "";
+ false ->
+ "*WARNING* "
+ end,
+ map(fun({warning,W}) -> form_warn(Prefix, W) end, Warnings).
+
+form_warn(Prefix, {source_not_found,{Mod,_,App,_,_}}) ->
+ io_lib:format("~s~p: Source code not found: ~p.erl~n",
+ [Prefix,App,Mod]);
+form_warn(Prefix, {{parse_error, File},{_,_,App,_,_}}) ->
+ io_lib:format("~s~p: Parse error: ~p~n",
+ [Prefix,App,File]);
+form_warn(Prefix, {obj_out_of_date,{Mod,_,App,_,_}}) ->
+ io_lib:format("~s~p: Object code (~p) out of date~n",
+ [Prefix,App,Mod]);
+form_warn(Prefix, {exref_undef, Undef}) ->
+ F = fun({M,F,A}) ->
+ io_lib:format("~sUndefined function ~p:~p/~p~n",
+ [Prefix,M,F,A])
end,
map(F, Undef);
-form_warn(What) ->
- io_lib:format("*WARNING* ~p~n", [What]).
+form_warn(Prefix, What) ->
+ io_lib:format("~s ~p~n", [Prefix,What]).
diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl
index ec5486226c..6d9e922900 100644
--- a/lib/sasl/src/systools_relup.erl
+++ b/lib/sasl/src/systools_relup.erl
@@ -122,7 +122,7 @@
%% rel_filename() = description() = string()
%% Opts = [opt()]
%% opt() = {path, [path()]} | silent | noexec | restart_emulator
-%% | {outdir, string()}
+%% | {outdir, string()} | warnings_as_errors
%% path() = [string()]
%% Ret = ok | error | {ok, Relup, Module, Warnings} | {error, Module, Error}
%%
@@ -139,8 +139,9 @@
%%
%% The option `path' sets search path, `silent' suppresses printing of
%% error messages to the console, `noexec' inhibits the creation of
-%% the output "relup" file, and restart_emulator ensures that the new
-%% emulator is restarted (as the final step).
+%% the output "relup" file, restart_emulator ensures that the new
+%% emulator is restarted (as the final step), and `warnings_as_errors'
+%% treats warnings as errors.
%% ----------------------------------------------------------------
mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs) ->
mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, []).
@@ -153,14 +154,29 @@ mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Opts) ->
{false, false} ->
case R of
{ok, _Res, _Mod, Ws} ->
- print_warnings(Ws),
- ok;
+ print_warnings(Ws, Opts),
+ case systools_lib:werror(Opts, Ws) of
+ true ->
+ error;
+ false ->
+ ok
+ end;
Other ->
print_error(Other),
error
end;
- _ ->
- R
+ _ ->
+ case R of
+ {ok, _Res, _Mod, Ws} ->
+ case systools_lib:werror(Opts, Ws) of
+ true ->
+ error;
+ false ->
+ R
+ end;
+ R ->
+ R
+ end
end;
BadArg ->
erlang:error({badarg, BadArg})
@@ -195,7 +211,12 @@ do_mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Path, Opts) ->
{Dn, Ws2} = foreach_baserel_dn(TopRel, TopApps, BaseDnRelDcs,
Path, Opts, Ws1),
Relup = {TopRel#release.vsn, Up, Dn},
- write_relup_file(Relup, Opts),
+ case systools_lib:werror(Opts, Ws2) of
+ true ->
+ ok;
+ false ->
+ write_relup_file(Relup, Opts)
+ end,
{ok, Relup, ?MODULE, Ws2};
Other ->
throw(Other)
@@ -527,20 +548,29 @@ format_error(Error) ->
io:format("~p~n", [Error]).
-print_warnings(Ws) when is_list(Ws) ->
- lists:foreach(fun(W) -> print_warning(W) end, Ws);
-print_warnings(W) ->
- print_warning(W).
+print_warnings(Ws, Opts) when is_list(Ws) ->
+ lists:foreach(fun(W) -> print_warning(W, Opts) end, Ws);
+print_warnings(W, Opts) ->
+ print_warning(W, Opts).
-print_warning(W) ->
- S = format_warning(W),
+print_warning(W, Opts) ->
+ Prefix = case lists:member(warnings_as_errors, Opts) of
+ true ->
+ "";
+ false ->
+ "*WARNING* "
+ end,
+ S = format_warning(Prefix, W),
io:format("~s", [S]).
-format_warning({erts_vsn_changed, {Rel1, Rel2}}) ->
- io_lib:format("*WARNING* The ERTS version changed between ~p and ~p~n",
- [Rel1, Rel2]);
-format_warning(What) ->
- io_lib:format("*WARNING* ~p~n",[What]).
+format_warning(W) ->
+ format_warning("*WARNING* ", W).
+
+format_warning(Prefix, {erts_vsn_changed, {Rel1, Rel2}}) ->
+ io_lib:format("~sThe ERTS version changed between ~p and ~p~n",
+ [Prefix, Rel1, Rel2]);
+format_warning(Prefix, What) ->
+ io_lib:format("~s~p~n",[Prefix, What]).
get_reason({error, {open, _, _}}) -> open;
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
index 9c7733b7ec..af2183bfff 100644
--- a/lib/sasl/test/release_handler_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -55,7 +55,10 @@ win32_cases() ->
%% Cases that can be run on all platforms
cases() ->
- [otp_2740, otp_2760, otp_5761, otp_9402, otp_9417, instructions, eval_appup].
+ [otp_2740, otp_2760, otp_5761, otp_9402, otp_9417,
+ otp_9395_check_old_code, otp_9395_check_and_purge,
+ otp_9395_update_many_mods, otp_9395_rm_many_mods,
+ instructions, eval_appup, supervisor_which_children_timeout].
groups() ->
[{release,[],
@@ -520,6 +523,29 @@ no_cc() ->
%%%-----------------------------------------------------------------
%%-----------------------------------------------------------------
+%% release_handler_1:get_supervised_procs/0 test
+%%-----------------------------------------------------------------
+supervisor_which_children_timeout(Conf) ->
+ PrivDir = priv_dir(Conf),
+ Dir = filename:join(PrivDir,"supervisor_which_children_timeout"),
+ DataDir = ?config(data_dir,Conf),
+ LibDir = filename:join([DataDir,release_handler_timeouts]),
+
+ Rel1 = create_and_install_fake_first_release(Dir,[{dummy,"0.1",LibDir}]),
+
+ {ok, Node} = t_start_node(supervisor_which_children_timeout, Rel1, []),
+ Proc = rpc:call(Node, erlang, whereis, [dummy_sup_2]),
+ ok = rpc:call(Node, sys, suspend, [Proc]),
+ Result = {badrpc, {'EXIT', {suspended_supervisor, _}}} =
+ rpc:call(Node, release_handler_1, get_supervised_procs, []),
+ ?t:format("release_handler_1:get_supervised_procs/0: ~p~n", [Result]),
+
+ ok.
+
+supervisor_which_children_timeout(cleanup, Conf) ->
+ stop_node(node_name(supervisor_which_children_timeout)).
+
+%%-----------------------------------------------------------------
%% Ticket: OTP-2740
%% Slogan: vsn not numeric doesn't work so good in release_handling
%%-----------------------------------------------------------------
@@ -556,7 +582,7 @@ otp_2760(Conf) ->
LibDir = filename:join([DataDir,app1_app2,lib1]),
Rel1 = create_and_install_fake_first_release(Dir,[{app1,"1.0",LibDir}]),
- Rel2 = create_fake_upgrade_release(Dir,"after",[],{Rel1,Rel1,[LibDir]}),
+ Rel2 = create_fake_upgrade_release(Dir,"after",[],{[Rel1],[Rel1],[LibDir]}),
Rel2Dir = filename:dirname(Rel2),
%% Start a node with Rel1.boot and check that the app1 module is loaded
@@ -569,9 +595,12 @@ otp_2760(Conf) ->
{ok, []} = rpc:call(Node, release_handler_1, eval_script, [Script]),
false = rpc:call(Node, code, is_loaded, [app1]),
- true = stop_node(Node),
ok.
+otp_2760(cleanup,_Conf) ->
+ stop_node(node_name(otp_2760)).
+
+
%% Test upgrade using other filesystem than the defined in OTP and
%% option {update_paths, true}
otp_5761(Conf) when is_list(Conf) ->
@@ -597,7 +626,7 @@ otp_5761(Conf) when is_list(Conf) ->
"2",
[{app1,"2.0",LibDir2},
{app2,"1.0",LibDir2}],
- {Rel1,Rel1,[LibDir1]}),
+ {[Rel1],[Rel1],[LibDir1]}),
Rel1Dir = filename:dirname(Rel1),
Rel2Dir = filename:dirname(Rel2),
@@ -653,10 +682,11 @@ otp_5761(Conf) when is_list(Conf) ->
App11Dir = rpc:call(Node, code, lib_dir, [app1]),
App2aDir = rpc:call(Node, code, lib_dir, [app2]),
- %% Stop the slave node
- true = stop_node(Node),
ok.
+otp_5761(cleanup,_Conf) ->
+ stop_node(node_name(otp_5761)).
+
%% When a new version of an application is added, but no module is
%% changed - the path was not updated - i.e. code:priv_dir would point
@@ -673,7 +703,7 @@ otp_9402(Conf) when is_list(Conf) ->
Rel2 = create_fake_upgrade_release(Dir,
"2",
[{a,"1.2",LibDir}],
- {Rel1,Rel1,[LibDir]}),
+ {[Rel1],[Rel1],[LibDir]}),
Rel1Dir = filename:dirname(Rel1),
Rel2Dir = filename:dirname(Rel2),
@@ -722,6 +752,9 @@ otp_9402(Conf) when is_list(Conf) ->
ok.
+otp_9402(cleanup,_Conf) ->
+ stop_node(node_name(otp_9402)).
+
%% When a module is deleted in an appup instruction, the upgrade
%% failed if the module was not loaded.
@@ -737,7 +770,7 @@ otp_9417(Conf) when is_list(Conf) ->
Rel2 = create_fake_upgrade_release(Dir,
"2",
[{b,"2.0",LibDir}],
- {Rel1,Rel1,[LibDir]}),
+ {[Rel1],[Rel1],[LibDir]}),
Rel1Dir = filename:dirname(Rel1),
Rel2Dir = filename:dirname(Rel2),
@@ -777,6 +810,282 @@ otp_9417(Conf) when is_list(Conf) ->
{file,BServerBeam} = rpc:call(Node,code,is_loaded,[b_server]),
ok.
+otp_9417(cleanup,_Conf) ->
+ stop_node(node_name(otp_9417)).
+
+
+%% OTP-9395 - performance problems when there are MANY processes
+%% Test that the procedure of checking for old code before an upgrade
+%% can be started is "very much faster" when there is no old code in
+%% the system.
+otp_9395_check_old_code(Conf) when is_list(Conf) ->
+
+ NProcs = 1000,
+ MPath = filename:join([?config(data_dir,Conf),"lib","many_mods-1.0","ebin"]),
+ code:add_path(MPath),
+
+ %% Start NProc processes, each referencing each module
+ {Modules,Pids} = m:start(NProcs),
+
+ %% Load each module again in order to get old code
+ [code:load_file(Mod) || Mod <- Modules],
+ true = erlang:check_old_code(m10),
+
+ S = [point_of_no_return |
+ [{remove,{M,soft_purge,soft_purge}} || M <- Modules]],
+
+ %% Do the old code check, then purge, and redo
+ {T1,{ok,PurgeMods}} = timer:tc(release_handler_1,check_script,[S,[]]),
+ true = (lists:sort(PurgeMods) == lists:sort(Modules)),
+ [code:purge(M) || M <- PurgeMods],
+ {T2,{ok,[]}} = timer:tc(release_handler_1,check_script,[S,[]]),
+
+ %% Cleanup
+ lists:foreach(fun(Pid) -> Pid ! stop end, Pids),
+ lists:foreach(fun(Mod) -> code:purge(Mod),
+ code:delete(Mod),
+ code:purge(Mod)
+ end, Modules),
+ code:del_path(MPath),
+
+ %% Test that second run was much faster than the first
+ if T2 > 0 ->
+ X = T1/T2,
+ ct:log("~p procs, ~p mods -> ~n"
+ "\tWith old code: ~.2f sec~n"
+ "\tAfter purge: ~.2f sec~n"
+ "\tT1/T2: ~.2f",
+ [NProcs,length(Modules),T1/1000000,T2/1000000,X]),
+ if X < 1000 ->
+ ct:fail({not_enough_improvement_after_purge,round(X)});
+ true ->
+ ok
+ end;
+ T1 > 0 -> %% Means T1/T2 = infinite
+ ok;
+ true ->
+ ct:fail({unexpected_values,T1,T2})
+ end,
+ ok.
+
+
+%% OTP-9395 - performance problems when there are MANY processes
+%% Added option 'purge' to check_install_release
+otp_9395_check_and_purge(Conf) when is_list(Conf) ->
+ %% Set some paths
+ PrivDir = priv_dir(Conf),
+ Dir = filename:join(PrivDir,"otp_9395_check_and_purge"),
+ LibDir = filename:join(?config(data_dir, Conf), "lib"),
+
+ %% Create the releases
+ Rel1 = create_and_install_fake_first_release(Dir,
+ [{b,"1.0",LibDir}]),
+ Rel2 = create_fake_upgrade_release(Dir,
+ "2",
+ [{b,"2.0",LibDir}],
+ {[Rel1],[Rel1],[LibDir]}),
+ Rel1Dir = filename:dirname(Rel1),
+ Rel2Dir = filename:dirname(Rel2),
+
+ %% Start a slave node
+ {ok, Node} = t_start_node(otp_9395_check_and_purge, Rel1,
+ filename:join(Rel1Dir,"sys.config")),
+
+ %% Make sure there is old code for b_lib and b_server
+ rpc:call(Node,code,load_file,[b_lib]),
+ rpc:call(Node,code,load_file,[b_lib]),
+ rpc:call(Node,code,load_file,[b_server]),
+ rpc:call(Node,code,load_file,[b_server]),
+ true = rpc:call(Node,erlang,check_old_code,[b_lib]),
+ true = rpc:call(Node,erlang,check_old_code,[b_server]),
+
+ %% Unpack second release, which removes b_lib module and loads b_server
+ {ok, RelVsn2} =
+ rpc:call(Node, release_handler, set_unpacked,
+ [Rel2++".rel", [{b,"2.0",LibDir}]]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "relup")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "start.boot")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "sys.config")]),
+
+ %% Do check_install_release, and check that old code still exists
+ {ok, _RelVsn1, []} =
+ rpc:call(Node, release_handler, check_install_release, [RelVsn2]),
+ true = rpc:call(Node,erlang,check_old_code,[b_lib]),
+ true = rpc:call(Node,erlang,check_old_code,[b_server]),
+
+ %% Do check_install_release with option 'purge' and check that old
+ %% code is gone
+ {ok, _RelVsn1, []} =
+ rpc:call(Node, release_handler, check_install_release, [RelVsn2,[purge]]),
+ false = rpc:call(Node,erlang,check_old_code,[b_lib]),
+ false = rpc:call(Node,erlang,check_old_code,[b_server]),
+
+ ok.
+
+otp_9395_check_and_purge(cleanup,_Conf) ->
+ stop_node(node_name(otp_9395_check_and_purge)).
+
+
+%% OTP-9395 - performance problems when there are MANY processes
+%% Upgrade which updates many modules (brutal_purge)
+otp_9395_update_many_mods(Conf) when is_list(Conf) ->
+ %% Set some paths
+ PrivDir = priv_dir(Conf),
+ Dir = filename:join(PrivDir,"otp_9395_update_many_mods"),
+ LibDir = filename:join(?config(data_dir, Conf), "lib"),
+
+ %% Create the releases
+ Rel1 = create_and_install_fake_first_release(Dir,
+ [{many_mods,"1.0",LibDir}]),
+ Rel2 = create_fake_upgrade_release(Dir,
+ "2",
+ [{many_mods,"1.1",LibDir}],
+ {[Rel1],[Rel1],[LibDir]}),
+ Rel1Dir = filename:dirname(Rel1),
+ Rel2Dir = filename:dirname(Rel2),
+
+ %% Start a slave node
+ {ok, Node} = t_start_node(otp_9395_update_many_mods, Rel1,
+ filename:join(Rel1Dir,"sys.config")),
+
+ %% Start a lot of processes on the new node, all with refs to each
+ %% module that will be updated
+ NProcs = 1000,
+ {Modules,Pids1} = rpc:call(Node,m,start,[NProcs]),
+
+ %% Then load modules in order to get old code
+ [rpc:call(Node,code,load_file,[Mod]) || Mod <- Modules],
+ true = rpc:call(Node,erlang,check_old_code,[m10]),
+
+ %% Unpack second release, which updates all mX modules
+ {ok, RelVsn2} =
+ rpc:call(Node, release_handler, set_unpacked,
+ [Rel2++".rel", [{many_mods,"1.1",LibDir}]]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "relup")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "start.boot")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "sys.config")]),
+
+ %% First, install release directly and check how much time it takes
+ {TInst0,{ok, _, []}} =
+ timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn2]]),
+ ct:log("install_release: ~.2f",[TInst0/1000000]),
+
+ %% Restore to old release, spawn processes again and load to get old code
+ {_,RelVsn1} = init:script_id(),
+ {_TInst1,{ok, _, []}} =
+ timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn1]]),
+% ct:log("install_release: ~.2f",[_TInst1/1000000]),
+
+ [exit(Pid,kill) || Pid <- Pids1],
+ {Modules,_Pids2} = rpc:call(Node,m,start,[NProcs]),
+ [rpc:call(Node,code,load_file,[Mod]) || Mod <- Modules],
+ true = rpc:call(Node,erlang,check_old_code,[m10]),
+
+ %% Run check_install_release with purge before install this time
+ {TCheck,{ok, _RelVsn1, []}} =
+ timer:tc(rpc,call,[Node, release_handler, check_install_release,
+ [RelVsn2,[purge]]]),
+ ct:log("check_install_release with purge: ~.2f",[TCheck/1000000]),
+
+ %% Finally install release after check and purge, and check that
+ %% this install was faster than the first.
+ {TInst2,{ok, _RelVsn1, []}} =
+ timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn2]]),
+ ct:log("install_release: ~.2f",[TInst2/1000000]),
+
+ true = (TInst2 < TInst0),
+
+ ok.
+
+otp_9395_update_many_mods(cleanup,_Conf) ->
+ stop_node(node_name(otp_9395_update_many_mods)).
+
+
+%% OTP-9395 - performance problems when there are MANY processes
+%% Upgrade which removes many modules (brutal_purge)
+otp_9395_rm_many_mods(Conf) when is_list(Conf) ->
+ %% Set some paths
+ PrivDir = priv_dir(Conf),
+ Dir = filename:join(PrivDir,"otp_9395_rm_many_mods"),
+ LibDir = filename:join(?config(data_dir, Conf), "lib"),
+
+ %% Create the releases
+ Rel1 = create_and_install_fake_first_release(Dir,
+ [{many_mods,"1.0",LibDir}]),
+ Rel2 = create_fake_upgrade_release(Dir,
+ "2",
+ [{many_mods,"2.0",LibDir}],
+ {[Rel1],[Rel1],[LibDir]}),
+ Rel1Dir = filename:dirname(Rel1),
+ Rel2Dir = filename:dirname(Rel2),
+
+ %% Start a slave node
+ {ok, Node} = t_start_node(otp_9395_rm_many_mods, Rel1,
+ filename:join(Rel1Dir,"sys.config")),
+
+ %% Start a lot of processes on the new node, all with refs to each
+ %% module that will be updated
+ NProcs = 1000,
+ {Modules,Pids1} = rpc:call(Node,m,start,[NProcs]),
+
+ %% Then load modules in order to get old code
+ [rpc:call(Node,code,load_file,[Mod]) || Mod <- Modules],
+ true = rpc:call(Node,erlang,check_old_code,[m10]),
+
+ %% Unpack second release, which removes all mX modules
+ {ok, RelVsn2} =
+ rpc:call(Node, release_handler, set_unpacked,
+ [Rel2++".rel", [{many_mods,"2.0",LibDir}]]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "relup")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "start.boot")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "sys.config")]),
+
+ %% First, install release directly and check how much time it takes
+ {TInst0,{ok, _, []}} =
+ timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn2]]),
+ ct:log("install_release: ~.2f",[TInst0/1000000]),
+
+ %% Restore to old release, spawn processes again and load to get old code
+ {_,RelVsn1} = init:script_id(),
+ {_TInst1,{ok, _, []}} =
+ timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn1]]),
+% ct:log("install_release: ~.2f",[_TInst1/1000000]),
+
+ [exit(Pid,kill) || Pid <- Pids1],
+ {Modules,_Pids2} = rpc:call(Node,m,start,[NProcs]),
+ [rpc:call(Node,code,load_file,[Mod]) || Mod <- Modules],
+ true = rpc:call(Node,erlang,check_old_code,[m10]),
+
+ %% Run check_install_release with purge before install this time
+ {TCheck,{ok, _RelVsn1, []}} =
+ timer:tc(rpc,call,[Node, release_handler, check_install_release,
+ [RelVsn2,[purge]]]),
+ ct:log("check_install_release with purge: ~.2f",[TCheck/1000000]),
+
+ %% Finally install release after check and purge, and check that
+ %% this install was faster than the first.
+ {TInst2,{ok, _RelVsn1, []}} =
+ timer:tc(rpc,call,[Node, release_handler, install_release, [RelVsn2]]),
+ ct:log("install_release: ~.2f",[TInst2/1000000]),
+
+ true = (TInst2 =< TInst0),
+
+ ok.
+
+otp_9395_rm_many_mods(cleanup,_Conf) ->
+ stop_node(node_name(otp_9395_rm_many_mods)).
+
+
+
%% Test upgrade and downgrade of applications
eval_appup(Conf) when is_list(Conf) ->
@@ -1838,9 +2147,8 @@ create_fake_upgrade_release(Dir,RelVsn,AppDirs,{UpFrom,DownTo,ExtraLibs}) ->
%% And a relup file so it can be upgraded to
RelupPath = Paths ++ [filename:join([Lib,"*","ebin"]) || Lib <- ExtraLibs],
- ok = systools:make_relup(Rel,[UpFrom],[DownTo],
- [{path,RelupPath},
- {outdir,RelDir}]),
+ ok = systools:make_relup(Rel,UpFrom,DownTo,[{path,RelupPath},
+ {outdir,RelDir}]),
Rel.
diff --git a/lib/sasl/test/release_handler_SUITE_data/Makefile.src b/lib/sasl/test/release_handler_SUITE_data/Makefile.src
index a12e526d2e..edb446413d 100644
--- a/lib/sasl/test/release_handler_SUITE_data/Makefile.src
+++ b/lib/sasl/test/release_handler_SUITE_data/Makefile.src
@@ -13,7 +13,30 @@ LIB= \
lib/a-1.0/ebin/a_sup.@EMULATOR@ \
lib/b-1.0/ebin/b_server.@EMULATOR@ \
lib/b-1.0/ebin/b_lib.@EMULATOR@ \
- lib/b-2.0/ebin/b_server.@EMULATOR@
+ lib/b-2.0/ebin/b_server.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m1.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m2.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m3.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m4.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m5.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m6.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m7.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m8.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m9.@EMULATOR@ \
+ lib/many_mods-1.0/ebin/m10.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m1.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m2.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m3.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m4.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m5.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m6.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m7.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m8.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m9.@EMULATOR@ \
+ lib/many_mods-1.1/ebin/m10.@EMULATOR@ \
+ lib/many_mods-2.0/ebin/m.@EMULATOR@
APP= \
app1_app2/lib1/app1-1.0/ebin/app1_sup.@EMULATOR@ \
@@ -41,8 +64,13 @@ C= \
c/b.@EMULATOR@ \
c/c_sup.@EMULATOR@
+SUP= \
+ release_handler_timeouts/dummy-0.1/ebin/dummy_app.@EMULATOR@ \
+ release_handler_timeouts/dummy-0.1/ebin/dummy_server.@EMULATOR@ \
+ release_handler_timeouts/dummy-0.1/ebin/dummy_sup.@EMULATOR@ \
+ release_handler_timeouts/dummy-0.1/ebin/dummy_sup_2.@EMULATOR@
-all: $(P2B) $(LIB) $(APP) $(OTP2740) $(C)
+all: $(P2B) $(LIB) $(APP) $(OTP2740) $(C) $(SUP)
P2B/a-2.0/ebin/a.@EMULATOR@: P2B/a-2.0/src/a.erl
erlc $(EFLAGS) -oP2B/a-2.0/ebin P2B/a-2.0/src/a.erl
@@ -75,6 +103,52 @@ lib/b-1.0/ebin/b_lib.@EMULATOR@: lib/b-1.0/src/b_lib.erl
lib/b-2.0/ebin/b_server.@EMULATOR@: lib/b-2.0/src/b_server.erl
erlc $(EFLAGS) -olib/b-2.0/ebin lib/b-2.0/src/b_server.erl
+lib/many_mods-1.0/ebin/m.@EMULATOR@: lib/many_mods-1.0/src/m.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m.erl
+lib/many_mods-1.0/ebin/m1.@EMULATOR@: lib/many_mods-1.0/src/m1.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m1.erl
+lib/many_mods-1.0/ebin/m2.@EMULATOR@: lib/many_mods-1.0/src/m2.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m2.erl
+lib/many_mods-1.0/ebin/m3.@EMULATOR@: lib/many_mods-1.0/src/m3.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m3.erl
+lib/many_mods-1.0/ebin/m4.@EMULATOR@: lib/many_mods-1.0/src/m4.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m4.erl
+lib/many_mods-1.0/ebin/m5.@EMULATOR@: lib/many_mods-1.0/src/m5.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m5.erl
+lib/many_mods-1.0/ebin/m6.@EMULATOR@: lib/many_mods-1.0/src/m6.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m6.erl
+lib/many_mods-1.0/ebin/m7.@EMULATOR@: lib/many_mods-1.0/src/m7.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m7.erl
+lib/many_mods-1.0/ebin/m8.@EMULATOR@: lib/many_mods-1.0/src/m8.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m8.erl
+lib/many_mods-1.0/ebin/m9.@EMULATOR@: lib/many_mods-1.0/src/m9.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m9.erl
+lib/many_mods-1.0/ebin/m10.@EMULATOR@: lib/many_mods-1.0/src/m10.erl
+ erlc $(EFLAGS) -olib/many_mods-1.0/ebin lib/many_mods-1.0/src/m10.erl
+lib/many_mods-1.1/ebin/m.@EMULATOR@: lib/many_mods-1.1/src/m.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m.erl
+lib/many_mods-1.1/ebin/m1.@EMULATOR@: lib/many_mods-1.1/src/m1.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m1.erl
+lib/many_mods-1.1/ebin/m2.@EMULATOR@: lib/many_mods-1.1/src/m2.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m2.erl
+lib/many_mods-1.1/ebin/m3.@EMULATOR@: lib/many_mods-1.1/src/m3.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m3.erl
+lib/many_mods-1.1/ebin/m4.@EMULATOR@: lib/many_mods-1.1/src/m4.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m4.erl
+lib/many_mods-1.1/ebin/m5.@EMULATOR@: lib/many_mods-1.1/src/m5.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m5.erl
+lib/many_mods-1.1/ebin/m6.@EMULATOR@: lib/many_mods-1.1/src/m6.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m6.erl
+lib/many_mods-1.1/ebin/m7.@EMULATOR@: lib/many_mods-1.1/src/m7.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m7.erl
+lib/many_mods-1.1/ebin/m8.@EMULATOR@: lib/many_mods-1.1/src/m8.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m8.erl
+lib/many_mods-1.1/ebin/m9.@EMULATOR@: lib/many_mods-1.1/src/m9.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m9.erl
+lib/many_mods-1.1/ebin/m10.@EMULATOR@: lib/many_mods-1.1/src/m10.erl
+ erlc $(EFLAGS) -olib/many_mods-1.1/ebin lib/many_mods-1.1/src/m10.erl
+lib/many_mods-2.0/ebin/m.@EMULATOR@: lib/many_mods-2.0/src/m.erl
+ erlc $(EFLAGS) -olib/many_mods-2.0/ebin lib/many_mods-2.0/src/m.erl
app1_app2/lib1/app1-1.0/ebin/app1_sup.@EMULATOR@: app1_app2/lib1/app1-1.0/src/app1_sup.erl
@@ -126,3 +200,12 @@ c/b.@EMULATOR@: c/b.erl
erlc $(EFLAGS) -oc c/b.erl
c/c_sup.@EMULATOR@: c/c_sup.erl
erlc $(EFLAGS) -oc c/c_sup.erl
+
+release_handler_timeouts/dummy-0.1/ebin/dummy_app.@EMULATOR@: release_handler_timeouts/dummy-0.1/src/dummy_app.erl
+ erlc $(EFLAGS) -orelease_handler_timeouts/dummy-0.1/ebin release_handler_timeouts/dummy-0.1/src/dummy_app.erl
+release_handler_timeouts/dummy-0.1/ebin/dummy_server.@EMULATOR@: release_handler_timeouts/dummy-0.1/src/dummy_server.erl
+ erlc $(EFLAGS) -orelease_handler_timeouts/dummy-0.1/ebin release_handler_timeouts/dummy-0.1/src/dummy_server.erl
+release_handler_timeouts/dummy-0.1/ebin/dummy_sup.@EMULATOR@: release_handler_timeouts/dummy-0.1/src/dummy_sup.erl
+ erlc $(EFLAGS) -orelease_handler_timeouts/dummy-0.1/ebin release_handler_timeouts/dummy-0.1/src/dummy_sup.erl
+release_handler_timeouts/dummy-0.1/ebin/dummy_sup_2.@EMULATOR@: release_handler_timeouts/dummy-0.1/src/dummy_sup_2.erl
+ erlc $(EFLAGS) -orelease_handler_timeouts/dummy-0.1/ebin release_handler_timeouts/dummy-0.1/src/dummy_sup_2.erl
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/README b/lib/sasl/test/release_handler_SUITE_data/lib/README
index 667d21d4cf..639a4ca0fb 100644
--- a/lib/sasl/test/release_handler_SUITE_data/lib/README
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/README
@@ -13,4 +13,21 @@ start version, includes b_lib and b_server
b-2.0:
can be upgraded to from b-1.0.
-Removes b_lib and updates b_server
+Removes b_lib (soft_purge) and updates b_server (brutal_purge)
+* The diff in purge method is important for test "check_and_purge", in
+ order to check that the purge option to check_install_release works
+ for both methods.
+
+many_mods-1.0:
+start version.
+m:start/1 starts N procs, each calling Mod:bar() in all other modules (m1-m10).
+m1-m10: implements bar() which returns a big constant.
+The point is to get many processes with references to many modules,
+and then load the modules again so that old code exists. See tests
+otp_9395_update_many_mods and otp_9395_rm_many_mods.
+
+many_mods-1.1:
+can be upgraded to from many_mods-1.0. Updates modules m1-m10.
+
+many_mods-2.0:
+can be upgraded to from many_mods-1.0. Removes modules m1-m10. \ No newline at end of file
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.appup b/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.appup
index d261a37732..001255a88c 100644
--- a/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.appup
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/b-2.0/ebin/b.appup
@@ -1,3 +1,6 @@
+%% -*- erlang -*-
{"2.0",
- [{"1.0",[{delete_module,b_lib}, {update,b_server,{advanced,[]}}]}],
- [{"1.0",[{add_module,b_lib},{update,b_server,{advanced,[]}}]}]}.
+ [{"1.0",[{remove_module,b_lib,soft_purge,soft_purge,[]},
+ {update,b_server,{advanced,[]}}]}],
+ [{"1.0",[{add_module,b_lib},
+ {update,b_server,{advanced,[]}}]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/ebin/many_mods.app b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/ebin/many_mods.app
new file mode 100644
index 0000000000..aa39adfffa
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/ebin/many_mods.app
@@ -0,0 +1,17 @@
+%% -*- erlang -*-
+{application, many_mods,
+ [{description, "Application with many modules CXC 138 11"},
+ {vsn, "1.0"},
+ {modules, [{m, 1},
+ {m1,1},
+ {m2,1},
+ {m3,1},
+ {m4,1},
+ {m5,1},
+ {m6,1},
+ {m7,1},
+ {m8,1},
+ {m9,1},
+ {m10,1}]},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m.erl
new file mode 100644
index 0000000000..418102bebb
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m.erl
@@ -0,0 +1,11 @@
+-module(m).
+-compile(export_all).
+
+start(NProcs) ->
+ Modules = [m1,m2,m3,m4,m5,m6,m7,m8,m9,m10],
+ Pids = [spawn_link(fun() ->
+ Cs = [M:bar() || M <- Modules],
+ receive stop -> Cs end
+ end) ||
+ _ <- lists:seq(1,NProcs)],
+ {Modules,Pids}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m1.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m1.erl
new file mode 100644
index 0000000000..cacc13f5d7
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m1.erl
@@ -0,0 +1,4 @@
+-module(m1).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m10.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m10.erl
new file mode 100644
index 0000000000..81e120b891
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m10.erl
@@ -0,0 +1,4 @@
+-module(m10).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m2.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m2.erl
new file mode 100644
index 0000000000..481276ba7b
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m2.erl
@@ -0,0 +1,4 @@
+-module(m2).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m3.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m3.erl
new file mode 100644
index 0000000000..9a04ed5fc9
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m3.erl
@@ -0,0 +1,4 @@
+-module(m3).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m4.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m4.erl
new file mode 100644
index 0000000000..90de9a30c9
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m4.erl
@@ -0,0 +1,4 @@
+-module(m4).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m5.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m5.erl
new file mode 100644
index 0000000000..8a9b690dfa
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m5.erl
@@ -0,0 +1,4 @@
+-module(m5).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m6.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m6.erl
new file mode 100644
index 0000000000..cd0d3977ed
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m6.erl
@@ -0,0 +1,4 @@
+-module(m6).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m7.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m7.erl
new file mode 100644
index 0000000000..1f79918d6e
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m7.erl
@@ -0,0 +1,4 @@
+-module(m7).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m8.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m8.erl
new file mode 100644
index 0000000000..2ce03a0b7e
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m8.erl
@@ -0,0 +1,4 @@
+-module(m8).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m9.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m9.erl
new file mode 100644
index 0000000000..1c5f72e628
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.0/src/m9.erl
@@ -0,0 +1,4 @@
+-module(m9).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.app b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.app
new file mode 100644
index 0000000000..36c50caf2f
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.app
@@ -0,0 +1,17 @@
+%% -*- erlang -*-
+{application, many_mods,
+ [{description, "Application with many modules CXC 138 11"},
+ {vsn, "1.1"},
+ {modules, [{m, 1},
+ {m1,1},
+ {m2,1},
+ {m3,1},
+ {m4,1},
+ {m5,1},
+ {m6,1},
+ {m7,1},
+ {m8,1},
+ {m9,1},
+ {m10,1}]},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.appup b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.appup
new file mode 100644
index 0000000000..696435e06f
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/ebin/many_mods.appup
@@ -0,0 +1,22 @@
+%% -*- erlang -*-
+{"1.1",
+ [{"1.0",[{update,m1},
+ {update,m2},
+ {update,m3},
+ {update,m4},
+ {update,m5},
+ {update,m6},
+ {update,m7},
+ {update,m8},
+ {update,m9},
+ {update,m10}]}],
+ [{"1.0",[{update,m1},
+ {update,m2},
+ {update,m3},
+ {update,m4},
+ {update,m5},
+ {update,m6},
+ {update,m7},
+ {update,m8},
+ {update,m9},
+ {update,m10}]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m.erl
new file mode 100644
index 0000000000..418102bebb
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m.erl
@@ -0,0 +1,11 @@
+-module(m).
+-compile(export_all).
+
+start(NProcs) ->
+ Modules = [m1,m2,m3,m4,m5,m6,m7,m8,m9,m10],
+ Pids = [spawn_link(fun() ->
+ Cs = [M:bar() || M <- Modules],
+ receive stop -> Cs end
+ end) ||
+ _ <- lists:seq(1,NProcs)],
+ {Modules,Pids}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m1.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m1.erl
new file mode 100644
index 0000000000..cacc13f5d7
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m1.erl
@@ -0,0 +1,4 @@
+-module(m1).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m10.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m10.erl
new file mode 100644
index 0000000000..81e120b891
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m10.erl
@@ -0,0 +1,4 @@
+-module(m10).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m2.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m2.erl
new file mode 100644
index 0000000000..481276ba7b
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m2.erl
@@ -0,0 +1,4 @@
+-module(m2).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m3.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m3.erl
new file mode 100644
index 0000000000..9a04ed5fc9
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m3.erl
@@ -0,0 +1,4 @@
+-module(m3).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m4.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m4.erl
new file mode 100644
index 0000000000..90de9a30c9
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m4.erl
@@ -0,0 +1,4 @@
+-module(m4).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m5.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m5.erl
new file mode 100644
index 0000000000..8a9b690dfa
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m5.erl
@@ -0,0 +1,4 @@
+-module(m5).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m6.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m6.erl
new file mode 100644
index 0000000000..cd0d3977ed
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m6.erl
@@ -0,0 +1,4 @@
+-module(m6).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m7.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m7.erl
new file mode 100644
index 0000000000..1f79918d6e
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m7.erl
@@ -0,0 +1,4 @@
+-module(m7).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m8.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m8.erl
new file mode 100644
index 0000000000..2ce03a0b7e
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m8.erl
@@ -0,0 +1,4 @@
+-module(m8).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m9.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m9.erl
new file mode 100644
index 0000000000..1c5f72e628
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-1.1/src/m9.erl
@@ -0,0 +1,4 @@
+-module(m9).
+-compile(export_all).
+%% A module with a big constant...
+bar() -> {now(),[{1,'1',"1"},{2,'2',"2"},{3,'3',"3"},{4,'4',"4"},{5,'5',"5"},{6,'6',"6"},{7,'7',"7"},{8,'8',"8"},{9,'9',"9"},{10,'10',"10"},{11,'11',"11"},{12,'12',"12"},{13,'13',"13"},{14,'14',"14"},{15,'15',"15"},{16,'16',"16"},{17,'17',"17"},{18,'18',"18"},{19,'19',"19"},{20,'20',"20"},{21,'21',"21"},{22,'22',"22"},{23,'23',"23"},{24,'24',"24"},{25,'25',"25"},{26,'26',"26"},{27,'27',"27"},{28,'28',"28"},{29,'29',"29"},{30,'30',"30"},{31,'31',"31"},{32,'32',"32"},{33,'33',"33"},{34,'34',"34"},{35,'35',"35"},{36,'36',"36"},{37,'37',"37"},{38,'38',"38"},{39,'39',"39"},{40,'40',"40"},{41,'41',"41"},{42,'42',"42"},{43,'43',"43"},{44,'44',"44"},{45,'45',"45"},{46,'46',"46"},{47,'47',"47"},{48,'48',"48"},{49,'49',"49"},{50,'50',"50"},{51,'51',"51"},{52,'52',"52"},{53,'53',"53"},{54,'54',"54"},{55,'55',"55"},{56,'56',"56"},{57,'57',"57"},{58,'58',"58"},{59,'59',"59"},{60,'60',"60"},{61,'61',"61"},{62,'62',"62"},{63,'63',"63"},{64,'64',"64"},{65,'65',"65"},{66,'66',"66"},{67,'67',"67"},{68,'68',"68"},{69,'69',"69"},{70,'70',"70"},{71,'71',"71"},{72,'72',"72"},{73,'73',"73"},{74,'74',"74"},{75,'75',"75"},{76,'76',"76"},{77,'77',"77"},{78,'78',"78"},{79,'79',"79"},{80,'80',"80"},{81,'81',"81"},{82,'82',"82"},{83,'83',"83"},{84,'84',"84"},{85,'85',"85"},{86,'86',"86"},{87,'87',"87"},{88,'88',"88"},{89,'89',"89"},{90,'90',"90"},{91,'91',"91"},{92,'92',"92"},{93,'93',"93"},{94,'94',"94"},{95,'95',"95"},{96,'96',"96"},{97,'97',"97"},{98,'98',"98"},{99,'99',"99"},{100,'100',"100"}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.app b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.app
new file mode 100644
index 0000000000..98f6527750
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.app
@@ -0,0 +1,7 @@
+%% -*- erlang -*-
+{application, many_mods,
+ [{description, "Application with many modules CXC 138 11"},
+ {vsn, "2.0"},
+ {modules, [{m, 1}]},
+ {registered, []},
+ {applications, [kernel, stdlib]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.appup b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.appup
new file mode 100644
index 0000000000..3a34db78c1
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/ebin/many_mods.appup
@@ -0,0 +1,24 @@
+%% -*- erlang -*-
+{"2.0",
+ [{"1.0",[{update,m},
+ {delete_module,m1},
+ {delete_module,m2},
+ {delete_module,m3},
+ {delete_module,m4},
+ {delete_module,m5},
+ {delete_module,m6},
+ {delete_module,m7},
+ {delete_module,m8},
+ {delete_module,m9},
+ {delete_module,m10}]}],
+ [{"1.0",[{update,m},
+ {add_module,m1},
+ {add_module,m2},
+ {add_module,m3},
+ {add_module,m4},
+ {add_module,m5},
+ {add_module,m6},
+ {add_module,m7},
+ {add_module,m8},
+ {add_module,m9},
+ {add_module,m10}]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/src/m.erl b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/src/m.erl
new file mode 100644
index 0000000000..2edc1e6be4
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/many_mods-2.0/src/m.erl
@@ -0,0 +1,11 @@
+-module(m).
+-compile(export_all).
+
+start(NProcs) ->
+ Modules = [],
+ Pids = [spawn_link(fun() ->
+ Cs = [M:bar() || M <- Modules],
+ receive stop -> Cs end
+ end) ||
+ _ <- lists:seq(1,NProcs)],
+ {Modules,Pids}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/ebin/dummy.app b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/ebin/dummy.app
new file mode 100644
index 0000000000..9efdc2e5da
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/ebin/dummy.app
@@ -0,0 +1,7 @@
+{application,dummy,
+ [{description,"a dummy app"},
+ {vsn,"0.1"},
+ {registered,[dummy_app]},
+ {mod,{dummy_app,[]}},
+ {applications,[kernel,stdlib,sasl]},
+ {modules,[dummy_app,dummy_server,dummy_sup,dummy_sup_2]}]}. \ No newline at end of file
diff --git a/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_app.erl b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_app.erl
new file mode 100644
index 0000000000..51363b3630
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_app.erl
@@ -0,0 +1,9 @@
+-module(dummy_app).
+-behaviour(application).
+
+-export([start/2, stop/1]).
+
+start(_,_) ->
+ dummy_sup:start_link().
+
+stop(_) -> ok.
diff --git a/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_server.erl b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_server.erl
new file mode 100644
index 0000000000..382251eba7
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_server.erl
@@ -0,0 +1,56 @@
+-module(dummy_server).
+-behaviour(gen_server).
+
+-export([start_link/0, set_state/1, get_state/0]).
+
+-export([init/1,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ terminate/2,
+ code_change/3]).
+
+%%
+
+start_link() ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+
+set_state(What) ->
+ gen_server:call(?MODULE, {set_state, What}).
+
+get_state() ->
+ gen_server:call(?MODULE, get_state).
+
+
+%%
+
+init([]) ->
+ say("init, setting state to 0", []),
+ {ok, 0}.
+
+
+handle_call({set_state, NewState}, _From, _State) ->
+ {reply, {ok, NewState}, NewState};
+
+handle_call(get_state, _From, State) ->
+ {reply, State, State}.
+
+handle_cast('__not_implemented', State) ->
+ {noreply, State}.
+
+handle_info(_Info, State) ->
+ say("info ~p, ~p.", [_Info, State]),
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ say("terminate ~p, ~p", [_Reason, _State]),
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ say("code_change ~p, ~p, ~p", [_OldVsn, State, _Extra]),
+ {ok, State}.
+
+%% Internal
+
+say(Format, Data) ->
+ io:format("~p:~p: ~s~n", [?MODULE, self(), io_lib:format(Format, Data)]).
diff --git a/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_sup.erl b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_sup.erl
new file mode 100644
index 0000000000..3d7b5060df
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_sup.erl
@@ -0,0 +1,15 @@
+-module(dummy_sup).
+-behaviour(supervisor).
+
+-export([start_link/0]).
+-export([init/1]).
+
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+init([]) ->
+ DummySup2 = {dummy_sup_2,
+ {dummy_sup_2, start_link, []},
+ permanent, 5000, supervisor, [dummy_sup_2]},
+
+ {ok, {{one_for_one, 10, 10}, [DummySup2]}}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_sup_2.erl b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_sup_2.erl
new file mode 100644
index 0000000000..d936cbcbd6
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/release_handler_timeouts/dummy-0.1/src/dummy_sup_2.erl
@@ -0,0 +1,15 @@
+-module(dummy_sup_2).
+-behaviour(supervisor).
+
+-export([start_link/0]).
+-export([init/1]).
+
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+init([]) ->
+ Dummy = {dummy_server,
+ {dummy_server, start_link, []},
+ permanent, 5000, worker, [dummy_server]},
+
+ {ok, {{one_for_one, 10, 10}, [Dummy]}}.
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
index 9190b111ef..e352247d44 100644
--- a/lib/sasl/test/systools_SUITE.erl
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -48,7 +48,7 @@
included_fail_script/1, included_bug_script/1, exref_script/1]).
-export([ tar_options/1, normal_tar/1, no_mod_vsn_tar/1, variable_tar/1,
src_tests_tar/1, shadow_tar/1, var_tar/1,
- exref_tar/1, link_tar/1]).
+ exref_tar/1, link_tar/1, otp_9507/1]).
-export([ normal_relup/1, abnormal_relup/1, no_appup_relup/1,
bad_appup_relup/1, app_start_type_relup/1, otp_3065/1]).
-export([
@@ -81,7 +81,7 @@ groups() ->
{tar, [],
[tar_options, normal_tar, no_mod_vsn_tar, variable_tar,
src_tests_tar, shadow_tar, var_tar,
- exref_tar, link_tar]},
+ exref_tar, link_tar, otp_9507]},
{relup, [],
[normal_relup, abnormal_relup, no_appup_relup,
bad_appup_relup, app_start_type_relup]},
@@ -396,6 +396,7 @@ src_tests_script(Config) when is_list(Config) ->
?line PSAVE = code:get_path(), % Save path
?line {LatestDir, LatestName} = create_script(latest,Config),
+ ?line BootFile = LatestName ++ ".boot",
?line DataDir = filename:absname(?copydir),
?line LibDir = fname([DataDir, d_missing_src, lib]),
@@ -416,14 +417,32 @@ src_tests_script(Config) when is_list(Config) ->
?line Erl2 = filename:join([P1,"..","src","db2.erl"]),
?line file:delete(Erl2),
- %% Then make script - two warnings should be issued when
- %% src_tests is given
+ %% Then make script
+
+ %% .boot file should not exist
+ ?line ok = file:delete(BootFile),
+ ?line false = filelib:is_regular(BootFile),
+ %% With warnings_as_errors and src_tests option, an error should be issued
+ ?line error =
+ systools:make_script(LatestName, [silent, {path, N}, src_tests,
+ warnings_as_errors]),
+ ?line error =
+ systools:make_script(LatestName, [{path, N}, src_tests,
+ warnings_as_errors]),
+
+ %% due to warnings_as_errors .boot file should still not exist
+ ?line false = filelib:is_regular(BootFile),
+
+ %% Two warnings should be issued when src_tests is given
%% 1. old object code for db1.beam
%% 2. missing source code for db2.beam
?line {ok, _, [{warning,{obj_out_of_date,_}},
{warning,{source_not_found,_}}]} =
systools:make_script(LatestName, [silent, {path, N}, src_tests]),
+ %% .boot file should exist now
+ ?line true = filelib:is_regular(BootFile),
+
%% Without the src_tests option, no warning should be issued
?line {ok, _, []} =
systools:make_script(LatestName, [silent, {path, N}]),
@@ -1066,6 +1085,48 @@ exref_tar(Config) when is_list(Config) ->
?line ok = file:set_cwd(OldDir),
ok.
+
+
+%% otp_9507
+%%
+otp_9507(suite) -> [];
+otp_9507(doc) ->
+ ["make_tar failed when path given as just 'ebin'."];
+otp_9507(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {LatestDir, LatestName} = create_script(latest_small,Config),
+
+ ?line DataDir = filename:absname(?copydir),
+ ?line LibDir = fname([DataDir, d_normal, lib]),
+ ?line FeDir = fname([LibDir, 'fe-3.1']),
+
+ ?line ok = file:set_cwd(FeDir),
+
+ RelName = fname([LatestDir,LatestName]),
+
+ ?line P1 = ["./ebin",
+ fname([DataDir, lib, kernel, ebin]),
+ fname([DataDir, lib, stdlib, ebin])],
+ ?line {ok, _, _} = systools:make_script(RelName, [silent, {path, P1}]),
+ ?line ok = systools:make_tar(RelName, [{path, P1}]),
+ ?line Content1 = tar_contents(RelName),
+
+ ?line P2 = ["ebin",
+ fname([DataDir, lib, kernel, ebin]),
+ fname([DataDir, lib, stdlib, ebin])],
+
+ %% Tickets solves the following line - it used to fail with
+ %% {function_clause,[{filename,join,[[]]},...}
+ ?line ok = systools:make_tar(RelName, [{path, P2}]),
+ ?line Content2 = tar_contents(RelName),
+ true = (Content1 == Content2),
+
+ ?line ok = file:set_cwd(OldDir),
+
+ ok.
+
+
%% The relup stuff.
%%
%%
@@ -1108,6 +1169,21 @@ normal_relup(Config) when is_list(Config) ->
[{path, P}, silent]),
?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]),
+ %% file should not be written if warnings_as_errors is enabled.
+ %% delete before running tests.
+ ?line ok = file:delete("relup"),
+
+ %% Check that warnings are treated as errors
+ ?line error =
+ systools:make_relup(LatestName, [LatestName2], [LatestName1],
+ [{path, P}, warnings_as_errors]),
+ ?line error =
+ systools:make_relup(LatestName, [LatestName2], [LatestName1],
+ [{path, P}, silent, warnings_as_errors]),
+
+ %% relup file should not exist
+ ?line false = filelib:is_regular("relup"),
+
%% Check that warnings get through
?line ok = systools:make_relup(LatestName, [LatestName2], [LatestName1],
[{path, P}]),
@@ -1117,6 +1193,9 @@ normal_relup(Config) when is_list(Config) ->
[{path, P}, silent]),
?line ok = check_relup([{fe, "3.1"}, {db, "2.1"}], [{db, "1.0"}]),
+ %% relup file should exist now
+ ?line true = filelib:is_regular("relup"),
+
?line ok = file:set_cwd(OldDir),
ok.
diff --git a/lib/snmp/test/snmp_compiler_test.erl b/lib/snmp/test/snmp_compiler_test.erl
index cee11ba97a..c964b08168 100644
--- a/lib/snmp/test/snmp_compiler_test.erl
+++ b/lib/snmp/test/snmp_compiler_test.erl
@@ -47,7 +47,7 @@
module_identity/1,
agent_capabilities/1,
module_compliance/1,
- warnings_as_errors/1,
+ warnings_as_errors/1,
otp_6150/1,
otp_8574/1,
@@ -101,7 +101,7 @@ all() ->
module_identity,
agent_capabilities,
module_compliance,
- warnings_as_errors,
+ warnings_as_errors,
{group, tickets}
].
@@ -282,8 +282,8 @@ warnings_as_errors(Config) when is_list(Config) ->
MibDir = ?config(mib_dir, Config),
MibFile = join(MibDir, "OTP8574-MIB.mib"),
OutFile = join(Dir, "OTP8574-MIB.bin"),
- Opts = [{group_check, false},
- {outdir, Dir},
+ Opts = [{group_check, false},
+ {outdir, Dir},
{verbosity, trace},
relaxed_row_name_assign_check],
{error, compilation_failed} =
@@ -291,6 +291,7 @@ warnings_as_errors(Config) when is_list(Config) ->
false = filelib:is_regular(OutFile),
{ok, _} = snmpc:compile(MibFile, Opts),
true = filelib:is_regular(OutFile),
+ ok = file:delete(OutFile),
ok.
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 74900936a3..d1ec0c141e 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -99,11 +99,11 @@ stop() ->
application:stop(ssl).
%%--------------------------------------------------------------------
--spec connect(host() | inet:port_num(), [connect_option()]) -> {ok, #sslsocket{}} |
+-spec connect(host() | port(), [connect_option()]) -> {ok, #sslsocket{}} |
{error, reason()}.
--spec connect(host() | inet:port_num(), [connect_option()] | inet:port_num(), timeout() | list()) ->
+-spec connect(host() | port(), [connect_option()] | inet:port_number(), timeout() | list()) ->
{ok, #sslsocket{}} | {error, reason()}.
--spec connect(host() | inet:port_num(), inet:port_num(), list(), timeout()) ->
+-spec connect(host() | port(), inet:port_number(), list(), timeout()) ->
{ok, #sslsocket{}} | {error, reason()}.
%%
@@ -151,7 +151,7 @@ connect(Host, Port, Options0, Timeout) ->
end.
%%--------------------------------------------------------------------
--spec listen(inet:port_num(), [listen_option()]) ->{ok, #sslsocket{}} | {error, reason()}.
+-spec listen(inet:port_number(), [listen_option()]) ->{ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Creates an ssl listen socket.
@@ -376,7 +376,7 @@ select_part(plain, Cert, Opts) ->
end.
%%--------------------------------------------------------------------
--spec peername(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_num()}} | {error, reason()}.
+-spec peername(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
%%
%% Description: same as inet:peername/1.
%%--------------------------------------------------------------------
@@ -470,7 +470,7 @@ shutdown(#sslsocket{pid = Pid, fd = new_ssl}, How) ->
ssl_connection:shutdown(Pid, How).
%%--------------------------------------------------------------------
--spec sockname(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_num()}} | {error, reason()}.
+-spec sockname(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
%%
%% Description: Same as inet:sockname/1
%%--------------------------------------------------------------------
@@ -1007,7 +1007,7 @@ version() ->
%% Only used to remove exit messages from old ssl
%% First is a nonsense clause to provide some
-%% backward compability for orber that uses this
+%% backward compatibility for orber that uses this
%% function in a none recommended way, but will
%% work correctly if a valid pid is returned.
pid(#sslsocket{fd = new_ssl}) ->
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 0ae39689cc..cec81d551b 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -127,7 +127,7 @@ send(Pid, Data) ->
recv(Pid, Length, Timeout) ->
sync_send_all_state_event(Pid, {recv, Length}, Timeout).
%%--------------------------------------------------------------------
--spec connect(host(), inet:port_num(), port(), {#ssl_options{}, #socket_options{}},
+-spec connect(host(), inet:port_number(), port(), {#ssl_options{}, #socket_options{}},
pid(), tuple(), timeout()) ->
{ok, #sslsocket{}} | {error, reason()}.
%%
@@ -141,7 +141,7 @@ connect(Host, Port, Socket, Options, User, CbInfo, Timeout) ->
{error, ssl_not_started}
end.
%%--------------------------------------------------------------------
--spec ssl_accept(inet:port_num(), port(), {#ssl_options{}, #socket_options{}},
+-spec ssl_accept(inet:port_number(), port(), {#ssl_options{}, #socket_options{}},
pid(), tuple(), timeout()) ->
{ok, #sslsocket{}} | {error, reason()}.
%%
@@ -212,14 +212,14 @@ shutdown(ConnectionPid, How) ->
new_user(ConnectionPid, User) ->
sync_send_all_state_event(ConnectionPid, {new_user, User}).
%%--------------------------------------------------------------------
--spec sockname(pid()) -> {ok, {inet:ip_adress(), inet:port_num()}} | {error, reason()}.
+-spec sockname(pid()) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
%%
%% Description: Same as inet:sockname/1
%%--------------------------------------------------------------------
sockname(ConnectionPid) ->
sync_send_all_state_event(ConnectionPid, sockname).
%%--------------------------------------------------------------------
--spec peername(pid()) -> {ok, {inet:ip_adress(), inet:port_num()}} | {error, reason()}.
+-spec peername(pid()) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
%%
%% Description: Same as inet:peername/1
%%--------------------------------------------------------------------
@@ -277,7 +277,7 @@ renegotiation(ConnectionPid) ->
%%====================================================================
%%--------------------------------------------------------------------
--spec start_link(atom(), host(), inet:port_num(), port(), list(), pid(), tuple()) ->
+-spec start_link(atom(), host(), inet:port_number(), port(), list(), pid(), tuple()) ->
{ok, pid()} | ignore | {error, reason()}.
%%
%% Description: Creates a gen_fsm process which calls Module:init/1 to
@@ -1778,7 +1778,8 @@ format_reply(binary, _, N, Data) when N > 0 -> % Header mode
format_reply(binary, _, _, Data) ->
Data;
format_reply(list, Packet, _, Data)
- when Packet == http; Packet == {http, headers}; Packet == http_bin; Packet == {http_bin, headers} ->
+ when Packet == http; Packet == {http, headers}; Packet == http_bin; Packet == {http_bin, headers}; Packet == httph;
+ Packet == httph_bin->
Data;
format_reply(list, _,_, Data) ->
binary_to_list(Data).
@@ -2090,7 +2091,9 @@ set_socket_opts(Socket, [{packet, Packet}| Opts], SockOpts, Other) when Packet =
Packet == tpkt;
Packet == line;
Packet == http;
- Packet == http_bin ->
+ Packet == httph;
+ Packet == http_bin;
+ Packet == httph_bin ->
set_socket_opts(Socket, Opts,
SockOpts#socket_options{packet = Packet}, Other);
set_socket_opts(_, [{packet, _} = Opt| _], SockOpts, _) ->
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 2dfa1741c5..453ea20f99 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -48,7 +48,7 @@
%% Internal application API
%%====================================================================
%%--------------------------------------------------------------------
--spec client_hello(host(), inet:port_num(), #connection_states{},
+-spec client_hello(host(), inet:port_number(), #connection_states{},
#ssl_options{}, boolean(), der_cert()) -> #client_hello{}.
%%
%% Description: Creates a client hello message.
@@ -106,7 +106,7 @@ hello_request() ->
%%--------------------------------------------------------------------
-spec hello(#server_hello{} | #client_hello{}, #ssl_options{},
- #connection_states{} | {inet:port_num(), #session{}, db_handle(),
+ #connection_states{} | {inet:port_number(), #session{}, db_handle(),
atom(), #connection_states{}, binary()},
boolean()) -> {tls_version(), session_id(), #connection_states{}}|
{tls_version(), {resumed | new, #session{}},
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index 56c43a16d1..725a085d1f 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -113,7 +113,7 @@ lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) ->
issuer_candidate(PrevCandidateKey, DbHandle) ->
ssl_certificate_db:issuer_candidate(PrevCandidateKey, DbHandle).
%%--------------------------------------------------------------------
--spec client_session_id(host(), inet:port_num(), #ssl_options{},
+-spec client_session_id(host(), inet:port_number(), #ssl_options{},
der_cert() | undefined) -> session_id().
%%
%% Description: Select a session id for the client.
@@ -122,7 +122,7 @@ client_session_id(Host, Port, SslOpts, OwnCert) ->
call({client_session_id, Host, Port, SslOpts, OwnCert}).
%%--------------------------------------------------------------------
--spec server_session_id(host(), inet:port_num(), #ssl_options{},
+-spec server_session_id(host(), inet:port_number(), #ssl_options{},
der_cert()) -> session_id().
%%
%% Description: Select a session id for the server.
@@ -131,8 +131,8 @@ server_session_id(Port, SuggestedSessionId, SslOpts, OwnCert) ->
call({server_session_id, Port, SuggestedSessionId, SslOpts, OwnCert}).
%%--------------------------------------------------------------------
--spec register_session(inet:port_num(), #session{}) -> ok.
--spec register_session(host(), inet:port_num(), #session{}) -> ok.
+-spec register_session(inet:port_number(), #session{}) -> ok.
+-spec register_session(host(), inet:port_number(), #session{}) -> ok.
%%
%% Description: Make the session available for reuse.
%%--------------------------------------------------------------------
@@ -142,8 +142,8 @@ register_session(Host, Port, Session) ->
register_session(Port, Session) ->
cast({register_session, Port, Session}).
%%--------------------------------------------------------------------
--spec invalidate_session(inet:port_num(), #session{}) -> ok.
--spec invalidate_session(host(), inet:port_num(), #session{}) -> ok.
+-spec invalidate_session(inet:port_number(), #session{}) -> ok.
+-spec invalidate_session(host(), inet:port_number(), #session{}) -> ok.
%%
%% Description: Make the session unavailable for reuse. After
%% a the session has been marked "is_resumable = false" for some while
diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl
index a0643f616c..bf738649f6 100644
--- a/lib/ssl/src/ssl_session.erl
+++ b/lib/ssl/src/ssl_session.erl
@@ -48,7 +48,7 @@ is_new(_ClientSuggestion, _ServerDecision) ->
true.
%%--------------------------------------------------------------------
--spec id({host(), inet:port_num(), #ssl_options{}}, db_handle(), atom(),
+-spec id({host(), inet:port_number(), #ssl_options{}}, db_handle(), atom(),
undefined | binary()) -> binary().
%%
%% Description: Should be called by the client side to get an id
@@ -63,7 +63,7 @@ id(ClientInfo, Cache, CacheCb, OwnCert) ->
end.
%%--------------------------------------------------------------------
--spec id(inet:port_num(), binary(), #ssl_options{}, db_handle(),
+-spec id(inet:port_number(), binary(), #ssl_options{}, db_handle(),
atom(), seconds(), binary()) -> binary().
%%
%% Description: Should be called by the server side to get an id
diff --git a/lib/ssl/src/ssl_session_cache.erl b/lib/ssl/src/ssl_session_cache.erl
index d026bf179e..93969f628f 100644
--- a/lib/ssl/src/ssl_session_cache.erl
+++ b/lib/ssl/src/ssl_session_cache.erl
@@ -28,7 +28,7 @@
-export([init/1, terminate/1, lookup/2, update/3, delete/2, foldl/3,
select_session/2]).
--type key() :: {{host(), inet:port_num()}, session_id()} | {inet:port_num(), session_id()}.
+-type key() :: {{host(), inet:port_number()}, session_id()} | {inet:port_number(), session_id()}.
%%--------------------------------------------------------------------
-spec init(list()) -> db_handle(). %% Returns reference to the cache (opaque)
@@ -91,7 +91,7 @@ foldl(Fun, Acc0, Cache) ->
ets:foldl(Fun, Acc0, Cache).
%%--------------------------------------------------------------------
--spec select_session(db_handle(), {host(), inet:port_num()} | inet:port_num()) -> [#session{}].
+-spec select_session(db_handle(), {host(), inet:port_number()} | inet:port_number()) -> [#session{}].
%%
%% Description: Selects a session that could be reused. Should be callable
%% from any process.
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 37a021e7cf..8da1d947d3 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -253,7 +253,7 @@ all() ->
unknown_server_ca_fail, der_input,
unknown_server_ca_accept_verify_none,
unknown_server_ca_accept_verify_peer,
- unknown_server_ca_accept_backwardscompatibilty,
+ unknown_server_ca_accept_backwardscompatibility,
%%different_ca_peer_sign,
no_reuses_session_server_restart_new_cert,
no_reuses_session_server_restart_new_cert_file, reuseaddr,
@@ -3282,11 +3282,11 @@ unknown_server_ca_accept_verify_peer(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
-unknown_server_ca_accept_backwardscompatibilty(doc) ->
+unknown_server_ca_accept_backwardscompatibility(doc) ->
["Test that old style verify_funs will work"];
-unknown_server_ca_accept_backwardscompatibilty(suite) ->
+unknown_server_ca_accept_backwardscompatibility(suite) ->
[];
-unknown_server_ca_accept_backwardscompatibilty(Config) when is_list(Config) ->
+unknown_server_ca_accept_backwardscompatibility(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index d22d5d2954..9d2599b778 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -151,6 +151,9 @@ all() ->
packet_cdr_decode, packet_cdr_decode_list,
packet_http_decode, packet_http_decode_list,
packet_http_bin_decode_multi, packet_http_error_passive,
+ packet_httph_active, packet_httph_bin_active,
+ packet_httph_active_once, packet_httph_bin_active_once,
+ packet_httph_passive, packet_httph_bin_passive,
packet_line_decode, packet_line_decode_list,
packet_asn1_decode, packet_asn1_decode_list,
packet_tpkt_decode, packet_tpkt_decode_list,
@@ -1594,7 +1597,7 @@ client_http_decode(Socket, HttpRequest) ->
%%--------------------------------------------------------------------
packet_http_decode_list(doc) ->
["Test setting the packet option {packet, http}, {mode, list}"
- "(Body will be litst too)"];
+ "(Body will be list too)"];
packet_http_decode_list(suite) ->
[];
packet_http_decode_list(Config) when is_list(Config) ->
@@ -1804,7 +1807,304 @@ server_http_decode_error(Socket, HttpResponse) ->
assert_packet_opt(Socket, http),
ok = ssl:send(Socket, HttpResponse),
ok.
+%%--------------------------------------------------------------------
+packet_httph_active(doc) ->
+ ["Test setting the packet option {packet, httph}"];
+packet_httph_active(suite) ->
+ [];
+packet_httph_active(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Trailer = "Content-Encoding: gzip\r\n"
+ "\r\n",
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, server_send_trailer,
+ [Trailer]}},
+ {options, [{active, true}, binary |
+ ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, client_http_decode_trailer_active,
+ []}},
+ {options, [{active, true},
+ {packet, httph},
+ list |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+server_send_trailer(Socket, Trailer)->
+ ssl:send(Socket, Trailer),
+ ok.
+
+client_http_decode_trailer_active(Socket) ->
+ receive
+ {ssl, Socket,
+ {http_header,36,'Content-Encoding',undefined,"gzip"}} ->
+ ok;
+ Other1 ->
+ exit({?LINE, Other1})
+ end,
+ receive
+ {ssl, Socket, http_eoh} ->
+ ok;
+ Other2 ->
+ exit({?LINE, Other2})
+ end,
+ ok.
+
+%%--------------------------------------------------------------------
+packet_httph_bin_active(doc) ->
+ ["Test setting the packet option {packet, httph_bin}"];
+packet_httph_bin_active(suite) ->
+ [];
+packet_httph_bin_active(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Trailer = "Content-Encoding: gzip\r\n"
+ "\r\n",
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, server_send_trailer,
+ [Trailer]}},
+ {options, [{active, true}, binary |
+ ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, client_http_decode_trailer_bin_active,
+ []}},
+ {options, [{active, true},
+ {packet, httph_bin},
+ list |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+client_http_decode_trailer_bin_active(Socket) ->
+ receive
+ {ssl, Socket,
+ {http_header,36,'Content-Encoding',undefined, <<"gzip">>}} ->
+ ok;
+ Other1 ->
+ exit({?LINE, Other1})
+ end,
+ receive
+ {ssl, Socket, http_eoh} ->
+ ok;
+ Other2 ->
+ exit({?LINE, Other2})
+ end,
+ ok.
+%%--------------------------------------------------------------------
+packet_httph_active_once(doc) ->
+ ["Test setting the packet option {packet, httph}"];
+packet_httph_active_once(suite) ->
+ [];
+packet_httph_active_once(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Trailer = "Content-Encoding: gzip\r\n"
+ "\r\n",
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, server_send_trailer,
+ [Trailer]}},
+ {options, [{active, true}, binary |
+ ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, client_http_decode_trailer_active_once,
+ []}},
+ {options, [{active, false},
+ {packet, httph},
+ list |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
+client_http_decode_trailer_active_once(Socket) ->
+ ssl:setopts(Socket, [{active, once}]),
+ receive
+ {ssl, Socket,
+ {http_header,36,'Content-Encoding',undefined,"gzip"}} ->
+ ok;
+ Other1 ->
+ exit({?LINE, Other1})
+ end,
+ ssl:setopts(Socket, [{active, once}]),
+ receive
+ {ssl, Socket, http_eoh} ->
+ ok;
+ Other2 ->
+ exit({?LINE, Other2})
+ end,
+ ok.
+%%--------------------------------------------------------------------
+packet_httph_bin_active_once(doc) ->
+ ["Test setting the packet option {packet, httph_bin}"];
+packet_httph_bin_active_once(suite) ->
+ [];
+packet_httph_bin_active_once(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Trailer = "Content-Encoding: gzip\r\n"
+ "\r\n",
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, server_send_trailer,
+ [Trailer]}},
+ {options, [{active, true}, binary |
+ ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, client_http_decode_trailer_bin_active_once,
+ []}},
+ {options, [{active, false},
+ {packet, httph_bin},
+ list |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+client_http_decode_trailer_bin_active_once(Socket) ->
+ ssl:setopts(Socket, [{active, once}]),
+ receive
+ {ssl, Socket,
+ {http_header,36,'Content-Encoding',undefined, <<"gzip">>}} ->
+ ok;
+ Other1 ->
+ exit({?LINE, Other1})
+ end,
+ ssl:setopts(Socket, [{active, once}]),
+ receive
+ {ssl, Socket, http_eoh} ->
+ ok;
+ Other2 ->
+ exit({?LINE, Other2})
+ end,
+ ok.
+
+%%--------------------------------------------------------------------
+
+packet_httph_passive(doc) ->
+ ["Test setting the packet option {packet, httph}"];
+packet_httph_passive(suite) ->
+ [];
+packet_httph_passive(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Trailer = "Content-Encoding: gzip\r\n"
+ "\r\n",
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, server_send_trailer,
+ [Trailer]}},
+ {options, [{active, true}, binary |
+ ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, client_http_decode_trailer_passive,
+ []}},
+ {options, [{active, false},
+ {packet, httph},
+ list |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+client_http_decode_trailer_passive(Socket) ->
+ {ok,{http_header,36,'Content-Encoding',undefined,"gzip"}} = ssl:recv(Socket, 0),
+ {ok, http_eoh} = ssl:recv(Socket, 0),
+ ok.
+
+%%--------------------------------------------------------------------
+packet_httph_bin_passive(doc) ->
+ ["Test setting the packet option {packet, httph_bin}"];
+packet_httph_bin_passive(suite) ->
+ [];
+packet_httph_bin_passive(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Trailer = "Content-Encoding: gzip\r\n"
+ "\r\n",
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, server_send_trailer,
+ [Trailer]}},
+ {options, [{active, true}, binary |
+ ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, client_http_decode_trailer_bin_passive,
+ []}},
+ {options, [{active, false},
+ {packet, httph_bin},
+ list |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+client_http_decode_trailer_bin_passive(Socket) ->
+ {ok,{http_header,36,'Content-Encoding',undefined,<<"gzip">>}} = ssl:recv(Socket, 0),
+ {ok, http_eoh} = ssl:recv(Socket, 0),
+ ok.
%%--------------------------------------------------------------------
packet_line_decode(doc) ->
diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml
index 8c952708c5..f19f92be6f 100644
--- a/lib/stdlib/doc/src/ets.xml
+++ b/lib/stdlib/doc/src/ets.xml
@@ -513,6 +513,9 @@ Error: fun containing local Erlang function calls
the table has been fixed by the process.</p>
<p>If the table never has been fixed, the call returns
<c>false</c>.</p>
+ <item><c>Item=stats, Value=tuple()</c> <br></br>
+ Returns internal statistics about set, bag and duplicate_bag tables on an internal format used by OTP test suites.
+ Not for production use.</item>
</item>
</list>
</desc>
diff --git a/lib/stdlib/src/dets_v8.erl b/lib/stdlib/src/dets_v8.erl
index af36958c1c..299b037c28 100644
--- a/lib/stdlib/src/dets_v8.erl
+++ b/lib/stdlib/src/dets_v8.erl
@@ -163,7 +163,7 @@
%% The 8(c) version uses a different hashing algorithm, erlang:phash
%% (former versions use erlang:hash).
%% Version 8(b) files are only converted to version 8(c) if repair is
-%% done, so we need compatability with 8(b) for a _long_ time.
+%% done, so we need compatibility with 8(b) for a _long_ time.
%%
%% There are known bugs due to the fact that keys and objects are
%% sometimes compared (==) and sometimes matched (=:=). The version
diff --git a/lib/stdlib/src/erl_compile.erl b/lib/stdlib/src/erl_compile.erl
index abff37e4bc..d833f626bf 100644
--- a/lib/stdlib/src/erl_compile.erl
+++ b/lib/stdlib/src/erl_compile.erl
@@ -41,7 +41,6 @@ compiler(".idl") -> {ic, compile};
compiler(".asn1") -> {asn1ct, compile_asn1};
compiler(".asn") -> {asn1ct, compile_asn};
compiler(".py") -> {asn1ct, compile_py};
-compiler(".xml") -> {xmerl_scan, process};
compiler(_) -> no.
%% Entry from command line.
diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl
index eada563914..20fd247cea 100644
--- a/lib/stdlib/src/erl_expand_records.erl
+++ b/lib/stdlib/src/erl_expand_records.erl
@@ -35,7 +35,7 @@
trecords=sets:new(), % Typed records
uses_types=false, % Are there -spec or -type in the module
strict_ra=[], % strict record accesses
- checked_ra=[] % succesfully accessed records
+ checked_ra=[] % successfully accessed records
}).
-spec(module(AbsForms, CompileOptions) -> AbsForms when
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 9341300f90..57df963ae2 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -819,6 +819,14 @@ t_delete_all_objects(Config) when is_list(Config) ->
repeat_for_opts(t_delete_all_objects_do),
?line verify_etsmem(EtsMem).
+get_kept_objects(T) ->
+ case ets:info(T,stats) of
+ false ->
+ 0;
+ {_,_,_,_,_,_,KO} ->
+ KO
+ end.
+
t_delete_all_objects_do(Opts) ->
?line T=ets_new(x,Opts),
?line filltabint(T,4000),
@@ -828,10 +836,10 @@ t_delete_all_objects_do(Opts) ->
?line true = ets:delete_all_objects(T),
?line '$end_of_table' = ets:next(T,O),
?line 0 = ets:info(T,size),
- ?line 4000 = ets:info(T,kept_objects),
+ ?line 4000 = get_kept_objects(T),
?line ets:safe_fixtable(T,false),
?line 0 = ets:info(T,size),
- ?line 0 = ets:info(T,kept_objects),
+ ?line 0 = get_kept_objects(T),
?line filltabint(T,4000),
?line 4000 = ets:info(T,size),
?line true = ets:delete_all_objects(T),
@@ -861,10 +869,10 @@ t_delete_object_do(Opts) ->
?line ets:delete_object(T,{First, integer_to_list(First)}),
?line Next = ets:next(T,First),
?line 3999 = ets:info(T,size),
- ?line 1 = ets:info(T,kept_objects),
+ ?line 1 = get_kept_objects(T),
?line ets:safe_fixtable(T,false),
?line 3999 = ets:info(T,size),
- ?line 0 = ets:info(T,kept_objects),
+ ?line 0 = get_kept_objects(T),
?line ets:delete(T),
?line T1 = ets_new(x,[ordered_set | Opts]),
?line filltabint(T1,4000),
@@ -2717,7 +2725,8 @@ ordered_do(Opts) ->
9,10,11,12,
1,2,3,4,
17,18,19,20,
- 13,14,15,16
+ 13,14,15,16,
+ 1 bsl 33
],
?line lists:foreach(fun(X) ->
ets:insert(T,{X,integer_to_list(X)})
@@ -2732,13 +2741,14 @@ ordered_do(Opts) ->
?line S2 = L2,
?line [{1,"1"}] = ets:slot(T,0),
?line [{28,"28"}] = ets:slot(T,27),
+ ?line [{1 bsl 33,_}] = ets:slot(T,28),
?line 27 = ets:prev(T,28),
?line [{7,"7"}] = ets:slot(T,6),
- ?line '$end_of_table' = ets:next(T,28),
+ ?line '$end_of_table' = ets:next(T,1 bsl 33),
?line [{12,"12"}] = ets:slot(T,11),
- ?line '$end_of_table' = ets:slot(T,28),
+ ?line '$end_of_table' = ets:slot(T,29),
?line [{1,"1"}] = ets:slot(T,0),
- ?line 28 = ets:prev(T,29),
+ ?line 28 = ets:prev(T,1 bsl 33),
?line 1 = ets:next(T,0),
?line pick_all_forward(T),
?line [{7,"7"}] = ets:slot(T,6),
@@ -4969,7 +4979,7 @@ grow_pseudo_deleted_do(Type) ->
[true]}]),
Left = Mult*(Mod-1),
?line Left = ets:info(T,size),
- ?line Mult = ets:info(T,kept_objects),
+ ?line Mult = get_kept_objects(T),
filltabstr(T,Mult),
spawn_opt(fun()-> ?line true = ets:info(T,fixed),
Self ! start,
@@ -4983,7 +4993,7 @@ grow_pseudo_deleted_do(Type) ->
?line true = ets:safe_fixtable(T,false),
io:format("Unfix table done. ~p nitems=~p\n",[now(),ets:info(T,size)]),
?line false = ets:info(T,fixed),
- ?line 0 = ets:info(T,kept_objects),
+ ?line 0 = get_kept_objects(T),
?line done = receive_any(),
%%verify_table_load(T), % may fail if concurrency is poor (genny)
ets:delete(T),
@@ -5010,7 +5020,7 @@ shrink_pseudo_deleted_do(Type) ->
[{'>', '$1', Half}],
[true]}]),
?line Half = ets:info(T,size),
- ?line Half = ets:info(T,kept_objects),
+ ?line Half = get_kept_objects(T),
spawn_opt(fun()-> ?line true = ets:info(T,fixed),
Self ! start,
io:format("Starting to delete... ~p\n",[now()]),
@@ -5023,7 +5033,7 @@ shrink_pseudo_deleted_do(Type) ->
?line true = ets:safe_fixtable(T,false),
io:format("Unfix table done. ~p nitems=~p\n",[now(),ets:info(T,size)]),
?line false = ets:info(T,fixed),
- ?line 0 = ets:info(T,kept_objects),
+ ?line 0 = get_kept_objects(T),
?line done = receive_any(),
%%verify_table_load(T), % may fail if concurrency is poor (genny)
ets:delete(T),
@@ -5139,7 +5149,7 @@ smp_fixed_delete_do() ->
?line 0 = ets:info(T,size),
?line true = ets:info(T,fixed),
?line Buckets = num_of_buckets(T),
- ?line NumOfObjs = ets:info(T,kept_objects),
+ ?line NumOfObjs = get_kept_objects(T),
ets:safe_fixtable(T,false),
%% Will fail as unfix does not shrink the table:
%%?line Mem = ets:info(T,memory),
@@ -5171,7 +5181,7 @@ smp_unfix_fix_do() ->
Left = NumOfObjs - Deleted,
?line Left = ets:info(T,size),
?line true = ets:info(T,fixed),
- ?line Deleted = ets:info(T,kept_objects),
+ ?line Deleted = get_kept_objects(T),
{Child, Mref} =
spawn_opt(fun()-> ?line true = ets:info(T,fixed),
@@ -5188,7 +5198,7 @@ smp_unfix_fix_do() ->
end,
Deleted),
?line 0 = ets:info(T,size),
- ?line true = ets:info(T,kept_objects) >= Left,
+ ?line true = get_kept_objects(T) >= Left,
?line done = receive_any()
end,
[link, monitor, {scheduler,2}]),
@@ -5201,7 +5211,7 @@ smp_unfix_fix_do() ->
Child ! done,
{'DOWN', Mref, process, Child, normal} = receive_any(),
?line false = ets:info(T,fixed),
- ?line 0 = ets:info(T,kept_objects),
+ ?line 0 = get_kept_objects(T),
%%verify_table_load(T),
ets:delete(T),
process_flag(scheduler,0).
@@ -5239,7 +5249,7 @@ otp_8166_do(WC) ->
ZombieCrPid ! quit,
{'DOWN', ZombieCrMref, process, ZombieCrPid, normal} = receive_any(),
?line false = ets:info(T,fixed),
- ?line 0 = ets:info(T,kept_objects),
+ ?line 0 = get_kept_objects(T),
%%verify_table_load(T),
ets:delete(T),
process_flag(scheduler,0).
@@ -5306,7 +5316,7 @@ otp_8166_zombie_creator(T,Deleted) ->
verify_table_load(T) ->
?line Stats = ets:info(T,stats),
- ?line {Buckets,AvgLen,StdDev,ExpSD,_MinLen,_MaxLen} = Stats,
+ ?line {Buckets,AvgLen,StdDev,ExpSD,_MinLen,_MaxLen,_} = Stats,
?line ok = if
AvgLen > 7 ->
io:format("Table overloaded: Stats=~p\n~p\n",
@@ -5918,7 +5928,7 @@ very_big_num(0, Result) ->
?line Result.
make_port() ->
- ?line open_port({spawn, efile}, [eof]).
+ ?line open_port({spawn, "efile"}, [eof]).
make_pid() ->
?line spawn_link(?MODULE, sleeper, []).
diff --git a/lib/stdlib/test/tar_SUITE.erl b/lib/stdlib/test/tar_SUITE.erl
index 48f58cd05d..9ad3936928 100644
--- a/lib/stdlib/test/tar_SUITE.erl
+++ b/lib/stdlib/test/tar_SUITE.erl
@@ -283,17 +283,16 @@ long_names(doc) ->
long_names(Config) when is_list(Config) ->
?line DataDir = ?config(data_dir, Config),
?line Long = filename:join(DataDir, "long_names.tar"),
+ run_in_short_tempdir(Config,
+ fun() -> do_long_names(Long) end).
+do_long_names(Long) ->
%% Try table/2 and extract/2.
?line case erl_tar:table(Long, [verbose]) of
{ok,List} when is_list(List) ->
?line io:format("~p\n", [List])
end,
-
- %% To avoid getting too long paths for Windows to handle, extract into
- %% the current directory (which is the test_server directory). Its path
- %% is quite a bit shorter than the path to priv_dir.
?line {ok,Cwd} = file:get_cwd(),
?line ok = erl_tar:extract(Long),
?line Base = filename:join([Cwd, "original_software", "written_by",
@@ -312,17 +311,16 @@ long_names(Config) when is_list(Config) ->
?line "Here"++_ = binary_to_list(First),
?line "And"++_ = binary_to_list(Second),
- %% Clean up.
- ?line delete_files([filename:join(Cwd, "original_software"),EmptyDir]),
-
ok.
create_long_names(doc) ->
["Creates a tar file from a deep directory structure (filenames are ",
"longer than 100 characters)."];
create_long_names(Config) when is_list(Config) ->
- ?line PrivDir = ?config(priv_dir, Config),
- ?line ok = file:set_cwd(PrivDir),
+ run_in_short_tempdir(Config, fun create_long_names/0).
+
+create_long_names() ->
+ ?line {ok,Dir} = file:get_cwd(),
Dirs = ["aslfjkshjkhliuf",
"asdhjfehnbfsky",
"sahajfskdfhsz",
@@ -334,7 +332,7 @@ create_long_names(Config) when is_list(Config) ->
?line AFile = filename:join(DeepDir, "a_file"),
?line Hello = "hello, world\n",
?line ok = file:write_file(AFile, Hello),
- ?line TarName = filename:join(PrivDir, "my_tar_with_long_names.tar"),
+ ?line TarName = filename:join(Dir, "my_tar_with_long_names.tar"),
?line ok = erl_tar:create(TarName, [AFile]),
%% Print contents.
@@ -347,9 +345,6 @@ create_long_names(Config) when is_list(Config) ->
?line {ok, Bin} = file:read_file(filename:join(ExtractDir, AFile)),
?line Hello = binary_to_list(Bin),
- %% Clean up.
- ?line delete_files([ExtractDir,TarName,hd(Dirs)]),
-
ok.
make_dirs([Dir|Rest], []) ->
@@ -734,3 +729,42 @@ delete_files([Item|Rest]) ->
end,
delete_files(Rest).
+%% Move to a temporary directory with as short name as possible and
+%% execute Fun. Remove the directory and any files in it afterwards.
+%% This is necessary because pathnames on Windows may be limited to
+%% 260 characters.
+run_in_short_tempdir(Config, Fun) ->
+ {ok,Cwd} = file:get_cwd(),
+ PrivDir0 = ?config(priv_dir, Config),
+
+ %% Normalize name to make sure that there is no slash at the end.
+ PrivDir = filename:absname(PrivDir0),
+
+ %% We need a base directory with a much shorter pathname than
+ %% priv_dir. We KNOW that priv_dir is located four levels below
+ %% the directory that common_test puts the ct_run.* directories
+ %% in. That fact is not documented, but an usually reliable source
+ %% assured me that the directory structure is unlikely to change
+ %% in future versions of common_test because of backward
+ %% compatibility (tools developed by users of common_test depend
+ %% on the current directory layout).
+ Base = lists:foldl(fun(_, D) ->
+ filename:dirname(D)
+ end, PrivDir, [1,2,3,4]),
+
+ Dir = make_temp_dir(Base, 0),
+ ok = file:set_cwd(Dir),
+ io:format("Running test in ~s\n", [Dir]),
+ try
+ Fun()
+ after
+ file:set_cwd(Cwd),
+ delete_files([Dir])
+ end.
+
+make_temp_dir(Base, I) ->
+ Name = filename:join(Base, integer_to_list(I, 36)),
+ case file:make_dir(Name) of
+ ok -> Name;
+ {error,eexist} -> make_temp_dir(Base, I+1)
+ end.
diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl
index de9b962dfc..f3445b742b 100644
--- a/lib/test_server/src/test_server_ctrl.erl
+++ b/lib/test_server/src/test_server_ctrl.erl
@@ -4674,13 +4674,13 @@ collect_subcases(Mod, Case, MFA, St, Suite) ->
[] when Case == all -> {ok,[],St};
[] when element(1, Case) == conf -> {ok,[],St};
[] -> {ok,[MFA],St};
-%%%! --- START Kept for backwards compatibilty ---
+%%%! --- START Kept for backwards compatibility ---
%%%! Requirements are not used
{req,ReqList} ->
collect_case_deny(Mod, Case, MFA, ReqList, [], St);
{req,ReqList,SubCases} ->
collect_case_deny(Mod, Case, MFA, ReqList, SubCases, St);
-%%%! --- END Kept for backwards compatibilty ---
+%%%! --- END Kept for backwards compatibility ---
{Skip,Reason} when Skip==skip; Skip==skipped ->
{ok,[{skip_case,{MFA,Reason}}],St};
{error,Reason} ->
diff --git a/lib/test_server/src/ts.config b/lib/test_server/src/ts.config
index f021f5958b..cf3d269616 100644
--- a/lib/test_server/src/ts.config
+++ b/lib/test_server/src/ts.config
@@ -12,7 +12,7 @@
% "10.10.0.1", %IP string
% {10,10,0,1}, %IP tuple
% ["my_ip4_host"], %Any aliases
-% "::ffff:10.10.0.1", %IPv6 string (compatibilty addr)
+% "::ffff:10.10.0.1", %IPv6 string (compatibility addr)
% {0,0,0,0,0,65535,2570,1} %IPv6 tuple
% }}.
diff --git a/lib/toolbar/src/toolbar_toolconfig.erl b/lib/toolbar/src/toolbar_toolconfig.erl
index 7d8f2b4d21..693a7b4570 100644
--- a/lib/toolbar/src/toolbar_toolconfig.erl
+++ b/lib/toolbar/src/toolbar_toolconfig.erl
@@ -126,7 +126,7 @@ loop(S,Window) ->
show_info(Window,Info),
move_focus(Window,file);
- %% Erronous version number -- Notify user
+ %% Erroneous version number -- Notify user
{error,version} ->
Win = Window#tfwindow.window,
tool_utils:notify(Win,[FileName,
@@ -136,7 +136,7 @@ loop(S,Window) ->
_Error ->
Win = Window#tfwindow.window,
tool_utils:notify(Win,[FileName,
- "File is on erronous format"])
+ "File is in erroneous format"])
end;
%% The file can not be read, show default values
diff --git a/lib/tools/doc/src/instrument.xml b/lib/tools/doc/src/instrument.xml
index 12877994de..a7c62c8770 100644
--- a/lib/tools/doc/src/instrument.xml
+++ b/lib/tools/doc/src/instrument.xml
@@ -342,7 +342,7 @@
<p>Stores the current memory allocation map on the file
<c>File</c>. Returns <c>true</c> if the emulator has been
started with the "<c>+Mim true</c>" command-line argument, and
- the map was successfuly stored; otherwise, <c>false</c>. The
+ the map was successfully stored; otherwise, <c>false</c>. The
contents of the file can later be read using
<seealso marker="#read_memory_data/1">read_memory_data/1</seealso>.
<em>NOTE:</em><c>store_memory_data/0</c> blocks execution of
@@ -360,7 +360,7 @@
<p>Stores the current memory status on the file
<c>File</c>. Returns <c>true</c> if the emulator has been
started with the "<c>+Mis true</c>", or "<c>+Mim true</c>"
- command-line arguments, and the data was successfuly stored;
+ command-line arguments, and the data was successfully stored;
otherwise, <c>false</c>. The contents of the file can later be
read using
<seealso marker="#read_memory_status/1">read_memory_status/1</seealso>.</p>
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index a8dd3ec3ac..bc7a190fb4 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -1225,7 +1225,7 @@ Lock syntax table. The effect is that `apply' in the atom
`( (char-after (1- (or ,pos (point)))))))
;; defvar some obsolete variables, which we still support for
-;; backwardscompatibility reasons.
+;; backwards compatibility reasons.
(eval-when-compile
(defvar comment-indent-hook)
(defvar dabbrev-case-fold-search)
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index 905ad895c9..fb9744d759 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -55,14 +55,14 @@
%% compiled module. This is necessary so that the code can be loaded
%% on remote nodes that are started after the compilation.
%%
-%% PARELLALISM
+%% PARALLELISM
%% To take advantage of SMP when doing the cover analysis both the data
%% collection and analysis has been parallelized. One process is spawned for
%% each node when collecting data, and on the remote node when collecting data
%% one process is spawned per module.
%%
%% When analyzing data it is possible to issue multiple analyse(_to_file)/X
-%% calls at once. They are however all calls (for backwardscompatability
+%% calls at once. They are however all calls (for backwards compatibility
%% reasons) so the user of cover will have to spawn several processes to to the
%% calls ( or use async_analyse_to_file ).
%%
diff --git a/lib/wx/api_gen/gl_gen.erl b/lib/wx/api_gen/gl_gen.erl
index 374e0bd12b..b665d949b3 100644
--- a/lib/wx/api_gen/gl_gen.erl
+++ b/lib/wx/api_gen/gl_gen.erl
@@ -44,7 +44,7 @@ devcode() -> spawn(fun() -> safe(fun gen_code/0,false) end).
safe(What, QuitOnErr) ->
try
What(),
- io:format("Completed succesfully~n~n", []),
+ io:format("Completed successfully~n~n", []),
QuitOnErr andalso gen_util:halt(0)
catch Err:Reason ->
io:format("Error ~p: ~p:~p~n ~p~n",
diff --git a/lib/wx/api_gen/wx_gen.erl b/lib/wx/api_gen/wx_gen.erl
index 2f20c42a5d..b36653c570 100644
--- a/lib/wx/api_gen/wx_gen.erl
+++ b/lib/wx/api_gen/wx_gen.erl
@@ -38,7 +38,7 @@ devcode() -> erase(),safe(fun gen_code/0,false).
safe(What, QuitOnErr) ->
try
What(),
- io:format("Completed succesfully~n~n", []),
+ io:format("Completed successfully~n~n", []),
QuitOnErr andalso gen_util:halt(0)
catch Err:Reason ->
io:format("Error in ~p ~p~n", [get(current_class),get(current_func)]),
diff --git a/lib/xmerl/src/xmerl_ucs.erl b/lib/xmerl/src/xmerl_ucs.erl
index 7c45c838ab..feb16070a0 100644
--- a/lib/xmerl/src/xmerl_ucs.erl
+++ b/lib/xmerl/src/xmerl_ucs.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
+%%
%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
-%%
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% %CopyrightEnd%
%%
@@ -43,6 +43,7 @@
-export([to_utf16be/1, from_utf16be/1, from_utf16be/2]).
-export([to_utf16le/1, from_utf16le/1, from_utf16le/2]).
-export([to_utf8/1, from_utf8/1]).
+-export([from_latin9/1]).
%%% NB: Non-canonical UTF-8 encodings and incorrectly used
%%% surrogate-pair codes are disallowed by this code. There are
@@ -177,13 +178,27 @@ to_utf8(List) when is_list(List) -> lists:flatmap(fun to_utf8/1, List);
to_utf8(Ch) -> char_to_utf8(Ch).
from_utf8(Bin) when is_binary(Bin) -> from_utf8(binary_to_list(Bin));
-from_utf8(List) ->
+from_utf8(List) ->
case expand_utf8(List) of
{Result,0} -> Result;
{_Res,_NumBadChar} ->
exit({ucs,{bad_utf8_character_code}})
end.
+%%% Latin9 support
+from_latin9(Bin) when is_binary(Bin) -> from_latin9(binary_to_list(Bin));
+from_latin9(List) ->
+ [ latin9_to_ucs4(Char) || Char <- List].
+
+latin9_to_ucs4(16#A4) -> 16#20AC;
+latin9_to_ucs4(16#A6) -> 16#160;
+latin9_to_ucs4(16#A8) -> 16#161;
+latin9_to_ucs4(16#B4) -> 16#17D;
+latin9_to_ucs4(16#B8) -> 16#17E;
+latin9_to_ucs4(16#BC) -> 16#152;
+latin9_to_ucs4(16#BD) -> 16#153;
+latin9_to_ucs4(16#BE) -> 16#178;
+latin9_to_ucs4(Other) -> Other.
@@ -238,7 +253,7 @@ from_ucs4le(Bin,Acc,Tail) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% UCS-2 support
-%%% FIXME! Don't know how to encode UCS-2!!
+%%% FIXME! Don't know how to encode UCS-2!!
%%% Currently I just encode as UCS-4, but strips the 16 higher bits.
char_to_ucs2be(Ch) ->
true = is_iso10646(Ch),
@@ -259,15 +274,15 @@ from_ucs2be(Bin,Acc,Tail) ->
char_to_ucs2le(Ch) ->
true = is_iso10646(Ch),
- [(Ch bsr 16) band 16#FF,
- (Ch bsr 24)].
+ [Ch band 16#FF,
+ (Ch bsr 8) band 16#FF].
from_ucs2le(<<Ch:16/little-signed-integer, Rest/binary>>,Acc,Tail) ->
if Ch < 0; Ch >= 16#D800, Ch < 16#E000; Ch =:= 16#FFFE; Ch =:= 16#FFFF ->
exit({bad_character_code,Ch});
true ->
- from_ucs4le(Rest,[Ch|Acc],Tail)
+ from_ucs2le(Rest,[Ch|Acc],Tail)
end;
from_ucs2le(<<>>,Acc,Tail) ->
lists:reverse(Acc,Tail);
@@ -476,6 +491,8 @@ to_unicode(Input,Cs) when Cs=='iso_8859-1:1987';Cs=='iso-ir-100';
Cs=='l1';Cs=='ibm819';
Cs=='cp819';Cs=='csisolatin1' ->
Input;
+to_unicode(Input,Cs) when Cs=='iso_8859-15';Cs=='iso-8859-15';Cs=='latin9' ->
+ from_latin9(Input);
% to_unicode(Input,Cs) when Cs=='mnemonic';Cs=='"mnemonic+ascii+38';
% Cs=='mnem';Cs=='"mnemonic+ascii+8200' ->
% from_mnemonic(Input);
diff --git a/lib/xmerl/src/xmerl_xsd.erl b/lib/xmerl/src/xmerl_xsd.erl
index f003cc74ba..50c0a79016 100644
--- a/lib/xmerl/src/xmerl_xsd.erl
+++ b/lib/xmerl/src/xmerl_xsd.erl
@@ -742,7 +742,7 @@ element_content({IDC,S},El,Env)
{{IDC,IDConstr},S3};
Err ->
S3 = acc_errs(S2,{error_path(El,El#xmlElement.name),?MODULE,
- {erronous_content_in_identity_constraint,IDC,Err}}),
+ {erroneous_content_in_identity_constraint,IDC,Err}}),
{{IDC,[]},S3}
end;
element_content({selector,S},Sel,_Env) ->
@@ -5571,7 +5571,7 @@ format_error({incomplete_file,_FileName,_Other}) ->
"Schema: The file containing a schema state must be produced by xmerl_xsd:state2file/[1,2].";
format_error({unexpected_content_in_any,A}) ->
io_lib:format("Schema: The any type is considered to have no content besides annotation. ~p was found.",[A]);
-format_error({erronous_content_in_identity_constraint,IDC,Err}) ->
+format_error({erroneous_content_in_identity_constraint,IDC,Err}) ->
io_lib:format("Schema: An ~p identity constraint must have one selector and one or more field in content. This case ~p",[IDC,Err]);
format_error({missing_xpath_attribute,IDCContent}) ->
io_lib:format("Schema: A ~p in a identity constraint must have a xpath attribute.",[IDCContent]);