diff options
Diffstat (limited to 'lib')
111 files changed, 2912 insertions, 1006 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/erl_interface/src/legacy/erl_fix_alloc.c b/lib/erl_interface/src/legacy/erl_fix_alloc.c index 20f3024e41..ca09fc3b8b 100644 --- a/lib/erl_interface/src/legacy/erl_fix_alloc.c +++ b/lib/erl_interface/src/legacy/erl_fix_alloc.c @@ -109,6 +109,10 @@ void *erl_eterm_alloc (void) erl_eterm_state->freed--; } else if ((b = malloc(sizeof(*b))) == NULL) { erl_errno = ENOMEM; +#ifdef _REENTRANT + ei_mutex_unlock(erl_eterm_state->lock); +#endif /* _REENTRANT */ + return NULL; } erl_eterm_state->allocated++; b->free = 0; diff --git a/lib/erl_interface/src/registry/reg_dump.c b/lib/erl_interface/src/registry/reg_dump.c index 1e640fb506..d2854c10b5 100644 --- a/lib/erl_interface/src/registry/reg_dump.c +++ b/lib/erl_interface/src/registry/reg_dump.c @@ -215,6 +215,7 @@ static int mn_send_write(int fd, erlang_pid *mnesia, const char *key, ei_reg_obj else ei_encode_long(msgbuf,&index,(long)(obj->val.p)); /* just the pointer */ break; default: + if (dbuf) free(dbuf); return -1; } diff --git a/lib/erl_interface/src/registry/reg_restore.c b/lib/erl_interface/src/registry/reg_restore.c index 765c3f4314..7bc1c758af 100644 --- a/lib/erl_interface/src/registry/reg_restore.c +++ b/lib/erl_interface/src/registry/reg_restore.c @@ -303,6 +303,9 @@ int ei_reg_restore(int fd, ei_reg *reg, const char *mntab) if (mn_decode_insert(reg,msgbuf,&index,keybuf)) goto restore_failure; } + if (keybuf) free(keybuf); + if (dbuf) free(dbuf); + /* wait for unlink */ if (mn_unlink(fd)) return -1; @@ -310,8 +313,6 @@ int ei_reg_restore(int fd, ei_reg *reg, const char *mntab) ei_hash_foreach(reg->tab,clean_obj); /* success */ - if (keybuf) free(keybuf); - if (dbuf) free(dbuf); return 0; restore_failure: 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/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl index d7eb035551..cfed410240 100644 --- a/lib/hipe/icode/hipe_beam_to_icode.erl +++ b/lib/hipe/icode/hipe_beam_to_icode.erl @@ -720,7 +720,7 @@ trans_fun([{test,bs_get_float2,{f,Lbl},[Ms,_Live,Size,Unit,{field_flags,Flags0}, ?EXIT({bad_bs_size_constant,Size}); BitReg -> Bits = mk_var(BitReg), - {{bs_get_float,Unit,Flags}, [Bits,MsVar]} + {{bs_get_float,Unit,Flags}, [MsVar,Bits]} end, trans_op_call({hipe_bs_primop,Name}, Lbl, Args, [Dst,MsVar], Env, Instructions); trans_fun([{test,bs_get_integer2,{f,Lbl},[Ms,_Live,Size,Unit,{field_flags,Flags0},X]}| 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/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/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> 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> Dir = string()</v> <v>Result = ok | error | {ok,Relup,Module,Warnings} | {error,Module,Error}</v> <v> 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> Dir = string()</v> <v> Var = {VarName,Prefix}</v> <v> 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_1.erl b/lib/sasl/src/release_handler_1.erl index ef95606bb5..8d0baf3ab1 100644 --- a/lib/sasl/src/release_handler_1.erl +++ b/lib/sasl/src/release_handler_1.erl @@ -21,7 +21,7 @@ %% External exports -export([eval_script/1, eval_script/5, check_script/2, check_old_processes/2]). --export([get_current_vsn/1]). %% exported because used in a test case +-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 = [], @@ -493,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 @@ -502,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 5dc83e7b2a..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 @@ -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 b44da72d35..af2183bfff 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -58,7 +58,7 @@ cases() -> [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]. + instructions, eval_appup, supervisor_which_children_timeout]. groups() -> [{release,[], @@ -523,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 %%----------------------------------------------------------------- diff --git a/lib/sasl/test/release_handler_SUITE_data/Makefile.src b/lib/sasl/test/release_handler_SUITE_data/Makefile.src index 9b07e7ce0a..edb446413d 100644 --- a/lib/sasl/test/release_handler_SUITE_data/Makefile.src +++ b/lib/sasl/test/release_handler_SUITE_data/Makefile.src @@ -64,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 @@ -195,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/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 539f6de99d..e352247d44 100644 --- a/lib/sasl/test/systools_SUITE.erl +++ b/lib/sasl/test/systools_SUITE.erl @@ -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}]), @@ -1150,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}]), @@ -1159,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 59f8479a4c..d1ec0c141e 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -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 5187d0f78f..cec81d551b 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -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/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]); |