diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/compiler/src/beam_ssa_opt.erl | 93 | ||||
-rw-r--r-- | lib/compiler/src/beam_ssa_type.erl | 187 | ||||
-rw-r--r-- | lib/compiler/src/erl_bifs.erl | 16 | ||||
-rw-r--r-- | lib/compiler/src/v3_core.erl | 22 | ||||
-rw-r--r-- | lib/kernel/test/logger_disk_log_h_SUITE.erl | 2 | ||||
-rw-r--r-- | lib/observer/test/crashdump_helper.erl | 2 | ||||
-rw-r--r-- | lib/reltool/test/reltool_server_SUITE.erl | 128 | ||||
-rw-r--r-- | lib/reltool/test/reltool_test_lib.erl | 3 | ||||
-rw-r--r-- | lib/reltool/test/reltool_wx_SUITE.erl | 7 | ||||
-rw-r--r-- | lib/sasl/test/test_lib.hrl | 4 | ||||
-rw-r--r-- | lib/ssl/doc/src/ssl.xml | 51 | ||||
-rw-r--r-- | lib/ssl/src/ssl.erl | 21 | ||||
-rw-r--r-- | lib/ssl/test/ssl_bench_SUITE.erl | 37 | ||||
-rw-r--r-- | lib/stdlib/src/erl_pp.erl | 4 | ||||
-rw-r--r-- | lib/stdlib/test/erl_pp_SUITE.erl | 11 |
15 files changed, 374 insertions, 214 deletions
diff --git a/lib/compiler/src/beam_ssa_opt.erl b/lib/compiler/src/beam_ssa_opt.erl index 0f03d0e736..f8e19d0aa7 100644 --- a/lib/compiler/src/beam_ssa_opt.erl +++ b/lib/compiler/src/beam_ssa_opt.erl @@ -164,12 +164,14 @@ repeated_passes(Opts) -> epilogue_passes(Opts) -> Ps = [?PASS(ssa_opt_type_finish), ?PASS(ssa_opt_float), - ?PASS(ssa_opt_live), %One last time to clean up the - %mess left by the float pass. + ?PASS(ssa_opt_sw), + + %% Run live one more time to clean up after the float and sw + %% passes. + ?PASS(ssa_opt_live), ?PASS(ssa_opt_bsm), ?PASS(ssa_opt_bsm_units), ?PASS(ssa_opt_bsm_shortcut), - ?PASS(ssa_opt_sw), ?PASS(ssa_opt_blockify), ?PASS(ssa_opt_sink), ?PASS(ssa_opt_merge_blocks), @@ -1830,12 +1832,16 @@ opt_tup_size_is([], _, _, _Acc) -> none. %%% ssa_opt_sw({#st{ssa=Linear0,cnt=Count0}=St, FuncDb}) -> - {Linear,Count} = opt_sw(Linear0, #{}, Count0, []), + {Linear,Count} = opt_sw(Linear0, Count0, []), {St#st{ssa=Linear,cnt=Count}, FuncDb}. -opt_sw([{L,#b_blk{is=Is,last=#b_switch{}=Last0}=Blk0}|Bs], Phis0, Count0, Acc) -> - Phis = opt_sw_phis(Is, Phis0), - case opt_sw_last(Last0, Phis) of +opt_sw([{L,#b_blk{is=Is,last=#b_switch{}=Sw0}=Blk0}|Bs], Count0, Acc) -> + %% Ensure that no label in the switch list is the same + %% as the failure label. + #b_switch{fail=Fail,list=List0} = Sw0, + List = [{Val,Lbl} || {Val,Lbl} <- List0, Lbl =/= Fail], + Sw1 = beam_ssa:normalize(Sw0#b_switch{list=List}), + case Sw1 of #b_switch{arg=Arg,fail=Fail,list=[{Lit,Lbl}]} -> %% Rewrite a single value switch to a br. Bool = #b_var{name={'@ssa_bool',Count0}}, @@ -1843,7 +1849,7 @@ opt_sw([{L,#b_blk{is=Is,last=#b_switch{}=Last0}=Blk0}|Bs], Phis0, Count0, Acc) - IsEq = #b_set{op={bif,'=:='},dst=Bool,args=[Arg,Lit]}, Br = #b_br{bool=Bool,succ=Lbl,fail=Fail}, Blk = Blk0#b_blk{is=Is++[IsEq],last=Br}, - opt_sw(Bs, Phis, Count, [{L,Blk}|Acc]); + opt_sw(Bs, Count, [{L,Blk}|Acc]); #b_switch{arg=Arg,fail=Fail, list=[{#b_literal{val=B1},Lbl},{#b_literal{val=B2},Lbl}]} when B1 =:= not B2 -> @@ -1853,71 +1859,18 @@ opt_sw([{L,#b_blk{is=Is,last=#b_switch{}=Last0}=Blk0}|Bs], Phis0, Count0, Acc) - IsBool = #b_set{op={bif,is_boolean},dst=Bool,args=[Arg]}, Br = #b_br{bool=Bool,succ=Lbl,fail=Fail}, Blk = Blk0#b_blk{is=Is++[IsBool],last=Br}, - opt_sw(Bs, Phis, Count, [{L,Blk}|Acc]); - Last0 -> - opt_sw(Bs, Phis, Count0, [{L,Blk0}|Acc]); - Last -> - Blk = Blk0#b_blk{last=Last}, - opt_sw(Bs, Phis, Count0, [{L,Blk}|Acc]) + opt_sw(Bs, Count, [{L,Blk}|Acc]); + Sw0 -> + opt_sw(Bs, Count0, [{L,Blk0}|Acc]); + Sw -> + Blk = Blk0#b_blk{last=Sw}, + opt_sw(Bs, Count0, [{L,Blk}|Acc]) end; -opt_sw([{L,#b_blk{is=Is}=Blk}|Bs], Phis0, Count, Acc) -> - Phis = opt_sw_phis(Is, Phis0), - opt_sw(Bs, Phis, Count, [{L,Blk}|Acc]); -opt_sw([], _Phis, Count, Acc) -> +opt_sw([{L,#b_blk{}=Blk}|Bs], Count, Acc) -> + opt_sw(Bs, Count, [{L,Blk}|Acc]); +opt_sw([], Count, Acc) -> {reverse(Acc),Count}. -opt_sw_phis([#b_set{op=phi,dst=Dst,args=Args}|Is], Phis) -> - case opt_sw_literals(Args, []) of - error -> - opt_sw_phis(Is, Phis); - Literals -> - opt_sw_phis(Is, Phis#{Dst=>Literals}) - end; -opt_sw_phis(_, Phis) -> Phis. - -opt_sw_last(#b_switch{arg=Arg,fail=Fail,list=List0}=Sw0, Phis) -> - case Phis of - #{Arg:=Values0} -> - Values = gb_sets:from_list(Values0), - - %% Prune the switch list to only contain the possible values. - List1 = [P || {Lit,_}=P <- List0, gb_sets:is_member(Lit, Values)], - - %% Now test whether the failure label can ever be reached. - Sw = case gb_sets:size(Values) =:= length(List1) of - true -> - %% The switch list has the same number of values as the phi node. - %% The values must be the same, because the values that were not - %% possible were pruned from the switch list. Therefore, the - %% failure label can't possibly be reached, and we can choose a - %% a new failure label by picking a value from the list. - case List1 of - [{#b_literal{},Lbl}|List] -> - Sw0#b_switch{fail=Lbl,list=List}; - [] -> - Sw0#b_switch{list=List1} - end; - false -> - %% There are some values in the phi node that are not in the - %% switch list; thus, the failure label can still be reached. - Sw0 - end, - beam_ssa:normalize(Sw); - #{} -> - %% Ensure that no label in the switch list is the same - %% as the failure label. - List = [{Val,Lbl} || {Val,Lbl} <- List0, Lbl =/= Fail], - Sw = Sw0#b_switch{list=List}, - beam_ssa:normalize(Sw) - end. - -opt_sw_literals([{#b_literal{}=Lit,_}|T], Acc) -> - opt_sw_literals(T, [Lit|Acc]); -opt_sw_literals([_|_], _Acc) -> - error; -opt_sw_literals([], Acc) -> Acc. - - %%% %%% Merge blocks. %%% diff --git a/lib/compiler/src/beam_ssa_type.erl b/lib/compiler/src/beam_ssa_type.erl index 3b5d25efce..5fbb679c6f 100644 --- a/lib/compiler/src/beam_ssa_type.erl +++ b/lib/compiler/src/beam_ssa_type.erl @@ -23,7 +23,8 @@ -include("beam_ssa_opt.hrl"). -import(lists, [all/2,any/2,droplast/1,foldl/3,last/1,member/2, - partition/2,reverse/1,reverse/2,seq/2,sort/1]). + keyfind/3,partition/2,reverse/1,reverse/2, + seq/2,sort/1]). -define(UNICODE_INT, #t_integer{elements={0,16#10FFFF}}). @@ -260,22 +261,33 @@ opt_is([#b_set{op=phi,dst=Dst,args=Args0}=I0|Is], opt_is(Is, Ts, Ds, Fdb, D, Sub0, [I|Acc]) end; opt_is([#b_set{op=call,args=Args0,dst=Dst}=I0|Is], - Ts0, Ds0, Fdb0, D, Sub, Acc) -> - Args = simplify_args(Args0, Sub, Ts0), + Ts0, Ds0, Fdb0, D, Sub0, Acc) -> + Args = simplify_args(Args0, Sub0, Ts0), I1 = beam_ssa:normalize(I0#b_set{args=Args}), - {Ts,Ds,Fdb,I} = opt_call(I1, D, Ts0, Ds0, Fdb0), - case {map_get(Dst, Ts),Is} of - {none,[#b_set{op=succeeded}]} -> + {Ts1,Ds,Fdb,I2} = opt_call(I1, D, Ts0, Ds0, Fdb0), + case {map_get(Dst, Ts1),Is} of + {_,[#b_set{op=succeeded}]} -> %% This call instruction is inside a try/catch %% block. Don't attempt to optimize it. - opt_is(Is, Ts, Ds, Fdb, D, Sub, [I|Acc]); + opt_is(Is, Ts1, Ds, Fdb, D, Sub0, [I2|Acc]); {none,_} -> %% This call never returns. The rest of the %% instructions will not be executed. Ret = #b_ret{arg=Dst}, - {no_return,Ret,reverse(Acc, [I]),Ds,Fdb,Sub}; - _ -> - opt_is(Is, Ts, Ds, Fdb, D, Sub, [I|Acc]) + {no_return,Ret,reverse(Acc, [I2]),Ds,Fdb,Sub0}; + {_,_} -> + case simplify_call(I2) of + #b_set{}=I -> + opt_is(Is, Ts1, Ds, Fdb, D, Sub0, [I|Acc]); + #b_literal{}=Lit -> + Sub = Sub0#{Dst=>Lit}, + Ts = maps:remove(Dst, Ts1), + opt_is(Is, Ts, Ds0, Fdb, D, Sub, Acc); + #b_var{}=Var -> + Ts = maps:remove(Dst, Ts1), + Sub = Sub0#{Dst=>Var}, + opt_is(Is, Ts, Ds0, Fdb, D, Sub, Acc) + end end; opt_is([#b_set{op=succeeded,args=[Arg],dst=Dst}=I], Ts0, Ds0, Fdb, D, Sub0, Acc) -> @@ -328,6 +340,48 @@ opt_is([#b_set{args=Args0,dst=Dst}=I0|Is], opt_is([], Ts, Ds, Fdb, _D, Sub, Acc) -> {reverse(Acc), Ts, Ds, Fdb, Sub}. +simplify_call(#b_set{op=call,args=[#b_remote{}=Rem|Args]}=I) -> + case Rem of + #b_remote{mod=#b_literal{val=Mod}, + name=#b_literal{val=Name}} -> + case erl_bifs:is_pure(Mod, Name, length(Args)) of + true -> + simplify_remote_call(Mod, Name, Args, I); + false -> + I + end; + #b_remote{} -> + I + end; +simplify_call(I) -> I. + +%% Simplify a remote call to a pure BIF. +simplify_remote_call(erlang, '++', [#b_literal{val=[]},Tl], _I) -> + Tl; +simplify_remote_call(Mod, Name, Args0, I) -> + case make_literal_list(Args0) of + none -> + I; + Args -> + %% The arguments are literals. Try to evaluate the BIF. + try apply(Mod, Name, Args) of + Val -> + case cerl:is_literal_term(Val) of + true -> + #b_literal{val=Val}; + false -> + %% The value can't be expressed as a literal + %% (e.g. a pid). + I + end + catch + _:_ -> + %% Failed. Don't bother trying to optimize + %% the call. + I + end + end. + opt_call(#b_set{dst=Dst,args=[#b_local{}=Callee|Args]}=I0, D, Ts0, Ds0, Fdb0) -> {Ts, Ds, I} = opt_local_call(I0, Ts0, Ds0, Fdb0), case Fdb0 of @@ -452,10 +506,19 @@ simplify(#b_set{op={bif,'=='},args=Args}=I, Ts) -> end; simplify(#b_set{op={bif,'=:='},args=[Same,Same]}, _Ts) -> #b_literal{val=true}; -simplify(#b_set{op={bif,'=:='},args=Args}=I, Ts) -> - case meet(get_types(Args, Ts)) of - none -> #b_literal{val=false}; - _ -> eval_bif(I, Ts) +simplify(#b_set{op={bif,'=:='},args=[A1,_A2]=Args}=I, Ts) -> + [T1,T2] = get_types(Args, Ts), + case meet(T1, T2) of + none -> + #b_literal{val=false}; + _ -> + case {t_is_boolean(T1),T2} of + {true,#t_atom{elements=[true]}} -> + %% Bool =:= true ==> Bool + A1; + {_,_} -> + eval_bif(I, Ts) + end end; simplify(#b_set{op={bif,Op},args=Args}=I, Ts) -> Types = get_types(Args, Ts), @@ -598,41 +661,49 @@ anno_float_arg(_) -> convert. opt_terminator(#b_br{bool=#b_literal{}}=Br, _Ts, _Ds) -> beam_ssa:normalize(Br); -opt_terminator(#b_br{bool=#b_var{}=V}=Br, Ts, Ds) -> - #{V:=Set} = Ds, - case Set of - #b_set{op={bif,'=:='},args=[Bool,#b_literal{val=true}]} -> - case t_is_boolean(get_type(Bool, Ts)) of - true -> - %% Bool =:= true ==> Bool - simplify_not(Br#b_br{bool=Bool}, Ts, Ds); - false -> - Br - end; - #b_set{} -> - simplify_not(Br, Ts, Ds) - end; +opt_terminator(#b_br{bool=#b_var{}}=Br, Ts, Ds) -> + simplify_not(Br, Ts, Ds); opt_terminator(#b_switch{arg=#b_literal{}}=Sw, _Ts, _Ds) -> beam_ssa:normalize(Sw); -opt_terminator(#b_switch{arg=#b_var{}=V}=Sw0, Ts, Ds) -> - Type = get_type(V, Ts), +opt_terminator(#b_switch{arg=#b_var{}=V}=Sw, Ts, Ds) -> + case get_type(V, Ts) of + any -> + beam_ssa:normalize(Sw); + Type -> + beam_ssa:normalize(opt_switch(Sw, Type, Ts, Ds)) + end; +opt_terminator(#b_ret{}=Ret, _Ts, _Ds) -> Ret. + + +opt_switch(#b_switch{fail=Fail,list=List0}=Sw0, Type, Ts, Ds) -> + List = prune_switch_list(List0, Fail, Type, Ts), + Sw1 = Sw0#b_switch{list=List}, case Type of #t_integer{elements={_,_}=Range} -> - simplify_switch_int(Sw0, Range); - _ -> + simplify_switch_int(Sw1, Range); + #t_atom{elements=[_|_]} -> case t_is_boolean(Type) of true -> - case simplify_switch_bool(Sw0, Ts, Ds) of - #b_br{}=Br -> - opt_terminator(Br, Ts, Ds); - Sw -> - beam_ssa:normalize(Sw) - end; + #b_br{} = Br = simplify_switch_bool(Sw1, Ts, Ds), + opt_terminator(Br, Ts, Ds); false -> - beam_ssa:normalize(Sw0) - end + simplify_switch_atom(Type, Sw1) + end; + _ -> + Sw1 + end. + +prune_switch_list([{_,Fail}|T], Fail, Type, Ts) -> + prune_switch_list(T, Fail, Type, Ts); +prune_switch_list([{Arg,_}=Pair|T], Fail, Type, Ts) -> + case meet(get_type(Arg, Ts), Type) of + none -> + %% Different types. This value can never match. + prune_switch_list(T, Fail, Type, Ts); + _ -> + [Pair|prune_switch_list(T, Fail, Type, Ts)] end; -opt_terminator(#b_ret{}=Ret, _Ts, _Ds) -> Ret. +prune_switch_list([], _, _, _) -> []. update_successors(#b_br{bool=#b_literal{val=true},succ=S}, Ts, D) -> update_successor(S, Ts, D); @@ -641,8 +712,8 @@ update_successors(#b_br{bool=#b_var{}=Bool,succ=Succ,fail=Fail}, Ts0, D0) -> true -> %% This variable is defined in this block and is only %% referenced by this br terminator. Therefore, there is - %% no need to include the type database passed on to the - %% successors of this block. + %% no need to include it in the type database passed on to + %% the successors of this block. Ts = maps:remove(Bool, Ts0), {SuccTs,FailTs} = infer_types_br(Bool, Ts, D0), D = update_successor(Fail, FailTs, D0), @@ -1029,6 +1100,17 @@ bs_match_type(utf16, _) -> bs_match_type(utf32, _) -> ?UNICODE_INT. +simplify_switch_atom(#t_atom{elements=Atoms}, #b_switch{list=List0}=Sw) -> + case sort([A || {#b_literal{val=A},_} <- List0]) of + Atoms -> + %% All possible atoms are included in the list. The + %% failure label will never be used. + [{_,Fail}|List] = List0, + Sw#b_switch{fail=Fail,list=List}; + _ -> + Sw + end. + simplify_switch_int(#b_switch{list=List0}=Sw, {Min,Max}) -> List1 = sort(List0), Vs = [V || {#b_literal{val=V},_} <- List1], @@ -1073,14 +1155,14 @@ simplify_is_record(I, any, _Size, _Tag, _Ts) -> simplify_is_record(_I, _Type, _Size, _Tag, _Ts) -> #b_literal{val=false}. -simplify_switch_bool(#b_switch{arg=B,list=List0}=Sw, Ts, Ds) -> - List = sort(List0), - case List of - [{#b_literal{val=false},Fail},{#b_literal{val=true},Succ}] -> - simplify_not(#b_br{bool=B,succ=Succ,fail=Fail}, Ts, Ds); - [_|_] -> - Sw - end. +simplify_switch_bool(#b_switch{arg=B,fail=Fail,list=List0}, Ts, Ds) -> + FalseVal = #b_literal{val=false}, + TrueVal = #b_literal{val=true}, + List1 = List0 ++ [{FalseVal,Fail},{TrueVal,Fail}], + {_,FalseLbl} = keyfind(FalseVal, 1, List1), + {_,TrueLbl} = keyfind(TrueVal, 1, List1), + Br = beam_ssa:normalize(#b_br{bool=B,succ=TrueLbl,fail=FalseLbl}), + simplify_not(Br, Ts, Ds). simplify_not(#b_br{bool=#b_var{}=V,succ=Succ,fail=Fail}=Br0, Ts, Ds) -> case Ds of @@ -1094,7 +1176,8 @@ simplify_not(#b_br{bool=#b_var{}=V,succ=Succ,fail=Fail}=Br0, Ts, Ds) -> end; #{} -> Br0 - end. + end; +simplify_not(#b_br{bool=#b_literal{}}=Br, _Ts, _Ds) -> Br. %%% %%% Calculate the set of variables that are only used once in the diff --git a/lib/compiler/src/erl_bifs.erl b/lib/compiler/src/erl_bifs.erl index d925decce6..94a5dfe012 100644 --- a/lib/compiler/src/erl_bifs.erl +++ b/lib/compiler/src/erl_bifs.erl @@ -32,6 +32,22 @@ %% Returns `true' if the function `Module:Name/Arity' does not %% affect the state, nor depend on the state, although its %% evaluation is not guaranteed to complete normally for all input. +%% +%% NOTE: There is no need to include every new pure BIF +%% here. Including it here means that the value of the function +%% will be evaluated at compile-time if the arguments are +%% constant. If that optimization is not useful/desired, there is +%% no need to include the new BIF here. +%% +%% Functions whose return value could conceivably change in a +%% future version of the runtime system must NOT be included here. +%% +%% Here are some example of functions that should not be +%% included: `term_to_binary/1', hashing functions, non-trivial +%% encode/decode functions. +%% +%% When unsure whether a new BIF should be included here, the +%% conservative safe choice is NOT to include it. -spec is_pure(atom(), atom(), arity()) -> boolean(). diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index e2bcd25801..3699c9d22e 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -330,7 +330,7 @@ gexpr({protect,Line,Arg}, Bools0, St0) -> {#iprotect{anno=#a{anno=Anno},body=Eps++[E]},[],Bools0,St} end; gexpr({op,_,'andalso',_,_}=E0, Bools, St0) -> - {op,L,'andalso',E1,E2} = right_assoc(E0, 'andalso', St0), + {op,L,'andalso',E1,E2} = right_assoc(E0, 'andalso'), Anno = lineno_anno(L, St0), {#c_var{name=V0},St} = new_var(Anno, St0), V = {var,L,V0}, @@ -338,7 +338,7 @@ gexpr({op,_,'andalso',_,_}=E0, Bools, St0) -> E = make_bool_switch_guard(L, E1, V, E2, False), gexpr(E, Bools, St); gexpr({op,_,'orelse',_,_}=E0, Bools, St0) -> - {op,L,'orelse',E1,E2} = right_assoc(E0, 'orelse', St0), + {op,L,'orelse',E1,E2} = right_assoc(E0, 'orelse'), Anno = lineno_anno(L, St0), {#c_var{name=V0},St} = new_var(Anno, St0), V = {var,L,V0}, @@ -768,7 +768,7 @@ expr({op,_,'++',{lc,Llc,E,Qs0},More}, St0) -> {Y,Yps,St} = lc_tq(Llc, E, Qs, Mc, St2), {Y,Mps++Yps,St}; expr({op,_,'andalso',_,_}=E0, St0) -> - {op,L,'andalso',E1,E2} = right_assoc(E0, 'andalso', St0), + {op,L,'andalso',E1,E2} = right_assoc(E0, 'andalso'), Anno = lineno_anno(L, St0), {#c_var{name=V0},St} = new_var(Anno, St0), V = {var,L,V0}, @@ -776,7 +776,7 @@ expr({op,_,'andalso',_,_}=E0, St0) -> E = make_bool_switch(L, E1, V, E2, False, St0), expr(E, St); expr({op,_,'orelse',_,_}=E0, St0) -> - {op,L,'orelse',E1,E2} = right_assoc(E0, 'orelse', St0), + {op,L,'orelse',E1,E2} = right_assoc(E0, 'orelse'), Anno = lineno_anno(L, St0), {#c_var{name=V0},St} = new_var(Anno, St0), V = {var,L,V0}, @@ -2060,17 +2060,9 @@ fail_clause(Pats, Anno, Arg) -> args=[Arg]}]}. %% Optimization for Dialyzer. -right_assoc(E, Op, St) -> - case member(dialyzer, St#core.opts) of - true -> - right_assoc2(E, Op); - false -> - E - end. - -right_assoc2({op,L1,Op,{op,L2,Op,E1,E2},E3}, Op) -> - right_assoc2({op,L2,Op,E1,{op,L1,Op,E2,E3}}, Op); -right_assoc2(E, _Op) -> E. +right_assoc({op,L1,Op,{op,L2,Op,E1,E2},E3}, Op) -> + right_assoc({op,L2,Op,E1,{op,L1,Op,E2,E3}}, Op); +right_assoc(E, _Op) -> E. annotate_tuple(A, Es, St) -> case member(dialyzer, St#core.opts) of diff --git a/lib/kernel/test/logger_disk_log_h_SUITE.erl b/lib/kernel/test/logger_disk_log_h_SUITE.erl index 9bbec42de8..13b30835a1 100644 --- a/lib/kernel/test/logger_disk_log_h_SUITE.erl +++ b/lib/kernel/test/logger_disk_log_h_SUITE.erl @@ -293,7 +293,7 @@ logging(Config) -> ok = start_and_add(Name, #{filter_default=>log, formatter=>{?MODULE,self()}}, #{file => LogFile}), - MsgFormatter = fun(Term) -> {io_lib:format("Term:~p",[Term]),[]} end, + MsgFormatter = fun(Term) -> {"Term:~p",[Term]} end, logger:notice([{x,y}], #{report_cb => MsgFormatter}), logger:notice([{x,y}], #{}), ct:pal("Checking contents of ~p", [?log_no(LogFile,1)]), diff --git a/lib/observer/test/crashdump_helper.erl b/lib/observer/test/crashdump_helper.erl index d6b5eff9b5..84ed99afa5 100644 --- a/lib/observer/test/crashdump_helper.erl +++ b/lib/observer/test/crashdump_helper.erl @@ -24,7 +24,7 @@ create_binaries/0,create_sub_binaries/1, dump_persistent_terms/0, create_persistent_terms/0]). --compile(r18). +-compile(r20). -include_lib("common_test/include/ct.hrl"). n1_proc(N2,Creator) -> diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl index f11aae61c6..bb092e8bbf 100644 --- a/lib/reltool/test/reltool_server_SUITE.erl +++ b/lib/reltool/test/reltool_server_SUITE.erl @@ -172,7 +172,7 @@ break(_Config) -> start_server(_Config) -> {ok, Pid} = ?msym({ok, _}, reltool:start_server([])), - Libs = lists:sort(erl_libs()), + Libs = reltool_test_lib:erl_libs(), StrippedDefault = case Libs of [] -> {sys, []}; @@ -186,7 +186,7 @@ start_server(_Config) -> %% Start a server process and check that it does not crash set_config(_Config) -> - Libs = lists:sort(erl_libs()), + Libs = reltool_test_lib:erl_libs(), Default = {sys, [ @@ -220,7 +220,15 @@ get_config(_Config) -> StdLibDir = filename:join(LibDir,"stdlib-"++StdVsn), SaslLibDir = filename:join(LibDir,"sasl-"++SaslVsn), - Sys = {sys,[{incl_cond, exclude}, + Libs = reltool_test_lib:erl_libs(), + LibDirs = + case Libs of + [] -> []; + _ -> [{lib_dirs,Libs}] + end, + + Sys = {sys,LibDirs ++ + [{incl_cond, exclude}, {app,kernel,[{incl_cond,include}]}, {app,sasl,[{incl_cond,include},{vsn,SaslVsn}]}, {app,stdlib,[{incl_cond,include},{lib_dir,StdLibDir}]}]}, @@ -229,13 +237,27 @@ get_config(_Config) -> ?m({ok, Sys}, reltool:get_config(Pid,false,false)), %% Include derived info - ?msym({ok,{sys,[{incl_cond, exclude}, - {erts,[]}, - {app,kernel,[{incl_cond,include},{mod,_,[]}|_]}, - {app,sasl,[{incl_cond,include},{vsn,SaslVsn},{mod,_,[]}|_]}, - {app,stdlib,[{incl_cond,include},{lib_dir,StdLibDir}, - {mod,_,[]}|_]}]}}, - reltool:get_config(Pid,false,true)), + case Libs of + [] -> + ?msym({ok,{sys,[{incl_cond, exclude}, + {erts,[]}, + {app,kernel,[{incl_cond,include},{mod,_,[]}|_]}, + {app,sasl,[{incl_cond,include},{vsn,SaslVsn}, + {mod,_,[]}|_]}, + {app,stdlib,[{incl_cond,include},{lib_dir,StdLibDir}, + {mod,_,[]}|_]}]}}, + reltool:get_config(Pid,false,true)); + _ -> + ?msym({ok,{sys,[{lib_dirs,Libs}, + {incl_cond, exclude}, + {erts,[]}, + {app,kernel,[{incl_cond,include},{mod,_,[]}|_]}, + {app,sasl,[{incl_cond,include},{vsn,SaslVsn}, + {mod,_,[]}|_]}, + {app,stdlib,[{incl_cond,include},{lib_dir,StdLibDir}, + {mod,_,[]}|_]}]}}, + reltool:get_config(Pid,false,true)) + end, %% Include defaults ?msym({ok,{sys,[{root_dir,_}, @@ -306,11 +328,11 @@ get_config(_Config) -> %% OTP-9135, test that app_file option can be set to all | keep | strip otp_9135(_Config) -> - Libs = lists:sort(erl_libs()), + Libs = reltool_test_lib:erl_libs(), StrippedDefaultSys = case Libs of [] -> []; - _ -> {lib_dirs, Libs} + _ -> [{lib_dirs, Libs}] end, Config1 = {sys,[{app_file, keep}]}, % this is the default @@ -1746,13 +1768,19 @@ set_sys_and_undo(Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% load_config_and_undo(Config) -> - Sys1 = {sys,[{incl_cond, exclude}, - {app,kernel,[{incl_cond,include}]}, - {app,sasl,[{incl_cond,include}]}, - {app,stdlib,[{incl_cond,include}]}, - {app,tools,[{incl_cond,include}]}]}, + Sys1 = {sys,Cfg1=[{incl_cond, exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,tools,[{incl_cond,include}]}]}, {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])), - ?m({ok, Sys1}, reltool:get_config(Pid)), + Libs = reltool_test_lib:erl_libs(), + Sys11 = + case Libs of + [] -> Sys1; + _ -> {sys, [{lib_dirs, Libs}|Cfg1]} + end, + ?m({ok, Sys11}, reltool:get_config(Pid)), ?m({ok,[]}, reltool_server:get_status(Pid)), %% Get app and mod @@ -1807,13 +1835,19 @@ load_config_and_undo(Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Test that load_config is properly rolled back if it fails load_config_fail(_Config) -> - Sys1 = {sys,[{incl_cond, exclude}, - {app,kernel,[{incl_cond,include}]}, - {app,sasl,[{incl_cond,include}]}, - {app,stdlib,[{incl_cond,include}]}, - {app,tools,[{incl_cond,include}]}]}, + Sys1 = {sys,Cfg1=[{incl_cond, exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}, + {app,tools,[{incl_cond,include}]}]}, {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys1}])), - ?m({ok, Sys1}, reltool:get_config(Pid)), + Libs = reltool_test_lib:erl_libs(), + Sys11 = + case Libs of + [] -> Sys1; + _ -> {sys, [{lib_dirs, Libs}|Cfg1]} + end, + ?m({ok, Sys11}, reltool:get_config(Pid)), ?m({ok,[]}, reltool_server:get_status(Pid)), %% Get app and mod @@ -1831,7 +1865,7 @@ load_config_fail(_Config) -> reltool_server:load_config(Pid,Sys2)), %% Check that a rollback is done to the old configuration - ?m({ok, Sys1}, reltool:get_config(Pid,false,false)), + ?m({ok, Sys11}, reltool:get_config(Pid,false,false)), %% and that tools is not changed (i.e. that the new configuration %% is not applied) @@ -2101,25 +2135,42 @@ gen_rel_files(_Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% save_config(Config) -> PrivDir = ?config(priv_dir,Config), - Sys = {sys,[{incl_cond, exclude}, - {app,kernel,[{incl_cond,include}]}, - {app,sasl,[{incl_cond,include}]}, - {app,stdlib,[{incl_cond,include}]}]}, + Sys = {sys,Cfg=[{incl_cond, exclude}, + {app,kernel,[{incl_cond,include}]}, + {app,sasl,[{incl_cond,include}]}, + {app,stdlib,[{incl_cond,include}]}]}, {ok, Pid} = ?msym({ok, _}, reltool:start_server([{config, Sys}])), - ?m({ok, Sys}, reltool:get_config(Pid)), + Libs = reltool_test_lib:erl_libs(), + Sys1 = + case Libs of + [] -> Sys; + _ -> {sys, [{lib_dirs, Libs}|Cfg]} + end, + ?m({ok, Sys1}, reltool:get_config(Pid)), Simple = filename:join(PrivDir,"save_simple.reltool"), ?m(ok, reltool_server:save_config(Pid,Simple,false,false)), - ?m({ok,[Sys]}, file:consult(Simple)), + ?m({ok,[Sys1]}, file:consult(Simple)), Derivates = filename:join(PrivDir,"save_derivates.reltool"), ?m(ok, reltool_server:save_config(Pid,Derivates,false,true)), - ?msym({ok,[{sys,[{incl_cond, exclude}, - {erts,[]}, - {app,kernel,[{incl_cond,include},{mod,_,[]}|_]}, - {app,sasl,[{incl_cond,include},{mod,_,[]}|_]}, - {app,stdlib,[{incl_cond,include},{mod,_,[]}|_]}]}]}, - file:consult(Derivates)), + case Libs of + [] -> + ?msym({ok,[{sys,[{incl_cond, exclude}, + {erts,[]}, + {app,kernel,[{incl_cond,include},{mod,_,[]}|_]}, + {app,sasl,[{incl_cond,include},{mod,_,[]}|_]}, + {app,stdlib,[{incl_cond,include},{mod,_,[]}|_]}]}]}, + file:consult(Derivates)); + _ -> + ?msym({ok,[{sys,[{lib_dirs,Libs}, + {incl_cond, exclude}, + {erts,[]}, + {app,kernel,[{incl_cond,include},{mod,_,[]}|_]}, + {app,sasl,[{incl_cond,include},{mod,_,[]}|_]}, + {app,stdlib,[{incl_cond,include},{mod,_,[]}|_]}]}]}, + file:consult(Derivates)) + end, Defaults = filename:join(PrivDir,"save_defaults.reltool"), ?m(ok, reltool_server:save_config(Pid,Defaults,true,false)), @@ -2587,9 +2638,6 @@ windows_erl_libs(_Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Library functions -erl_libs() -> - reltool_utils:erl_libs(). - datadir(Config) -> %% Removes the trailing slash... filename:nativename(?config(data_dir,Config)). diff --git a/lib/reltool/test/reltool_test_lib.erl b/lib/reltool/test/reltool_test_lib.erl index be48ea4726..033d952d0a 100644 --- a/lib/reltool/test/reltool_test_lib.erl +++ b/lib/reltool/test/reltool_test_lib.erl @@ -237,7 +237,8 @@ wait_for_close() -> wait_for_close() end. - +erl_libs() -> + lists:sort([filename:absname(P) || P<-reltool_utils:erl_libs()]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% A small test server, which can be run standalone in a shell diff --git a/lib/reltool/test/reltool_wx_SUITE.erl b/lib/reltool/test/reltool_wx_SUITE.erl index f6f7721762..983c8f6c52 100644 --- a/lib/reltool/test/reltool_wx_SUITE.erl +++ b/lib/reltool/test/reltool_wx_SUITE.erl @@ -74,7 +74,12 @@ start_all_windows(_Config) -> %% Test that server pid can be fetched, and that server is alive {ok, Server} = ?msym({ok,_}, reltool:get_server(SysPid)), ?m(true, erlang:is_process_alive(Server)), - ?m({ok,{sys,[]}}, reltool:get_config(Server)), + Sys = + case reltool_test_lib:erl_libs() of + [] -> []; + Libs -> [{lib_dirs,Libs}] + end, + ?m({ok,{sys,Sys}}, reltool:get_config(Server)), %% Terminate check_no_win_crash(), diff --git a/lib/sasl/test/test_lib.hrl b/lib/sasl/test/test_lib.hrl index f5210d4f27..7867d3da39 100644 --- a/lib/sasl/test/test_lib.hrl +++ b/lib/sasl/test/test_lib.hrl @@ -1,3 +1,3 @@ -define(ertsvsn,"4.4"). --define(kernelvsn,"5.3"). --define(stdlibvsn,"3.4"). +-define(kernelvsn,"6.0"). +-define(stdlibvsn,"3.5"). diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index be5abac7bc..3f643f32e1 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -190,15 +190,18 @@ <name name="legacy_hash"/> </datatype> - <datatype> <name name="signature_algs"/> </datatype> - + <datatype> <name name="sign_algo"/> </datatype> - + + <datatype> + <name name="sign_scheme"/> + </datatype> + <datatype> <name name="key_algo"/> </datatype> @@ -334,7 +337,30 @@ and to restrict their usage when using a cipher suite supporting them.</p> </desc> </datatype> - + + <datatype> + <name name="signature_schemes"/> + <desc> + <p> + In addition to the signature_algorithms extension from TLS 1.2, + <url href="http://www.ietf.org/rfc/rfc8446.txt#section-4.2.3">TLS 1.3 + (RFC 5246 Section 4.2.3)</url>adds the signature_algorithms_cert extension + which enables having special requirements on the signatures used in the + certificates that differs from the requirements on digital signatures as a whole. + If this is not required this extension is not needed. + </p> + <p> + The client will send a signature_algorithms_cert extension (ClientHello), + if TLS version 1.3 or later is used, and the signature_algs_cert option is + explicitly specified. By default, only the signature_algs extension is sent. + </p> + <p> + The signature schemes shall be ordered according to the client's preference + (favorite choice first). + </p> + </desc> + </datatype> + <datatype> <name name="secure_renegotiation"/> <desc><p>Specifies if to reject renegotiation attempt that does @@ -606,10 +632,19 @@ fun(srp, Username :: string(), UserState :: term()) -> </desc> </datatype> - <datatype> - <name name="log_alert"/> - <desc><p>If set to <c>false</c>, error reports are not displayed.</p> - </desc> + <datatype> + <name name="log_alert"/> + <desc><p>If set to <c>false</c>, error reports are not displayed. + Deprecated in OTP 22, use {log_level, <seealso marker="#type-logging_level">logging_level()</seealso>} instead.</p> + </desc> + </datatype> + + <datatype> + <name name="logging_level"/> + <desc><p>Specifies the log level for TLS/DTLS. At verbosity level <c>notice</c> and above error reports are + displayed in TLS. The level <c>debug</c> triggers verbose logging of TLS protocol + messages and logging of ignored alerts in DTLS.</p> + </desc> </datatype> <datatype> diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index d06f61f17d..980b773a84 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -136,6 +136,22 @@ -type legacy_hash() :: md5. -type sign_algo() :: rsa | dsa | ecdsa. + +-type sign_scheme() :: rsa_pkcs1_sha256 + | rsa_pkcs1_sha384 + | rsa_pkcs1_sha512 + | ecdsa_secp256r1_sha256 + | ecdsa_secp384r1_sha384 + | ecdsa_secp521r1_sha512 + | rsa_pss_rsae_sha256 + | rsa_pss_rsae_sha384 + | rsa_pss_rsae_sha512 + | rsa_pss_pss_sha256 + | rsa_pss_pss_sha384 + | rsa_pss_pss_sha512 + | rsa_pkcs1_sha1 + | ecdsa_sha1. + -type key_algo() :: rsa | dhe_rsa | dhe_dss | ecdhe_ecdsa | ecdh_ecdsa | ecdh_rsa | @@ -229,6 +245,7 @@ {password, key_password()} | {ciphers, cipher_suites()} | {eccs, eccs()} | + {signature_algs_cert, signature_schemes()} | {secure_renegotiate, secure_renegotiation()} | {depth, allowed_cert_chain_length()} | {verify_fun, custom_verify()} | @@ -238,6 +255,7 @@ {partial_chain, root_fun()} | {versions, protocol_versions()} | {user_lookup_fun, custom_user_lookup()} | + {log_level, logging_level()} | {log_alert, log_alert()} | {hibernate_after, hibernate_after()} | {padding_check, padding_check()} | @@ -272,13 +290,14 @@ -type root_fun() :: fun(). -type protocol_versions() :: [protocol_version()]. -type signature_algs() :: [{hash(), sign_algo()}]. +-type signature_schemes() :: [sign_scheme()]. -type custom_user_lookup() :: {Lookupfun :: fun(), UserState :: term()}. -type padding_check() :: boolean(). -type beast_mitigation() :: one_n_minus_one | zero_n | disabled. -type srp_identity() :: {Username :: string(), Password :: string()}. -type psk_identity() :: string(). -type log_alert() :: boolean(). - +-type logging_level() :: logger:level(). %% ------------------------------------------------------------------------------------------------------- -type client_option() :: {verify, client_verify_type()} | diff --git a/lib/ssl/test/ssl_bench_SUITE.erl b/lib/ssl/test/ssl_bench_SUITE.erl index 0b2011a627..35efa2b8a3 100644 --- a/lib/ssl/test/ssl_bench_SUITE.erl +++ b/lib/ssl/test/ssl_bench_SUITE.erl @@ -41,6 +41,7 @@ end_per_group(_GroupName, _Config) -> ok. init_per_suite(Config) -> + ct:timetrap({minutes, 1}), case node() of nonode@nohost -> {skipped, "Node not distributed"}; @@ -163,7 +164,7 @@ do_test(Type, TC, Loop, ParallellConnections, Server) -> end end, Spawn = fun(Id) -> - Pid = spawn(fun() -> Test(Id) end), + Pid = spawn_link(fun() -> Test(Id) end), receive {Pid, init} -> Pid end end, Pids = [Spawn(Id) || Id <- lists:seq(ParallellConnections, 1, -1)], @@ -180,42 +181,42 @@ do_test(Type, TC, Loop, ParallellConnections, Server) -> {ok, TestPerSecond}. server_init(ssl, setup_connection, _, _, Server) -> - {ok, Socket} = ssl:listen(0, ssl_opts(listen)), - {ok, {_Host, Port}} = ssl:sockname(Socket), + {ok, LSocket} = ssl:listen(0, ssl_opts(listen)), + {ok, {_Host, Port}} = ssl:sockname(LSocket), {ok, Host} = inet:gethostname(), ?FPROF_SERVER andalso start_profile(fprof, [whereis(ssl_manager), new]), %%?EPROF_SERVER andalso start_profile(eprof, [ssl_connection_sup, ssl_manager]), ?EPROF_SERVER andalso start_profile(eprof, [ssl_manager]), Server ! {self(), {init, Host, Port}}, Test = fun(TSocket) -> - ok = ssl:ssl_accept(TSocket), - ssl:close(TSocket) + {ok, Socket} = ssl:handshake(TSocket), + ssl:close(Socket) end, - setup_server_connection(Socket, Test); + setup_server_connection(LSocket, Test); server_init(ssl, payload, Loop, _, Server) -> - {ok, Socket} = ssl:listen(0, ssl_opts(listen)), - {ok, {_Host, Port}} = ssl:sockname(Socket), + {ok, LSocket} = ssl:listen(0, ssl_opts(listen)), + {ok, {_Host, Port}} = ssl:sockname(LSocket), {ok, Host} = inet:gethostname(), Server ! {self(), {init, Host, Port}}, Test = fun(TSocket) -> - ok = ssl:ssl_accept(TSocket), + {ok, Socket} = ssl:handshake(TSocket), Size = byte_size(msg()), - server_echo(TSocket, Size, Loop), - ssl:close(TSocket) + server_echo(Socket, Size, Loop), + ssl:close(Socket) end, - setup_server_connection(Socket, Test); + setup_server_connection(LSocket, Test); server_init(ssl, pem_cache, Loop, _, Server) -> - {ok, Socket} = ssl:listen(0, ssl_opts(listen_der)), - {ok, {_Host, Port}} = ssl:sockname(Socket), + {ok, LSocket} = ssl:listen(0, ssl_opts(listen_der)), + {ok, {_Host, Port}} = ssl:sockname(LSocket), {ok, Host} = inet:gethostname(), Server ! {self(), {init, Host, Port}}, Test = fun(TSocket) -> - ok = ssl:ssl_accept(TSocket), + {ok, Socket} = ssl:handshake(TSocket), Size = byte_size(msg()), - server_echo(TSocket, Size, Loop), - ssl:close(TSocket) + server_echo(Socket, Size, Loop), + ssl:close(Socket) end, - setup_server_connection(Socket, Test); + setup_server_connection(LSocket, Test); server_init(Type, Tc, _, _, Server) -> io:format("No server init code for ~p ~p~n",[Type, Tc]), diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl index dd302a2880..ada3ff5de3 100644 --- a/lib/stdlib/src/erl_pp.erl +++ b/lib/stdlib/src/erl_pp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2018. All Rights Reserved. +%% Copyright Ericsson AB 1996-2019. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -697,6 +697,8 @@ fun_info(Extra) -> %% BITS: +bit_grp([], _Opts) -> + leaf("<<>>"); bit_grp(Fs, Opts) -> append([['<<'], [bit_elems(Fs, Opts)], ['>>']]). diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl index dda8d0a12e..f5d80e7e68 100644 --- a/lib/stdlib/test/erl_pp_SUITE.erl +++ b/lib/stdlib/test/erl_pp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2018. All Rights Reserved. +%% Copyright Ericsson AB 2006-2019. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -51,7 +51,7 @@ otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1, otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1, otp_10302/1, otp_10820/1, otp_11100/1, otp_11861/1, pr_1014/1, - otp_13662/1, otp_14285/1]). + otp_13662/1, otp_14285/1, otp_15592/1]). %% Internal export. -export([ehook/6]). @@ -81,7 +81,7 @@ groups() -> [otp_6321, otp_6911, otp_6914, otp_8150, otp_8238, otp_8473, otp_8522, otp_8567, otp_8664, otp_9147, otp_10302, otp_10820, otp_11100, otp_11861, pr_1014, otp_13662, - otp_14285]}]. + otp_14285, otp_15592]}]. init_per_suite(Config) -> Config. @@ -1167,6 +1167,11 @@ otp_14285(_Config) -> [{encoding,latin1}])), ok. +otp_15592(_Config) -> + ok = pp_expr(<<"long12345678901234567890123456789012345678901234" + "56789012345678901234:f(<<>>)">>), + ok. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% compile(Config, Tests) -> |