aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/asn1/src/asn1ct_imm.erl33
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Prim.asn17
-rw-r--r--lib/asn1/test/testPrim.erl29
-rw-r--r--lib/compiler/src/beam_bool.erl50
-rw-r--r--lib/compiler/src/cerl.erl11
-rw-r--r--lib/compiler/src/v3_codegen.erl58
-rw-r--r--lib/compiler/src/v3_core.erl2
-rw-r--r--lib/compiler/test/guard_SUITE.erl79
-rw-r--r--lib/compiler/test/map_SUITE.erl3
-rw-r--r--lib/crypto/c_src/crypto.c5
-rw-r--r--lib/crypto/test/crypto_SUITE.erl18
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl22
-rw-r--r--lib/dialyzer/src/dialyzer_callgraph.erl27
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/fun_arity2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/maps14
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/non_existing1
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/maps1.erl12
-rw-r--r--lib/diameter/src/base/diameter_service.erl9
-rw-r--r--lib/diameter/src/diameter.appup.src2
-rw-r--r--lib/edoc/src/edoc_specs.erl6
-rw-r--r--lib/hipe/cerl/cerl_prettypr.erl18
-rw-r--r--lib/hipe/cerl/erl_types.erl14
-rw-r--r--lib/ssh/doc/src/notes.xml18
-rw-r--r--lib/ssh/src/ssh_auth.erl2
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl6
-rw-r--r--lib/ssh/test/Makefile5
-rw-r--r--lib/ssh/test/ssh.spec11
-rw-r--r--lib/ssh/test/ssh_bench.spec1
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE.erl539
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/id_dsa13
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa2565
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256.pub1
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa3846
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384.pub1
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa5217
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521.pub1
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/id_rsa15
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key13
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key.pub11
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key2565
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256.pub1
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key3846
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384.pub1
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key5217
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521.pub1
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key16
-rw-r--r--lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key.pub5
-rw-r--r--lib/ssh/test/ssh_protocol_SUITE.erl128
-rw-r--r--lib/ssh/test/ssh_test_lib.erl35
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE.erl4
-rw-r--r--lib/ssh/vsn.mk2
-rw-r--r--lib/ssl/src/inet_tls_dist.erl12
-rw-r--r--lib/ssl/src/ssl_tls_dist_proxy.erl10
-rw-r--r--lib/ssl/test/ssl_test_lib.erl62
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl33
-rw-r--r--lib/stdlib/src/erl_eval.erl33
-rw-r--r--lib/stdlib/src/erl_lint.erl6
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl23
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl15
59 files changed, 1228 insertions, 244 deletions
diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl
index 527f4f0ba9..e09256cde9 100644
--- a/lib/asn1/src/asn1ct_imm.erl
+++ b/lib/asn1/src/asn1ct_imm.erl
@@ -1120,38 +1120,41 @@ per_enc_constrained(Val0, Lb, Ub, false) ->
per_enc_constrained(Val0, Lb, Ub, true) ->
{Prefix,Val} = sub_lb(Val0, Lb),
Range = Ub - Lb + 1,
+ Check = {ult,Val,Range},
if
Range < 256 ->
NumBits = per_num_bits(Range),
- Check = {ult,Val,Range},
Put = [{put_bits,Val,NumBits,[1]}],
{Prefix,Check,Put};
Range =:= 256 ->
NumBits = 8,
- Check = {ult,Val,Range},
Put = [{put_bits,Val,NumBits,[1,align]}],
{Prefix,Check,Put};
Range =< 65536 ->
- Check = {ult,Val,Range},
Put = [{put_bits,Val,16,[1,align]}],
{Prefix,Check,Put};
true ->
- {var,VarBase} = Val,
- Bin = {var,VarBase++"@bin"},
- BinSize0 = {var,VarBase++"@bin_size0"},
- BinSize = {var,VarBase++"@bin_size"},
- Check = {ult,Val,Range},
RangeOctsLen = byte_size(binary:encode_unsigned(Range - 1)),
BitsNeeded = per_num_bits(RangeOctsLen),
- Enc = [{call,binary,encode_unsigned,[Val],Bin},
- {call,erlang,byte_size,[Bin],BinSize0},
- {sub,BinSize0,1,BinSize},
- {'cond',[['_',
- {put_bits,BinSize,BitsNeeded,[1]},
- {put_bits,Bin,binary,[8,align]}]]}],
- {Prefix,Check,Enc}
+ {Prefix,Check,per_enc_constrained_huge(BitsNeeded, Val)}
end.
+per_enc_constrained_huge(BitsNeeded, {var,VarBase}=Val) ->
+ Bin = {var,VarBase++"@bin"},
+ BinSize0 = {var,VarBase++"@bin_size0"},
+ BinSize = {var,VarBase++"@bin_size"},
+ [{call,binary,encode_unsigned,[Val],Bin},
+ {call,erlang,byte_size,[Bin],BinSize0},
+ {sub,BinSize0,1,BinSize},
+ {'cond',[['_',
+ {put_bits,BinSize,BitsNeeded,[1]},
+ {put_bits,Bin,binary,[8,align]}]]}];
+per_enc_constrained_huge(BitsNeeded, Val) when is_integer(Val) ->
+ Bin = binary:encode_unsigned(Val),
+ BinSize = erlang:byte_size(Bin),
+ [{put_bits,BinSize-1,BitsNeeded,[1]},
+ {put_bits,Val,8*BinSize,[1,align]}].
+
per_enc_unconstrained(Val, Aligned) ->
case Aligned of
false -> [];
diff --git a/lib/asn1/test/asn1_SUITE_data/Prim.asn1 b/lib/asn1/test/asn1_SUITE_data/Prim.asn1
index b4c011fd39..4fe0901683 100644
--- a/lib/asn1/test/asn1_SUITE_data/Prim.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/Prim.asn1
@@ -60,4 +60,11 @@ BEGIN
e BOOLEAN,
magic INTEGER
}
+
+ Longitude ::= INTEGER {
+ oneMicrodegreeEast(10),
+ oneMicrodegreeWest(-10),
+ unavailable(1800000001)
+ } (-1799999999..1800000001)
+
END
diff --git a/lib/asn1/test/testPrim.erl b/lib/asn1/test/testPrim.erl
index 8fa9973ea5..dc2e0fa2e7 100644
--- a/lib/asn1/test/testPrim.erl
+++ b/lib/asn1/test/testPrim.erl
@@ -78,8 +78,37 @@ int(Rules) ->
roundtrip('ASeq', {'ASeq',false,250,true,200,true,199,true,77788}),
roundtrip('ASeq', {'ASeq',true,0,false,0,true,0,true,68789}),
+ %%==========================================================
+ %% Longitude ::= INTEGER {
+ %% oneMicrodegreeEast(10),
+ %% oneMicrodegreeWest(-10),
+ %% unavailable(1800000001)
+ %% } (-1799999999..1800000001)
+ %%==========================================================
+
+ Enc10 = encoding(Rules, oneMicrodegreeEast),
+ Enc10 = roundtrip('Longitude', oneMicrodegreeEast),
+ Enc10 = roundtrip('Longitude', 10, oneMicrodegreeEast),
+
+ Enc20 = encoding(Rules, oneMicrodegreeWest),
+ Enc20 = roundtrip('Longitude', oneMicrodegreeWest),
+ Enc20 = roundtrip('Longitude', -10, oneMicrodegreeWest),
+
+ Enc30 = roundtrip('Longitude', unavailable),
+ Enc30 = roundtrip('Longitude', 1800000001, unavailable),
+
ok.
+encoding(Rules, Type) ->
+ asn1_test_lib:hex_to_bin(encoding_1(Rules, Type)).
+
+encoding_1(ber, oneMicrodegreeEast) -> "02010A";
+encoding_1(per, oneMicrodegreeEast) -> "C06B49D2 09";
+encoding_1(uper, oneMicrodegreeEast) -> "6B49D209";
+
+encoding_1(ber, oneMicrodegreeWest) -> "0201F6";
+encoding_1(per, oneMicrodegreeWest) -> "C06B49D1 F5";
+encoding_1(uper, oneMicrodegreeWest) -> "6B49D1F5".
enum(Rules) ->
diff --git a/lib/compiler/src/beam_bool.erl b/lib/compiler/src/beam_bool.erl
index 14b6381230..d14be83496 100644
--- a/lib/compiler/src/beam_bool.erl
+++ b/lib/compiler/src/beam_bool.erl
@@ -142,11 +142,6 @@ bopt_block(Reg, Fail, OldIs, [{block,Bl0}|Acc0], St0) ->
throw:not_boolean_expr ->
failed;
- %% The block contains a 'move' instruction that could
- %% not be handled.
- throw:move ->
- failed;
-
%% The optimization is not safe. (A register
%% used by the instructions following the
%% optimized code is either not assigned a
@@ -215,37 +210,14 @@ ensure_opt_safe(Bl, NewCode, OldIs, Fail, PrecedingCode, St) ->
false -> throw(all_registers_not_killed);
true -> ok
end,
- Same = assigned_same_value(Bl, NewCode),
MustBeUnused = ordsets:subtract(ordsets:union(NotSet, NewDst),
- ordsets:union(MustBeKilled, Same)),
+ MustBeKilled),
case none_used(MustBeUnused, OldIs, Fail, St) of
false -> throw(registers_used);
true -> ok
end,
ok.
-%% assigned_same_value(OldCode, NewCodeReversed) -> [DestinationRegs]
-%% Return an ordset with a list of all y registers that are always
-%% assigned the same value in the old and new code. Currently, we
-%% are very conservative in that we only consider identical move
-%% instructions in the same order.
-%%
-assigned_same_value(Old, New) ->
- case reverse(New) of
- [{block,Bl}|_] ->
- assigned_same_value(Old, Bl, []);
- _ ->
- ordsets:new()
- end.
-
-assigned_same_value([{set,[{y,_}=D],[S],move}|T1],
- [{set,[{y,_}=D],[S],move}|T2], Acc) ->
- assigned_same_value(T1, T2, [D|Acc]);
-assigned_same_value(_, _, Acc) ->
- ordsets:from_list(Acc).
-
-update_fail_label([{set,_,_,move}=I|Is], Fail, Acc) ->
- update_fail_label(Is, Fail, [I|Acc]);
update_fail_label([{set,Ds,As,{bif,N,{f,_}}}|Is], Fail, Acc) ->
update_fail_label(Is, Fail, [{set,Ds,As,{bif,N,{f,Fail}}}|Acc]);
update_fail_label([{set,Ds,As,{alloc,Regs,{gc_bif,N,{f,_}}}}|Is], Fail, Acc) ->
@@ -314,8 +286,6 @@ split_block_1(Is, Fail, ProhibitFailLabel) ->
end
end.
-split_block_2([{set,_,_,move}=I|Is], Fail, Acc) ->
- split_block_2(Is, Fail, [I|Acc]);
split_block_2([{set,[_],_,{bif,_,{f,Fail}}}=I|Is], Fail, Acc) ->
split_block_2(Is, Fail, [I|Acc]);
split_block_2([{set,[_],_,{alloc,_,{gc_bif,_,{f,Fail}}}}=I|Is], Fail, Acc) ->
@@ -343,8 +313,6 @@ dst_regs([{set,[D],_,{bif,_,{f,_}}}|Is], Acc) ->
dst_regs(Is, [D|Acc]);
dst_regs([{set,[D],_,{alloc,_,{gc_bif,_,{f,_}}}}|Is], Acc) ->
dst_regs(Is, [D|Acc]);
-dst_regs([{set,[D],_,move}|Is], Acc) ->
- dst_regs(Is, [D|Acc]);
dst_regs([_|Is], Acc) ->
dst_regs(Is, Acc);
dst_regs([], Acc) -> ordsets:from_list(Acc).
@@ -411,13 +379,6 @@ bopt_tree([{protected,[Dst],Code,_}|Is], Forest0, Pre) ->
_Res ->
throw(not_boolean_expr)
end;
-bopt_tree([{set,[Dst],[Src],move}=Move|Is], Forest, Pre) ->
- case {Src,Dst} of
- {{tmp,_},_} -> throw(move);
- {_,{tmp,_}} -> throw(move);
- _ -> ok
- end,
- bopt_tree(Is, Forest, [Move|Pre]);
bopt_tree([{set,[Dst],As,{bif,N,_}}=Bif|Is], Forest0, Pre) ->
Ar = length(As),
case safe_bool_op(N, Ar) of
@@ -589,10 +550,6 @@ free_variables(Is) ->
E = gb_sets:empty(),
free_vars_1(Is, E, E, E).
-free_vars_1([{set,Ds,As,move}|Is], F0, N0, A) ->
- F = gb_sets:union(F0, gb_sets:difference(var_list(As), N0)),
- N = gb_sets:union(N0, var_list(Ds)),
- free_vars_1(Is, F, N, A);
free_vars_1([{set,Ds,As,{bif,_,_}}|Is], F0, N0, A) ->
F = gb_sets:union(F0, gb_sets:difference(var_list(As), N0)),
N = gb_sets:union(N0, var_list(Ds)),
@@ -632,8 +589,6 @@ free_vars_regs(X) -> [{x,X-1}|free_vars_regs(X-1)].
rename_regs(Is, Regs) ->
rename_regs(Is, Regs, []).
-rename_regs([{set,_,_,move}=I|Is], Regs, Acc) ->
- rename_regs(Is, Regs, [I|Acc]);
rename_regs([{set,[Dst0],Ss0,{alloc,_,Info}}|Is], Regs0, Acc) ->
Live = live_regs(Regs0),
Ss = rename_sources(Ss0, Regs0),
@@ -737,8 +692,7 @@ ssa_assign({x,_}=R, #ssa{sub=Sub0}=Ssa0) ->
Sub1 = gb_trees:update(R, NewReg, Sub0),
Sub = gb_trees:insert(NewReg, NewReg, Sub1),
Ssa#ssa{sub=Sub}
- end;
-ssa_assign(_, Ssa) -> Ssa.
+ end.
ssa_sub_list(List, Sub) ->
[ssa_sub(E, Sub) || E <- List].
diff --git a/lib/compiler/src/cerl.erl b/lib/compiler/src/cerl.erl
index 010327b5e3..e7a2b8177a 100644
--- a/lib/compiler/src/cerl.erl
+++ b/lib/compiler/src/cerl.erl
@@ -1598,13 +1598,20 @@ is_c_map(#c_literal{val = V}) when is_map(V) ->
is_c_map(_) ->
false.
--spec map_es(c_map()) -> [c_map_pair()].
+-spec map_es(c_map() | c_literal()) -> [c_map_pair()].
+map_es(#c_literal{anno=As,val=M}) when is_map(M) ->
+ [ann_c_map_pair(As,
+ #c_literal{anno=As,val='assoc'},
+ #c_literal{anno=As,val=K},
+ #c_literal{anno=As,val=V}) || {K,V} <- maps:to_list(M)];
map_es(#c_map{es = Es}) ->
Es.
--spec map_arg(c_map()) -> c_map() | c_literal().
+-spec map_arg(c_map() | c_literal()) -> c_map() | c_literal().
+map_arg(#c_literal{anno=As,val=M}) when is_map(M) ->
+ #c_literal{anno=As,val=#{}};
map_arg(#c_map{arg=M}) ->
M.
diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl
index 34c67b16ca..2a89305f4d 100644
--- a/lib/compiler/src/v3_codegen.erl
+++ b/lib/compiler/src/v3_codegen.erl
@@ -1327,12 +1327,13 @@ bif_cg(Bif, As, [{var,V}], Le, Vdb, Bef, St0) ->
%% that we save any variable that will be live after this BIF call.
MayFail = not erl_bifs:is_safe(erlang, Bif, length(As)),
- {Sis,Int0} = case St0#cg.in_catch andalso
- St0#cg.bfail =:= 0 andalso
- MayFail of
- true -> adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb);
- false -> {[],Bef}
- end,
+ {Sis,Int0} =
+ case MayFail of
+ true ->
+ maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St0);
+ false ->
+ {[],Bef}
+ end,
Int1 = clear_dead(Int0, Le#l.i, Vdb),
Reg = put_reg(V, Int1#sr.reg),
Int = Int1#sr{reg=Reg},
@@ -1363,11 +1364,7 @@ gc_bif_cg(Bif, As, [{var,V}], Le, Vdb, Bef, St0) ->
%% Currently, we are somewhat pessimistic in
%% that we save any variable that will be live after this BIF call.
- {Sis,Int0} =
- case St0#cg.in_catch andalso St0#cg.bfail =:= 0 of
- true -> adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb);
- false -> {[],Bef}
- end,
+ {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St0),
Int1 = clear_dead(Int0, Le#l.i, Vdb),
Reg = put_reg(V, Int1#sr.reg),
@@ -1512,8 +1509,7 @@ set_cg([{var,R}], {cons,Es}, Le, Vdb, Bef, St) ->
Int1 = Int0#sr{reg=put_reg(R, Int0#sr.reg)},
Ret = fetch_reg(R, Int1#sr.reg),
{[{put_list,S1,S2,Ret}], Int1, St};
-set_cg([{var,R}], {binary,Segs}, Le, Vdb, Bef,
- #cg{in_catch=InCatch, bfail=Bfail}=St) ->
+set_cg([{var,R}], {binary,Segs}, Le, Vdb, Bef, #cg{bfail=Bfail}=St) ->
%% At run-time, binaries are constructed in three stages:
%% 1) First the size of the binary is calculated.
%% 2) Then the binary is allocated.
@@ -1532,11 +1528,7 @@ set_cg([{var,R}], {binary,Segs}, Le, Vdb, Bef,
%% First generate the code that constructs each field.
Fail = {f,Bfail},
PutCode = cg_bin_put(Segs, Fail, Bef),
- {Sis,Int1} =
- case InCatch of
- true -> adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb);
- false -> {[],Int0}
- end,
+ {Sis,Int1} = maybe_adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb, St),
MaxRegs = max_reg(Bef#sr.reg),
Aft = clear_dead(Int1, Le#l.i, Vdb),
@@ -1545,14 +1537,11 @@ set_cg([{var,R}], {binary,Segs}, Le, Vdb, Bef,
{Sis++Code,Aft,St};
% Map single variable key
set_cg([{var,R}], {map,Op,Map,[{map_pair,{var,_}=K,V}]}, Le, Vdb, Bef,
- #cg{in_catch=InCatch,bfail=Bfail}=St) ->
+ #cg{bfail=Bfail}=St) ->
Fail = {f,Bfail},
- {Sis,Int0} =
- case InCatch of
- true -> adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb);
- false -> {[],Bef}
- end,
+ {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St),
+
SrcReg = cg_reg_arg(Map,Int0),
Line = line(Le#l.a),
@@ -1573,17 +1562,13 @@ set_cg([{var,R}], {map,Op,Map,[{map_pair,{var,_}=K,V}]}, Le, Vdb, Bef,
% Map (possibly) multiple literal keys
set_cg([{var,R}], {map,Op,Map,Es}, Le, Vdb, Bef,
- #cg{in_catch=InCatch,bfail=Bfail}=St) ->
+ #cg{bfail=Bfail}=St) ->
%% assert key literals
[] = [Var||{map_pair,{var,_}=Var,_} <- Es],
Fail = {f,Bfail},
- {Sis,Int0} =
- case InCatch of
- true -> adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb);
- false -> {[],Bef}
- end,
+ {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St),
SrcReg = cg_reg_arg(Map,Int0),
Line = line(Le#l.a),
@@ -2038,6 +2023,19 @@ trim_free([R|Rs0]) ->
end;
trim_free([]) -> [].
+%% maybe_adjust_stack(Bef, FirstBefore, LastFrom, Vdb, St) -> {[Ainstr],Aft}.
+%% Adjust the stack, but only if the code is inside a catch and not
+%% inside a guard. Use this funtion before instructions that may
+%% cause an exception.
+
+maybe_adjust_stack(Bef, Fb, Lf, Vdb, St) ->
+ case St of
+ #cg{in_catch=true,bfail=0} ->
+ adjust_stack(Bef, Fb, Lf, Vdb);
+ #cg{} ->
+ {[],Bef}
+ end.
+
%% adjust_stack(Bef, FirstBefore, LastFrom, Vdb) -> {[Ainstr],Aft}.
%% Do complete stack adjustment by compressing stack and adding
%% variables to be saved. Try to optimise ordering on stack by
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 0941ad5dd5..7d93e2ae16 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -804,7 +804,7 @@ map_op(map_field_assoc) -> #c_literal{val=assoc};
map_op(map_field_exact) -> #c_literal{val=exact}.
is_valid_map_src(#c_literal{val = M}) when is_map(M) -> true;
-is_valid_map_src(#c_var{}) -> true;
+is_valid_map_src(#c_var{}=Var) -> not cerl:is_c_fname(Var);
is_valid_map_src(_) -> false.
%% try_exception([ExcpClause], St) -> {[ExcpVar],Handler,St}.
diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl
index b3b67155b3..47eb1ba78b 100644
--- a/lib/compiler/test/guard_SUITE.erl
+++ b/lib/compiler/test/guard_SUITE.erl
@@ -34,7 +34,8 @@
tricky/1,rel_ops/1,rel_op_combinations/1,literal_type_tests/1,
basic_andalso_orelse/1,traverse_dcd/1,
check_qlc_hrl/1,andalso_semi/1,t_tuple_size/1,binary_part/1,
- bad_constants/1,bad_guards/1]).
+ bad_constants/1,bad_guards/1,scotland/1,
+ guard_in_catch/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -52,7 +53,7 @@ groups() ->
rel_ops,rel_op_combinations,
literal_type_tests,basic_andalso_orelse,traverse_dcd,
check_qlc_hrl,andalso_semi,t_tuple_size,binary_part,
- bad_constants,bad_guards]}].
+ bad_constants,bad_guards,scotland,guard_in_catch]}].
init_per_suite(Config) ->
Config.
@@ -1831,6 +1832,80 @@ bad_guards_2(M, [_]) when M#{a := 0, b => 0}, map_size(M) ->
bad_guards_3(M, [_]) when is_map(M) andalso M#{a := 0, b => 0}, length(M) ->
ok.
+%% beam_bool would remove the initialization of {y,0}.
+%% (Thanks to Thomas Arts and QuickCheck.)
+
+scotland(_Config) ->
+ million = do_scotland(placed),
+ {'EXIT',{{badmatch,placed},_}} = (catch do_scotland(false)),
+ {'EXIT',{{badmatch,placed},_}} = (catch do_scotland(true)),
+ {'EXIT',{{badmatch,placed},_}} = (catch do_scotland(echo)),
+ ok.
+
+do_scotland(Echo) ->
+ found(case Echo of
+ Echo when true; Echo, Echo, Echo ->
+ Echo;
+ echo ->
+ []
+ end,
+ Echo = placed).
+
+found(_, _) -> million.
+
+%% Building maps in a guard in a 'catch' would crash v3_codegen.
+
+guard_in_catch(_Config) ->
+ {'EXIT',{if_clause,_}} = do_guard_in_catch_map_1(#{}),
+ {'EXIT',{if_clause,_}} = do_guard_in_catch_map_1(#{a=>b}),
+ {'EXIT',{if_clause,_}} = do_guard_in_catch_map_1(atom),
+
+ {'EXIT',{if_clause,_}} = do_guard_in_catch_map_2(#{}),
+ {'EXIT',{if_clause,_}} = do_guard_in_catch_map_2(#{a=>b}),
+ {'EXIT',{if_clause,_}} = do_guard_in_catch_map_2(atom),
+
+ {'EXIT',{if_clause,_}} = (catch do_guard_in_catch_map_3()),
+
+ {'EXIT',{if_clause,_}} = do_guard_in_catch_bin(42),
+ {'EXIT',{if_clause,_}} = do_guard_in_catch_bin(<<1,2,3>>),
+ {'EXIT',{if_clause,_}} = do_guard_in_catch_bin(atom),
+ {'EXIT',{if_clause,_}} = do_guard_in_catch_bin(#{}),
+
+ ok.
+
+do_guard_in_catch_map_1(From) ->
+ catch
+ if
+ From#{[] => sufficient} ->
+ saint
+ end.
+
+do_guard_in_catch_map_2(From) ->
+ catch
+ if
+ From#{From => sufficient} ->
+ saint
+ end.
+
+do_guard_in_catch_map_3() ->
+ try
+ if [] -> solo end
+ catch
+ Friendly when Friendly#{0 => []} -> minutes
+ after
+ membership
+ end.
+
+do_guard_in_catch_bin(From) ->
+ %% Would not crash v3_codegen, but there would be an unnecessary
+ %% 'move' to a Y register.
+ catch
+ if
+ <<From:32>> ->
+ saint
+ end.
+
+
%% Call this function to turn off constant propagation.
id(I) -> I.
diff --git a/lib/compiler/test/map_SUITE.erl b/lib/compiler/test/map_SUITE.erl
index 411b15eebe..cff3b5deb4 100644
--- a/lib/compiler/test/map_SUITE.erl
+++ b/lib/compiler/test/map_SUITE.erl
@@ -883,6 +883,9 @@ t_update_map_expressions(Config) when is_list(Config) ->
%% Error cases.
{'EXIT',{{badmap,<<>>},_}} = (catch (id(<<>>))#{ a := 42, b => 2 }),
{'EXIT',{{badmap,[]},_}} = (catch (id([]))#{ a := 42, b => 2 }),
+ {'EXIT',{{badmap,_},_}} =
+ (catch (fun t_update_map_expressions/1)#{u => 42}),
+
ok.
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 9de8dc74c2..3c73c318ed 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -2042,6 +2042,7 @@ static ERL_NIF_TERM aes_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
ErlNifBinary key_bin, data_bin;
AES_KEY aes_key;
int i;
+ int j;
unsigned char* ret_ptr;
ERL_NIF_TERM ret;
@@ -2064,7 +2065,9 @@ static ERL_NIF_TERM aes_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
}
ret_ptr = enif_make_new_binary(env, data_bin.size, &ret);
- AES_ecb_encrypt(data_bin.data, ret_ptr, &aes_key, i);
+ for (j = 0; j < data_bin.size; j += 16) {
+ AES_ecb_encrypt(data_bin.data+j, ret_ptr+j, &aes_key, i);
+ }
CONSUME_REDS(env,data_bin);
return ret;
}
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index e84f5e1075..802c8a4df4 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -1301,7 +1301,23 @@ aes_ecb() ->
<<"0000000000000000">>},
{aes_ecb,
<<"FEDCBA9876543210">>,
- <<"FFFFFFFFFFFFFFFF">>}
+ <<"FFFFFFFFFFFFFFFF">>},
+ %% AES ECB test vectors from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
+ %% F.1.1 ECB-AES128.Encrypt, F.1.2 ECB-AES128.Decrypt
+ {aes_ecb,
+ hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a"
+ "ae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52ef"
+ "f69f2445df4f9b17ad2b417be66c3710")},
+ %% F.1.5 ECB-AES256.Encrypt, F.1.6 ECB-AES256.Decrypt
+ {aes_ecb,
+ hexstr2bin("603deb1015ca71be2b73aef0857d7781"
+ "1f352c073b6108d72d9810a30914dff4"),
+ hexstr2bin("6bc1bee22e409f96e93d7e117393172a"
+ "ae2d8a571e03ac9c9eb76fac45af8e51"
+ "30c81c46a35ce411e5fbc1191a0a52ef"
+ "f69f2445df4f9b17ad2b417be66c3710")}
].
aes_ige256() ->
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index c57a22129c..826ac51775 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -624,6 +624,28 @@ find_call_file_and_line(Tree, MFA) ->
MFA ->
Ann = cerl:get_ann(SubTree),
[{get_file(Ann), get_line(Ann)}|Acc];
+ {erlang, make_fun, 3} ->
+ [CA1, CA2, CA3] = cerl:call_args(SubTree),
+ case
+ cerl:is_c_atom(CA1) andalso
+ cerl:is_c_atom(CA2) andalso
+ cerl:is_c_int(CA3)
+ of
+ true ->
+ case
+ {cerl:concrete(CA1),
+ cerl:concrete(CA2),
+ cerl:concrete(CA3)}
+ of
+ MFA ->
+ Ann = cerl:get_ann(SubTree),
+ [{get_file(Ann), get_line(Ann)}|Acc];
+ _ ->
+ Acc
+ end;
+ false ->
+ Acc
+ end;
_ -> Acc
end;
false -> Acc
diff --git a/lib/dialyzer/src/dialyzer_callgraph.erl b/lib/dialyzer/src/dialyzer_callgraph.erl
index a1cd2015ca..9e53e171c0 100644
--- a/lib/dialyzer/src/dialyzer_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_callgraph.erl
@@ -478,14 +478,37 @@ scan_one_core_fun(TopTree, FunName) ->
call ->
CalleeM = cerl:call_module(Tree),
CalleeF = cerl:call_name(Tree),
- A = length(cerl:call_args(Tree)),
+ CalleeArgs = cerl:call_args(Tree),
+ A = length(CalleeArgs),
case (cerl:is_c_atom(CalleeM) andalso
cerl:is_c_atom(CalleeF)) of
true ->
M = cerl:atom_val(CalleeM),
F = cerl:atom_val(CalleeF),
case erl_bif_types:is_known(M, F, A) of
- true -> Acc;
+ true ->
+ case {M, F, A} of
+ {erlang, make_fun, 3} ->
+ [CA1, CA2, CA3] = CalleeArgs,
+ case
+ cerl:is_c_atom(CA1) andalso
+ cerl:is_c_atom(CA2) andalso
+ cerl:is_c_int(CA3)
+ of
+ true ->
+ MM = cerl:atom_val(CA1),
+ FF = cerl:atom_val(CA2),
+ AA = cerl:int_val(CA3),
+ case erl_bif_types:is_known(MM, FF, AA) of
+ true -> Acc;
+ false -> [{FunName, {MM, FF, AA}}|Acc]
+ end;
+ false ->
+ Acc
+ end;
+ _ ->
+ Acc
+ end;
false -> [{FunName, {M, F, A}}|Acc]
end;
false ->
diff --git a/lib/dialyzer/test/small_SUITE_data/results/fun_arity b/lib/dialyzer/test/small_SUITE_data/results/fun_arity
index 280f5490d0..cc9db65152 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/fun_arity
+++ b/lib/dialyzer/test/small_SUITE_data/results/fun_arity
@@ -31,5 +31,7 @@ fun_arity.erl:81: Function mfa_ne_1_ko/0 has no local return
fun_arity.erl:83: Function mf_ne/1 will never be called
fun_arity.erl:89: Fun application will fail since _cor0 :: fun(() -> any()) is not a function of arity 1
fun_arity.erl:89: Function mfa_nd_0_ko/0 has no local return
+fun_arity.erl:90: Call to missing or unexported function fun_arity:mf_nd/0
fun_arity.erl:93: Fun application will fail since _cor0 :: fun((_) -> any()) is not a function of arity 0
fun_arity.erl:93: Function mfa_nd_1_ko/0 has no local return
+fun_arity.erl:94: Call to missing or unexported function fun_arity:mf_nd/1
diff --git a/lib/dialyzer/test/small_SUITE_data/results/maps1 b/lib/dialyzer/test/small_SUITE_data/results/maps1
new file mode 100644
index 0000000000..5a78d66a92
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/maps1
@@ -0,0 +1,4 @@
+
+maps1.erl:43: Function t3/0 has no local return
+maps1.erl:44: The call maps1:foo(~{'greger'=>3, ~{'arne'=>'anka'}~=>45}~,1) will never return since it differs in the 2nd argument from the success typing arguments: (#{},'b')
+maps1.erl:52: The call Mod:'function'(~{'literal'=>'map'}~,'another_arg') requires that Mod is of type atom() | tuple() not #{}
diff --git a/lib/dialyzer/test/small_SUITE_data/results/non_existing b/lib/dialyzer/test/small_SUITE_data/results/non_existing
index 58da2bfc8b..b0da5998c7 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/non_existing
+++ b/lib/dialyzer/test/small_SUITE_data/results/non_existing
@@ -1,2 +1,3 @@
+non_existing.erl:12: Call to missing or unexported function lists:non_existing_fun/1
non_existing.erl:9: Call to missing or unexported function lists:non_existing_call/1
diff --git a/lib/dialyzer/test/small_SUITE_data/src/maps1.erl b/lib/dialyzer/test/small_SUITE_data/src/maps1.erl
index 06ced5b69e..bb2f66a498 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/maps1.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/maps1.erl
@@ -39,3 +39,15 @@ t2() -> ok.
update(#{ id := Id, val := Val } = M, X) when is_integer(Id) ->
M#{ val := [Val,X] }.
+
+t3() ->
+ foo(#{greger => 3, #{arne=>anka} => 45}, 1).
+
+foo(#{} = M, b) -> %% Error
+ M#{alfa => 42, beta := 1337}.
+
+t4() ->
+ case #{} of
+ #{} -> ok;
+ Mod -> Mod:function(#{literal => map}, another_arg) %% Error
+ end.
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index 13508321c3..d49176ec3e 100644
--- a/lib/diameter/src/base/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -208,7 +208,7 @@ stop_transport(SvcName, [_|_] = Refs) ->
info(SvcName, Item) ->
case lookup_state(SvcName) of
- [#state{} = S] ->
+ [S] ->
service_info(Item, S);
[] ->
undefined
@@ -217,7 +217,12 @@ info(SvcName, Item) ->
%% lookup_state/1
lookup_state(SvcName) ->
- ets:lookup(?STATE_TABLE, SvcName).
+ case ets:lookup(?STATE_TABLE, SvcName) of
+ [#state{}] = L ->
+ L;
+ _ ->
+ []
+ end.
%% ---------------------------------------------------------------------------
%% # subscribe/1
diff --git a/lib/diameter/src/diameter.appup.src b/lib/diameter/src/diameter.appup.src
index ddde648e08..de0f324f47 100644
--- a/lib/diameter/src/diameter.appup.src
+++ b/lib/diameter/src/diameter.appup.src
@@ -44,6 +44,7 @@
{"1.9.1", [{restart_application, diameter}]}, %% 17.5.3
{"1.9.2", [{restart_application, diameter}]}, %% 17.5.5
{"1.9.2.1", [{restart_application, diameter}]}, %% 17.5.6.3
+ {"1.9.2.2", [{restart_application, diameter}]}, %% 17.5.6.7
{"1.10", [{load_module, diameter_codec}, %% 18.0
{load_module, diameter_peer_fsm},
{load_module, diameter_watchdog},
@@ -87,6 +88,7 @@
{"1.9.1", [{restart_application, diameter}]},
{"1.9.2", [{restart_application, diameter}]},
{"1.9.2.1", [{restart_application, diameter}]},
+ {"1.9.2.2", [{restart_application, diameter}]},
{"1.10", [{load_module, diameter_gen_relay},
{load_module, diameter_gen_base_accounting},
{load_module, diameter_gen_base_rfc3588},
diff --git a/lib/edoc/src/edoc_specs.erl b/lib/edoc/src/edoc_specs.erl
index bb98e8b04f..f2e5891c2e 100644
--- a/lib/edoc/src/edoc_specs.erl
+++ b/lib/edoc/src/edoc_specs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
@@ -270,12 +270,8 @@ parms([], []) ->
parms([A | As], [D | Ds]) ->
[param(A, D) | parms(As, Ds)].
-param(#t_list{type = Type}, Default) ->
- param(Type, Default);
param(#t_paren{type = Type}, Default) ->
param(Type, Default);
-param(#t_nonempty_list{type = Type}, Default) ->
- param(Type, Default);
param(#t_record{name = #t_atom{val = Name}}, _Default) ->
list_to_atom(capitalize(atom_to_list(Name)));
param(T, Default) ->
diff --git a/lib/hipe/cerl/cerl_prettypr.erl b/lib/hipe/cerl/cerl_prettypr.erl
index 7e8b7f60bd..1a6e6999fe 100644
--- a/lib/hipe/cerl/cerl_prettypr.erl
+++ b/lib/hipe/cerl/cerl_prettypr.erl
@@ -64,8 +64,8 @@
seq_arg/1, seq_body/1, string_lit/1, try_arg/1,
try_body/1, try_vars/1, try_evars/1, try_handler/1,
tuple_es/1, type/1, values_es/1, var_name/1,
- c_map/1, map_arg/1, map_es/1, is_c_map_empty/1,
- c_map_pair/2, map_pair_key/1, map_pair_val/1, map_pair_op/1
+ map_arg/1, map_es/1, is_c_map_empty/1,
+ map_pair_key/1, map_pair_val/1, map_pair_op/1
]).
-define(PAPER, 76).
@@ -499,12 +499,8 @@ lay_literal(Node, Ctxt) ->
lay_cons(Node, Ctxt);
V when is_tuple(V) ->
lay_tuple(Node, Ctxt);
- M when is_map(M), map_size(M) =:= 0 ->
- text("~{}~");
M when is_map(M) ->
- lay_map(c_map([c_map_pair(abstract(K),abstract(V))
- || {K,V} <- maps:to_list(M)]),
- Ctxt)
+ lay_map(Node, Ctxt)
end.
lay_var(Node, Ctxt) ->
@@ -627,12 +623,10 @@ lay_map_pair(Node, Ctxt) ->
K = map_pair_key(Node),
V = map_pair_val(Node),
OpTxt = case concrete(map_pair_op(Node)) of
- assoc -> "::<";
- exact -> "~<"
+ assoc -> "=>";
+ exact -> ":="
end,
- beside(floating(text(OpTxt)),
- beside(lay(K,Ctxt),beside(floating(text(",")), beside(lay(V,Ctxt),
- floating(text(">")))))).
+ beside(lay(K,Ctxt),beside(floating(text(OpTxt)),lay(V,Ctxt))).
lay_let(Node, Ctxt) ->
V = lay_value_list(let_vars(Node), Ctxt),
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index cd2d2fe207..7a2abc226f 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -2711,7 +2711,6 @@ is_compat_args([A1|Args1], [A2|Args2]) ->
is_compat_args([], []) -> true;
is_compat_args(_, _) -> false.
-is_compat_arg(A, A) -> true;
is_compat_arg(A1, A2) ->
is_specialization(A1, A2) orelse is_specialization(A2, A1).
@@ -2722,6 +2721,7 @@ is_compat_arg(A1, A2) ->
%% any(). For example, {_,_} is a specialization of any(), but not of
%% tuple(). Does not handle variables, but any() and unions (sort of).
+is_specialization(T, T) -> true;
is_specialization(_, ?any) -> true;
is_specialization(?any, _) -> false;
is_specialization(?function(Domain1, Range1), ?function(Domain2, Range2)) ->
@@ -2747,8 +2747,8 @@ is_specialization(?tuple(Elements1, Arity, _),
specialization_list(Elements1, sup_tuple_elements(List));
is_specialization(?tuple_set(List1), ?tuple_set(List2)) ->
try
- specialization_list(lists:append([T || {_Arity, T} <- List1]),
- lists:append([T || {_Arity, T} <- List2]))
+ specialization_list_list([sup_tuple_elements(T) || {_Arity, T} <- List1],
+ [sup_tuple_elements(T) || {_Arity, T} <- List2])
catch _:_ -> false
end;
is_specialization(?union(List1)=T1, ?union(List2)=T2) ->
@@ -2772,13 +2772,19 @@ is_specialization(T1, ?opaque(_) = T2) ->
is_specialization(T1, t_opaque_structure(T2));
is_specialization(?var(_), _) -> exit(error);
is_specialization(_, ?var(_)) -> exit(error);
-is_specialization(T, T) -> true;
is_specialization(?none, _) -> false;
is_specialization(_, ?none) -> false;
is_specialization(?unit, _) -> false;
is_specialization(_, ?unit) -> false;
is_specialization(#c{}, #c{}) -> false.
+specialization_list_list(LL1, LL2) ->
+ length(LL1) =:= length(LL2) andalso specialization_list_list1(LL1, LL2).
+
+specialization_list_list1([], []) -> true;
+specialization_list_list1([L1|LL1], [L2|LL2]) ->
+ specialization_list(L1, L2) andalso specialization_list_list1(LL1, LL2).
+
specialization_list(L1, L2) ->
length(L1) =:= length(L2) andalso specialization_list1(L1, L2).
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 8fb689fdd5..75e1615c09 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,24 @@
<file>notes.xml</file>
</header>
+<section><title>Ssh 4.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The authentication method 'keyboard-interactive' failed
+ in the Erlang client when the server after successful
+ authentication continued by asking for zero more
+ passwords.</p>
+ <p>
+ Own Id: OTP-13225</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 4.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index fdbb5c152a..b71bed033a 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -477,7 +477,7 @@ keyboard_interact_get_responses(_, undefined, Password, _, _, _, _, _,
1) when Password =/= undefined ->
[Password]; %% Password auth implemented with keyboard-interaction and passwd is known
keyboard_interact_get_responses(_, _, _, _, _, _, _, _, 0) ->
- [""];
+ [];
keyboard_interact_get_responses(false, undefined, undefined, _, _, _, [Prompt|_], Opts, _) ->
ssh_no_io:read_line(Prompt, Opts); %% Throws error as keyboard interaction is not allowed
keyboard_interact_get_responses(true, undefined, _,IoCb, Name, Instr, PromptInfos, Opts, _) ->
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index f082db136c..ce1931e4f4 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -648,10 +648,12 @@ userauth_keyboard_interactive(Msg = #ssh_msg_userauth_failure{},
userauth_keyboard_interactive_info_response(Msg=#ssh_msg_userauth_failure{},
#state{ssh_params = #ssh{role = client}} = State) ->
userauth(Msg, State);
-
userauth_keyboard_interactive_info_response(Msg=#ssh_msg_userauth_success{},
#state{ssh_params = #ssh{role = client}} = State) ->
- userauth(Msg, State).
+ userauth(Msg, State);
+userauth_keyboard_interactive_info_response(Msg=#ssh_msg_userauth_info_request{},
+ #state{ssh_params = #ssh{role = client}} = State) ->
+ userauth_keyboard_interactive(Msg, State).
%%--------------------------------------------------------------------
-spec connected({#ssh_msg_kexinit{}, binary()}, %%| %% #ssh_msg_kexdh_init{},
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index 781a876723..9cd98f069f 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -35,9 +35,8 @@ MODULES= \
ssh_algorithms_SUITE \
ssh_options_SUITE \
ssh_renegotiate_SUITE \
- \
ssh_basic_SUITE \
- \
+ ssh_benchmark_SUITE \
ssh_connection_SUITE \
ssh_protocol_SUITE \
ssh_sftp_SUITE \
@@ -129,7 +128,7 @@ release_spec: opt
release_tests_spec: opt
$(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)"
- $(INSTALL_DATA) ssh.spec ssh.cover "$(RELSYSDIR)"
+ $(INSTALL_DATA) ssh.spec ssh_bench.spec ssh.cover "$(RELSYSDIR)"
$(INSTALL_DATA) $(HRL_FILES_NEEDED_IN_TEST) "$(RELSYSDIR)"
chmod -R u+w "$(RELSYSDIR)"
@tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
diff --git a/lib/ssh/test/ssh.spec b/lib/ssh/test/ssh.spec
index 8de0fe44e4..0076fc275e 100644
--- a/lib/ssh/test/ssh.spec
+++ b/lib/ssh/test/ssh.spec
@@ -1,7 +1,6 @@
{suites,"../ssh_test",all}.
-{skip_cases,"../ssh_test",ssh_ssh_SUITE,
- [ssh],
- "Current implementation is timingdependent and\nhence will succeed/fail on a whim"}.
-{skip_cases,"../ssh_test",ssh_ssh_SUITE,
- [ssh_compressed],
- "Current implementation is timingdependent hence will succeed/fail on a whim"}.
+
+{skip_suites, "../ssh_test", [ssh_benchmark_SUITE],
+ "Benchmarks run separately"}.
+
+
diff --git a/lib/ssh/test/ssh_bench.spec b/lib/ssh/test/ssh_bench.spec
new file mode 100644
index 0000000000..029f0bd074
--- /dev/null
+++ b/lib/ssh/test/ssh_bench.spec
@@ -0,0 +1 @@
+{suites,"../ssh_test",[ssh_benchmark_SUITE]}.
diff --git a/lib/ssh/test/ssh_benchmark_SUITE.erl b/lib/ssh/test/ssh_benchmark_SUITE.erl
new file mode 100644
index 0000000000..e90bfa3d16
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE.erl
@@ -0,0 +1,539 @@
+%%%-------------------------------------------------------------------
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2015. 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.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(ssh_benchmark_SUITE).
+-compile(export_all).
+
+-include_lib("common_test/include/ct_event.hrl").
+-include_lib("common_test/include/ct.hrl").
+
+-include_lib("ssh/src/ssh.hrl").
+-include_lib("ssh/src/ssh_transport.hrl").
+-include_lib("ssh/src/ssh_connect.hrl").
+-include_lib("ssh/src/ssh_userauth.hrl").
+
+
+suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]}].
+%%suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() -> [{group, opensshc_erld}
+%% {group, erlc_opensshd}
+ ].
+
+groups() ->
+ [{opensshc_erld, [{repeat, 3}], [openssh_client_shell,
+ openssh_client_sftp]}
+ ].
+
+
+init_per_suite(Config) ->
+ catch ssh:stop(),
+ catch crypto:stop(),
+ try
+ ok = crypto:start(),
+ report_client_algorithms(),
+ ok = ssh:start(),
+ {ok,TracerPid} = erlang_trace(),
+ [{tracer_pid,TracerPid} | init_sftp_dirs(Config)]
+ catch
+ C:E ->
+ {skip, io_lib:format("Couldn't start ~p:~p",[C,E])}
+ end.
+
+end_per_suite(_Config) ->
+ catch ssh:stop(),
+ catch crypto:stop(),
+ ok.
+
+
+
+init_per_group(opensshc_erld, Config) ->
+ case ssh_test_lib:ssh_type() of
+ openSSH ->
+ DataDir = ?config(data_dir, Config),
+ UserDir = ?config(priv_dir, Config),
+ ssh_test_lib:setup_dsa(DataDir, UserDir),
+ ssh_test_lib:setup_rsa(DataDir, UserDir),
+ ssh_test_lib:setup_ecdsa("256", DataDir, UserDir),
+ Common = ssh_test_lib:intersect_bi_dir(
+ ssh_test_lib:intersection(ssh:default_algorithms(),
+ ssh_test_lib:default_algorithms(sshc))),
+ [{c_kexs, ssh_test_lib:sshc(kex)},
+ {c_ciphers, ssh_test_lib:sshc(cipher)},
+ {common_algs, Common}
+ | Config];
+ _ ->
+ {skip, "No OpenSsh client found"}
+ end;
+
+init_per_group(erlc_opensshd, _) ->
+ {skip, "Group erlc_opensshd not implemented"};
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, _Config) ->
+ ok.
+
+
+init_per_testcase(_Func, Conf) ->
+ Conf.
+
+end_per_testcase(_Func, _Conf) ->
+ ok.
+
+
+init_sftp_dirs(Config) ->
+ UserDir = ?config(priv_dir, Config),
+ SrcDir = filename:join(UserDir, "sftp_src"),
+ ok = file:make_dir(SrcDir),
+ SrcFile = "big_data",
+ DstDir = filename:join(UserDir, "sftp_dst"),
+ ok = file:make_dir(DstDir),
+ N = 100 * 1024*1024,
+ ok = file:write_file(filename:join(SrcDir,SrcFile), crypto:rand_bytes(N)),
+ [{sftp_src_dir,SrcDir}, {sftp_dst_dir,DstDir}, {src_file,SrcFile}, {sftp_size,N}
+ | Config].
+
+%%%================================================================
+openssh_client_shell(Config) ->
+ lists:foreach(
+ fun(PrefAlgs=[{kex,[Kex]}]) when Kex == 'diffie-hellman-group-exchange-sha256' ->
+ lists:foreach(
+ fun(Grp) ->
+ openssh_client_shell(Config,
+ [{preferred_algorithms, PrefAlgs},
+ {dh_gex_groups, [Grp]}
+ ])
+ end, moduli());
+ (PrefAlgs) ->
+ openssh_client_shell(Config,
+ [{preferred_algorithms, PrefAlgs}])
+ end, variants(kex,Config) ++ variants(cipher,Config)
+ ).
+
+
+openssh_client_shell(Config, Options) ->
+ SystemDir = ?config(data_dir, Config),
+ UserDir = ?config(priv_dir, Config),
+ KnownHosts = filename:join(UserDir, "known_hosts"),
+
+ {ok, TracerPid} = erlang_trace(),
+ {ServerPid, _Host, Port} =
+ ssh_test_lib:daemon([{system_dir, SystemDir},
+ {public_key_alg, ssh_dsa},
+ {failfun, fun ssh_test_lib:failfun/2} |
+ Options]),
+ ct:sleep(500),
+
+ Data = lists:duplicate(100000, $a),
+ Cmd = lists:concat(["ssh -p ",Port,
+ " -o UserKnownHostsFile=", KnownHosts,
+ " -o \"StrictHostKeyChecking no\"",
+ " localhost '\"",Data,"\"'."]),
+%% ct:pal("Cmd ="++Cmd),
+
+ Parent = self(),
+ SlavePid = spawn(fun() ->
+ Parent ! {self(),os:cmd(Cmd)}
+ end),
+ receive
+ {SlavePid, _ClientResponse} ->
+%% ct:pal("ClientResponse = ~p",[_ClientResponse]),
+ {ok, List} = get_trace_list(TracerPid),
+ Times = find_times(List, [accept_to_hello, kex, kex_to_auth, auth, to_prompt]),
+ Algs = find_algs(List),
+ ct:pal("Algorithms = ~p~n~nTimes = ~p",[Algs,Times]),
+ lists:foreach(
+ fun({Tag,Value,Unit}) ->
+ EventData =
+ case Tag of
+ {A,B} when A==encrypt ; A==decrypt ->
+ [{value, Value},
+ {suite, ?MODULE},
+ {name, mk_name(["Cipher ",A," ",B," [",Unit,"]"])}
+ ];
+ kex ->
+ KexAlgStr = fmt_alg(Algs#alg.kex, List),
+ [{value, Value},
+ {suite, ?MODULE},
+ {name, mk_name(["Erl server kex ",KexAlgStr," [",Unit,"]"])}
+ ];
+ _ when is_atom(Tag) ->
+ [{value, Value},
+ {suite, ?MODULE},
+ {name, mk_name(["Erl server ",Tag," [",Unit,"]"])}
+ ]
+ end,
+ ct:pal("ct_event:notify ~p",[EventData]),
+ ct_event:notify(#event{name = benchmark_data,
+ data = EventData})
+ end, Times),
+ ssh:stop_daemon(ServerPid),
+ ok
+ after 10000 ->
+ ssh:stop_daemon(ServerPid),
+ exit(SlavePid, kill),
+ {fail, timeout}
+ end.
+
+
+%%%================================================================
+openssh_client_sftp(Config) ->
+ lists:foreach(
+ fun(PrefAlgs) ->
+ openssh_client_sftp(Config, [{preferred_algorithms,PrefAlgs}])
+ end, variants(cipher,Config)).
+
+
+openssh_client_sftp(Config, Options) ->
+ SystemDir = ?config(data_dir, Config),
+ UserDir = ?config(priv_dir, Config),
+ SftpSrcDir = ?config(sftp_src_dir, Config),
+ SrcFile = ?config(src_file, Config),
+ SrcSize = ?config(sftp_size, Config),
+ KnownHosts = filename:join(UserDir, "known_hosts"),
+
+ {ok, TracerPid} = erlang_trace(),
+ {ServerPid, _Host, Port} =
+ ssh_test_lib:daemon([{system_dir, SystemDir},
+ {public_key_alg, ssh_dsa},
+ {subsystems,[ssh_sftpd:subsystem_spec([%{cwd, SftpSrcDir},
+ {root, SftpSrcDir}])]},
+ {failfun, fun ssh_test_lib:failfun/2}
+ | Options]),
+ ct:sleep(500),
+ Cmd = lists:concat(["sftp",
+ " -b -",
+ " -P ",Port,
+ " -o UserKnownHostsFile=", KnownHosts,
+ " -o \"StrictHostKeyChecking no\"",
+ " localhost:",SrcFile
+ ]),
+%% ct:pal("Cmd = ~p",[Cmd]),
+
+ Parent = self(),
+ SlavePid = spawn(fun() ->
+ Parent ! {self(),os:cmd(Cmd)}
+ end),
+ receive
+ {SlavePid, _ClientResponse} ->
+ ct:pal("ClientResponse = ~p",[_ClientResponse]),
+ {ok, List} = get_trace_list(TracerPid),
+%%ct:pal("List=~p",[List]),
+ Times = find_times(List, [channel_open_close]),
+ Algs = find_algs(List),
+ ct:pal("Algorithms = ~p~n~nTimes = ~p",[Algs,Times]),
+ lists:foreach(
+ fun({{A,B},Value,Unit}) when A==encrypt ; A==decrypt ->
+ Data = [{value, Value},
+ {suite, ?MODULE},
+ {name, mk_name(["Sftp Cipher ",A," ",B," [",Unit,"]"])}
+ ],
+ ct:pal("sftp ct_event:notify ~p",[Data]),
+ ct_event:notify(#event{name = benchmark_data,
+ data = Data});
+ ({channel_open_close,Value,Unit}) ->
+ Cipher = fmt_alg(Algs#alg.encrypt, List),
+ Data = [{value, round( (1024*Value) / SrcSize )},
+ {suite, ?MODULE},
+ {name, mk_name(["Sftp transfer ",Cipher," [",Unit," per kbyte]"])}
+ ],
+ ct:pal("sftp ct_event:notify ~p",[Data]),
+ ct_event:notify(#event{name = benchmark_data,
+ data = Data});
+ (_) ->
+ skip
+ end, Times),
+ ssh:stop_daemon(ServerPid),
+ ok
+ after 10000 ->
+ ssh:stop_daemon(ServerPid),
+ exit(SlavePid, kill),
+ {fail, timeout}
+ end.
+
+%%%================================================================
+variants(Tag, Config) ->
+ TagType =
+ case proplists:get_value(Tag, ssh:default_algorithms()) of
+ [{_,_}|_] -> one_way;
+ [A|_] when is_atom(A) -> two_way
+ end,
+ [ [{Tag,tag_value(TagType,Alg)}]
+ || Alg <- proplists:get_value(Tag, ?config(common_algs,Config))
+ ].
+
+tag_value(two_way, Alg) -> [Alg];
+tag_value(one_way, Alg) -> [{client2server,[Alg]},
+ {server2client,[Alg]}].
+
+%%%----------------------------------------------------------------
+fmt_alg(Alg, List) when is_atom(Alg) ->
+ fmt_alg(atom_to_list(Alg), List);
+fmt_alg(Alg = "diffie-hellman-group-exchange-sha" ++ _, List) ->
+ try
+ integer_to_list(find_gex_size_string(List))
+ of
+ GexSize -> lists:concat([Alg," ",GexSize])
+ catch
+ _:_ -> Alg
+ end;
+fmt_alg(Alg, _List) ->
+ Alg.
+
+%%%----------------------------------------------------------------
+mk_name(Name) -> [char(C) || C <- lists:concat(Name)].
+
+char($-) -> $_;
+char(C) -> C.
+
+%%%----------------------------------------------------------------
+find_times(L, Xs) ->
+ [find_time(X,L) || X <- Xs] ++
+ function_algs_times_sizes([{ssh_transport,encrypt,2},
+ {ssh_transport,decrypt,2},
+ {ssh_message,decode,1},
+ {ssh_message,encode,1}], L).
+
+-record(call, {
+ mfa,
+ pid,
+ t_call,
+ t_return,
+ args,
+ result
+ }).
+
+%%%----------------
+-define(send(M), fun(C=#call{mfa = {ssh_message,encode,1},
+ args = [M]}) ->
+ C#call.t_return
+ end).
+
+-define(recv(M), fun(C=#call{mfa = {ssh_message,decode,1},
+ result = M}) ->
+ C#call.t_call
+ end).
+
+find_time(accept_to_hello, L) ->
+ [T0,T1] = find([fun(C=#call{mfa = {ssh_acceptor,handle_connection,5}}) ->
+ C#call.t_call
+ end,
+ fun(C=#call{mfa = {ssh_connection_handler,hello,_},
+ args = [socket_control|_]}) ->
+ C#call.t_return
+ end
+ ], L, []),
+ {accept_to_hello, now2micro_sec(now_diff(T1,T0)), microsec};
+find_time(kex, L) ->
+ [T0,T1] = find([fun(C=#call{mfa = {ssh_connection_handler,hello,_},
+ args = [socket_control|_]}) ->
+ C#call.t_call
+ end,
+ ?send(#ssh_msg_newkeys{})
+ ], L, []),
+ {kex, now2micro_sec(now_diff(T1,T0)), microsec};
+find_time(kex_to_auth, L) ->
+ [T0,T1] = find([?send(#ssh_msg_newkeys{}),
+ ?recv(#ssh_msg_userauth_request{})
+ ], L, []),
+ {kex_to_auth, now2micro_sec(now_diff(T1,T0)), microsec};
+find_time(auth, L) ->
+ [T0,T1] = find([?recv(#ssh_msg_userauth_request{}),
+ ?send(#ssh_msg_userauth_success{})
+ ], L, []),
+ {auth, now2micro_sec(now_diff(T1,T0)), microsec};
+find_time(to_prompt, L) ->
+ [T0,T1] = find([fun(C=#call{mfa = {ssh_acceptor,handle_connection,5}}) ->
+ C#call.t_call
+ end,
+ ?recv(#ssh_msg_channel_request{request_type="env"})
+ ], L, []),
+ {to_prompt, now2micro_sec(now_diff(T1,T0)), microsec};
+find_time(channel_open_close, L) ->
+ [T0,T1] = find([?recv(#ssh_msg_channel_request{request_type="subsystem"}),
+ ?send(#ssh_msg_channel_close{})
+ ], L, []),
+ {channel_open_close, now2micro_sec(now_diff(T1,T0)), microsec}.
+
+
+
+find([F|Fs], [C|Cs], Acc) when is_function(F,1) ->
+ try
+ F(C)
+ of
+ T -> find(Fs, Cs, [T|Acc])
+ catch
+ _:_ -> find([F|Fs], Cs, Acc)
+ end;
+find([], _, Acc) ->
+ lists:reverse(Acc).
+
+
+find_algs(L) ->
+ {value, #call{result={ok,Algs}}} =
+ lists:keysearch({ssh_transport,select_algorithm,3}, #call.mfa, L),
+ Algs.
+
+find_gex_size_string(L) ->
+ %% server
+ {value, #call{result={ok,{Size, _}}}} =
+ lists:keysearch({public_key,dh_gex_group,4}, #call.mfa, L),
+ Size.
+
+%%%----------------
+function_algs_times_sizes(EncDecs, L) ->
+ Raw = [begin
+ {Tag,Size} = function_ats_result(EncDec, C),
+ {Tag, Size, now2micro_sec(now_diff(T1,T0))}
+ end
+ || EncDec <- EncDecs,
+ C = #call{mfa = ED,
+ args = Args, %%[S,Data],
+ t_call = T0,
+ t_return = T1} <- L,
+ ED == EncDec
+ ],
+ [{Alg, round(1024*Time/Size), "microsec per kbyte"} % Microseconds per 1k bytes.
+ || {Alg,Size,Time} <- lists:foldl(fun increment/2, [], Raw)].
+
+function_ats_result({ssh_transport,encrypt,2}, #call{args=[S,Data]}) ->
+ {{encrypt,S#ssh.encrypt}, size(Data)};
+function_ats_result({ssh_transport,decrypt,2}, #call{args=[S,Data]}) ->
+ {{decrypt,S#ssh.decrypt}, size(Data)};
+function_ats_result({ssh_message,encode,1}, #call{result=Data}) ->
+ {encode, size(Data)};
+function_ats_result({ssh_message,decode,1}, #call{args=[Data]}) ->
+ {decode, size(Data)}.
+
+
+increment({Alg,Sz,T}, [{Alg,SumSz,SumT}|Acc]) ->
+ [{Alg,SumSz+Sz,SumT+T} | Acc];
+increment(Spec, [X|Acc]) ->
+ [X | increment(Spec,Acc)]; % Not so many Alg, 2 or 3
+increment({Alg,Sz,T},[]) ->
+ [{Alg,Sz,T}].
+
+%%%----------------------------------------------------------------
+%%%
+%%% API for the traceing
+%%%
+get_trace_list(TracerPid) ->
+ TracerPid ! {get_trace_list,self()},
+ receive
+ {trace_list,L} -> {ok, pair_events(lists:reverse(L))}
+ after 5000 -> {error,no_reply}
+ end.
+
+erlang_trace() ->
+ TracerPid = spawn(fun trace_loop/0),
+ 0 = erlang:trace(new, true, [call,timestamp,{tracer,TracerPid}]),
+ [init_trace(MFA, tp(MFA))
+ || MFA <- [{ssh_acceptor,handle_connection,5},
+ {ssh_connection_handler,hello,2},
+ {ssh_message,encode,1},
+ {ssh_message,decode,1},
+ {ssh_transport,select_algorithm,3},
+ {ssh_transport,encrypt,2},
+ {ssh_transport,decrypt,2},
+ {ssh_message,encode,1},
+ {ssh_message,decode,1},
+ {public_key,dh_gex_group,4} % To find dh_gex group size
+ ]],
+ {ok, TracerPid}.
+
+tp({_M,_F,Arity}) ->
+ [{lists:duplicate(Arity,'_'), [], [{return_trace}]}].
+
+%%%----------------------------------------------------------------
+init_trace(MFA = {Module,_,_}, TP) ->
+ case code:is_loaded(Module) of
+ false -> code:load_file(Module);
+ _ -> ok
+ end,
+ erlang:trace_pattern(MFA, TP, [local]).
+
+
+trace_loop() ->
+ trace_loop([]).
+
+trace_loop(L) ->
+ receive
+ {get_trace_list, From} ->
+ From ! {trace_list, L},
+ trace_loop(L);
+ Ev ->
+ trace_loop([Ev|L])
+ end.
+
+pair_events(L) ->
+ pair_events(L, []).
+
+pair_events([{trace_ts,Pid,call,{M,F,Args},TS0} | L], Acc) ->
+ Arity = length(Args),
+ {ReturnValue,TS1} = find_return(Pid, {M,F,Arity}, L),
+ pair_events(L, [#call{mfa = {M,F,Arity},
+ pid = Pid,
+ t_call = TS0,
+ t_return = TS1,
+ args = Args,
+ result = ReturnValue} | Acc]);
+pair_events([_|L], Acc) ->
+ pair_events(L, Acc);
+pair_events([], Acc) ->
+ lists:reverse(Acc).
+
+
+find_return(Pid, MFA,
+ [{trace_ts, Pid, return_from, MFA, ReturnValue, TS}|_]) ->
+ {ReturnValue, TS};
+find_return(Pid, MFA, [_|L]) ->
+ find_return(Pid, MFA, L);
+find_return(_, _, []) ->
+ {undefined, undefined}.
+
+%%%----------------------------------------------------------------
+report_client_algorithms() ->
+ try
+ ssh_test_lib:extract_algos( ssh_test_lib:default_algorithms(sshc) )
+ of
+ ClientAlgs ->
+ ct:pal("The client supports:~n~p",[ClientAlgs])
+ catch
+ Cls:Err ->
+ ct:pal("Testing client about algorithms failed:~n~p ~p",[Cls,Err])
+ end.
+
+%%%----------------------------------------------------------------
+
+
+now2sec({A,B,C}) -> A*1000000 + B + C/1000000.
+
+now2micro_sec({A,B,C}) -> (A*1000000 + B)*1000000 + C.
+
+now_diff({A1,B1,C1}, {A0,B0,C0}) -> {A1-A0, B1-B0, C1-C0}.
+
+%%%================================================================
+moduli() ->
+ [{1023, 5, 16#CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D182EB7},
+ {2047, 5, 16#F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE5E381EF},
+ {4095, 2, 16#C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BA7321EB},
+ {6143, 5, 16#FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23C3BEB637},
+ {8191, 2, 16#DC61EF13E4F3FC10CC946EEABC33F83EFCB35E0F47E4EC25C1CCBB2C7B502B2EFB0691AA231C8476DD51BA73204E6EA10B1A970FE2CF14AF01E72E1AEA87519A91D00D1499189F94A6CDA9E29C05F11F17FE74A4919A710A2787E180744465DF81C62AA65662FDA46FA6175E8A31E5B29E66DED6701C8FC4217E91D733FE94380F046680967D4CEA7BAC8F3916CDF96AA2C474FAD9650F48403FD0B5B756D34667D36A07767FA33027AE55484D0F701C3CA16632F413A14E4B8645AFAF15B78978C19A7661EDC569BEC72394B1204B166A48FCD5F56BE29840C7794CA6D3440356F15858CDCA9B429C7EA92E17242893FDC8C9C63841A382C32F20CFAB121B4BCAFD7BF9EF07FBF7CDFFECA0CEF3A49C3E2B24FA836F3318435255655E1B281071F62D5E4CD63361299B7828F72936E3FEA9E8044562A6F6ADD5321187C3101E4669C6271598FE1A866C93FE2870A4CEB9254BA32A4719E439317EA42200A335B5CFFA7946A7D0F1BD1A69AA11288B73C71C80B77FE3707CB077DDDEA5CA36A449FAB230C9625A0B12F8275D3FF82F5DA380E7A3F11B6F155FE7E91AC960BD95D9B13F7423AB9B15CC3C4DC34EF296033F009468EA16A721AD659F56C18516025050749ABF05E6D3EBD9778142A530979291F46DAA399A86B7BCDF09CC3E6EEF101419762A306DB45AEFC96C64E83F28338D55905F6A387E0F515E580C3A9B35330E21C32198CDEE3AFB355967A098F635FCA7C49CB4E1E82464B2B390EF1F259E40B9A06235C0273F76284FE6BD534EF3AF7CB01A4A5252B8B94CADC2850B2E56D53F9A31D7C029DF967D0A30C05BC64E119BED6076818FABC8CDD93F3255693E14EFC1A740A5D63A5E847FFE87BAB1DDE0506E1762EA61EFA9F9756151ECCCADD91B98A961A901A2D8B01ABDDD29EC804E8C8D28214BBA26048F924CA66316696E51A49D02FF034D20E44914B1115339CAD3819E0CB1640F0084886FEDDE5E28C29DC48ED30A8C3D789734338F5A9DF42584326E536FD1CF30BC85B8DCBD6120D127C98FE4B3614074F13C2CA4854E6D794156C185C40EB3DA7619CE96ADAF0941BD5499848B034C2B11DFECC0BDFA81C594241F759EF53FC7CDE7F2DE4F23CF81A5A0B7D62E31DABB9198D40307F7824DD130B7D1B80E9B6D322FEEDB5ACE34944F0BFB7D016762A9B2E173BFDD69303766AFBAB45FAB75D05430B4A3515858C4B7F04E23414E4AD03842CB0A20D8FF4B59B7C852BA9A5BE982A8ADA5CB70C36CE2A4D2C31A7015C9F3275E43D192C1B2924424088907A057DA7F2D32A2149922AB2E33F2147D637A3508911CB3FEA5E1AAB4525BACF27B6DD7A3E0AFA978FC3A39DE8882FB22688C3CCC92B6E69ACB0BBF575AB3368E51A2F6A20C414C6F146727CC0045F29061E695D29F7C030CE6929EB3AD11A5CBD0CDEE37347869A3}].
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_dsa b/lib/ssh/test/ssh_benchmark_SUITE_data/id_dsa
new file mode 100644
index 0000000000..d306f8b26e
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/id_dsa
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ
+APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod
+/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP
+kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW
+JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD
+OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt
++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e
+uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX
+Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE
+ZU8w8Q+H7z0j+a+70x2iAw==
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256 b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256
new file mode 100644
index 0000000000..4b1eb12eaa
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIJfCaBKIIKhjbJl5F8BedqlXOQYDX5ba9Skypllmx/w+oAoGCCqGSM49
+AwEHoUQDQgAE49RbK2xQ/19ji3uDPM7uT4692LbwWF1TiaA9vUuebMGazoW/98br
+N9xZu0L1AWwtEjs3kmJDTB7eJEGXnjUAcQ==
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256.pub
new file mode 100644
index 0000000000..a0147e60fa
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa256.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOPUWytsUP9fY4t7gzzO7k+Ovdi28FhdU4mgPb1LnmzBms6Fv/fG6zfcWbtC9QFsLRI7N5JiQ0we3iRBl541AHE= uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384 b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384
new file mode 100644
index 0000000000..4e8aa40959
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384
@@ -0,0 +1,6 @@
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDCYXb6OSAZyXRfLXOtMo43za197Hdc/T0YKjgQQjwDt6rlRwqTh7v7S
+PV2kXwNGdWigBwYFK4EEACKhZANiAARN2khlJUOOIiwsWHEALwDieeZR96qL4pUd
+ci7aeGaczdUK5jOA9D9zmBZtSYTfO8Cr7ekVghDlcWAIJ/BXcswgQwSEQ6wyfaTF
+8FYfyr4l3u9IirsnyaFzeIgeoNis8Gw=
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384.pub
new file mode 100644
index 0000000000..41e722e545
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa384.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBE3aSGUlQ44iLCxYcQAvAOJ55lH3qovilR1yLtp4ZpzN1QrmM4D0P3OYFm1JhN87wKvt6RWCEOVxYAgn8FdyzCBDBIRDrDJ9pMXwVh/KviXe70iKuyfJoXN4iB6g2KzwbA== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521 b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521
new file mode 100644
index 0000000000..7196f46e97
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521
@@ -0,0 +1,7 @@
+-----BEGIN EC PRIVATE KEY-----
+MIHbAgEBBEFMadoz4ckEcClfqXa2tiUuYkJdDfwq+/iFQcpt8ESuEd26IY/vm47Q
+9UzbPkO4ou8xkNsQ3WvCRQBBWtn5O2kUU6AHBgUrgQQAI6GBiQOBhgAEAde5BRu5
+01/jS0jRk212xsb2DxPrxNpgp6IMCV8TA4Eps+8bSqHB091nLiBcP422HXYfuCd7
+XDjSs8ihcmhp0hCRASLqZR9EzW9W/SOt876May1Huj5X+WSO6RLe7vPn9vmf7kHf
+pip6m7M7qp2qGgQ3q2vRwS2K/O6156ohiOlmuuFs
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521.pub
new file mode 100644
index 0000000000..8f059120bc
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/id_ecdsa521.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAHXuQUbudNf40tI0ZNtdsbG9g8T68TaYKeiDAlfEwOBKbPvG0qhwdPdZy4gXD+Nth12H7gne1w40rPIoXJoadIQkQEi6mUfRM1vVv0jrfO+jGstR7o+V/lkjukS3u7z5/b5n+5B36YqepuzO6qdqhoEN6tr0cEtivzuteeqIYjpZrrhbA== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/id_rsa b/lib/ssh/test/ssh_benchmark_SUITE_data/id_rsa
new file mode 100644
index 0000000000..9d7e0dd5fb
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/id_rsa
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQD1OET+3O/Bvj/dtjxDTXmj1oiJt4sIph5kGy0RfjoPrZfaS+CU
+DhakCmS6t2ivxWFgtpKWaoGMZMJqWj6F6ZsumyFl3FPBtujwY/35cgifrI9Ns4Tl
+zR1uuengNBmV+WRQ5cd9F2qS6Z8aDQihzt0r8JUqLcK+VQbrmNzboCCQQwIDAQAB
+AoGAPQEyqPTt8JUT7mRXuaacjFXiweAXhp9NEDpyi9eLOjtFe9lElZCrsUOkq47V
+TGUeRKEm9qSodfTbKPoqc8YaBJGJPhUaTAcha+7QcDdfHBvIsgxvU7ePVnlpXRp3
+CCUEMPhlnx6xBoTYP+fRU0e3+xJIPVyVCqX1jAdUMkzfRoECQQD6ux7B1QJAIWyK
+SGkbDUbBilNmzCFNgIpOP6PA+bwfi5d16diTpra5AX09keQABAo/KaP1PdV8Vg0p
+z4P3A7G3AkEA+l+AKG6m0kQTTBMJDqOdVPYwe+5GxunMaqmhokpEbuGsrZBl5Dvd
+WpcBjR7jmenrhKZRIuA+Fz5HPo/UQJPl1QJBAKxstDkeED8j/S2XoFhPKAJ+6t39
+sUVICVTIZQeXdmzHJXCcUSkw8+WEhakqw/3SyW0oaK2FSWQJFWJUZ+8eJj8CQEh3
+xeduB5kKnS9CvzdeghZqX6QvVosSdtlUmfUYW/BgH5PpHKTP8wTaeld3XldZTpMJ
+dKiMkUw2+XYROVUrubUCQD+Na1LhULlpn4ISEtIEfqpdlUhxDgO15Wg8USmsng+x
+ICliVOSQtwaZjm8kwaFt0W7XnpnDxbRs37vIEbIMWak=
+-----END RSA PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key
new file mode 100644
index 0000000000..51ab6fbd88
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK
+wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q
+diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA
+l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X
+skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF
+Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP
+ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah
+/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U
+ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W
+Lv62jKcdskxNyz2NQoBx
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key.pub
new file mode 100644
index 0000000000..4dbb1305b0
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_dsa_key.pub
@@ -0,0 +1,11 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j
+YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2
+KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU
+aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI
+fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT
+MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh
+DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48
+wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2
+/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256 b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256
new file mode 100644
index 0000000000..2979ea88ed
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIMe4MDoit0t8RzSVPwkCBemQ9fhXL+xnTSAWISw8HNCioAoGCCqGSM49
+AwEHoUQDQgAEo2q7U3P6r0W5WGOLtM78UQtofM9UalEhiZeDdiyylsR/RR17Op0s
+VPGSADLmzzgcucLEKy17j2S+oz42VUJy5A==
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256.pub
new file mode 100644
index 0000000000..85dc419345
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key256.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKNqu1Nz+q9FuVhji7TO/FELaHzPVGpRIYmXg3YsspbEf0UdezqdLFTxkgAy5s84HLnCxCste49kvqM+NlVCcuQ= uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384 b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384
new file mode 100644
index 0000000000..fb1a862ded
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384
@@ -0,0 +1,6 @@
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDArxbDfh3p1okrD9wQw6jJ4d4DdlBPD5GqXE8bIeRJiK41Sh40LgvPw
+mkqEDSXK++CgBwYFK4EEACKhZANiAAScl43Ih2lWTDKrSox5ve5uiTXil4smsup3
+CfS1XPjKxgBAmlfBim8izbdrT0BFdQzz2joduNMtpt61wO4rGs6jm0UP7Kim9PC7
+Hneb/99fIYopdMH5NMnk60zGO1uZ2vc=
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384.pub
new file mode 100644
index 0000000000..428d5fb7d7
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key384.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBJyXjciHaVZMMqtKjHm97m6JNeKXiyay6ncJ9LVc+MrGAECaV8GKbyLNt2tPQEV1DPPaOh240y2m3rXA7isazqObRQ/sqKb08Lsed5v/318hiil0wfk0yeTrTMY7W5na9w== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521 b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521
new file mode 100644
index 0000000000..3e51ec2ecd
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521
@@ -0,0 +1,7 @@
+-----BEGIN EC PRIVATE KEY-----
+MIHcAgEBBEIB8O1BFkl2HQjQLRLonEZ97da/h39DMa9/0/hvPZWAI8gUPEQcHxRx
+U7b09p3Zh+EBbMFq8+1ae9ds+ZTxE4WFSvKgBwYFK4EEACOhgYkDgYYABAAlWVjq
+Bzg7Wt4gE6UNb1lRE2cnlmH2L/A5uo6qZRx5lPnSKOxEhxSb/Oay1+9d6KRdrh6/
+vlhd9SHDBhLcAPDvWgBnJIEj92Q3pXX4JtoitL0yl+SvvU+vUh966mzHShHzj8p5
+ccOgPkPNoA70yrpGzkIhPezpZOQdCaOXj/jFqNCTDg==
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521.pub
new file mode 100644
index 0000000000..017a29f4da
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_ecdsa_key521.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAAlWVjqBzg7Wt4gE6UNb1lRE2cnlmH2L/A5uo6qZRx5lPnSKOxEhxSb/Oay1+9d6KRdrh6/vlhd9SHDBhLcAPDvWgBnJIEj92Q3pXX4JtoitL0yl+SvvU+vUh966mzHShHzj8p5ccOgPkPNoA70yrpGzkIhPezpZOQdCaOXj/jFqNCTDg== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key
new file mode 100644
index 0000000000..79968bdd7d
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key
@@ -0,0 +1,16 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337
+zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB
+6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB
+AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW
+NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++
+udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW
+WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt
+n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5
+sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY
++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt
+64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB
+m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT
+tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR
+-----END RSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key.pub
new file mode 100644
index 0000000000..75d2025c71
--- /dev/null
+++ b/lib/ssh/test/ssh_benchmark_SUITE_data/ssh_host_rsa_key.pub
@@ -0,0 +1,5 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8
+semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW
+RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl
index 5af60adfae..fe197f8672 100644
--- a/lib/ssh/test/ssh_protocol_SUITE.erl
+++ b/lib/ssh/test/ssh_protocol_SUITE.erl
@@ -48,6 +48,7 @@ all() ->
[{group,tool_tests},
{group,kex},
{group,service_requests},
+ {group,authentication},
{group,packet_size_error},
{group,field_size_error}
].
@@ -78,7 +79,9 @@ groups() ->
bad_very_long_service_name,
empty_service_name,
bad_service_name_then_correct
- ]}
+ ]},
+ {authentication, [], [client_handles_keyboard_interactive_0_pwds
+ ]}
].
@@ -277,12 +280,7 @@ no_common_alg_server_disconnects(Config) ->
{send, hello},
{match, #ssh_msg_kexinit{_='_'}, receive_msg},
{send, ssh_msg_kexinit}, % with server unsupported 'ssh-dss' !
- {match,
- {'or',[#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, _='_'},
- tcp_closed,
- {tcp_error,econnaborted}
- ]},
- receive_msg}
+ {match, disconnect(), receive_msg}
]
).
@@ -323,10 +321,7 @@ no_common_alg_client_disconnects(Config) ->
first_kex_packet_follows = false,
reserved = 0
}},
- {match,
- {'or',[#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED, _='_'},
- tcp_closed]},
- receive_msg}
+ {match, disconnect(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED), receive_msg}
],
InitialState)
}
@@ -437,10 +432,7 @@ bad_service_name_then_correct(Config) ->
[{set_options, [print_ops, print_seqnums, print_messages]},
{send, #ssh_msg_service_request{name = "kdjglkfdjgkldfjglkdfjglkfdjglkj"}},
{send, #ssh_msg_service_request{name = "ssh-connection"}},
- {match, {'or',[#ssh_msg_disconnect{_='_'},
- tcp_closed
- ]},
- receive_msg}
+ {match, disconnect(), receive_msg}
], InitialState).
@@ -450,10 +442,7 @@ bad_service_name(Config, Name) ->
ssh_trpt_test_lib:exec(
[{set_options, [print_ops, print_seqnums, print_messages]},
{send, #ssh_msg_service_request{name = Name}},
- {match, {'or',[#ssh_msg_disconnect{_='_'},
- tcp_closed
- ]},
- receive_msg}
+ {match, disconnect(), receive_msg}
], InitialState).
%%%--------------------------------------------------------------------
@@ -476,11 +465,7 @@ bad_packet_length(Config, LengthExcess) ->
PacketFun}},
%% Prohibit remote decoder starvation:
{send, #ssh_msg_service_request{name="ssh-userauth"}},
- {match, {'or',[#ssh_msg_disconnect{_='_'},
- tcp_closed,
- {tcp_error,econnaborted}
- ]},
- receive_msg}
+ {match, disconnect(), receive_msg}
], InitialState).
%%%--------------------------------------------------------------------
@@ -509,13 +494,85 @@ bad_service_name_length(Config, LengthExcess) ->
PacketFun} },
%% Prohibit remote decoder starvation:
{send, #ssh_msg_service_request{name="ssh-userauth"}},
- {match, {'or',[#ssh_msg_disconnect{_='_'},
- tcp_closed,
- {tcp_error,econnaborted}
- ]},
- receive_msg}
+ {match, disconnect(), receive_msg}
], InitialState).
+%%%--------------------------------------------------------------------
+%%% This is due to a fault report (OTP-13255) with OpenSSH-6.6.1
+client_handles_keyboard_interactive_0_pwds(Config) ->
+ {User,_Pwd} = server_user_password(Config),
+
+ %% Create a listening socket as server socket:
+ {ok,InitialState} = ssh_trpt_test_lib:exec(listen),
+ HostPort = ssh_trpt_test_lib:server_host_port(InitialState),
+
+ %% Start a process handling one connection on the server side:
+ spawn_link(
+ fun() ->
+ {ok,_} =
+ ssh_trpt_test_lib:exec(
+ [{set_options, [print_ops, print_messages]},
+ {accept, [{system_dir, system_dir(Config)},
+ {user_dir, user_dir(Config)}]},
+ receive_hello,
+ {send, hello},
+
+ {send, ssh_msg_kexinit},
+ {match, #ssh_msg_kexinit{_='_'}, receive_msg},
+
+ {match, #ssh_msg_kexdh_init{_='_'}, receive_msg},
+ {send, ssh_msg_kexdh_reply},
+
+ {send, #ssh_msg_newkeys{}},
+ {match, #ssh_msg_newkeys{_='_'}, receive_msg},
+
+ {match, #ssh_msg_service_request{name="ssh-userauth"}, receive_msg},
+ {send, #ssh_msg_service_accept{name="ssh-userauth"}},
+
+ {match, #ssh_msg_userauth_request{service="ssh-connection",
+ method="none",
+ user=User,
+ _='_'}, receive_msg},
+ {send, #ssh_msg_userauth_failure{authentications = "keyboard-interactive",
+ partial_success = false}},
+
+ {match, #ssh_msg_userauth_request{service="ssh-connection",
+ method="keyboard-interactive",
+ user=User,
+ _='_'}, receive_msg},
+ {send, #ssh_msg_userauth_info_request{name = "",
+ instruction = "",
+ language_tag = "",
+ num_prompts = 1,
+ data = <<0,0,0,10,80,97,115,115,119,111,114,100,58,32,0>>
+ }},
+ {match, #ssh_msg_userauth_info_response{num_responses = 1,
+ _='_'}, receive_msg},
+
+ %% the next is strange, but openssh 6.6.1 does this and this is what this testcase is about
+ {send, #ssh_msg_userauth_info_request{name = "",
+ instruction = "",
+ language_tag = "",
+ num_prompts = 0,
+ data = <<>>
+ }},
+ {match, #ssh_msg_userauth_info_response{num_responses = 0,
+ data = <<>>,
+ _='_'}, receive_msg},
+ %% Here we know that the tested fault is fixed
+ {send, #ssh_msg_userauth_success{}},
+ close_socket,
+ print_state
+ ],
+ InitialState)
+ end),
+
+ %% and finally connect to it with a regular Erlang SSH client:
+ {ok,_} = std_connect(HostPort, Config,
+ [{preferred_algorithms,[{kex,['diffie-hellman-group1-sha1']}]}]
+ ).
+
+
%%%================================================================
%%%==== Internal functions ========================================
%%%================================================================
@@ -644,3 +701,16 @@ connect_and_kex(Config, InitialState) ->
{match, #ssh_msg_newkeys{_='_'}, receive_msg}
],
InitialState).
+
+%%%----------------------------------------------------------------
+
+%%% For matching peer disconnection
+disconnect() ->
+ disconnect('_').
+
+disconnect(Code) ->
+ {'or',[#ssh_msg_disconnect{code = Code,
+ _='_'},
+ tcp_closed,
+ {tcp_error,econnaborted}
+ ]}.
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index ed76f4f795..2db55b97b4 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -541,7 +541,6 @@ default_algorithms(sshc, DaemonOptions) ->
ct:fail("No server respons 2")
end.
-
run_fake_ssh({ok,InitialState}) ->
KexInitPattern =
#ssh_msg_kexinit{
@@ -583,6 +582,40 @@ run_fake_ssh({ok,InitialState}) ->
{server2client, to_atoms(CompS2C)}]}].
+%%%----------------------------------------------------------------
+extract_algos(Spec) ->
+ [{Tag,get_atoms(List)} || {Tag,List} <- Spec].
+
+get_atoms(L) ->
+ lists:usort(
+ [ A || X <- L,
+ A <- case X of
+ {_,L1} when is_list(L1) -> L1;
+ Y when is_atom(Y) -> [Y]
+ end]).
+
+
+intersection(AlgoSpec1, AlgoSpec2) -> intersect(sort_spec(AlgoSpec1), sort_spec(AlgoSpec2)).
+
+intersect([{Tag,S1}|Ss1], [{Tag,S2}|Ss2]) ->
+ [{Tag,intersect(S1,S2)} | intersect(Ss1,Ss2)];
+intersect(L1=[A1|_], L2=[A2|_]) when is_atom(A1),is_atom(A2) ->
+ Diff = L1 -- L2,
+ L1 -- Diff;
+intersect(_, _) ->
+ [].
+
+intersect_bi_dir([{Tag,[{client2server,L1},{server2client,L2}]}|T]) ->
+ [{Tag,intersect(L1,L2)} | intersect_bi_dir(T)];
+intersect_bi_dir([H={_,[A|_]}|T]) when is_atom(A) ->
+ [H | intersect_bi_dir(T)];
+intersect_bi_dir([]) ->
+ [].
+
+
+sort_spec(L = [{_,_}|_] ) -> [{Tag,sort_spec(Es)} || {Tag,Es} <- L];
+sort_spec(L) -> lists:usort(L).
+
%%--------------------------------------------------------------------
sshc(Tag) ->
to_atoms(
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 02cc79e4d5..67a61d3c11 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -110,9 +110,9 @@ end_per_testcase(_TestCase, _Config) ->
chk_key(Pgm, Name, File, Config) ->
case ssh_test_lib:openssh_supports(Pgm, public_key, Name) of
- true ->
- {skip,lists:concat(["openssh client does not support ",Name])};
false ->
+ {skip,lists:concat(["openssh client does not support ",Name])};
+ true ->
{ok,[[Home]]} = init:get_argument(home),
KeyFile = filename:join(Home, File),
case file:read_file(KeyFile) of
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index 25b19133b1..55d12abffe 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,5 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.2
+SSH_VSN = 4.2.1
APP_VSN = "ssh-$(SSH_VSN)"
diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl
index 404ae93d20..6fe99a81c5 100644
--- a/lib/ssl/src/inet_tls_dist.erl
+++ b/lib/ssl/src/inet_tls_dist.erl
@@ -76,23 +76,23 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
Timer, Version, Ip, TcpPort, Address,
Type),
dist_util:handshake_we_started(HSData);
- _ ->
+ Other ->
%% Other Node may have closed since
%% port_please !
?trace("other node (~p) "
"closed since port_please.~n",
[Node]),
- ?shutdown(Node)
+ ?shutdown2(Node, {shutdown, {connect_failed, Other}})
end;
- _ ->
+ Other ->
?trace("port_please (~p) "
"failed.~n", [Node]),
- ?shutdown(Node)
+ ?shutdown2(Node, {shutdown, {port_please_failed, Other}})
end;
- _Other ->
+ Other ->
?trace("inet_getaddr(~p) "
"failed (~p).~n", [Node,Other]),
- ?shutdown(Node)
+ ?shutdown2(Node, {shutdown, {inet_getaddr_failed, Other}})
end.
close(Socket) ->
diff --git a/lib/ssl/src/ssl_tls_dist_proxy.erl b/lib/ssl/src/ssl_tls_dist_proxy.erl
index d384264b53..3edd352891 100644
--- a/lib/ssl/src/ssl_tls_dist_proxy.erl
+++ b/lib/ssl/src/ssl_tls_dist_proxy.erl
@@ -204,6 +204,11 @@ accept_loop(Proxy, world = Type, Listen, Extra) ->
end),
ok = ssl:controlling_process(SslSocket, PairHandler),
flush_old_controller(PairHandler, SslSocket);
+ {error, {options, _}} = Error ->
+ %% Bad options: that's probably our fault. Let's log that.
+ error_logger:error_msg("Cannot accept TLS distribution connection: ~s~n",
+ [ssl:format_error(Error)]),
+ gen_tcp:close(Socket);
_ ->
gen_tcp:close(Socket)
end;
@@ -235,6 +240,11 @@ setup_proxy(Ip, Port, Parent) ->
Err ->
Parent ! {self(), Err}
end;
+ {error, {options, _}} = Err ->
+ %% Bad options: that's probably our fault. Let's log that.
+ error_logger:error_msg("Cannot open TLS distribution connection: ~s~n",
+ [ssl:format_error(Err)]),
+ Parent ! {self(), Err};
Err ->
Parent ! {self(), Err}
end.
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 9a76d603b1..77c29668b5 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -1158,23 +1158,27 @@ cipher_restriction(Config0) ->
end.
check_sane_openssl_version(Version) ->
- case {Version, os:cmd("openssl version")} of
- {_, "OpenSSL 1.0.2" ++ _} ->
- true;
- {_, "OpenSSL 1.0.1" ++ _} ->
- true;
- {'tlsv1.2', "OpenSSL 1.0" ++ _} ->
- false;
- {'tlsv1.1', "OpenSSL 1.0" ++ _} ->
- false;
- {'tlsv1.2', "OpenSSL 0" ++ _} ->
- false;
- {'tlsv1.1', "OpenSSL 0" ++ _} ->
- false;
- {_, _} ->
- true
+ case supports_ssl_tls_version(Version) of
+ true ->
+ case {Version, os:cmd("openssl version")} of
+ {_, "OpenSSL 1.0.2" ++ _} ->
+ true;
+ {_, "OpenSSL 1.0.1" ++ _} ->
+ true;
+ {'tlsv1.2', "OpenSSL 1.0" ++ _} ->
+ false;
+ {'tlsv1.1', "OpenSSL 1.0" ++ _} ->
+ false;
+ {'tlsv1.2', "OpenSSL 0" ++ _} ->
+ false;
+ {'tlsv1.1', "OpenSSL 0" ++ _} ->
+ false;
+ {_, _} ->
+ true
+ end;
+ false ->
+ false
end.
-
enough_openssl_crl_support("OpenSSL 0." ++ _) -> false;
enough_openssl_crl_support(_) -> true.
@@ -1198,7 +1202,9 @@ version_flag('tlsv1.1') ->
version_flag('tlsv1.2') ->
"-tls1_2";
version_flag(sslv3) ->
- "-ssl3".
+ "-ssl3";
+version_flag(sslv2) ->
+ "-ssl2".
filter_suites(Ciphers0) ->
Version = tls_record:highest_protocol_version([]),
@@ -1249,3 +1255,25 @@ portable_open_port(Exe, Args) ->
ct:pal("open_port({spawn_executable, ~p}, [{args, ~p}, stderr_to_stdout]).", [AbsPath, Args]),
open_port({spawn_executable, AbsPath},
[{args, Args}, stderr_to_stdout]).
+
+supports_ssl_tls_version(Version) ->
+ VersionFlag = version_flag(Version),
+ Exe = "openssl",
+ Args = ["s_client", VersionFlag],
+ Port = ssl_test_lib:portable_open_port(Exe, Args),
+ do_supports_ssl_tls_version(Port).
+
+do_supports_ssl_tls_version(Port) ->
+ receive
+ {Port, {data, "unknown option" ++ _}} ->
+ false;
+ {Port, {data, Data}} ->
+ case lists:member("error", string:tokens(Data, ":")) of
+ true ->
+ false;
+ false ->
+ do_supports_ssl_tls_version(Port)
+ end
+ after 500 ->
+ true
+ end.
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index 13523730b0..bcdefb5fca 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -175,7 +175,12 @@ special_init(TestCase, Config)
check_sane_openssl_renegotaite(Config, Version);
special_init(ssl2_erlang_server_openssl_client, Config) ->
- check_sane_openssl_sslv2(Config);
+ case ssl_test_lib:supports_ssl_tls_version(sslv2) of
+ true ->
+ Config;
+ false ->
+ {skip, "sslv2 not supported by openssl"}
+ end;
special_init(TestCase, Config)
when TestCase == erlang_client_alpn_openssl_server_alpn;
@@ -1756,32 +1761,6 @@ check_sane_openssl_renegotaite(Config) ->
Config
end.
-check_sane_openssl_sslv2(Config) ->
- Exe = "openssl",
- Args = ["s_client", "-ssl2"],
- Port = ssl_test_lib:portable_open_port(Exe, Args),
- case supports_sslv2(Port) of
- true ->
- Config;
- false ->
- {skip, "sslv2 not supported by openssl"}
- end.
-
-supports_sslv2(Port) ->
- receive
- {Port, {data, "unknown option -ssl2" ++ _}} ->
- false;
- {Port, {data, Data}} ->
- case lists:member("error", string:tokens(Data, ":")) of
- true ->
- false;
- false ->
- supports_sslv2(Port)
- end
- after 500 ->
- true
- end.
-
workaround_openssl_s_clinent() ->
%% http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=683159
%% https://bugs.archlinux.org/task/33919
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index ca3cc43b19..40a34aa30f 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
@@ -415,7 +415,7 @@ expr({call,_,{atom,_,Func},As0}, Bs0, Lf, Ef, RBs) ->
{As,Bs} = expr_list(As0, Bs0, Lf, Ef),
bif(Func, As, Bs, Ef, RBs);
false ->
- local_func(Func, As0, Bs0, Lf, RBs)
+ local_func(Func, As0, Bs0, Lf, Ef, RBs)
end;
expr({call,_,Func0,As0}, Bs0, Lf, Ef, RBs) -> % function or {Mod,Fun}
{value,Func,Bs1} = expr(Func0, Bs0, Lf, Ef, none),
@@ -542,33 +542,34 @@ unhide_calls([E | Es], MaxLine, D) ->
unhide_calls(E, _MaxLine, _D) ->
E.
-%% local_func(Function, Arguments, Bindings, LocalFuncHandler, RBs) ->
+%% local_func(Function, Arguments, Bindings, LocalFuncHandler,
+%% ExternalFuncHandler, RBs) ->
%% {value,Value,Bindings} | Value when
%% LocalFuncHandler = {value,F} | {value,F,Eas} |
%% {eval,F} | {eval,F,Eas} | none.
-local_func(Func, As0, Bs0, {value,F}, value) ->
- {As1,_Bs1} = expr_list(As0, Bs0, {value,F}),
+local_func(Func, As0, Bs0, {value,F}, Ef, value) ->
+ {As1,_Bs1} = expr_list(As0, Bs0, {value,F}, Ef),
%% Make tail recursive calls when possible.
F(Func, As1);
-local_func(Func, As0, Bs0, {value,F}, RBs) ->
- {As1,Bs1} = expr_list(As0, Bs0, {value,F}),
+local_func(Func, As0, Bs0, {value,F}, Ef, RBs) ->
+ {As1,Bs1} = expr_list(As0, Bs0, {value,F}, Ef),
ret_expr(F(Func, As1), Bs1, RBs);
-local_func(Func, As0, Bs0, {value,F,Eas}, RBs) ->
+local_func(Func, As0, Bs0, {value,F,Eas}, Ef, RBs) ->
Fun = fun(Name, Args) -> apply(F, [Name,Args|Eas]) end,
- local_func(Func, As0, Bs0, {value, Fun}, RBs);
-local_func(Func, As, Bs, {eval,F}, RBs) ->
+ local_func(Func, As0, Bs0, {value, Fun}, Ef, RBs);
+local_func(Func, As, Bs, {eval,F}, _Ef, RBs) ->
local_func2(F(Func, As, Bs), RBs);
-local_func(Func, As, Bs, {eval,F,Eas}, RBs) ->
+local_func(Func, As, Bs, {eval,F,Eas}, _Ef, RBs) ->
local_func2(apply(F, [Func,As,Bs|Eas]), RBs);
%% These two clauses are for backwards compatibility.
-local_func(Func, As0, Bs0, {M,F}, RBs) ->
- {As1,Bs1} = expr_list(As0, Bs0, {M,F}),
+local_func(Func, As0, Bs0, {M,F}, Ef, RBs) ->
+ {As1,Bs1} = expr_list(As0, Bs0, {M,F}, Ef),
ret_expr(M:F(Func,As1), Bs1, RBs);
-local_func(Func, As, _Bs, {M,F,Eas}, RBs) ->
+local_func(Func, As, _Bs, {M,F,Eas}, _Ef, RBs) ->
local_func2(apply(M, F, [Func,As|Eas]), RBs);
%% Default unknown function handler to undefined function.
-local_func(Func, As0, _Bs0, none, _RBs) ->
+local_func(Func, As0, _Bs0, none, _Ef, _RBs) ->
erlang:raise(error, undef, [{erl_eval,Func,length(As0)}|stacktrace()]).
local_func2({value,V,Bs}, RBs) ->
@@ -1184,7 +1185,7 @@ match_tuple([], _, _, Bs, _BBs) ->
match_map([{map_field_exact, _, K, V}|Fs], Map, Bs0, BBs) ->
Vm = try
- {value, Ke, _} = expr(K, Bs0),
+ {value, Ke, _} = expr(K, BBs),
maps:get(Ke,Map)
catch error:_ ->
throw(nomatch)
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 5678e7eebe..e940ad6956 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2016. 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.
@@ -100,7 +100,7 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
%% 'called' and 'exports' contain {Line, {Function, Arity}},
%% the other function collections contain {Function, Arity}.
-record(lint, {state=start :: 'start' | 'attribute' | 'function',
- module=[], %Module
+ module='', %Module
behaviour=[], %Behaviour
exports=gb_sets:empty() :: gb_sets:set(fa()),%Exports
imports=[] :: [fa()], %Imports, an orddict()
@@ -729,7 +729,7 @@ start_state(Form, St) ->
%% attribute_state(Form, State) ->
%% State'
-attribute_state({attribute,_L,module,_M}, #lint{module=[]}=St) ->
+attribute_state({attribute,_L,module,_M}, #lint{module=''}=St) ->
St;
attribute_state({attribute,L,module,_M}, St) ->
add_error(L, redefine_module, St);
diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl
index b9c4ad0a46..c21c4e61ee 100644
--- a/lib/stdlib/test/erl_eval_SUITE.erl
+++ b/lib/stdlib/test/erl_eval_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2016. 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.
@@ -39,6 +39,7 @@
otp_7550/1,
otp_8133/1,
otp_10622/1,
+ otp_13228/1,
funs/1,
try_catch/1,
eval_expr_5/1,
@@ -83,7 +84,8 @@ all() ->
pattern_expr, match_bin, guard_3, guard_4, guard_5, lc,
simple_cases, unary_plus, apply_atom, otp_5269,
otp_6539, otp_6543, otp_6787, otp_6977, otp_7550,
- otp_8133, otp_10622, funs, try_catch, eval_expr_5, zero_width,
+ otp_8133, otp_10622, otp_13228,
+ funs, try_catch, eval_expr_5, zero_width,
eep37, eep43].
groups() ->
@@ -1042,6 +1044,13 @@ otp_10622(Config) when is_list(Config) ->
ok.
+otp_13228(doc) ->
+ ["OTP-13228. ERL-32: non-local function handler bug."];
+otp_13228(_Config) ->
+ LFH = {value, fun(foo, [io_fwrite]) -> worked end},
+ EFH = {value, fun({io, fwrite}, [atom]) -> io_fwrite end},
+ {value, worked, []} = parse_and_run("foo(io:fwrite(atom)).", LFH, EFH).
+
funs(doc) ->
["Simple cases, just to cover some code."];
funs(suite) ->
@@ -1483,6 +1492,16 @@ eep43(Config) when is_list(Config) ->
" #{ K1 := 1, K2 := 2, K3 := 3, {2,2} := 4} = Map "
"end.",
#{ 1 => 1, <<42:301>> => 2, {3,<<42:301>>} => 3, {2,2} => 4}),
+ check(fun () ->
+ X = key,
+ (fun(#{X := value}) -> true end)(#{X => value})
+ end,
+ "begin "
+ " X = key, "
+ " (fun(#{X := value}) -> true end)(#{X => value}) "
+ "end.",
+ true),
+
error_check("[camembert]#{}.", {badmap,[camembert]}),
error_check("[camembert]#{nonexisting:=v}.", {badmap,[camembert]}),
error_check("#{} = 1.", {badmatch,1}),
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index 5347ccaf1f..375fb6bc93 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2016. 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.
@@ -65,7 +65,7 @@
too_many_arguments/1,
basic_errors/1,bin_syntax_errors/1,
predef/1,
- maps/1,maps_type/1,otp_11851/1,otp_12195/1
+ maps/1,maps_type/1,otp_11851/1,otp_12195/1, otp_13230/1
]).
% Default timetrap timeout (set in init_per_testcase).
@@ -94,7 +94,7 @@ all() ->
bif_clash, behaviour_basic, behaviour_multiple, otp_11861,
otp_7550, otp_8051, format_warn, {group, on_load},
too_many_arguments, basic_errors, bin_syntax_errors, predef,
- maps, maps_type, otp_11851, otp_12195].
+ maps, maps_type, otp_11851, otp_12195, otp_13230].
groups() ->
[{unused_vars_warn, [],
@@ -3877,6 +3877,15 @@ otp_12195(Config) when is_list(Config) ->
[] = run(Config, Ts),
ok.
+otp_13230(doc) ->
+ "OTP-13230: -deprecated without -module";
+otp_13230(Config) when is_list(Config) ->
+ Abstr = <<"-deprecated([{frutt,0,next_version}]).">>,
+ {errors,[{1,erl_lint,undefined_module},
+ {1,erl_lint,{bad_deprecated,{frutt,0}}}],
+ []} = run_test2(Config, Abstr, []),
+ ok.
+
run(Config, Tests) ->
F = fun({N,P,Ws,E}, BadL) ->
case catch run_test(Config, P, Ws) of