summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/common_test/doc/src/ct_suite.xml8
-rw-r--r--lib/common_test/doc/src/run_test_chapter.xml2
-rw-r--r--lib/common_test/doc/src/write_test_chapter.xml6
-rw-r--r--lib/common_test/src/ct_suite.erl4
-rw-r--r--lib/compiler/doc/src/notes.xml37
-rw-r--r--lib/compiler/src/beam_call_types.erl32
-rw-r--r--lib/compiler/src/beam_jump.erl1
-rw-r--r--lib/compiler/src/beam_ssa.erl15
-rw-r--r--lib/compiler/src/beam_ssa_check.erl5
-rw-r--r--lib/compiler/src/beam_ssa_codegen.erl6
-rw-r--r--lib/compiler/src/beam_ssa_private_append.erl21
-rw-r--r--lib/compiler/src/beam_types.erl25
-rw-r--r--lib/compiler/src/beam_validator.erl14
-rw-r--r--lib/compiler/test/beam_jump_SUITE.erl8
-rw-r--r--lib/compiler/test/beam_ssa_SUITE.erl90
-rw-r--r--lib/compiler/test/beam_ssa_check_SUITE_data/private_append.erl27
-rw-r--r--lib/compiler/test/beam_ssa_check_SUITE_data/sanity_checks.erl16
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl81
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl21
-rw-r--r--lib/compiler/test/bif_SUITE.erl43
-rw-r--r--lib/compiler/vsn.mk2
-rw-r--r--lib/crypto/c_src/dh.c2
-rw-r--r--lib/crypto/c_src/openssl_config.h9
-rw-r--r--lib/crypto/doc/src/notes.xml16
-rw-r--r--lib/crypto/src/crypto.erl2
-rw-r--r--lib/crypto/test/crypto_SUITE.erl25
-rw-r--r--lib/crypto/vsn.mk2
-rw-r--r--lib/dialyzer/doc/src/dialyzer.xml26
-rw-r--r--lib/dialyzer/src/dialyzer.app.src2
-rw-r--r--lib/dialyzer/src/dialyzer.erl4
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl9
-rw-r--r--lib/dialyzer/src/dialyzer_cl_parse.erl28
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl23
-rw-r--r--lib/dialyzer/src/dialyzer_options.erl78
-rw-r--r--lib/dialyzer/test/incremental_SUITE.erl176
-rw-r--r--lib/dialyzer/test/incremental_SUITE_data/extra_modules/ebin/.gitignore5
-rw-r--r--lib/dialyzer/test/incremental_SUITE_data/extra_modules/src/extra_module.erl14
-rw-r--r--lib/dialyzer/test/incremental_SUITE_data/extra_modules/src/extra_modules.app.src8
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/bs_segments3
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/gh_71533
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/bs_segments.erl7
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/gh_7153.erl5
-rw-r--r--lib/diameter/src/diameter.appup.src8
-rw-r--r--lib/edoc/test/edoc_SUITE.erl15
-rw-r--r--lib/edoc/test/edoc_SUITE_data/module_with_feature.erl2
-rw-r--r--lib/eldap/doc/src/eldap.xml2
-rw-r--r--lib/eldap/doc/src/notes.xml16
-rw-r--r--lib/eldap/vsn.mk2
-rw-r--r--lib/erl_interface/doc/src/notes.xml16
-rw-r--r--lib/erl_interface/src/connect/ei_connect.c4
-rw-r--r--lib/erl_interface/src/prog/erl_call.c8
-rw-r--r--lib/erl_interface/vsn.mk2
-rw-r--r--lib/inets/doc/src/notes.xml28
-rw-r--r--lib/inets/src/http_client/httpc.erl4
-rw-r--r--lib/inets/vsn.mk2
-rw-r--r--lib/kernel/Makefile2
-rw-r--r--lib/kernel/doc/src/code.xml2
-rw-r--r--lib/kernel/doc/src/disk_log.xml2
-rw-r--r--lib/kernel/doc/src/socket.xml131
-rw-r--r--lib/kernel/src/gen_tcp_socket.erl16
-rw-r--r--lib/kernel/src/socket.erl10
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl8
-rw-r--r--lib/kernel/test/socket_SUITE.erl222
-rw-r--r--lib/os_mon/doc/src/notes.xml17
-rw-r--r--lib/os_mon/src/cpu_sup.erl4
-rw-r--r--lib/os_mon/src/memsup.erl2
-rw-r--r--lib/os_mon/vsn.mk2
-rw-r--r--lib/snmp/doc/src/notes.xml18
-rw-r--r--lib/snmp/vsn.mk2
-rw-r--r--lib/ssl/doc/src/notes.xml24
-rw-r--r--lib/ssl/doc/src/ssl.xml2
-rw-r--r--lib/ssl/src/dtls_connection.erl9
-rw-r--r--lib/ssl/src/ssl.erl8
-rw-r--r--lib/ssl/test/openssl_alpn_SUITE.erl2
-rw-r--r--lib/ssl/test/openssl_renegotiate_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_api_SUITE.erl8
-rw-r--r--lib/ssl/test/ssl_test_lib.erl26
-rw-r--r--lib/ssl/vsn.mk2
-rw-r--r--lib/stdlib/doc/src/gb_sets.xml46
-rw-r--r--lib/stdlib/doc/src/notes.xml16
-rw-r--r--lib/stdlib/doc/src/ordsets.xml5
-rw-r--r--lib/stdlib/doc/src/sets.xml65
-rw-r--r--lib/stdlib/src/erl_lint.erl48
-rw-r--r--lib/stdlib/src/sets.erl17
-rw-r--r--lib/stdlib/src/stdlib.appup.src8
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl168
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/syntax_tools/src/epp_dodger.erl2
-rw-r--r--lib/wx/api_gen/gl_gen.erl2
-rw-r--r--lib/wx/api_gen/gl_gen_erl.erl2
-rw-r--r--lib/wx/api_gen/gl_gen_nif.erl2
-rw-r--r--lib/wx/api_gen/wx_gen_nif.erl2
-rw-r--r--lib/wx/api_gen/wxapi.conf2
-rw-r--r--lib/wx/c_src/egl_impl.c2
-rw-r--r--lib/wx/c_src/wxe_gl.cpp2
-rw-r--r--lib/wx/c_src/wxe_gl.h2
-rw-r--r--lib/wx/c_src/wxe_impl.cpp2
-rw-r--r--lib/wx/c_src/wxe_impl.h2
-rw-r--r--lib/wx/c_src/wxe_nif.c2
-rw-r--r--lib/wx/c_src/wxe_return.cpp2
-rw-r--r--lib/wx/doc/src/gl.xml2
-rw-r--r--lib/wx/doc/src/notes.xml16
-rw-r--r--lib/wx/src/wxe_master.erl2
-rw-r--r--lib/wx/src/wxe_util.erl2
-rw-r--r--lib/wx/test/wx_class_SUITE.erl2
-rw-r--r--lib/wx/test/wx_opengl_SUITE.erl2
-rw-r--r--lib/wx/vsn.mk2
107 files changed, 1541 insertions, 429 deletions
diff --git a/lib/common_test/doc/src/ct_suite.xml b/lib/common_test/doc/src/ct_suite.xml
index 8740a3ff79..cc926fbcbb 100644
--- a/lib/common_test/doc/src/ct_suite.xml
+++ b/lib/common_test/doc/src/ct_suite.xml
@@ -85,7 +85,9 @@
<fsummary>Returns the list of all test case groups and test cases
in the module.</fsummary>
<type>
- <v><seetype marker="#ct_test_def">ct_test_def()</seetype> = TestCase | {group, GroupName} | {group, GroupName, Properties} | {group, GroupName, Properties, SubGroups}</v>
+ <v><seetype marker="#ct_test_def">ct_test_def()</seetype> = TestCase |
+ {group, GroupName} | {group, GroupName, Properties} | {group, GroupName,
+ Properties, SubGroups} | {testcase, TestCase, TestCaseRepeatType}</v>
<v>TestCase = <seetype marker="#ct_testname">ct_testname()</seetype></v>
<v>GroupName = <seetype marker="#ct_groupname">ct_groupname()</seetype></v>
<v>Properties = [parallel | sequence | Shuffle | {RepeatType, N}] | default</v>
@@ -93,6 +95,7 @@
<v>Shuffle = shuffle | {shuffle, Seed}</v>
<v>Seed = {integer(), integer(), integer()}</v>
<v>RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | repeat_until_any_ok | repeat_until_any_fail</v>
+ <v>TestCaseRepeatType = [{repeat, N} | {repeat_until_ok, N} | {repeat_until_fail, N}]</v>
<v>N = integer() | forever</v>
<v>Reason = term()</v>
</type>
@@ -135,11 +138,12 @@
<v><seetype marker="#ct_group_def">ct_group_def()</seetype> = {GroupName, Properties, GroupsAndTestCases}</v>
<v>GroupName = <seetype marker="#ct_groupname">ct_groupname()</seetype></v>
<v>Properties = [parallel | sequence | Shuffle | {RepeatType, N}]</v>
- <v>GroupsAndTestCases = [Group | {group, GroupName} | TestCase]</v>
+ <v>GroupsAndTestCases = [Group | {group, GroupName} | TestCase | {testcase, TestCase, TestCaseRepeatType}]</v>
<v>TestCase = <seetype marker="#ct_testname">ct_testname()</seetype></v>
<v>Shuffle = shuffle | {shuffle, Seed}</v>
<v>Seed = {integer(), integer(), integer()}</v>
<v>RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | repeat_until_any_ok | repeat_until_any_fail</v>
+ <v>TestCaseRepeatType = [{repeat, N} | {repeat_until_ok, N} | {repeat_until_fail, N}]</v>
<v>N = integer() | forever</v>
</type>
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index f9416e1bee..ea33b9d8f9 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -763,7 +763,7 @@
finally function <c>end_per_group</c>. Also, if particular
test cases in a group are specified, <c>init_per_group</c>
and <c>end_per_group</c>, for the group in question, are
- called. If a group defined (in <c>Suite:group/0</c>) as
+ called. If a group defined (in <c>Suite:groups/0</c>) as
a subgroup of another group, is specified (or if particular test
cases of a subgroup are), <c>Common Test</c> calls the configuration
functions for the top-level groups and for the subgroup
diff --git a/lib/common_test/doc/src/write_test_chapter.xml b/lib/common_test/doc/src/write_test_chapter.xml
index 8f7c7e8177..99571bbdae 100644
--- a/lib/common_test/doc/src/write_test_chapter.xml
+++ b/lib/common_test/doc/src/write_test_chapter.xml
@@ -515,14 +515,14 @@
<c>{group,GroupName,Properties,SubGroups}</c>
Where, <c>SubGroups</c> is a list of tuples, <c>{GroupName,Properties}</c> or
<c>{GroupName,Properties,SubGroups}</c> representing the subgroups.
- Any subgroups defined in <c>group/0</c> for a group, that are not specified
+ Any subgroups defined in <c>groups/0</c> for a group, that are not specified
in the <c>SubGroups</c> list, executes with their predefined
properties.</p>
<p><em>Example:</em></p>
<pre>
- groups() -> {tests1, [], [{tests2, [], [t2a,t2b]},
- {tests3, [], [t31,t3b]}]}.</pre>
+ groups() -> [{tests1, [], [{tests2, [], [t2a,t2b]},
+ {tests3, [], [t31,t3b]}]}].</pre>
<p>To execute group <c>tests1</c> twice with different properties for <c>tests2</c>
each time:</p>
<pre>
diff --git a/lib/common_test/src/ct_suite.erl b/lib/common_test/src/ct_suite.erl
index a2d23e15ef..860efe3ae2 100644
--- a/lib/common_test/src/ct_suite.erl
+++ b/lib/common_test/src/ct_suite.erl
@@ -47,9 +47,9 @@
{group, ct_groupname(), ct_group_props_ref()} |
{group, ct_groupname(), ct_group_props_ref(), ct_subgroups_def()}.
-type ct_testcase_ref() :: {testcase, ct_testname(), ct_testcase_repeat_prop()}.
--type ct_testcase_repeat_prop() :: {repeat, ct_test_repeat()} |
+-type ct_testcase_repeat_prop() :: [{repeat, ct_test_repeat()} |
{repeat_until_ok, ct_test_repeat()} |
- {repeat_until_fail, ct_test_repeat()}.
+ {repeat_until_fail, ct_test_repeat()}].
-type ct_info() :: {timetrap, ct_info_timetrap()} |
{require, ct_info_required()} |
{require, Name :: atom(), ct_info_required()} |
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml
index af671ff7ba..f92505409c 100644
--- a/lib/compiler/doc/src/notes.xml
+++ b/lib/compiler/doc/src/notes.xml
@@ -32,6 +32,43 @@
<p>This document describes the changes made to the Compiler
application.</p>
+<section><title>Compiler 8.2.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed type handling bugs that could cause an internal
+ error in the compiler for correct code.</p>
+ <p>
+ Own Id: OTP-18565 Aux Id: GH-7147 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 8.2.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>When a map update such as <c>#{}#{key:=value}</c> that
+ should fail with an exception was unused, the exception
+ would be lost.</p>
+ <p>
+ Own Id: OTP-18497 Aux Id: GH-6960, PR-6965 </p>
+ </item>
+ <item>
+ <p>Fixed bug in the validator that made it reject valid
+ code.</p>
+ <p>
+ Own Id: OTP-18516 Aux Id: GH-6969 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Compiler 8.2.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/compiler/src/beam_call_types.erl b/lib/compiler/src/beam_call_types.erl
index 8b9cb836fd..4324080098 100644
--- a/lib/compiler/src/beam_call_types.erl
+++ b/lib/compiler/src/beam_call_types.erl
@@ -364,14 +364,30 @@ types(erlang, is_boolean, [Type]) ->
end;
types(erlang, is_float, [Type]) ->
sub_unsafe_type_test(Type, #t_float{});
-types(erlang, is_function, [Type, #t_integer{elements={Arity,Arity}}])
- when Arity >= 0, Arity =< ?MAX_FUNC_ARGS ->
- RetType =
- case meet(Type, #t_fun{arity=Arity}) of
- Type -> #t_atom{elements=[true]};
- none -> #t_atom{elements=[false]};
- _ -> beam_types:make_boolean()
- end,
+types(erlang, is_function, [Type, ArityType]) ->
+ RetType = case meet(ArityType, #t_integer{}) of
+ none ->
+ none;
+ #t_integer{elements={Arity,Arity}}
+ when is_integer(Arity) ->
+ if
+ Arity < 0 ->
+ none;
+ 0 =< Arity, Arity =< ?MAX_FUNC_ARGS ->
+ case meet(Type, #t_fun{arity=Arity}) of
+ Type -> #t_atom{elements=[true]};
+ none -> #t_atom{elements=[false]};
+ _ -> beam_types:make_boolean()
+ end;
+ Arity > ?MAX_FUNC_ARGS ->
+ #t_atom{elements=[false]}
+ end;
+ #t_integer{} ->
+ case meet(Type, #t_fun{}) of
+ none -> #t_atom{elements=[false]};
+ _ -> beam_types:make_boolean()
+ end
+ end,
sub_unsafe(RetType, [any, any]);
types(erlang, is_function, [Type]) ->
sub_unsafe_type_test(Type, #t_fun{});
diff --git a/lib/compiler/src/beam_jump.erl b/lib/compiler/src/beam_jump.erl
index 90672bab7c..9ae5a33d74 100644
--- a/lib/compiler/src/beam_jump.erl
+++ b/lib/compiler/src/beam_jump.erl
@@ -464,6 +464,7 @@ add_scope([I|Is], Scope) ->
[I|add_scope(Is, Scope)];
add_scope([], _Scope) -> [].
+is_shareable([{badmatch,_}|_]) -> false;
is_shareable([build_stacktrace|_]) -> false;
is_shareable([{case_end,_}|_]) -> false;
is_shareable([{'catch',_,_}|_]) -> false;
diff --git a/lib/compiler/src/beam_ssa.erl b/lib/compiler/src/beam_ssa.erl
index 619a9f032a..448b3b4313 100644
--- a/lib/compiler/src/beam_ssa.erl
+++ b/lib/compiler/src/beam_ssa.erl
@@ -383,10 +383,21 @@ successors(#b_blk{last=Terminator}) ->
-spec normalize(b_set() | terminator()) ->
b_set() | terminator().
-normalize(#b_set{op={bif,Bif},args=Args}=Set) ->
+normalize(#b_set{anno=Anno0,op={bif,Bif},args=Args}=Set) ->
case {is_commutative(Bif),Args} of
{true, [#b_literal{}=Lit,#b_var{}=Var]} ->
- Set#b_set{args=[Var,Lit]};
+ Anno = case Anno0 of
+ #{arg_types := ArgTypes0} ->
+ case ArgTypes0 of
+ #{1 := Type} ->
+ Anno0#{arg_types => #{0 => Type}};
+ #{} ->
+ Anno0
+ end;
+ #{} ->
+ Anno0
+ end,
+ Set#b_set{anno=Anno,args=[Var,Lit]};
{_, _} ->
Set
end;
diff --git a/lib/compiler/src/beam_ssa_check.erl b/lib/compiler/src/beam_ssa_check.erl
index 0d3faa0ee2..f344286943 100644
--- a/lib/compiler/src/beam_ssa_check.erl
+++ b/lib/compiler/src/beam_ssa_check.erl
@@ -285,8 +285,9 @@ env_post1(_Pattern, _Actual, _Env) ->
?DP("Failed to match ~p <-> ~p~n", [_Pattern, _Actual]),
error({internal_pattern_match_error,env_post1}).
-post_bitstring(Bytes, Actual, _Env) ->
- Actual = build_bitstring(Bytes, <<>>).
+post_bitstring(Bytes, Actual, Env) ->
+ Actual = build_bitstring(Bytes, <<>>),
+ Env.
%% Convert the parsed literal binary to an actual bitstring.
build_bitstring([{integer,_,V}|Bytes], Acc) ->
diff --git a/lib/compiler/src/beam_ssa_codegen.erl b/lib/compiler/src/beam_ssa_codegen.erl
index c4708e9b11..9f6169829b 100644
--- a/lib/compiler/src/beam_ssa_codegen.erl
+++ b/lib/compiler/src/beam_ssa_codegen.erl
@@ -1450,6 +1450,12 @@ cg_copy_1([], _St) -> [].
element(1, Val) =:= atom orelse
element(1, Val) =:= literal)).
+bif_to_test(min, Args, Fail, St) ->
+ %% The min/2 and max/2 BIFs can only be rewritten to tests when
+ %% both arguments are known to be booleans.
+ bif_to_test('and', Args, Fail, St);
+bif_to_test(max, Args, Fail, St) ->
+ bif_to_test('or', Args, Fail, St);
bif_to_test('or', [V1,V2], {f,Lbl}=Fail, St0) when Lbl =/= 0 ->
{SuccLabel,St} = new_label(St0),
{[{test,is_eq_exact,{f,SuccLabel},[V1,{atom,false}]},
diff --git a/lib/compiler/src/beam_ssa_private_append.erl b/lib/compiler/src/beam_ssa_private_append.erl
index bf51e8b81a..c295492762 100644
--- a/lib/compiler/src/beam_ssa_private_append.erl
+++ b/lib/compiler/src/beam_ssa_private_append.erl
@@ -86,6 +86,17 @@ find_appends_blk([], _, Found) ->
Found.
find_appends_is([#b_set{dst=Dst, op=bs_create_bin,
+ args=[#b_literal{val=append},
+ _,
+ Lit=#b_literal{val= <<>>}|_]}|Is],
+ Fun, Found0) ->
+ %% Special case for when the first fragment is a literal <<>> as
+ %% it won't be annotated as unique nor will it die with the
+ %% instruction.
+ AlreadyFound = maps:get(Fun, Found0, []),
+ Found = Found0#{Fun => [{append,Dst,Lit}|AlreadyFound]},
+ find_appends_is(Is, Fun, Found);
+find_appends_is([#b_set{dst=Dst, op=bs_create_bin,
args=[#b_literal{val=append},SegmentInfo,Var|_],
anno=#{first_fragment_dies:=Dies}=Anno}|Is],
Fun, Found0) ->
@@ -468,6 +479,16 @@ patch_appends_is([I0=#b_set{dst=Dst}|Rest], PD0, Cnt0, Acc, BlockAdditions0)
Ps = keysort(1, map(ExtractOpargs, Patches)),
{Is, Cnt} = patch_opargs(I0, Ps, Cnt0),
patch_appends_is(Rest, PD, Cnt, Is++Acc, BlockAdditions0);
+ [{append,Dst,#b_literal{val= <<>>}=Lit}] ->
+ %% Special case for when the first fragment is a literal
+ %% <<>> and it has to be replaced with a bs_init_writable.
+ #b_set{op=bs_create_bin,dst=Dst,args=Args0}=I0,
+ [#b_literal{val=append},SegInfo,Lit|OtherArgs] = Args0,
+ {V,Cnt} = new_var(Cnt0),
+ Init = #b_set{op=bs_init_writable,dst=V,args=[#b_literal{val=256}]},
+ I = I0#b_set{args=[#b_literal{val=private_append},
+ SegInfo,V|OtherArgs]},
+ patch_appends_is(Rest, PD, Cnt, [I,Init|Acc], BlockAdditions0);
[{append,Dst,_}] ->
#b_set{op=bs_create_bin,dst=Dst,args=Args0}=I0,
[#b_literal{val=append}|OtherArgs] = Args0,
diff --git a/lib/compiler/src/beam_types.erl b/lib/compiler/src/beam_types.erl
index 9c3da159c4..c3bf7c8fae 100644
--- a/lib/compiler/src/beam_types.erl
+++ b/lib/compiler/src/beam_types.erl
@@ -1179,14 +1179,23 @@ float_from_range(none) ->
none;
float_from_range(any) ->
#t_float{};
-float_from_range({'-inf','+inf'}) ->
- #t_float{};
-float_from_range({'-inf',Max}) ->
- #t_float{elements={'-inf',float(Max)}};
-float_from_range({Min,'+inf'}) ->
- #t_float{elements={float(Min),'+inf'}};
-float_from_range({Min,Max}) ->
- #t_float{elements={float(Min),float(Max)}}.
+float_from_range({Min0,Max0}) ->
+ case {safe_float(Min0),safe_float(Max0)} of
+ {'-inf','+inf'} ->
+ #t_float{};
+ {Min,Max} ->
+ #t_float{elements={Min,Max}}
+ end.
+
+safe_float(N) when is_number(N) ->
+ try
+ float(N)
+ catch
+ error:_ when N < 0 -> '-inf';
+ error:_ when N > 0 -> '+inf'
+ end;
+safe_float('-inf'=NegInf) -> NegInf;
+safe_float('+inf'=PosInf) -> PosInf.
integer_from_range(none) ->
none;
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 285db8a26a..217b7a2c97 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -1582,7 +1582,7 @@ update_create_bin_list([], Vst) -> Vst.
update_create_bin_type(append) -> #t_bitstring{};
update_create_bin_type(private_append) -> #t_bitstring{};
update_create_bin_type(binary) -> #t_bitstring{};
-update_create_bin_type(float) -> #t_float{};
+update_create_bin_type(float) -> #t_number{};
update_create_bin_type(integer) -> #t_integer{};
update_create_bin_type(utf8) -> #t_integer{};
update_create_bin_type(utf16) -> #t_integer{};
@@ -3435,7 +3435,17 @@ bif_types(Op, Ss, Vst) ->
Other
end;
{_,_} ->
- beam_call_types:types(erlang, Op, Args)
+ Res0 = beam_call_types:types(erlang, Op, Args),
+ {Ret0, ArgTypes, SubSafe} = Res0,
+
+ %% Match the non-converging range analysis done in
+ %% `beam_ssa_type:opt_ranges/1`. This is safe since the validator
+ %% doesn't have to worry about convergence.
+ case beam_call_types:arith_type({bif, Op}, Args) of
+ any -> Res0;
+ Ret0 -> Res0;
+ Ret -> {meet(Ret, Ret0), ArgTypes, SubSafe}
+ end
end.
join_tuple_elements(Tuple) ->
diff --git a/lib/compiler/test/beam_jump_SUITE.erl b/lib/compiler/test/beam_jump_SUITE.erl
index 713a1ea5ab..65fecd5b7c 100644
--- a/lib/compiler/test/beam_jump_SUITE.erl
+++ b/lib/compiler/test/beam_jump_SUITE.erl
@@ -82,6 +82,8 @@ ambiguous_catch_try_state(Config) ->
{'EXIT',{{badmatch,0},_}} = (catch ambiguous_catch_try_state_2()),
{'EXIT',{{badmatch,0},_}} = (catch ambiguous_catch_try_state_3()),
+ {'EXIT',{badarg,_}} = catch ambiguous_catch_try_state_4(),
+
ok.
river() -> song.
@@ -229,6 +231,12 @@ ambiguous_catch_try_state_3() ->
end.
+ambiguous_catch_try_state_4() ->
+ 0.0 = try binary_to_float(garbage_collect() orelse ((1.0 = tuple_to_list(ok)) -- ok))
+ after
+ ok
+ end.
+
-record(message2, {id, p1}).
-record(message3, {id, p1, p2}).
diff --git a/lib/compiler/test/beam_ssa_SUITE.erl b/lib/compiler/test/beam_ssa_SUITE.erl
index 6a91bdd7b8..0bb485c7f1 100644
--- a/lib/compiler/test/beam_ssa_SUITE.erl
+++ b/lib/compiler/test/beam_ssa_SUITE.erl
@@ -27,7 +27,7 @@
beam_ssa_dead_crash/1,stack_init/1,
mapfoldl/0,mapfoldl/1,
grab_bag/1,redundant_br/1,
- coverage/1]).
+ coverage/1,normalize/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -48,7 +48,8 @@ groups() ->
stack_init,
grab_bag,
redundant_br,
- coverage
+ coverage,
+ normalize
]}].
init_per_suite(Config) ->
@@ -1260,5 +1261,90 @@ coverage_5() ->
error
end#coverage{name = whatever}.
+%% Test beam_ssa:normalize/1, especially that argument types are
+%% correctly updated when arguments are swapped.
+normalize(_Config) ->
+ normalize_commutative({bif,'band'}),
+ normalize_commutative({bif,'+'}),
+
+ normalize_noncommutative({bif,'div'}),
+
+ ok.
+
+-record(b_var, {name}).
+-record(b_literal, {val}).
+
+normalize_commutative(Op) ->
+ A = #b_var{name=a},
+ B = #b_var{name=b},
+ Lit = #b_literal{val=42},
+
+ normalize_same(Op, [A,B]),
+ normalize_same(Op, [A,Lit]),
+
+ normalize_swapped(Op, [Lit,A]),
+
+ ok.
+
+normalize_noncommutative(Op) ->
+ A = #b_var{name=a},
+ B = #b_var{name=b},
+ Lit = #b_literal{val=42},
+
+ normalize_same(Op, [A,B]),
+ normalize_same(Op, [A,Lit]),
+
+ ArgTypes0 = [{1,beam_types:make_integer(0, 1023)}],
+ I1 = make_bset(ArgTypes0, Op, [Lit,A]),
+ I1 = beam_ssa:normalize(I1),
+
+ ok.
+
+normalize_same(Op, Args) ->
+ I0 = make_bset(#{}, Op, Args),
+ I0 = beam_ssa:normalize(I0),
+
+ ArgTypes0 = [{0,beam_types:make_integer(0, 1023)}],
+ I1 = make_bset(ArgTypes0, Op, Args),
+ I1 = beam_ssa:normalize(I1),
+
+ case Args of
+ [#b_var{},#b_var{}] ->
+ ArgTypes1 = [{0,beam_types:make_integer(0, 1023)},
+ {1,beam_types:make_integer(42)}],
+ I2 = make_bset(ArgTypes1, Op, Args),
+ I2 = beam_ssa:normalize(I2);
+ [_,_] ->
+ ok
+ end,
+
+ ok.
+
+normalize_swapped(Op, [#b_literal{}=Lit,#b_var{}=Var]=Args) ->
+ EmptyAnno = #{},
+ I0 = make_bset(EmptyAnno, Op, Args),
+ {b_set,EmptyAnno,#b_var{name=1000},Op,[Var,Lit]} = beam_ssa:normalize(I0),
+
+ EmptyTypes = #{arg_types => #{}},
+ I1 = make_bset(EmptyTypes, Op, Args),
+ {b_set,EmptyTypes,#b_var{name=1000},Op,[Var,Lit]} = beam_ssa:normalize(I1),
+
+ IntRange = beam_types:make_integer(0, 1023),
+ ArgTypes0 = [{1,IntRange}],
+ I2 = make_bset(ArgTypes0, Op, Args),
+ {[{0,IntRange}],Op,[Var,Lit]} = unpack_bset(beam_ssa:normalize(I2)),
+
+ ok.
+
+make_bset(ArgTypes, Op, Args) when is_list(ArgTypes) ->
+ Anno = #{arg_types => maps:from_list(ArgTypes)},
+ {b_set,Anno,#b_var{name=1000},Op,Args};
+make_bset(Anno, Op, Args) when is_map(Anno) ->
+ {b_set,Anno,#b_var{name=1000},Op,Args}.
+
+unpack_bset({b_set,Anno,{b_var,1000},Op,Args}) ->
+ ArgTypes = maps:get(arg_types, Anno, #{}),
+ {lists:sort(maps:to_list(ArgTypes)),Op,Args}.
+
%% The identity function.
id(I) -> I.
diff --git a/lib/compiler/test/beam_ssa_check_SUITE_data/private_append.erl b/lib/compiler/test/beam_ssa_check_SUITE_data/private_append.erl
index 4d4b0f1bbd..c1edc54460 100644
--- a/lib/compiler/test/beam_ssa_check_SUITE_data/private_append.erl
+++ b/lib/compiler/test/beam_ssa_check_SUITE_data/private_append.erl
@@ -22,6 +22,8 @@
%%
-module(private_append).
+-feature(maybe_expr, enable).
+
-export([transformable0/1,
transformable1/1,
transformable1b/1,
@@ -76,7 +78,9 @@
not_transformable14/0,
not_transformable15/2,
- id/1]).
+ id/1,
+
+ bs_create_bin_on_literal/0]).
%% Trivial smoke test
transformable0(L) ->
@@ -977,3 +981,24 @@ not_transformable15(_, V) ->
id(I) ->
I.
+
+%% Check that we don't try to private_append to something created by
+%% bs_create_bin `append`, _, `<<>>`, ...
+bs_create_bin_on_literal() ->
+%ssa% () when post_ssa_opt ->
+%ssa% X = bs_init_writable(_),
+%ssa% Y = bs_create_bin(private_append, _, X, ...),
+%ssa% Z = bs_create_bin(private_append, _, Y, ...),
+%ssa% ret(Z).
+ <<
+ <<
+ (maybe
+ 2147483647 ?= ok
+ else
+ <<_>> ->
+ ok;
+ _ ->
+ <<>>
+ end)/bytes
+ >>/binary
+ >>.
diff --git a/lib/compiler/test/beam_ssa_check_SUITE_data/sanity_checks.erl b/lib/compiler/test/beam_ssa_check_SUITE_data/sanity_checks.erl
index ae4bb28eea..47c60fd8d6 100644
--- a/lib/compiler/test/beam_ssa_check_SUITE_data/sanity_checks.erl
+++ b/lib/compiler/test/beam_ssa_check_SUITE_data/sanity_checks.erl
@@ -18,6 +18,8 @@
-module(sanity_checks).
+-compile(no_ssa_opt_private_append).
+
-export([check_fail/0,
check_wrong_pass/0,
check_xfail/0,
@@ -33,7 +35,9 @@
t25/0, t26/0, t27/0, t28/0, t29/0,
t30/0, t31/0, t32/1, t33/1, t34/1,
t35/1, t36/0, t37/0, t38/0, t39/1,
- t40/0, t41/0, t42/0, t43/0, t44/0]).
+ t40/0, t41/0, t42/0, t43/0, t44/0,
+
+ check_env/0]).
%% Check that we do not trigger on the wrong pass
check_wrong_pass() ->
@@ -325,3 +329,13 @@ t44() ->
%ssa% () when post_ssa_opt ->
%ssa% _ = call(fun e:f0/1, {...}).
e:f0({}).
+
+%% Ensure bug which trashed the environment after matching a literal
+%% bitstring stays fixed.
+check_env() ->
+%ssa% () when post_ssa_opt ->
+%ssa% X = bs_create_bin(append, _, <<>>, ...),
+%ssa% ret(X).
+ A = <<>>,
+ B = ex:f(),
+ <<A/binary, B/binary>>.
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
index 0b00e6d71c..707c7ca80b 100644
--- a/lib/compiler/test/beam_type_SUITE.erl
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -22,14 +22,16 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
integers/1,numbers/1,coverage/1,booleans/1,setelement/1,
- cons/1,tuple/1,record_float/1,binary_float/1,float_compare/1,
+ cons/1,tuple/1,
+ record_float/1,binary_float/1,float_compare/1,float_overflow/1,
arity_checks/1,elixir_binaries/1,find_best/1,
test_size/1,cover_lists_functions/1,list_append/1,bad_binary_unit/1,
none_argument/1,success_type_oscillation/1,type_subtraction/1,
container_subtraction/1,is_list_opt/1,connected_tuple_elements/1,
switch_fail_inference/1,failures/1,
cover_maps_functions/1,min_max_mixed_types/1,
- not_equal/1,infer_relops/1,binary_unit/1,premature_concretization/1]).
+ not_equal/1,infer_relops/1,binary_unit/1,premature_concretization/1,
+ funs/1]).
%% Force id/1 to return 'any'.
-export([id/1]).
@@ -51,6 +53,7 @@ groups() ->
record_float,
binary_float,
float_compare,
+ float_overflow,
arity_checks,
elixir_binaries,
find_best,
@@ -71,7 +74,8 @@ groups() ->
not_equal,
infer_relops,
binary_unit,
- premature_concretization
+ premature_concretization,
+ funs
]}].
init_per_suite(Config) ->
@@ -741,11 +745,17 @@ record_float(R, N0) ->
binary_float(_Config) ->
<<-1/float>> = binary_negate_float(<<1/float>>),
+ {'EXIT',{badarg,_}} = catch binary_float_1(id(64.0), id(0)),
ok.
binary_negate_float(<<Float/float>>) ->
<<-Float/float>>.
+%% GH-7147.
+binary_float_1(X, Y) ->
+ _ = <<Y:(ceil(64.0 = X))/float, (binary_to_integer(ok))>>,
+ ceil(X) band Y.
+
float_compare(_Config) ->
false = do_float_compare(-42.0),
false = do_float_compare(-42),
@@ -765,6 +775,46 @@ do_float_compare(X) ->
_T -> Y > 0
end.
+float_overflow(_Config) ->
+ Res1 = id((1 bsl 1023) * two()),
+ Res1 = float_overflow_1(),
+
+ Res2 = id((-1 bsl 1023) * two()),
+ Res2 = float_overflow_2(),
+
+ {'EXIT',{{bad_filter,[0]},_}} = catch float_overflow_3(),
+
+ ok.
+
+%% GH-7178: There would be an overflow when converting a number range
+%% to a float range.
+float_overflow_1() ->
+ round(
+ try
+ round(float(1 bsl 1023)) * two()
+ catch
+ _:_ ->
+ 0.0
+ end
+ ).
+
+float_overflow_2() ->
+ round(
+ try
+ round(float(-1 bsl 1023)) * two()
+ catch
+ _:_ ->
+ 0.0
+ end
+ ).
+
+two() -> 2.
+
+float_overflow_3() ->
+ [0 || <<>> <= <<>>,
+ [0 || (floor(1.7976931348623157e308) bsl 1) >= (1.0 + map_size(#{}))]
+ ].
+
arity_checks(_Config) ->
%% ERL-549: an unsafe optimization removed a test_arity instruction,
%% causing the following to return 'broken' instead of 'ok'.
@@ -1363,5 +1413,30 @@ pm_concretization_2(_, Tagged) -> {error, Tagged}.
pm_concretization_3(_) -> ok.
pm_concretization_4(_) -> ok.
+funs(_Config) ->
+ {'EXIT',{badarg,_}} = catch gh_7179(),
+ false = is_function(id(fun() -> ok end), 1024),
+
+ {'EXIT',{badarg,_}} = catch gh_7197(),
+
+ ok.
+
+%% GH-7179: The beam_ssa_type pass would crash.
+gh_7179() ->
+ << <<0>> || is_function([0 || <<_>> <= <<>>], -1),
+ [] <- [] >>.
+
+%% GH-7197: The beam_ssa_type pass would crash.
+gh_7197() ->
+ [0 || is_function([ok || <<_>> <= <<>>], get_keys()),
+ fun (_) ->
+ ok
+ end].
+
+
+%%%
+%%% Common utilities.
+%%%
+
id(I) ->
I.
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index 6b63f561c1..2092d7401a 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -43,7 +43,7 @@
container_performance/1,
infer_relops/1,
not_equal_inference/1,bad_bin_unit/1,singleton_inference/1,
- inert_update_type/1]).
+ inert_update_type/1,range_inference/1]).
-include_lib("common_test/include/ct.hrl").
@@ -80,7 +80,7 @@ groups() ->
bs_saved_position_units,parent_container,
container_performance,infer_relops,
not_equal_inference,bad_bin_unit,singleton_inference,
- inert_update_type]}].
+ inert_update_type,range_inference]}].
init_per_suite(Config) ->
test_lib:recompile(?MODULE),
@@ -1129,5 +1129,22 @@ mike([Head | _Rest]) -> joe(Head).
joe({Name, 42}) -> Name;
joe({sys_period, {A, _B}}) -> {41, 42, A}.
+range_inference(_Config) ->
+ ok = range_inference_1(id(<<$a>>)),
+ ok = range_inference_1(id(<<0>>)),
+ ok = range_inference_1(id(<<1114111/utf8>>)),
+
+ ok.
+
+range_inference_1(<<X/utf8>>) ->
+ case 9223372036854775807 - abs(X) of
+ Y when X < Y ->
+ ok;
+ 9223372036854775807 ->
+ ok;
+ -2147483648 ->
+ ok
+ end.
+
id(I) ->
I.
diff --git a/lib/compiler/test/bif_SUITE.erl b/lib/compiler/test/bif_SUITE.erl
index fc1d9ddfc0..e58db29114 100644
--- a/lib/compiler/test/bif_SUITE.erl
+++ b/lib/compiler/test/bif_SUITE.erl
@@ -25,7 +25,8 @@
init_per_group/2,end_per_group/2,
beam_validator/1,trunc_and_friends/1,cover_safe_and_pure_bifs/1,
cover_trim/1,
- head_tail/1]).
+ head_tail/1,
+ min_max/1]).
suite() ->
[{ct_hooks,[ts_install_cth]}].
@@ -34,12 +35,13 @@ all() ->
[{group,p}].
groups() ->
- [{p,[parallel],
+ [{p,test_lib:parallel(),
[beam_validator,
trunc_and_friends,
cover_safe_and_pure_bifs,
cover_trim,
- head_tail
+ head_tail,
+ min_max
]}].
init_per_suite(Config) ->
@@ -192,5 +194,40 @@ tail_case() ->
X -> {X, ok}
end.
+min_max(_Config) ->
+ False = id(false),
+ True = id(true),
+
+ false = bool_min_false(False, False),
+ false = bool_min_false(False, True),
+ false = bool_min_false(True, False),
+ true = bool_min_true(True, True),
+
+ false = bool_max_false(False, False),
+ true = bool_max_true(False, True),
+ true = bool_max_true(True, False),
+ true = bool_max_true(True, True),
+
+ ok.
+
+%% GH-7170: The following functions would cause a crash in
+%% beam_ssa_codegen.
+
+bool_min_false(A, B) when is_boolean(A), is_boolean(B) ->
+ false = min(A, B).
+
+bool_min_true(A, B) when is_boolean(A), is_boolean(B) ->
+ true = min(A, B).
+
+bool_max_false(A, B) when is_boolean(A), is_boolean(B) ->
+ false = max(A, B).
+
+bool_max_true(A, B) when is_boolean(A), is_boolean(B) ->
+ true = max(A, B).
+
+%%%
+%%% Common utilities.
+%%%
+
id(I) ->
I.
diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk
index 0a39fcf419..fa46ea4097 100644
--- a/lib/compiler/vsn.mk
+++ b/lib/compiler/vsn.mk
@@ -1 +1 @@
-COMPILER_VSN = 8.2.4
+COMPILER_VSN = 8.2.6
diff --git a/lib/crypto/c_src/dh.c b/lib/crypto/c_src/dh.c
index 92a339ab5f..15a08470a6 100644
--- a/lib/crypto/c_src/dh.c
+++ b/lib/crypto/c_src/dh.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2022. All Rights Reserved.
+ * Copyright Ericsson AB 2010-2023. 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.
diff --git a/lib/crypto/c_src/openssl_config.h b/lib/crypto/c_src/openssl_config.h
index 9c7b05660e..e356cf94fb 100644
--- a/lib/crypto/c_src/openssl_config.h
+++ b/lib/crypto/c_src/openssl_config.h
@@ -127,6 +127,15 @@
# define HAS_EVP_PKEY_CTX
# define HAVE_EVP_CIPHER_CTX_COPY
# endif
+# if LIBRESSL_VERSION_NUMBER >= 0x3070200fL
+# define HAVE_PKEY_new_raw_private_key
+# endif
+# if LIBRESSL_VERSION_NUMBER >= 0x3030300fL
+# define HAVE_EVP_PKEY_new_CMAC_key
+# endif
+# if LIBRESSL_VERSION_NUMBER >= 0x3040100fL
+# define HAVE_DigestSign_as_single_op
+# endif
#endif
#if defined(HAS_EVP_PKEY_CTX) \
diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml
index 954d5cd664..fa5e9d5bea 100644
--- a/lib/crypto/doc/src/notes.xml
+++ b/lib/crypto/doc/src/notes.xml
@@ -31,6 +31,22 @@
</header>
<p>This document describes the changes made to the Crypto application.</p>
+<section><title>Crypto 5.1.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ With this change, random errors are fixed for
+ crypto:generate_key calls with OpenSSL 3.</p>
+ <p>
+ Own Id: OTP-18555</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 5.1.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 69b01e6418..6abaacad5c 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -685,8 +685,6 @@ hash_final_xof(Context, Length) ->
-type hmac_hash_algorithm() :: sha1() | sha2() | sha3() | compatibility_only_hash().
-type cmac_cipher_algorithm() :: aes_128_cbc | aes_192_cbc | aes_256_cbc | aes_cbc
- | aes_128_cfb128 | aes_192_cfb128 | aes_256_cfb128 | aes_cfb128
- | aes_128_cfb8 | aes_192_cfb8 | aes_256_cfb8 | aes_cfb8
| blowfish_cbc
| des_cbc | des_ede3_cbc
| rc2_cbc
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 516ad02ee2..0572feaf33 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -1,7 +1,7 @@
%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2022. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2023. 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.
@@ -411,11 +411,11 @@ groups() ->
{ecdh, [], [compute, generate, use_all_ecdh_generate_compute]},
{eddh, [], [compute, generate, use_all_eddh_generate_compute]},
{srp, [], [generate_compute]},
- {des_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {des_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls, cmac, cmac_update]},
{des_cfb, [], [api_ng, api_ng_one_shot, api_ng_tls]},
- {des_ede3_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls, cmac]},
+ {des_ede3_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls, cmac, cmac_update]},
{des_ede3_cfb, [], [api_ng, api_ng_one_shot, api_ng_tls]},
- {rc2_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {rc2_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls, cmac, cmac_update]},
{aes_cfb8, [], []},
{aes_128_cfb8, [], [api_ng, api_ng_one_shot, api_ng_tls]},
{aes_192_cfb8, [], [api_ng, api_ng_one_shot, api_ng_tls]},
@@ -426,7 +426,7 @@ groups() ->
{aes_192_cfb128, [], [api_ng, api_ng_one_shot, api_ng_tls]},
{aes_256_cfb128, [], [api_ng, api_ng_one_shot, api_ng_tls]},
{no_aes_cfb128, [], [no_support]},
- {blowfish_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
+ {blowfish_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls, cmac, cmac_update]},
{blowfish_ecb, [], [api_ng, api_ng_one_shot]},
{blowfish_cfb64, [], [api_ng, api_ng_one_shot, api_ng_tls]},
{blowfish_ofb64, [], [api_ng, api_ng_one_shot, api_ng_tls]},
@@ -473,15 +473,15 @@ groups() ->
{des_ede3_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
{des_ede3_cfb, [], [api_ng, api_ng_one_shot, api_ng_tls]},
{aes_128_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls, cmac, cmac_update]},
- {aes_192_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls]},
- {aes_256_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls, cmac]},
+ {aes_192_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls, cmac, cmac_update]},
+ {aes_256_cbc, [], [api_ng, api_ng_one_shot, api_ng_tls, cmac, cmac_update]},
{aes_128_ctr, [], [api_ng, api_ng_one_shot, api_ng_tls]},
{aes_192_ctr, [], [api_ng, api_ng_one_shot, api_ng_tls]},
{aes_256_ctr, [], [api_ng, api_ng_one_shot, api_ng_tls]},
{aes_128_ccm, [], [aead_ng, aead_bad_tag]},
{aes_192_ccm, [], [aead_ng, aead_bad_tag]},
{aes_256_ccm, [], [aead_ng, aead_bad_tag]},
- {aes_128_ecb, [], [api_ng, api_ng_one_shot, cmac_update]},
+ {aes_128_ecb, [], [api_ng, api_ng_one_shot]},
{aes_192_ecb, [], [api_ng, api_ng_one_shot]},
{aes_256_ecb, [], [api_ng, api_ng_one_shot]},
{aes_128_gcm, [], [aead_ng, aead_bad_tag]},
@@ -2378,6 +2378,8 @@ do_configure_mac(cmac, Cipher, Config) ->
case Cipher of
aes_128_cbc ->
fun() -> read_rsp(Config, Cipher, ["CMACGenAES128.rsp", "CMACVerAES128.rsp"]) end;
+ aes_192_cbc ->
+ fun() -> read_rsp(Config, Cipher, ["CMACGenAES192.rsp", "CMACVerAES192.rsp"]) end;
aes_256_cbc ->
fun() -> read_rsp(Config, Cipher, ["CMACGenAES256.rsp", "CMACVerAES256.rsp"]) end;
des_ede3_cbc ->
@@ -2933,10 +2935,9 @@ hmac_inc(_) ->
[<<"Sampl">>, <<"e #1">>].
-cmac_key(aes_128_cbc) ->
- hexstr2bin("8eeca0d146fd09ffbbe0d47edcddfcec");
-cmac_key(aes_128_ecb) ->
- hexstr2bin("8eeca0d146fd09ffbbe0d47edcddfcec").
+cmac_key(SubType) ->
+ rand:bytes(
+ maps:get(key_length, crypto:cipher_info(SubType))).
cmac_inc(_) ->
[<<"Sampl">>, <<"e #1">>].
diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk
index 41dfbaef97..56f5a0f48e 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 5.1.3
+CRYPTO_VSN = 5.1.4
diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml
index 9a2b409348..334cfcb8d7 100644
--- a/lib/dialyzer/doc/src/dialyzer.xml
+++ b/lib/dialyzer/doc/src/dialyzer.xml
@@ -507,6 +507,32 @@ dialyzer --plts plt_1 ... plt_n -- files_to_analyze</code>
<p>Currently the only option used is the
<seeerl marker="#error_location"><c>error_location</c></seeerl> option.
</p>
+
+ <p><em>Dialyzer configuration file:</em></p>
+
+ <p>Dialyzer's configuration file may also be used to augment the default
+ options and those given directly to the Dialyzer command. It is commonly
+ used to avoid repeating options which would otherwise need to be given
+ explicitly to Dialyzer on every invocation.
+ </p>
+
+ <p>The location of the configuration file can be set via the
+ <c>DIALYZER_CONFIG</c> environment variable, and defaults to
+ within the <c>user_config</c> from <seemfa marker="stdlib:filename#basedir/3">
+ <c>filename:basedir/3</c></seemfa>.
+ </p>
+
+ <p>An example configuration file's contents might be:</p>
+
+ <code type="none">
+ {incremental,
+ {default_apps,[stdlib,kernel,erts]},
+ {default_warning_apps,[stdlib]}
+ }.
+ {warnings, [no_improper_lists]}.
+ {add_pathsa,["/users/samwise/potatoes/ebin"]}.
+ {add_pathsz,["/users/smeagol/fish/ebin"]}.
+ </code>
</section>
<section>
diff --git a/lib/dialyzer/src/dialyzer.app.src b/lib/dialyzer/src/dialyzer.app.src
index 9693aa66cd..311c019a31 100644
--- a/lib/dialyzer/src/dialyzer.app.src
+++ b/lib/dialyzer/src/dialyzer.app.src
@@ -56,6 +56,6 @@
{registered, []},
{applications, [compiler, kernel, stdlib]},
{env, []},
- {runtime_dependencies, ["wx-2.0","syntax_tools-2.0","stdlib-4.0",
+ {runtime_dependencies, ["wx-2.0","syntax_tools-2.0","stdlib-@OTP-18558@",
"kernel-8.0","erts-12.0",
"compiler-8.0"]}]}.
diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl
index a502f7107d..ecfc509e34 100644
--- a/lib/dialyzer/src/dialyzer.erl
+++ b/lib/dialyzer/src/dialyzer.erl
@@ -415,8 +415,8 @@ message_to_string({app_call, [M, F, Args, Culprit, ExpectedType, FoundType]},
[M, F, a(Args, I), c(Culprit, I),
t(ExpectedType, I), t(FoundType, I)]);
message_to_string({bin_construction, [Culprit, Size, Seg, Type]}, I, _E) ->
- io_lib:format("Binary construction will fail since the ~s field ~s in"
- " segment ~s has type ~s\n",
+ io_lib:format("Binary construction will fail since the ~ts field ~ts in"
+ " segment ~ts has type ~ts\n",
[Culprit, c(Size, I), c(Seg, I), t(Type, I)]);
message_to_string({call, [M, F, Args, ArgNs, FailReason,
SigArgs, SigRet, Contract]}, I, _E) ->
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index 6d163c2cf9..b5cc6c7392 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -504,10 +504,11 @@ expand_files(Analysis = #analysis{files = Files, start_from = StartFrom}) ->
case expand_files(Files, Ext, []) of
[] ->
Msg = "No " ++ Ext ++ " files to analyze" ++
- case StartFrom of
- byte_code -> " (no --src specified?)";
- src_code -> ""
- end,
+ case StartFrom of
+ byte_code -> " (no --src specified?)";
+ src_code -> ""
+ end ++
+ "\nConsider setting some default apps in your dialyzer.config file",
exit({error, Msg});
NewFiles ->
Analysis#analysis{files = NewFiles}
diff --git a/lib/dialyzer/src/dialyzer_cl_parse.erl b/lib/dialyzer/src/dialyzer_cl_parse.erl
index fe7ad2af01..2babea0073 100644
--- a/lib/dialyzer/src/dialyzer_cl_parse.erl
+++ b/lib/dialyzer/src/dialyzer_cl_parse.erl
@@ -252,6 +252,8 @@ Note:
the syntax of defines and includes is the same as that used by \"erlc\".
" ++ warning_options_msg() ++ "
+" ++ configuration_file_msg() ++ "
+
The exit status of the command line version is:
0 - No problems were encountered during the analysis and no
warnings were emitted.
@@ -383,3 +385,29 @@ They are primarily intended to be used with the -dialyzer attribute:
-Wno_missing_return
Suppress warnings about functions that return values that are not part of the specification.
".
+
+configuration_file_msg() ->
+ "Configuration file:
+ Dialyzer's configuration file may also be used to augment the default
+ options and those given directly to the Dialyzer command. It is commonly
+ used to avoid repeating options which would otherwise need to be given
+ explicitly to Dialyzer on every invocation.
+
+ The location of the configuration file can be set via the
+ DIALYZER_CONFIG environment variable, and defaults to
+ within the user_config location given by filename:basedir/3.
+
+ On your system, the location is currently configured as:
+ " ++ dialyzer_options:get_default_config_filename() ++
+ "
+
+ An example configuration file's contents might be:
+
+ {incremental,
+ {default_apps,[stdlib,kernel,erts]},
+ {default_warning_apps,[stdlib]}
+ }.
+ {warnings, [no_improper_lists]}.
+ {add_pathsa,[\"/users/samwise/potatoes/ebin\"]}.
+ {add_pathsz,[\"/users/smeagol/fish/ebin\"]}.
+".
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index bb77ea972f..7e0a75f062 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -1602,20 +1602,23 @@ bind_bin_segs([Seg|Segs], BinType, Acc, Map, State) ->
UnitVal = cerl:concrete(cerl:bitstr_unit(Seg)),
Size = cerl:bitstr_size(Seg),
case bitstr_bitsize_type(Size) of
- all ->
- binary = SegType, [] = Segs, %% just an assert
+ {literal, all} ->
+ binary = SegType, [] = Segs, %Assertion.
T = t_inf(t_bitstr(UnitVal, 0), BinType),
{Map1, [Type]} = do_bind_pat_vars([Val], [T], Map,
State, false, []),
Type1 = remove_local_opaque_types(Type, State#state.opaques),
bind_bin_segs(Segs, t_bitstr(0, 0), [Type1|Acc], Map1, State);
- utf -> % XXX: can possibly be strengthened
- true = lists:member(SegType, [utf8, utf16, utf32]),
+ SizeType when SegType =:= utf8; SegType =:= utf16; SegType =:= utf32 ->
+ {literal, undefined} = SizeType, %Assertion.
{Map1, [_]} = do_bind_pat_vars([Val], [t_integer()],
Map, State, false, []),
Type = t_binary(),
bind_bin_segs(Segs, BinType, [Type|Acc], Map1, State);
- any ->
+ {literal, N} when not is_integer(N); N < 0 ->
+ %% Bogus literal size, fails in runtime.
+ bind_error([Seg], BinType, t_none(), bind);
+ _ ->
{Map1, [SizeType]} = do_bind_pat_vars([Size], [t_non_neg_integer()],
Map, State, false, []),
Opaques = State#state.opaques,
@@ -1668,14 +1671,8 @@ bind_bin_segs([], _BinType, Acc, Map, _State) ->
bitstr_bitsize_type(Size) ->
case cerl:is_literal(Size) of
- true ->
- case cerl:concrete(Size) of
- all -> all;
- undefined -> utf;
- _ -> any
- end;
- false ->
- any
+ true -> {literal, cerl:concrete(Size)};
+ false -> variable
end.
%% Return the infimum (meet) of ExpectedType and Type if it describes a
diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl
index 27da2f9c83..de35f5f204 100644
--- a/lib/dialyzer/src/dialyzer_options.erl
+++ b/lib/dialyzer/src/dialyzer_options.erl
@@ -18,7 +18,7 @@
-module(dialyzer_options).
--export([build/1, build_warnings/2]).
+-export([build/1, build_warnings/2, get_default_config_filename/0]).
-include("dialyzer.hrl").
@@ -48,9 +48,12 @@ build(Opts) ->
?WARN_UNDEFINED_CALLBACK,
?WARN_UNKNOWN],
DefaultWarns1 = ordsets:from_list(DefaultWarns),
- DefaultOpts = #options{},
- DefaultOpts1 = DefaultOpts#options{legal_warnings = DefaultWarns1},
try
+ WarningsFromConfig = proplists:get_value(warnings, get_config(), []),
+ update_path_from_config(),
+ DefaultWarns2 = build_warnings(WarningsFromConfig, DefaultWarns1),
+ DefaultOpts = #options{},
+ DefaultOpts1 = DefaultOpts#options{legal_warnings = DefaultWarns2},
Opts1 = preprocess_opts(Opts),
Env = env_default_opts(),
ErrLoc = proplists:get_value(error_location, Env, ?ERROR_LOCATION),
@@ -61,6 +64,31 @@ build(Opts) ->
throw:{dialyzer_options_error, Msg} -> {error, Msg}
end.
+update_path_from_config() ->
+ Config = get_config(),
+ PAs = proplists:get_value(add_pathsa, Config, []),
+ PZs = proplists:get_value(add_pathsz, Config, []),
+ case is_list(PAs) of
+ true -> ok;
+ false -> bad_option("Bad list of paths in config", {add_pathsa, PAs})
+ end,
+ case is_list(PZs) of
+ true -> ok;
+ false -> bad_option("Bad list of paths in config", {add_pathsz, PZs})
+ end,
+ %% Add paths one-by-one so that we can report issues
+ %% if any path is invalid
+ %% (code:add_pathsa/1 and code:add_pathsz/1 always return ok)
+ [ case code:add_patha(PA) of
+ true -> ok;
+ {error, _} -> bad_option("Failed to add path from config", {add_patha, PA})
+ end || PA <- PAs ],
+ [ case code:add_pathz(PZ) of
+ true -> ok;
+ {error, _} -> bad_option("Failed to add path from config", {add_pathz, PZ})
+ end || PZ <- PZs ],
+ ok.
+
preprocess_opts([]) -> [];
preprocess_opts([{init_plt, File}|Opts]) ->
[{plts, [File]}|preprocess_opts(Opts)];
@@ -79,7 +107,7 @@ postprocess_opts(Opts = #options{}) ->
check_module_lookup_file_validity(Opts1),
Opts2 = check_output_plt(Opts1),
check_init_plt_kind(Opts2),
- Opts3 = manage_default_apps(Opts2),
+ Opts3 = manage_default_incremental_apps(Opts2),
adapt_get_warnings(Opts3).
check_metrics_file_validity(#options{analysis_type = incremental, metrics_file = none}) ->
@@ -160,31 +188,49 @@ check_init_plt_kind(#options{analysis_type = _NotIncremental, init_plts = InitPl
lists:foreach(RunCheck, InitPlts).
%% If no apps are set explicitly, we fall back to config
-manage_default_apps(Opts = #options{analysis_type = incremental, files = [], files_rec = [], warning_files = [], warning_files_rec = []}) ->
- DefaultConfig = get_default_config_filename(),
- case file:consult(DefaultConfig) of
- {ok, [{incremental, {default_apps, DefaultApps}=Term}]} when
+manage_default_incremental_apps(Opts = #options{analysis_type = incremental, files = [], files_rec = [], warning_files = [], warning_files_rec = []}) ->
+ set_default_apps(get_config(), Opts);
+manage_default_incremental_apps(Opts) ->
+ Opts.
+
+set_default_apps([ConfigElem|MoreConfig], Opts) ->
+ case ConfigElem of
+ {incremental, {default_apps, DefaultApps}=Term} when
is_list(DefaultApps) ->
AppDirs = get_app_dirs(DefaultApps),
assert_filenames_form(Term, AppDirs),
Opts#options{files_rec = AppDirs};
- {ok, [{incremental, {default_apps, DefaultApps}=TermApps,
- {default_warning_apps, DefaultWarningApps}=TermWarns}]} when
+ {incremental, {default_apps, DefaultApps}=TermApps,
+ {default_warning_apps, DefaultWarningApps}=TermWarns} when
is_list(DefaultApps), is_list(DefaultWarningApps) ->
- AppDirs = get_app_dirs(DefaultApps),
+ AppDirs = get_app_dirs(DefaultApps ++ DefaultWarningApps),
assert_filenames_form(TermApps, AppDirs),
WarningAppDirs = get_app_dirs(DefaultWarningApps),
assert_filenames_form(TermWarns, WarningAppDirs),
Opts#options{files_rec = AppDirs, warning_files_rec = WarningAppDirs};
- {ok, _Terms} ->
- bad_option("Given Erlang terms could not be understood as Dialyzer config", DefaultConfig);
- {error, Reason} ->
- bad_option(file:format_error(Reason), DefaultConfig)
+ _ when element(1, ConfigElem) =:= incremental ->
+ bad_option("Given Erlang terms in 'incremental' section could not be understood as Dialyzer config", ConfigElem);
+ _ ->
+ set_default_apps(MoreConfig, Opts)
end;
-manage_default_apps(Opts) ->
+set_default_apps([], Opts) ->
Opts.
+get_config() ->
+ DefaultConfig = get_default_config_filename(),
+ case filelib:is_regular(DefaultConfig) of
+ true ->
+ case file:consult(DefaultConfig) of
+ {ok, Config} when is_list(Config) -> Config;
+ {error, Reason} ->
+ bad_option(file:format_error(Reason), DefaultConfig)
+ end;
+ false ->
+ []
+ end.
+
% Intended to work like dialyzer_iplt:get_default_iplt_filename()
+-spec get_default_config_filename() -> string().
get_default_config_filename() ->
case os:getenv("DIALYZER_CONFIG") of
false ->
diff --git a/lib/dialyzer/test/incremental_SUITE.erl b/lib/dialyzer/test/incremental_SUITE.erl
index 831e718777..1bf5731db8 100644
--- a/lib/dialyzer/test/incremental_SUITE.erl
+++ b/lib/dialyzer/test/incremental_SUITE.erl
@@ -30,6 +30,8 @@
default_apps_config_xdg/1,
default_apps_config_env_var/1,
default_apps_config_env_var_prioritised_over_xdg/1,
+ legal_warnings_config_xdg/1,
+ paths_config_xdg/1,
multiple_plts_unsupported_in_incremental_mode/1]).
suite() ->
@@ -54,6 +56,8 @@ all() -> [report_new_plt_test,
default_apps_config_xdg,
default_apps_config_env_var,
default_apps_config_env_var_prioritised_over_xdg,
+ legal_warnings_config_xdg,
+ paths_config_xdg,
multiple_plts_unsupported_in_incremental_mode].
erlang_module() ->
@@ -739,7 +743,7 @@ default_apps_config_xdg(Config) ->
[{"HOME", TestHome}]
end,
- io:format("~p\n", [HomeEnv]),
+ io:format("~p~n", [HomeEnv]),
PrivDir = ?config(priv_dir, Config),
PltFile = filename:join(PrivDir, atom_to_list(?FUNCTION_NAME) ++ ".iplt"),
@@ -892,6 +896,176 @@ default_apps_config_env_var_prioritised_over_xdg(Config) ->
peer:stop(Peer).
+legal_warnings_config_xdg(Config) ->
+ TestHome = filename:join(?config(priv_dir, Config), ?FUNCTION_NAME),
+
+ %% We change the $HOME of the emulator to run this test
+ HomeEnv =
+ case os:type() of
+ {win32, _} ->
+ [Drive | Path] = filename:split(TestHome),
+ [{"APPDATA", filename:join(TestHome, "AppData")},
+ {"HOMEDRIVE", Drive},
+ {"HOMEPATH", filename:join(Path)}];
+ _ ->
+ [{"HOME", TestHome}]
+ end,
+
+ io:format("~p~n", [HomeEnv]),
+
+ {ok, Peer, Node} = ?CT_PEER(#{ env => HomeEnv }),
+
+ SrcWithImproperList = <<"
+ -module(my_improper_list_module).
+ -export([g/0]).
+
+ g() -> [a|b]. % Improper list: Last element is not the empty list
+ ">>,
+
+ {ok, BeamFileWithImproperList} =
+ compile(Config, SrcWithImproperList, my_improper_list_module, []),
+
+ AppsConfig =
+ {incremental, {default_apps, [stdlib, kernel, erts, compiler, mnesia, ftp]}},
+
+ erpc:call(
+ Node,
+ fun() ->
+ %% Find out the path of the config file
+ HomeConfigFilename =
+ filename:join(filename:basedir(user_config, "erlang"),
+ "dialyzer.config"),
+ io:format("~ts\n", [HomeConfigFilename]),
+ ok = filelib:ensure_dir(HomeConfigFilename),
+
+ %% Write configuration file
+ WarningsConfig1 =
+ {warnings, [no_unknown, no_improper_lists]},
+ ok = file:write_file(HomeConfigFilename,
+ io_lib:format("~p.~n~p.~n", [AppsConfig, WarningsConfig1])),
+ WarningsWithConfigSet =
+ dialyzer:run([{analysis_type, incremental},
+ {files, [BeamFileWithImproperList]},
+ {from, byte_code}]),
+ ?assertEqual([], WarningsWithConfigSet),
+
+ %% Write alternative configuration file
+ WarningsConfig2 =
+ {warnings, [no_unknown]},
+ ok = file:write_file(HomeConfigFilename,
+ io_lib:format("~p.~n~p.~n", [AppsConfig, WarningsConfig2])),
+ WarningsWithoutConfigSet =
+ dialyzer:run([{analysis_type, incremental},
+ {files, [BeamFileWithImproperList]},
+ {from, byte_code}]),
+ ?assertMatch([{warn_non_proper_list, _Loc, _Msg}], WarningsWithoutConfigSet)
+ end),
+
+ peer:stop(Peer).
+
+paths_config_xdg(Config) ->
+ TestHome = filename:join(?config(priv_dir, Config), ?FUNCTION_NAME),
+
+ %% We change the $HOME of the emulator to run this test
+ HomeEnv =
+ case os:type() of
+ {win32, _} ->
+ [Drive | Path] = filename:split(TestHome),
+ [{"APPDATA", filename:join(TestHome, "AppData")},
+ {"HOMEDRIVE", Drive},
+ {"HOMEPATH", filename:join(Path)}];
+ _ ->
+ [{"HOME", TestHome}]
+ end,
+
+ io:format("~p~n", [HomeEnv]),
+
+ ExtraModulesDirOrig =
+ filename:join(?config(data_dir, Config), "extra_modules"),
+ ExtraModulesDir =
+ filename:join(?config(priv_dir, Config), "extra_modules"),
+ ok = filelib:ensure_path(ExtraModulesDir),
+ ok = filelib:ensure_path(filename:join(ExtraModulesDir,"ebin")),
+ ok = filelib:ensure_path(filename:join(ExtraModulesDir,"src")),
+
+ {ok, _} =
+ file:copy(
+ filename:join([ExtraModulesDirOrig, "src", "extra_modules.app.src"]),
+ filename:join([ExtraModulesDir, "src", "extra_modules.app.src"])
+ ),
+ {ok, _} =
+ file:copy(
+ filename:join([ExtraModulesDirOrig, "src", "extra_module.erl"]),
+ filename:join([ExtraModulesDir, "src", "extra_module.erl"])
+ ),
+
+ {ok, Peer, Node} = ?CT_PEER(#{ env => HomeEnv }),
+ {ok, _} =
+ compile:file(
+ filename:join([ExtraModulesDir,"src","extra_module.erl"]),
+ [{outdir, filename:join([ExtraModulesDir,"ebin"])}, debug_info]
+ ),
+
+ AppsConfig =
+ {incremental,
+ {default_apps,
+ [stdlib,
+ kernel,
+ erts,
+ extra_modules
+ ]
+ },
+ {default_warning_apps,
+ [extra_modules % Only on path if added explicitly via config below
+ ]
+ }
+ },
+
+ WarningsConfig =
+ {warnings, [no_unknown]},
+
+ erpc:call(
+ Node,
+ fun() ->
+ %% Find out the path of the config file
+ HomeConfigFilename =
+ filename:join(filename:basedir(user_config, "erlang"),
+ "dialyzer.config"),
+ io:format("~ts~n", [HomeConfigFilename]),
+ ok = filelib:ensure_dir(HomeConfigFilename),
+
+ %% Write configuration file
+ PathConfig = {add_pathsa, [ExtraModulesDir, filename:join(ExtraModulesDir, "ebin"), filename:join(ExtraModulesDir, "src")]},
+ ok =
+ file:write_file(
+ HomeConfigFilename,
+ io_lib:format(
+ "~p.~n~p.~n~p.~n",
+ [AppsConfig, WarningsConfig, PathConfig])),
+
+ {Warnings, ModAnalyzed} =
+ % Will analyse apps from config, including the `extra_modules` app
+ % which contains a Dialyzer error
+ dialyzer:run_report_modules_analyzed([
+ {analysis_type, incremental},
+ {from, byte_code}]),
+
+ % Check we did actually analyze the module
+ ?assert(
+ lists:member(extra_module, ModAnalyzed),
+ lists:flatten(io_lib:format("Looking for 'extra_module' in ~tp~n", [ModAnalyzed]))),
+
+ % Check we got the warnings we expected from modules
+ % added to the path
+ ?assertMatch(
+ [ {warn_contract_types, {_,_}, {invalid_contract, [extra_module,f,1, {[1],true}, "(atom()) -> string()", "(integer()) -> nonempty_improper_list(integer(),3)"]}},
+ {warn_non_proper_list, {_,_}, {improper_list_constr,["3"]}}
+ ],
+ Warnings)
+ end),
+
+ peer:stop(Peer).
+
multiple_plts_unsupported_in_incremental_mode(Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
BazPltFile = filename:join(PrivDir, atom_to_list(?FUNCTION_NAME) ++ "-baz.iplt"),
diff --git a/lib/dialyzer/test/incremental_SUITE_data/extra_modules/ebin/.gitignore b/lib/dialyzer/test/incremental_SUITE_data/extra_modules/ebin/.gitignore
new file mode 100644
index 0000000000..9aedd49be8
--- /dev/null
+++ b/lib/dialyzer/test/incremental_SUITE_data/extra_modules/ebin/.gitignore
@@ -0,0 +1,5 @@
+# Ignore everything in this directory
+*
+# Except this file, to force the directory to stick around
+# for the tests to later make use of
+!.gitignore
diff --git a/lib/dialyzer/test/incremental_SUITE_data/extra_modules/src/extra_module.erl b/lib/dialyzer/test/incremental_SUITE_data/extra_modules/src/extra_module.erl
new file mode 100644
index 0000000000..21bb42ee61
--- /dev/null
+++ b/lib/dialyzer/test/incremental_SUITE_data/extra_modules/src/extra_module.erl
@@ -0,0 +1,14 @@
+-module(extra_module).
+
+-export([start/2,stop/1,f/1]).
+
+start(StartType, StartArgs) ->
+ error.
+
+stop(State) ->
+ error.
+
+% Purposely broken to generate a warning if the module is loaded and analysed
+-spec f(atom()) -> string().
+f(N) when is_integer(N) ->
+ [N + 1|3].
diff --git a/lib/dialyzer/test/incremental_SUITE_data/extra_modules/src/extra_modules.app.src b/lib/dialyzer/test/incremental_SUITE_data/extra_modules/src/extra_modules.app.src
new file mode 100644
index 0000000000..01b38e4098
--- /dev/null
+++ b/lib/dialyzer/test/incremental_SUITE_data/extra_modules/src/extra_modules.app.src
@@ -0,0 +1,8 @@
+{application, extra_modules,
+ [{description, "An app with some extra modules"},
+ {vsn, "1"},
+ {modules, [extra_module]},
+ {registered, []},
+ {applications, [kernel, stdlib]},
+ {mod, {extra_module,[]}}
+ ]}.
diff --git a/lib/dialyzer/test/small_SUITE_data/results/bs_segments b/lib/dialyzer/test/small_SUITE_data/results/bs_segments
new file mode 100644
index 0000000000..0c3c9a0717
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/bs_segments
@@ -0,0 +1,3 @@
+
+bs_segments.erl:6:1: Function t/1 has no local return
+bs_segments.erl:6:1: The pattern <<_>> can never match the type any()
diff --git a/lib/dialyzer/test/small_SUITE_data/results/gh_7153 b/lib/dialyzer/test/small_SUITE_data/results/gh_7153
new file mode 100644
index 0000000000..c596a89f82
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/gh_7153
@@ -0,0 +1,3 @@
+
+gh_7153.erl:4:1: Function t/1 has no local return
+gh_7153.erl:5:7: Binary construction will fail since the value field X in segment X/utf8 has type '原子'
diff --git a/lib/dialyzer/test/small_SUITE_data/src/bs_segments.erl b/lib/dialyzer/test/small_SUITE_data/src/bs_segments.erl
new file mode 100644
index 0000000000..b1b8a2e866
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/bs_segments.erl
@@ -0,0 +1,7 @@
+-module(bs_segments).
+
+-export([t/1]).
+
+%% GH-7138: bogus segment sizes crashed the analysis.
+t(<<_:undefined>>) ->
+ ok.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/gh_7153.erl b/lib/dialyzer/test/small_SUITE_data/src/gh_7153.erl
new file mode 100644
index 0000000000..ef2ef3a25b
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/gh_7153.erl
@@ -0,0 +1,5 @@
+-module(gh_7153).
+-export([t/1]).
+
+t(X = '原子') ->
+ <<X/utf8>>.
diff --git a/lib/diameter/src/diameter.appup.src b/lib/diameter/src/diameter.appup.src
index dca7ba72ef..4d6fedef61 100644
--- a/lib/diameter/src/diameter.appup.src
+++ b/lib/diameter/src/diameter.appup.src
@@ -69,8 +69,9 @@
{"2.2.4", [{restart_application, diameter}]}, %% 23.3.4
{"2.2.5", [{restart_application, diameter}]}, %% 24.3
{"2.2.6", [{restart_application, diameter}]}, %% 25.0
- {"2.2.7", [{restart_application, diameter}]} %% 25.1
- ],
+ {"2.2.7", [{restart_application, diameter}]}, %% 25.1
+ {"2.3", [{restart_application, diameter}]}
+],
[
{"0.9", [{restart_application, diameter}]},
{"0.10", [{restart_application, diameter}]},
@@ -120,6 +121,7 @@
{"2.2.4", [{restart_application, diameter}]},
{"2.2.5", [{restart_application, diameter}]},
{"2.2.6", [{restart_application, diameter}]},
- {"2.2.7", [{restart_application, diameter}]}
+ {"2.2.7", [{restart_application, diameter}]},
+ {"2.3", [{restart_application, diameter}]}
]
}.
diff --git a/lib/edoc/test/edoc_SUITE.erl b/lib/edoc/test/edoc_SUITE.erl
index c150ace008..d09e9a2ecb 100644
--- a/lib/edoc/test/edoc_SUITE.erl
+++ b/lib/edoc/test/edoc_SUITE.erl
@@ -24,13 +24,14 @@
%% Test cases
-export([app/1,appup/1,build_std/1,build_map_module/1,otp_12008/1,
- build_app/1, otp_14285/1, infer_module_app_test/1]).
+ build_app/1, otp_14285/1, infer_module_app_test/1,
+ module_with_feature/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[app,appup,build_std,build_map_module,otp_12008, build_app, otp_14285,
- infer_module_app_test].
+ infer_module_app_test, module_with_feature].
groups() ->
[].
@@ -159,3 +160,13 @@ infer_module_app_test_({M, Beam}) ->
R2 = filelib:is_regular(BeamPath2),
R1 orelse R2
end.
+
+module_with_feature(Config) ->
+ DataDir = ?config(data_dir, Config),
+ PrivDir = ?config(priv_dir, Config),
+ Source = filename:join(DataDir, "module_with_feature.erl"),
+ DodgerOpts = [{dir, PrivDir}],
+ ok = edoc:files([Source], DodgerOpts),
+ PreprocessOpts = [{preprocess, true}, {dir, PrivDir}],
+ ok = edoc:files([Source], PreprocessOpts),
+ ok.
diff --git a/lib/edoc/test/edoc_SUITE_data/module_with_feature.erl b/lib/edoc/test/edoc_SUITE_data/module_with_feature.erl
new file mode 100644
index 0000000000..0091b704b4
--- /dev/null
+++ b/lib/edoc/test/edoc_SUITE_data/module_with_feature.erl
@@ -0,0 +1,2 @@
+-module(module_with_feature).
+-feature(maybe_expr, enable).
diff --git a/lib/eldap/doc/src/eldap.xml b/lib/eldap/doc/src/eldap.xml
index 0b5577fe2f..b97bdebd16 100644
--- a/lib/eldap/doc/src/eldap.xml
+++ b/lib/eldap/doc/src/eldap.xml
@@ -549,7 +549,7 @@ Control2 = eldap:paged_result_control(PageSize, Cookie1),
</desc>
</func>
<func>
- <name since="OTP @OTP-18480@">info(Handle) -> connection_info()</name>
+ <name since="OTP 25.3.1">info(Handle) -> connection_info()</name>
<fsummary>Returns information about the LDAP connection.
</fsummary>
<type>
diff --git a/lib/eldap/doc/src/notes.xml b/lib/eldap/doc/src/notes.xml
index 563f75e827..881c1215b4 100644
--- a/lib/eldap/doc/src/notes.xml
+++ b/lib/eldap/doc/src/notes.xml
@@ -31,6 +31,22 @@
</header>
<p>This document describes the changes made to the Eldap application.</p>
+<section><title>Eldap 1.2.11</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Added a new function eldap:info/1 that returns the socket
+ and the transport protocol for the eldap connection.</p>
+ <p>
+ Own Id: OTP-18480</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Eldap 1.2.10</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/eldap/vsn.mk b/lib/eldap/vsn.mk
index 77d89248c9..a25f97cb89 100644
--- a/lib/eldap/vsn.mk
+++ b/lib/eldap/vsn.mk
@@ -1 +1 @@
-ELDAP_VSN = 1.2.10
+ELDAP_VSN = 1.2.11
diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml
index a1bb84f224..7bac4913ab 100644
--- a/lib/erl_interface/doc/src/notes.xml
+++ b/lib/erl_interface/doc/src/notes.xml
@@ -31,6 +31,22 @@
</header>
<p>This document describes the changes made to the Erl_interface application.</p>
+<section><title>Erl_Interface 5.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed configure tests for a few ARM-specific
+ instructions, which prevented the emulator from being
+ built on some platforms.</p>
+ <p>
+ Own Id: OTP-18554</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erl_Interface 5.3.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c
index e5f1c307fd..3f2becde5a 100644
--- a/lib/erl_interface/src/connect/ei_connect.c
+++ b/lib/erl_interface/src/connect/ei_connect.c
@@ -1058,11 +1058,11 @@ int ei_connect_init_ussi(ei_cnode* ec, const char* this_node_name,
strcpy(thishostname, hp->h_name);
}
}
- if (strlen(this_node_name) + 1 + strlen(thishostname) > MAXNODELEN) {
+ if (snprintf(thisnodename, sizeof(thisnodename), "%s@%s",
+ this_node_name, thishostname) > sizeof(thisnodename)) {
EI_TRACE_ERR0("ei_connect_init_ussi","this node name is too long");
return ERL_ERROR;
}
- sprintf(thisnodename, "%s@%s", this_node_name, thishostname);
res = ei_connect_xinit_ussi(ec, thishostname, thisalivename, thisnodename,
(struct in_addr *)*hp->h_addr_list, cookie, creation,
cbs, cbs_sz, setup_context);
diff --git a/lib/erl_interface/src/prog/erl_call.c b/lib/erl_interface/src/prog/erl_call.c
index 4548b9f4dd..1fb72c65cb 100644
--- a/lib/erl_interface/src/prog/erl_call.c
+++ b/lib/erl_interface/src/prog/erl_call.c
@@ -441,11 +441,11 @@ int main(int argc, char *argv[])
memcpy(&h_ipadr.s_addr, *hp->h_addr_list, sizeof(struct in_addr));
if (h_alivename) {
- if (strlen(h_alivename) + strlen(h_hostname) + 2 > sizeof(h_nodename_buf)) {
+ if (snprintf(h_nodename_buf, sizeof(h_nodename_buf), "%s@%s",
+ h_alivename, h_hostname) > sizeof(h_nodename_buf)) {;
fprintf(stderr,"erl_call: hostname too long: %s\n", h_hostname);
exit_free_flags_fields(1, &flags);
}
- sprintf(h_nodename, "%s@%s", h_alivename, h_hostname);
}
else {
/* dynamic node name */
@@ -490,11 +490,11 @@ int main(int argc, char *argv[])
}
if (flags.port == -1) {
- if (strlen(flags.node) + strlen(host_name) + 2 > sizeof(nodename)) {
+ if (snprintf(nodename, sizeof(nodename),
+ "%s@%s", flags.node, host_name) > sizeof(nodename)) {
fprintf(stderr,"erl_call: nodename too long: %s\n", flags.node);
exit_free_flags_fields(1, &flags);
}
- sprintf(nodename, "%s@%s", flags.node, host_name);
}
/*
* Try to connect. Start an Erlang system if the
diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk
index badd74c6da..683e6643c7 100644
--- a/lib/erl_interface/vsn.mk
+++ b/lib/erl_interface/vsn.mk
@@ -1,2 +1,2 @@
-EI_VSN = 5.3.1
+EI_VSN = 5.3.2
ERL_INTERFACE_VSN = $(EI_VSN)
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 9b234c37f1..a10ee19030 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -33,7 +33,33 @@
<file>notes.xml</file>
</header>
- <section><title>Inets 8.3</title>
+ <section><title>Inets 8.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Correct timing related pipelining/keepalive queue bug,
+ that could result in unexpected "socket_remotly_closed"
+ errors.</p>
+ <p>
+ Own Id: OTP-18509 Aux Id: OTP-18476 </p>
+ </item>
+ <item>
+ <p>
+ With this change, upon remote socket closure current
+ request is added to a retried queue (either pipeline or
+ keep_alive, but not both).</p>
+ <p>
+ Own Id: OTP-18545 Aux Id: OTP-18509, ERIERL-937,
+ ERIERL-928 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 8.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index b4315f4ba3..8f62b8906c 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -1009,12 +1009,14 @@ http_options_default() ->
error
end,
+ SslOpts = ssl_verify_host_options(true),
+
UrlDecodePost = boolfun(),
[
{version, {value, "HTTP/1.1"}, #http_options.version, VersionPost},
{timeout, {value, ?HTTP_REQUEST_TIMEOUT}, #http_options.timeout, TimeoutPost},
{autoredirect, {value, true}, #http_options.autoredirect, AutoRedirectPost},
- {ssl, {value, {ssl, []}}, #http_options.ssl, SslPost},
+ {ssl, {value, {ssl, SslOpts}}, #http_options.ssl, SslPost},
{proxy_auth, {value, undefined}, #http_options.proxy_auth, ProxyAuthPost},
{relaxed, {value, false}, #http_options.relaxed, RelaxedPost},
{url_encode, {value, false}, #http_options.url_encode, UrlDecodePost},
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 99285501c5..78efa696d8 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 8.3
+INETS_VSN = 8.3.1
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/kernel/Makefile b/lib/kernel/Makefile
index 534b564c2c..7586a4c981 100644
--- a/lib/kernel/Makefile
+++ b/lib/kernel/Makefile
@@ -35,7 +35,7 @@ SPECIAL_TARGETS =
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_subdir.mk
-DIA_PLT_APPS=crypto
+DIA_PLT_APPS=crypto compiler
TEST_NEEDS_RELEASE=true
include $(ERL_TOP)/make/app_targets.mk
diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml
index 1bc90f1e8b..ffa77641de 100644
--- a/lib/kernel/doc/src/code.xml
+++ b/lib/kernel/doc/src/code.xml
@@ -427,7 +427,7 @@ zip:create("mnesia-4.4.7.ez",
</func>
<func>
<name name="add_pathsa" arity="1" since=""/>
- <name name="add_pathsa" arity="2" since=""/>
+ <name name="add_pathsa" arity="2" since="OTP @OTP-18466@"/>
<fsummary>Add directories to the beginning of the code path.</fsummary>
<desc>
<p>Traverses <c><anno>Dirs</anno></c> and adds
diff --git a/lib/kernel/doc/src/disk_log.xml b/lib/kernel/doc/src/disk_log.xml
index dc774538fb..dc6f9ba5bf 100644
--- a/lib/kernel/doc/src/disk_log.xml
+++ b/lib/kernel/doc/src/disk_log.xml
@@ -713,7 +713,7 @@
</desc>
</func>
<func>
- <name name="next_file" arity="1" since=""/>
+ <name name="next_file" arity="1" since="OTP @OTP-18331@"/>
<fsummary>Change to the next log file of a disk log.</fsummary>
<type name="next_file_error_rsn"/>
<type name="invalid_header"/>
diff --git a/lib/kernel/doc/src/socket.xml b/lib/kernel/doc/src/socket.xml
index e8e77b8295..2861108da6 100644
--- a/lib/kernel/doc/src/socket.xml
+++ b/lib/kernel/doc/src/socket.xml
@@ -148,69 +148,8 @@
<c>Info</c> will be <c>{SelectHandle, closed}</c>. </p>
</note>
- <marker id="asynchronous-call"/>
<note>
- <p>OLD NOTE</p>
- <p>Select-based <i>asynchronous</i> message interface. </p>
- <p>
- Some functions allow for an <i>asynchronous</i> call.
- This is achieved by setting the <c>Timeout</c> argument to
- <c>nowait</c>.
- For instance, if calling the
- <seeerl marker="#recv-nowait"><c>recv/3</c></seeerl>
- function with Timeout set to <c>nowait</c>
- (<c>recv(Sock, 0, nowait)</c>)
- when there is actually nothing to read, it will return with
- <c>{select, </c>
- <seetype marker="#select_info"><c>SelectInfo</c></seetype><c>}</c>
- (<c>SelectInfo</c> contains the
- <seetype marker="socket#select_handle">SelectHandle</seetype>).
- When data eventually arrives a 'select' message
- will be sent to the caller:
- </p>
- <taglist>
- <!-- NOTE THAT THE EMPTY TAG IS INTENTIONAL -->
- <tag></tag>
- <item><c>{'$socket', socket(), select, SelectHandle}</c></item>
- </taglist>
- <p>
- The caller can now call the <c>recv</c> function again
- and probably expect data
- (it is really up to the OS network protocol implementation).
- </p>
- <p>
- Note that all other users are <em>locked out</em> until the
- 'current user' has called the function (<c>recv</c> in this case)
- and its return value shows that the operation has completed.
- An operation can also be cancelled with
- <seemfa marker="#cancel/2"><c>cancel/2</c></seemfa>.
- </p>
- <p>
- Instead of <c>Timeout = nowait</c> it is equivalent to create a
- <seetype marker="socket#select_handle"><c>SelectHandle</c></seetype>)
- with
- <seemfa marker="erts:erlang#make_ref/0"><c>make_ref()</c></seemfa>
- and give as <c>Timeout</c>.
- This will then be the <c>SelectHandle</c> in the 'select' message,
- which enables a compiler optimization for receiving
- a message containing a newly created <c>reference()</c>
- (ignore the part of the message queue that had arrived
- before the the <c>reference()</c> was created).
- </p>
- <p>Another message the user must be prepared for (when making asynchronous
- calls) is the <c>abort</c> message:</p>
- <taglist>
- <!-- NOTE THAT THE EMPTY TAG IS INTENTIONAL -->
- <tag></tag>
- <item><c>{'$socket', socket(), abort, Info}</c></item>
- </taglist>
- <p>This message indicates
- that the (asynchronous) operation has been aborted.
- If, for instance, the socket has been closed (by another process),
- <c>Info</c> will be <c>{SelectHandle, closed}</c>. </p>
- </note>
- <note>
- <p>There is currently <em>no</em> support for Windows. </p>
+ <p>The Windows support has currently <em>pre-release</em> status. </p>
<p>Support for IPv6 has been implemented but not <em>fully</em>
tested. </p>
<p>SCTP has only been partly implemented (and not tested). </p>
@@ -1652,7 +1591,72 @@
<func>
<name name="cancel" arity="2" clause_i="1" since="OTP 22.1"/>
- <name name="cancel" arity="2" clause_i="2" since="OTP-18029"/>
+ <fsummary>Cancel an asynchronous request.</fsummary>
+ <desc>
+ <p>Cancel an asynchronous (select) request.</p>
+ <p>
+ Call this function in order to cancel a previous
+ asynchronous call to, e.g.
+ <seemfa marker="#recv/3"><c>recv/3</c></seemfa>.
+ </p>
+ <p>
+ An ongoing asynchronous operation blocks the socket
+ until the operation has been finished in good order,
+ or until it has been cancelled by this function.
+ </p>
+ <p>
+ Any other process that tries an operation
+ of the same basic type (accept / send / recv) will be
+ enqueued and notified with the regular <c>select</c>
+ mechanism for asynchronous operations
+ when the current operation and all enqueued before it
+ has been completed.
+ </p>
+ <p>
+ If <c><anno>SelectInfo</anno></c> does not match an
+ operation in progress for the calling process,
+ this function returns
+ <c>{error,&nbsp;{invalid,&nbsp;SelectInfo}}</c>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="cancel" arity="2" clause_i="2" since="OTP 26.0"/>
+ <fsummary>Cancel an asynchronous request.</fsummary>
+ <desc>
+ <p>Cancel an asynchronous (completion) request.</p>
+ <p>
+ Call this function in order to cancel a previous
+ asynchronous call to, e.g.
+ <seemfa marker="#recv/3"><c>recv/3</c></seemfa>.
+ </p>
+ <p>
+ An ongoing asynchronous operation blocks the socket
+ until the operation has been finished in good order,
+ or until it has been cancelled by this function.
+ </p>
+ <p>
+ Any other process that tries an operation
+ of the same basic type (accept / send / recv) will be
+ enqueued and notified with the regular <c>select</c>
+ mechanism for asynchronous operations
+ when the current operation and all enqueued before it
+ has been completed.
+ </p>
+ <p>
+ If <c><anno>CompletionInfo</anno></c> does not match an
+ operation in progress for the calling process,
+ this function returns
+ <c>{error,&nbsp;{invalid,&nbsp;CompletionInfo}}</c>.
+ </p>
+ </desc>
+ </func>
+
+ <!--
+ <func>
+ <name name="cancel" arity="2" clause_i="1" since="OTP 22.1"/>
+ <name name="cancel" arity="2" clause_i="2" since="OTP 26.0"/>
<fsummary>Cancel an asynchronous request.</fsummary>
<desc>
<p>Cancel an asynchronous request.</p>
@@ -1683,6 +1687,7 @@
</p>
</desc>
</func>
+ -->
<func>
<name name="close" arity="1" since="OTP 22.0"/>
diff --git a/lib/kernel/src/gen_tcp_socket.erl b/lib/kernel/src/gen_tcp_socket.erl
index 84ea036c3f..fb0f807cc1 100644
--- a/lib/kernel/src/gen_tcp_socket.erl
+++ b/lib/kernel/src/gen_tcp_socket.erl
@@ -729,8 +729,10 @@ socket_close(Socket) ->
-compile({inline, [socket_cancel/2]}).
socket_cancel(Socket, SelectInfo) ->
case socket:cancel(Socket, SelectInfo) of
- ok -> ok;
- {error, closed} -> ok
+ ok -> ok;
+ {error, closed} -> ok;
+ {error, _} = ERROR -> ERROR
+
end.
%%% ========================================================================
@@ -1575,7 +1577,7 @@ handle_event(
info = SelectInfo, from = From,
listen_socket = ListenSocket},
{P, D}) ->
- socket_cancel(ListenSocket, SelectInfo),
+ _ = socket_cancel(ListenSocket, SelectInfo),
{next_state, 'closed', {P, D},
[{reply, From, {error, timeout}}]};
handle_event(Type, Content, #accept{} = State, P_D) ->
@@ -1661,7 +1663,7 @@ handle_event(
{timeout, connect}, connect,
#connect{info = SelectInfo, from = From},
{#params{socket = Socket} = _P, _D} = P_D) ->
- socket_cancel(Socket, SelectInfo),
+ _ = socket_cancel(Socket, SelectInfo),
_ = socket_close(Socket),
{next_state, 'closed', P_D,
[{reply, From, {error, timeout}}]};
@@ -2268,11 +2270,11 @@ cleanup_close_read(P, D, State, Reason) ->
case State of
#accept{
info = SelectInfo, from = From, listen_socket = ListenSocket} ->
- socket_cancel(ListenSocket, SelectInfo),
+ _ = socket_cancel(ListenSocket, SelectInfo),
{D,
[{reply, From, {error, Reason}}]};
#connect{info = SelectInfo, from = From} ->
- socket_cancel(P#params.socket, SelectInfo),
+ _ = socket_cancel(P#params.socket, SelectInfo),
{D,
[{reply, From, {error, Reason}}]};
_ ->
@@ -2283,7 +2285,7 @@ cleanup_recv(P, D, State, Reason) ->
%% ?DBG({P#params.socket, State, Reason}),
case State of
#recv{info = SelectInfo} ->
- socket_cancel(P#params.socket, SelectInfo),
+ _ = socket_cancel(P#params.socket, SelectInfo),
cleanup_recv_reply(P, D, [], Reason);
_ ->
cleanup_recv_reply(P, D, [], Reason)
diff --git a/lib/kernel/src/socket.erl b/lib/kernel/src/socket.erl
index 25be82543f..02e199d088 100644
--- a/lib/kernel/src/socket.erl
+++ b/lib/kernel/src/socket.erl
@@ -4548,6 +4548,7 @@ ioctl(Socket, SetRequest, Arg1, Arg2) ->
Socket :: socket(),
SelectInfo :: select_info(),
Reason :: 'closed' | invalid();
+
(Socket, CompletionInfo) -> 'ok' | {'error', Reason} when
Socket :: socket(),
CompletionInfo :: completion_info(),
@@ -4590,14 +4591,10 @@ cancel(Socket, Info) ->
erlang:error(badarg, [Socket, Info]).
-%% What about completion? There is no way to cancel a
-%% I/O completion "request" once it has been issued.
-%% But we may still have "stuff" in our own queues,
-%% which needs to be cleared out.
cancel(SockRef, Op, Handle) ->
case prim_socket:cancel(SockRef, Op, Handle) of
select_sent ->
- flush_select_msg(SockRef, Handle),
+ _ = flush_select_msg(SockRef, Handle),
_ = flush_abort_msg(SockRef, Handle),
ok;
not_found ->
@@ -4605,6 +4602,9 @@ cancel(SockRef, Op, Handle) ->
_ = flush_abort_msg(SockRef, Handle),
invalid;
Result ->
+ %% Since we do not actually if we are using
+ %% select or completion here, so flush both...
+ _ = flush_select_msg(SockRef, Handle),
_ = flush_completion_msg(SockRef, Handle),
_ = flush_abort_msg(SockRef, Handle),
Result
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index 0aab4e4fa0..4aefee8a79 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -2639,6 +2639,10 @@ do_simple_sockaddr_send_recv(#{family := _Fam} = SockAddr, _) ->
?P("[server] send failed: ~p",
[Reason1]),
exit({skip, Reason1});
+ {error, enetunreach = Reason1} ->
+ ?P("[server] send failed: ~p",
+ [Reason1]),
+ exit({skip, Reason1});
{error, Reason1} ->
exit({send_failed, Reason1})
end
@@ -2664,6 +2668,10 @@ do_simple_sockaddr_send_recv(#{family := _Fam} = SockAddr, _) ->
?P("[server] send failed: ~p",
[Reason2]),
exit({skip, Reason2});
+ {error, enetunreach = Reason2} ->
+ ?P("[server] send failed: ~p",
+ [Reason2]),
+ exit({skip, Reason2});
{error, Reason2} ->
exit({send_failed, Reason2})
end
diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl
index 5f0fd15923..196af34521 100644
--- a/lib/kernel/test/socket_SUITE.erl
+++ b/lib/kernel/test/socket_SUITE.erl
@@ -744,8 +744,11 @@
-define(TPP_LARGE_NUM, 50).
-define(TPP_NUM(Config, Base), (Base) div lookup(kernel_factor, 1, Config)).
+-define(WINDOWS, {win32,nt}).
+
-define(TTEST_RUNTIME, ?SECS(1)).
-define(TTEST_MIN_FACTOR, 3).
+-define(TTEST_MIN_FACTOR_WIN, ?TTEST_MIN_FACTOR-1).
-define(TTEST_DEFAULT_SMALL_MAX_OUTSTANDING, 50).
-define(TTEST_DEFAULT_MEDIUM_MAX_OUTSTANDING,
?TTEST_MK_DEFAULT_MAX_OUTSTANDING(
@@ -1404,7 +1407,12 @@ traffic_pp_sendmsg_recvmsg_cases() ->
%% No point in running these cases unless the machine is
%% reasonably fast.
ttest_condition(Config) ->
+ OsType = os:type(),
case ?config(kernel_factor, Config) of
+ Factor when (OsType =:= ?WINDOWS) andalso
+ is_integer(Factor) andalso
+ (Factor =< ?TTEST_MIN_FACTOR_WIN) ->
+ ok;
Factor when is_integer(Factor) andalso (Factor =< ?TTEST_MIN_FACTOR) ->
ok;
Factor when is_integer(Factor) ->
@@ -3492,7 +3500,10 @@ api_b_send_and_recv_seqpL(_Config) when is_list(_Config) ->
api_b_sendmsg_and_recvmsg_tcp4(_Config) when is_list(_Config) ->
?TT(?SECS(10)),
tc_try(api_b_sendmsg_and_recvmsg_tcp4,
- fun() -> has_support_ipv4() end,
+ fun() ->
+ is_not_windows(),
+ has_support_ipv4()
+ end,
fun() ->
Send = fun(Sock, Data) ->
Msg = #{iov => [Data]},
@@ -6926,7 +6937,8 @@ api_a_connect_tcp(InitState) ->
{ok, State#{asynch_tag => select,
connect_tag => ST}};
- {completion, {completion_info, CT, CompletionRef}}
+ {completion,
+ {completion_info, CT, CompletionRef}}
when SR =:= nowait ->
?SEV_IPRINT("completion nowait ->"
"~n tag: ~p"
@@ -6935,7 +6947,8 @@ api_a_connect_tcp(InitState) ->
{ok, State#{asynch_tag => completion,
connect_tag => CT,
connect_ref => CompletionRef}};
- {completion, {completion_info, CT, CR}}
+ {completion,
+ {completion_info, CT, CR}}
when is_reference(CR) ->
?SEV_IPRINT("completion ref ->"
"~n tag: ~p"
@@ -7988,7 +8001,10 @@ api_a_sendmsg_and_recvmsg_tcp4(Config) when is_list(Config) ->
?TT(?SECS(10)),
Nowait = nowait(Config),
tc_try(api_a_sendmsg_and_recvmsg_tcp4,
- fun() -> has_support_ipv4() end,
+ fun() ->
+ is_not_windows(),
+ has_support_ipv4()
+ end,
fun() ->
Send = fun(Sock, Data) ->
Msg = #{iov => [Data]},
@@ -9488,6 +9504,7 @@ api_a_recv_cancel_tcp(InitState) ->
cmd => fun(#{tester := Tester} = _State) ->
?SEV_AWAIT_CONTINUE(Tester, tester, recv)
end},
+
#{desc => "try recv request (with nowait, expect select|completion)",
cmd => fun(#{csock := Sock,
recv := Recv,
@@ -9506,13 +9523,15 @@ api_a_recv_cancel_tcp(InitState) ->
"~n Ref: ~p", [T, Ref]),
{ok, State#{recv_select_info => SI}};
- {completion, {completion_info, T, R} = CI}
+ {completion,
+ {completion_info, T, R} = CI}
when Ref =:= nowait ->
?SEV_IPRINT("recv completion nowait: "
"~n Tag: ~p"
"~n Ref: ~p", [T, R]),
{ok, State#{recv_completion_info => CI}};
- {completion, {completion_info, T, Ref} = CI}
+ {completion,
+ {completion_info, T, Ref} = CI}
when is_reference(Ref) ->
?SEV_IPRINT("recv completion ref: "
"~n Tag: ~p"
@@ -10913,6 +10932,7 @@ api_a_mrecvmsg_cancel_tcp4(Config) when is_list(Config) ->
Nowait = nowait(Config),
tc_try(?FUNCTION_NAME,
fun() ->
+ is_not_windows(),
has_support_ipv4()
end,
fun() ->
@@ -10937,7 +10957,10 @@ api_a_mrecvmsg_cancel_tcp6(Config) when is_list(Config) ->
?TT(?SECS(20)),
Nowait = nowait(Config),
tc_try(?FUNCTION_NAME,
- fun() -> has_support_ipv6() end,
+ fun() ->
+ is_not_windows(),
+ has_support_ipv6()
+ end,
fun() ->
Recv = fun(Sock) ->
socket:recvmsg(Sock, Nowait)
@@ -14034,6 +14057,10 @@ api_opt_sock_broadcast() ->
?SEV_IPRINT("Expected Success: "
"broadcast message sent"),
ok;
+ {error, eaddrnotavail = Reason} ->
+ ?SEV_EPRINT("Unexpected Failure: ~p => SKIP",
+ [Reason]),
+ {skip, Reason};
{error, eacces = Reason} ->
?SEV_EPRINT("Unexpected Failure: ~p => SKIP",
[Reason]),
@@ -21126,6 +21153,37 @@ api_opt_ip_recvttl_udp(InitState) ->
{skip,
?F("Cannot send with TTL: ~p", [Info])};
+ {error,
+ {completion_status,
+ #{file := File,
+ function := Function,
+ line := Line,
+ raw_info := RawInfo,
+ info := invalid_parameter = Info}}} ->
+ %% IF we can't send it the test will not work
+ ?SEV_EPRINT("Cannot send TTL: "
+ "~p => SKIP: "
+ "~n File: ~s"
+ "~n Function: ~s"
+ "~n Line: ~p"
+ "~n Raw Info: ~p",
+ [Info,
+ File, Function, Line,
+ RawInfo]),
+ (catch socket:close(SSock)),
+ (catch socket:close(DSock)),
+ {skip,
+ ?F("Cannot send with TTL: ~p", [Info])};
+ {error, {completion_status,
+ invalid_parameter = Info}} ->
+ %% IF we can't send it the test will not work
+ ?SEV_EPRINT("Cannot send TTL: "
+ "~p => SKIP", [Info]),
+ (catch socket:close(SSock)),
+ (catch socket:close(DSock)),
+ {skip,
+ ?F("Cannot send with TTL: ~p", [Info])};
+
{error, _Reason} = ERROR ->
ERROR
end
@@ -23420,7 +23478,7 @@ api_opt_ipv6_tclass_udp(InitState) ->
#{desc => "send req (to dst) (w explicit tc = 1)",
cmd => fun(#{sock_src := Sock, sa_dst := Dst, send := Send}) ->
case Send(Sock, ?BASIC_REQ, Dst, 1) of
- {error,
+ {error,
{get_overlapped_result,
#{file := File,
function := Function,
@@ -23449,6 +23507,35 @@ api_opt_ipv6_tclass_udp(InitState) ->
{skip,
?F("Cannot send with TClass: ~p", [Info])};
+ {error,
+ {completion_status,
+ #{file := File,
+ function := Function,
+ line := Line,
+ raw_info := RawInfo,
+ info := invalid_parameter = Info}}} ->
+ %% IF we can't send it the test will not work
+ ?SEV_EPRINT("Cannot send TClass: "
+ "~p => SKIP: "
+ "~n File: ~s"
+ "~n Function: ~s"
+ "~n Line: ~p"
+ "~n Raw Info: ~p",
+ [Info,
+ File, Function, Line,
+ RawInfo]),
+ (catch socket:close(Sock)),
+ {skip,
+ ?F("Cannot send with TClass: ~p", [Info])};
+ {error, {completion_status,
+ invalid_parameter = Info}} ->
+ %% IF we can't send it the test will not work
+ ?SEV_EPRINT("Cannot send TClass: "
+ "~p => SKIP", [Info]),
+ (catch socket:close(Sock)),
+ {skip,
+ ?F("Cannot send with TClass: ~p", [Info])};
+
Other ->
Other
end
@@ -32985,8 +33072,11 @@ sc_lc_receive_response_udp(InitState) ->
sc_lc_recvmsg_response_tcp4(_Config) when is_list(_Config) ->
?TT(?SECS(10)),
- tc_try(sc_lc_recvmsg_response_tcp4,
- fun() -> has_support_ipv4() end,
+ tc_try(?FUNCTION_NAME,
+ fun() ->
+ is_not_windows(),
+ has_support_ipv4()
+ end,
fun() ->
Recv = fun(Sock) -> socket:recvmsg(Sock) end,
InitState = #{domain => inet,
@@ -33003,8 +33093,11 @@ sc_lc_recvmsg_response_tcp4(_Config) when is_list(_Config) ->
sc_lc_recvmsg_response_tcp6(_Config) when is_list(_Config) ->
?TT(?SECS(10)),
- tc_try(sc_recvmsg_response_tcp6,
- fun() -> has_support_ipv6() end,
+ tc_try(?FUNCTION_NAME,
+ fun() ->
+ is_not_windows(),
+ has_support_ipv6()
+ end,
fun() ->
Recv = fun(Sock) -> socket:recvmsg(Sock) end,
InitState = #{domain => inet6,
@@ -36503,7 +36596,10 @@ traffic_send_and_recv_counters_tcpL(_Config) when is_list(_Config) ->
traffic_sendmsg_and_recvmsg_counters_tcp4(_Config) when is_list(_Config) ->
?TT(?SECS(15)),
tc_try(traffic_sendmsg_and_recvmsg_counters_tcp4,
- fun() -> has_support_ipv4() end,
+ fun() ->
+ is_not_windows(),
+ has_support_ipv4()
+ end,
fun() ->
InitState = #{domain => inet,
proto => tcp,
@@ -36532,7 +36628,10 @@ traffic_sendmsg_and_recvmsg_counters_tcp4(_Config) when is_list(_Config) ->
traffic_sendmsg_and_recvmsg_counters_tcp6(_Config) when is_list(_Config) ->
?TT(?SECS(15)),
tc_try(traffic_sendmsg_and_recvmsg_counters_tcp6,
- fun() -> has_support_ipv6() end,
+ fun() ->
+ is_not_windows(),
+ has_support_ipv6()
+ end,
fun() ->
InitState = #{domain => inet6,
proto => tcp,
@@ -48842,7 +48941,7 @@ otp16359_maccept_tcp(InitState) ->
%% This test case is to verify that we do not leak monitors.
otp18240_accept_mon_leak_tcp4(Config) when is_list(Config) ->
- ?TT(?SECS(10)),
+ ?TT(?SECS(30)),
tc_try(?FUNCTION_NAME,
fun() -> has_support_ipv4() end,
fun() ->
@@ -48857,7 +48956,7 @@ otp18240_accept_mon_leak_tcp4(Config) when is_list(Config) ->
%% This test case is to verify that we do not leak monitors.
otp18240_accept_mon_leak_tcp6(Config) when is_list(Config) ->
- ?TT(?SECS(10)),
+ ?TT(?SECS(30)),
tc_try(?FUNCTION_NAME,
fun() -> has_support_ipv6() end,
fun() ->
@@ -48883,26 +48982,42 @@ otp18240_accept_tcp(#{domain := Domain,
otp18240_await_acceptor(Pid, Mon) ->
receive
- {'DOWN', Mon, process, Pid, Info} ->
- i("acceptor terminated: "
- "~n ~p", [Info])
+ {'DOWN', Mon, process, Pid, ok} ->
+ i("acceptor successfully terminated"),
+ ok;
+ {'DOWN', Mon, process, Pid, {skip, _} = SKIP} ->
+ i("acceptor successfully terminated"),
+ exit(SKIP);
+ {'DOWN', Mon, process, Pid, Info} ->
+ i("acceptor unexpected termination: "
+ "~n ~p", [Info]),
+ exit({unexpected_result, Info})
after 5000 ->
- i("acceptor info"
+ i("acceptor process (~p) info"
"~n Refs: ~p"
"~n Info: ~p",
- [monitored_by(Pid), erlang:process_info(Pid)]),
+ [Pid, monitored_by(Pid), erlang:process_info(Pid)]),
otp18240_await_acceptor(Pid, Mon)
end.
otp18240_acceptor(Parent, Domain, Proto, NumSocks) ->
i("[acceptor] begin with: "
+ "~n Parent: ~p"
"~n Domain: ~p"
- "~n Protocol: ~p", [Domain, Proto]),
+ "~n Protocol: ~p", [Parent, Domain, Proto]),
MonitoredBy0 = monitored_by(),
- {ok, LSock} = socket:open(Domain, stream, Proto,
- #{use_registry => false}),
- ok = socket:bind(LSock, #{family => Domain, port => 0, addr => any}),
+ ?SLEEP(?SECS(5)),
+ Addr = case ?LIB:which_local_host_info(Domain) of
+ {ok, #{addr := A}} ->
+ A;
+ {error, Reason} ->
+ exit({skip, Reason})
+ end,
+ {ok, LSock} = socket:open(Domain, stream, Proto,
+ #{use_registry => false}),
+ ok = socket:bind(LSock, #{family => Domain, addr => Addr, port => 0}),
ok = socket:listen(LSock, NumSocks),
+ ?SLEEP(?SECS(5)),
MonitoredBy1 = monitored_by(),
i("[acceptor]: listen socket created"
"~n 'Montored By' before listen socket: ~p"
@@ -48922,7 +49037,7 @@ otp18240_acceptor(Parent, Domain, Proto, NumSocks) ->
_Clients = [spawn_link(fun() ->
otp18240_client(CID,
Domain, Proto,
- Port)
+ Addr, Port)
end) || CID <- lists:seq(1, NumSocks)],
i("[acceptor] accept ~w connections", [NumSocks]),
@@ -48956,26 +49071,49 @@ otp18240_acceptor(Parent, Domain, Proto, NumSocks) ->
end.
-otp18240_client(ID, Domain, Proto, PortNo) ->
+otp18240_client(ID, Domain, Proto, Addr, PortNo) ->
i("[connector ~w] try create connector socket", [ID]),
{ok, Sock} = socket:open(Domain, stream, Proto, #{use_registry => false}),
- ok = socket:bind(Sock, #{family => Domain, port => 0, addr => any}),
+ ok = socket:bind(Sock, #{family => Domain, addr => Addr, port => 0}),
%% ok = socket:setopt(Sock, otp, debug, true),
i("[connector ~w] try connect", [ID]),
- ok = socket:connect(Sock, #{family => Domain, addr => any, port => PortNo}),
- i("[connector ~w] connected - now try recv", [ID]),
- case socket:recv(Sock) of
- {ok, Data} ->
- i("[connector ~w] received unexpected data: "
- "~n ~p", [ID, Data]),
- (catch socket:close(Sock)),
- exit('unexpected data');
- {error, closed} ->
- i("[connector ~w] expected socket close", [ID]);
- {error, Reason} ->
- i("[connector ~w] unexpected error when reading: "
- "~n ~p", [ID, Reason]),
- (catch socket:close(Sock))
+ case socket:connect(Sock,
+ #{family => Domain, addr => Addr, port => PortNo}) of
+ ok ->
+ i("[connector ~w] connected - now try recv", [ID]),
+ case socket:recv(Sock) of
+ {ok, Data} ->
+ i("[connector ~w] received unexpected data: "
+ "~n ~p", [ID, Data]),
+ (catch socket:close(Sock)),
+ exit('unexpected data');
+ {error, closed} ->
+ i("[connector ~w] expected socket close", [ID]);
+ {error, Reason} ->
+ i("[connector ~w] unexpected error when reading: "
+ "~n ~p", [ID, Reason]),
+ (catch socket:close(Sock))
+ end;
+ {error, {completion_status, #{info := invalid_netname = R} = Reason}} ->
+ i("[connector ~w] failed connecting: "
+ "~n ~p", [ID, Reason]),
+ (catch socket:close(Sock)),
+ exit({skip, R});
+ {error, {completion_status, invalid_netname = Reason}} ->
+ i("[connector ~w] failed connecting: "
+ "~n ~p", [ID, Reason]),
+ (catch socket:close(Sock)),
+ exit({skip, Reason});
+ {error, enetunreach = Reason} ->
+ i("[connector ~w] failed connecting: "
+ "~n ~p", [ID, Reason]),
+ (catch socket:close(Sock)),
+ exit({skip, Reason});
+
+ {error, Reason} ->
+ i("[connector ~w] failed connecting: "
+ "~n ~p", [ID, Reason]),
+ (catch socket:close(Sock))
end,
i("[connector ~w] done", [ID]),
ok.
diff --git a/lib/os_mon/doc/src/notes.xml b/lib/os_mon/doc/src/notes.xml
index 1fac53d330..439c1e839a 100644
--- a/lib/os_mon/doc/src/notes.xml
+++ b/lib/os_mon/doc/src/notes.xml
@@ -31,6 +31,23 @@
</header>
<p>This document describes the changes made to the OS_Mon application.</p>
+<section><title>Os_Mon 2.8.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Avoid error report from failing <c>erlang:port_close</c>
+ at shutdown of <c>cpu_sup</c> and <c>memsup</c>. Bug
+ exists since OTP 25.3 (os_mon-2.8.1).</p>
+ <p>
+ Own Id: OTP-18559 Aux Id: ERIERL-942 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Os_Mon 2.8.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/os_mon/src/cpu_sup.erl b/lib/os_mon/src/cpu_sup.erl
index 522ffe5830..a82dfd9961 100644
--- a/lib/os_mon/src/cpu_sup.erl
+++ b/lib/os_mon/src/cpu_sup.erl
@@ -614,8 +614,8 @@ port_server_loop(Port, Timeout) ->
% Close port and this server
{Pid, ?quit} ->
- port_command(Port, ?quit),
- port_close(Port),
+ Port ! {self(), {command, ?quit}},
+ Port ! {self(), close},
Pid ! {self(), {data, quit}},
ok;
diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl
index 1c93bfbae4..c467adc2e5 100644
--- a/lib/os_mon/src/memsup.erl
+++ b/lib/os_mon/src/memsup.erl
@@ -653,7 +653,7 @@ start_portprogram() ->
port_shutdown(Port) ->
Port ! {self(), {command, [?EXIT]}},
- port_close(Port).
+ Port ! {self(), close}.
%% The connected process loops are a bit awkward (several different
%% functions doing almost the same thing) as
diff --git a/lib/os_mon/vsn.mk b/lib/os_mon/vsn.mk
index 9e64a83612..d6878e6773 100644
--- a/lib/os_mon/vsn.mk
+++ b/lib/os_mon/vsn.mk
@@ -1 +1 @@
-OS_MON_VSN = 2.8.1
+OS_MON_VSN = 2.8.2
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index cb4eb5985f..01cff8fa4b 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -34,7 +34,23 @@
</header>
- <section><title>SNMP 5.13.4</title>
+ <section><title>SNMP 5.13.5</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Attempts to minimize the number of the error reports
+ during a failed agent init.</p>
+ <p>
+ Own Id: OTP-18422 Aux Id: ERIERL-873 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SNMP 5.13.4</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index 4c11344234..13c7e9790e 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = snmp
-SNMP_VSN = 5.13.4
+SNMP_VSN = 5.13.5
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 6ff15d429a..911055d742 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -27,6 +27,30 @@
</header>
<p>This document describes the changes made to the SSL application.</p>
+<section><title>SSL 10.9.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ With this change, ssl:connection_information/2 returns
+ correct keylog data after TLS1.3 key update.</p>
+ <p>
+ Own Id: OTP-18489</p>
+ </item>
+ <item>
+ <p>
+ Client signature algorithm list input order is now
+ honored again , it was accidently reversed by a previous
+ fix.</p>
+ <p>
+ Own Id: OTP-18550</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 10.9</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 3574ae91ac..700709ed7a 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -819,7 +819,7 @@ marker="public_key:public_key#pkix_path_validation/3">public_key:pkix_path_valid
<desc>
<code>
fun(Chain::[public_key:der_encoded()]) ->
- {trusted_ca, DerCert::public_key:der_encoded()} | unknown_ca}
+ {trusted_ca, DerCert::public_key:der_encoded()} | unknown_ca.
</code>
<p>Claim an intermediate CA in the chain as trusted. TLS then
performs <seemfa
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index a37a72efdc..899e7d3305 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -479,10 +479,7 @@ wait_cert_verify(info, Event, State) ->
wait_cert_verify(state_timeout, Event, State) ->
handle_state_timeout(Event, ?FUNCTION_NAME, State);
wait_cert_verify(Type, Event, State) ->
- try tls_dtls_connection:gen_handshake(?FUNCTION_NAME, Type, Event, State)
- catch throw:#alert{} = Alert ->
- ssl_gen_statem:handle_own_alert(Alert, ?FUNCTION_NAME, State)
- end.
+ gen_handshake(?FUNCTION_NAME, Type, Event, State).
%%--------------------------------------------------------------------
-spec cipher(gen_statem:event_type(), term(), #state{}) ->
@@ -506,7 +503,7 @@ cipher(internal = Type, #finished{} = Event, #state{connection_states = Connecti
cipher(state_timeout, Event, State) ->
handle_state_timeout(Event, ?FUNCTION_NAME, State);
cipher(Type, Event, State) ->
- gen_handshake(?FUNCTION_NAME, Type, Event, State).
+ gen_handshake(?FUNCTION_NAME, Type, Event, State).
%%--------------------------------------------------------------------
-spec connection(gen_statem:event_type(),
@@ -761,6 +758,8 @@ alert_or_reset_connection(Alert, StateName, #state{connection_states = Cs} = Sta
{next_state, connection, NewState}
end.
+gen_handshake(_, {call, _From}, {application_data, _Data}, _State) ->
+ {keep_state_and_data, [postpone]};
gen_handshake(StateName, Type, Event, State) ->
try tls_dtls_connection:StateName(Type, Event, State)
catch
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 6e83e16e1e..c96173e98b 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -1703,18 +1703,22 @@ validate_versions(dtls, Vsns0) ->
opt_verification(UserOpts, Opts0, #{role := Role} = Env) ->
{Verify, Opts1} =
case get_opt_of(verify, [verify_none, verify_peer], default_verify(Role), UserOpts, Opts0) of
+ {old, Val} ->
+ {Val, Opts0};
{_, verify_none} ->
{verify_none, Opts0#{verify => verify_none, verify_fun => {none_verify_fun(), []}}};
{_, verify_peer} ->
%% If 'verify' is changed from verify_none to verify_peer, (via update_options/3)
%% the 'verify_fun' must also be changed to undefined.
%% i.e remove verify_none fun
- {verify_peer, Opts0#{verify => verify_peer, verify_fun => undefined}}
+ Temp = Opts0#{verify => verify_peer, verify_fun => undefined},
+ {verify_peer, maps:remove(fail_if_no_peer_cert, Temp)}
end,
Opts2 = opt_cacerts(UserOpts, Opts1, Env),
{_, PartialChain} = get_opt_fun(partial_chain, 1, fun(_) -> unknown_ca end, UserOpts, Opts2),
- {_, FailNoPeerCert} = get_opt_bool(fail_if_no_peer_cert, false, UserOpts, Opts2),
+ DefFailNoPeer = Role =:= server andalso Verify =:= verify_peer,
+ {_, FailNoPeerCert} = get_opt_bool(fail_if_no_peer_cert, DefFailNoPeer, UserOpts, Opts2),
assert_server_only(Role, FailNoPeerCert, fail_if_no_peer_cert),
option_incompatible(FailNoPeerCert andalso Verify =:= verify_none,
[{verify, verify_none}, {fail_if_no_peer_cert, true}]),
diff --git a/lib/ssl/test/openssl_alpn_SUITE.erl b/lib/ssl/test/openssl_alpn_SUITE.erl
index bb33165bcf..1d0bc82c4e 100644
--- a/lib/ssl/test/openssl_alpn_SUITE.erl
+++ b/lib/ssl/test/openssl_alpn_SUITE.erl
@@ -194,7 +194,7 @@ erlang_client_alpn_openssl_server_alpn(Config) when is_list(Config) ->
erlang_server_alpn_openssl_client_alpn(Config) when is_list(Config) ->
ClientOpts = proplists:get_value(client_rsa_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
Protocol = <<"spdy/2">>,
Server = ssl_test_lib:start_server(erlang, [{from, self()}],
[{server_opts, [{alpn_preferred_protocols,
diff --git a/lib/ssl/test/openssl_renegotiate_SUITE.erl b/lib/ssl/test/openssl_renegotiate_SUITE.erl
index 01b5a7a8a9..5102730396 100644
--- a/lib/ssl/test/openssl_renegotiate_SUITE.erl
+++ b/lib/ssl/test/openssl_renegotiate_SUITE.erl
@@ -230,7 +230,7 @@ erlang_server_openssl_client_nowrap_seqnum() ->
erlang_server_openssl_client_nowrap_seqnum(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
{_, ServerNode, _Hostname} = ssl_test_lib:run_where(Config),
diff --git a/lib/ssl/test/ssl_api_SUITE.erl b/lib/ssl/test/ssl_api_SUITE.erl
index a3bb2f6bdc..215097bd4d 100644
--- a/lib/ssl/test/ssl_api_SUITE.erl
+++ b/lib/ssl/test/ssl_api_SUITE.erl
@@ -2699,18 +2699,18 @@ options_verify(Config) -> %% fail_if_no_peer_cert, verify, verify_fun, partial_
?OK(#{fail_if_no_peer_cert := true, verify := verify_peer, verify_fun := undefined, partial_chain := _},
[{fail_if_no_peer_cert, true}, {verify, verify_peer}, {cacerts, [Cert]}],
server),
- ?OK(#{fail_if_no_peer_cert := false, verify := verify_peer, verify_fun := undefined, partial_chain := _},
- [{verify, verify_peer}, {cacerts, [Cert]}], server),
+ ?OK(#{fail_if_no_peer_cert := true, verify := verify_peer, verify_fun := undefined, partial_chain := _},
+ [{verify, verify_peer}, {cacerts, [Cert]}], server),
NewF3 = fun(_,_,_) -> ok end,
NewF4 = fun(_,_,_,_) -> ok end,
?OK(#{}, [], client, [fail_if_no_peer_cert]),
?OK(#{verify := verify_none, verify_fun := {NewF3, foo}, partial_chain := _},
[{verify_fun, {NewF3, foo}}], client),
- ?OK(#{fail_if_no_peer_cert := false, verify := verify_peer, verify_fun := {NewF3, foo}, partial_chain := _},
+ ?OK(#{fail_if_no_peer_cert := true, verify := verify_peer, verify_fun := {NewF3, foo}, partial_chain := _},
[{verify_fun, {NewF3, foo}}, {verify, verify_peer}, {cacerts, [Cert]}],
server),
- ?OK(#{fail_if_no_peer_cert := false, verify := verify_peer, verify_fun := {NewF4, foo}, partial_chain := _},
+ ?OK(#{fail_if_no_peer_cert := true, verify := verify_peer, verify_fun := {NewF4, foo}, partial_chain := _},
[{verify_fun, {NewF4, foo}}, {verify, verify_peer}, {cacerts, [Cert]}],
server),
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 01235a1d74..64ee3c9d0d 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -973,15 +973,19 @@ openssl_server_loop(Pid, SslPort, Args) ->
start_openssl_client(Args0, Config) ->
{ClientNode, _, Hostname} = run_where(Config),
- ClientOpts = get_client_opts(Config),
+
+ %% io:format("~p:~p: ~p~n",[?MODULE, ?LINE, Args0]),
+ %% io:format("~p:~p: ~p~n",[?MODULE, ?LINE, Config]),
+
+ ClientOpts0 = get_client_opts(Config),
+ ClientOpts = proplists:get_value(options, Args0, []) ++ ClientOpts0,
DefaultVersions = default_tls_version(ClientOpts),
[Version | _] = proplists:get_value(versions, ClientOpts, DefaultVersions),
Node = proplists:get_value(node, Args0, ClientNode),
- Args = [{from, self()},
- {host, Hostname},
- {options, ClientOpts} | Args0],
+ Args = [{from, self()}, {host, Hostname} | ClientOpts ++ Args0],
- Result = spawn_link(Node, ?MODULE, init_openssl_client, [[{version, Version} | lists:delete(return_port, Args)]]),
+ Result = spawn_link(Node, ?MODULE, init_openssl_client,
+ [[{version, Version} | lists:delete(return_port, Args)]]),
receive
{connected, OpenSSLPort} ->
case lists:member(return_port, Args) of
@@ -1636,9 +1640,7 @@ make_ec_cert_chains(UserConf, ClientChainType, ServerChainType, Config, Curve) -
[{server_config, ServerConf},
{client_config, ClientConf}] =
x509_test:gen_pem_config_files(GenCertData, ClientFileBase, ServerFileBase),
- {[{verify, verify_peer} | ClientConf],
- [{reuseaddr, true}, {verify, verify_peer} | ServerConf]
- }.
+ {ClientConf, [{reuseaddr, true} | ServerConf]}.
default_cert_chain_conf() ->
%% Use only default options
@@ -1654,8 +1656,8 @@ make_rsa_pss_pem(Alg, _UserConf, Config, Suffix) ->
Conf = x509_test:gen_pem_config_files(GenCertData, ClientFileBase, ServerFileBase),
CConf = proplists:get_value(client_config, Conf),
SConf = proplists:get_value(server_config, Conf),
- #{server_config => [{verify, verify_peer} | SConf],
- client_config => [{verify, verify_peer} | CConf]}.
+ #{server_config => SConf,
+ client_config => CConf}.
make_rsa_sni_configs() ->
Sha = appropriate_sha(crypto:supports()),
@@ -2032,7 +2034,7 @@ make_rsa_ecdsa_cert(Config, Curve) ->
[{server_rsa_ecdsa_opts, [{reuseaddr, true} | ServerConf]},
{server_rsa_ecdsa_verify_opts, [{ssl_imp, new},{reuseaddr, true},
{verify, verify_peer} | ServerConf]},
- {client_rsa_ecdsa_opts, [{verify, cerify_none} | ClientConf]} | Config];
+ {client_rsa_ecdsa_opts, [{verify, verify_none} | ClientConf]} | Config];
_ ->
Config
end.
@@ -2449,7 +2451,7 @@ start_server(erlang, _, ServerOpts, Config) ->
{mfa, {ssl_test_lib,
check_key_exchange_send_active,
[KeyEx]}},
- {options, [{verify, verify_peer} | ServerOpts]}]),
+ {options, ServerOpts}]),
{Server, inet_port(Server)}.
sig_algs(undefined) ->
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 7b821e2bc8..db6de41e50 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 10.9
+SSL_VSN = 10.9.1
diff --git a/lib/stdlib/doc/src/gb_sets.xml b/lib/stdlib/doc/src/gb_sets.xml
index 3477c2c90e..283c3f9198 100644
--- a/lib/stdlib/doc/src/gb_sets.xml
+++ b/lib/stdlib/doc/src/gb_sets.xml
@@ -68,48 +68,10 @@
<section>
<title>Compatibility</title>
- <p>The following functions in this module also exist and provides
- the same functionality in the
- <seeerl marker="sets"><c>sets(3)</c></seeerl> and
- <seeerl marker="ordsets"><c>ordsets(3)</c></seeerl>
- modules. That is, by only changing the module name for each call,
- you can try out different set representations.</p>
- <list type="bulleted">
- <item><seemfa marker="#add_element/2"><c>add_element/2</c></seemfa>
- </item>
- <item><seemfa marker="#del_element/2"><c>del_element/2</c></seemfa>
- </item>
- <item><seemfa marker="#filter/2"><c>filter/2</c></seemfa>
- </item>
- <item><seemfa marker="#fold/3"><c>fold/3</c></seemfa>
- </item>
- <item><seemfa marker="#from_list/1"><c>from_list/1</c></seemfa>
- </item>
- <item><seemfa marker="#intersection/1"><c>intersection/1</c></seemfa>
- </item>
- <item><seemfa marker="#intersection/2"><c>intersection/2</c></seemfa>
- </item>
- <item><seemfa marker="#is_element/2"><c>is_element/2</c></seemfa>
- </item>
- <item><seemfa marker="#is_empty/1"><c>is_empty/1</c></seemfa>
- </item>
- <item><seemfa marker="#is_set/1"><c>is_set/1</c></seemfa>
- </item>
- <item><seemfa marker="#is_subset/2"><c>is_subset/2</c></seemfa>
- </item>
- <item><seemfa marker="#new/0"><c>new/0</c></seemfa>
- </item>
- <item><seemfa marker="#size/1"><c>size/1</c></seemfa>
- </item>
- <item><seemfa marker="#subtract/2"><c>subtract/2</c></seemfa>
- </item>
- <item><seemfa marker="#to_list/1"><c>to_list/1</c></seemfa>
- </item>
- <item><seemfa marker="#union/1"><c>union/1</c></seemfa>
- </item>
- <item><seemfa marker="#union/2"><c>union/2</c></seemfa>
- </item>
- </list>
+ <p>See the <seeerl marker="sets#compatibility">Compatibility Section
+ in the <c>sets(3)</c> module</seeerl> for information about
+ the compatibility of the different implementations of sets in the
+ Standard Library.</p>
</section>
<datatypes>
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index 403abf2be8..0906db1359 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -31,6 +31,22 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
+<section><title>STDLIB 4.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>The type specs in the <c>erl_parse</c> module has been
+ updated to include the <c>maybe</c> construct and the
+ <c>!</c> operator.</p>
+ <p>
+ Own Id: OTP-18506 Aux Id: GH-6956 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 4.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/stdlib/doc/src/ordsets.xml b/lib/stdlib/doc/src/ordsets.xml
index 35127dcf95..7b02d13ab3 100644
--- a/lib/stdlib/doc/src/ordsets.xml
+++ b/lib/stdlib/doc/src/ordsets.xml
@@ -48,6 +48,11 @@
that while <c>sets</c> considers two elements as different if they
do not match (<c>=:=</c>), this module considers two elements as
different if and only if they do not compare equal (<c>==</c>).</p>
+
+ <p>See the <seeerl marker="sets#compatibility">Compatibility Section
+ in the <c>sets(3)</c> module</seeerl> for more information about
+ the compatibility of the different implementations of sets in the
+ Standard Library.</p>
</description>
<datatypes>
diff --git a/lib/stdlib/doc/src/sets.xml b/lib/stdlib/doc/src/sets.xml
index 53b64a3ac0..b3899c440f 100644
--- a/lib/stdlib/doc/src/sets.xml
+++ b/lib/stdlib/doc/src/sets.xml
@@ -69,6 +69,71 @@
</description>
+ <section>
+ <title>Compatibility</title>
+ <p>The following functions in this module also exist and provide
+ the same functionality in the
+ <seeerl marker="gb_sets"><c>gb_sets(3)</c></seeerl> and
+ <seeerl marker="ordsets"><c>ordsets(3)</c></seeerl>
+ modules. That is, by only changing the module name for each call,
+ you can try out different set representations.</p>
+ <list type="bulleted">
+ <item><seemfa marker="#add_element/2"><c>add_element/2</c></seemfa>
+ </item>
+ <item><seemfa marker="#del_element/2"><c>del_element/2</c></seemfa>
+ </item>
+ <item><seemfa marker="#filter/2"><c>filter/2</c></seemfa>
+ </item>
+ <item><seemfa marker="#fold/3"><c>fold/3</c></seemfa>
+ </item>
+ <item><seemfa marker="#from_list/1"><c>from_list/1</c></seemfa>
+ </item>
+ <item><seemfa marker="#intersection/1"><c>intersection/1</c></seemfa>
+ </item>
+ <item><seemfa marker="#intersection/2"><c>intersection/2</c></seemfa>
+ </item>
+ <item><seemfa marker="#is_element/2"><c>is_element/2</c></seemfa>
+ </item>
+ <item><seemfa marker="#is_empty/1"><c>is_empty/1</c></seemfa>
+ </item>
+ <item><seemfa marker="#is_set/1"><c>is_set/1</c></seemfa>
+ </item>
+ <item><seemfa marker="#is_subset/2"><c>is_subset/2</c></seemfa>
+ </item>
+ <item><seemfa marker="#new/0"><c>new/0</c></seemfa>
+ </item>
+ <item><seemfa marker="#size/1"><c>size/1</c></seemfa>
+ </item>
+ <item><seemfa marker="#subtract/2"><c>subtract/2</c></seemfa>
+ </item>
+ <item><seemfa marker="#to_list/1"><c>to_list/1</c></seemfa>
+ </item>
+ <item><seemfa marker="#union/1"><c>union/1</c></seemfa>
+ </item>
+ <item><seemfa marker="#union/2"><c>union/2</c></seemfa>
+ </item>
+ </list>
+ <note>
+ <p>
+ While the three set implementations offer the same <em>functionality</em>
+ with respect to the aforementioned functions, their overall <em>behavior</em>
+ may differ. As mentioned, this module considers elements as different if
+ and only if they do not match (<c>=:=</c>), while both
+ <seeerl marker="ordsets"><c>ordsets</c></seeerl> and
+ <seeerl marker="gb_sets"><c>gb_sets</c></seeerl> consider elements as
+ different if and only if they do not compare equal (<c>==</c>).
+ </p>
+ <p><em>Example:</em></p>
+ <pre>
+1> <input>sets:is_element(1.0, sets:from_list([1])).</input>
+false
+2> <input>ordsets:is_element(1.0, ordsets:from_list([1])).</input>
+true
+2> <input>gb_sets:is_element(1.0, gb_sets:from_list([1])).</input>
+true</pre>
+ </note>
+ </section>
+
<datatypes>
<datatype>
<name name="set" n_vars="1"/>
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index a4833f940b..55e53cad3d 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -669,6 +669,9 @@ start(File, Opts) ->
false, Opts)},
{redefined_builtin_type,
bool_option(warn_redefined_builtin_type, nowarn_redefined_builtin_type,
+ true, Opts)},
+ {singleton_typevar,
+ bool_option(warn_singleton_typevar, nowarn_singleton_typevar,
true, Opts)}
],
Enabled1 = [Category || {Category,true} <- Enabled0],
@@ -2931,6 +2934,16 @@ check_type(Types, St) ->
"_"++_ -> AccSt;
_ -> add_error(Anno, {singleton_typevar, Var}, AccSt)
end;
+ (Var, {seen_once_union, Anno}, AccSt) ->
+ case is_warn_enabled(singleton_typevar, AccSt) of
+ true ->
+ case atom_to_list(Var) of
+ "_"++_ -> AccSt;
+ _ -> add_warning(Anno, {singleton_typevar, Var}, AccSt)
+ end;
+ false ->
+ AccSt
+ end;
(_Var, seen_multiple, AccSt) ->
AccSt
end, St1, SeenVars).
@@ -2971,6 +2984,7 @@ check_type_2({var, A, Name}, SeenVars, St) ->
NewSeenVars =
case maps:find(Name, SeenVars) of
{ok, {seen_once, _}} -> maps:put(Name, seen_multiple, SeenVars);
+ {ok, {seen_once_union, _}} -> maps:put(Name, seen_multiple, SeenVars);
{ok, seen_multiple} -> SeenVars;
error -> maps:put(Name, {seen_once, A}, SeenVars)
end,
@@ -3022,16 +3036,30 @@ check_type_2({type, _A, Tag, Args}=_F, SeenVars, St) when Tag =:= product;
lists:foldl(fun(T, {AccSeenVars, AccSt}) ->
check_type_1(T, AccSeenVars, AccSt)
end, {SeenVars, St}, Args);
-check_type_2({type, _A, union, Args}=_F, SeenVars, St) ->
- lists:foldl(fun(T, {AccSeenVars, AccSt}) ->
- {SeenVars0, St0} = check_type_1(T, SeenVars, AccSt),
- UpdatedSeenVars = maps:merge_with(fun (_K, {seen_once, _}, {seen_once, _}=R) -> R;
- (_K, {seen_once, _}, Else) -> Else;
- (_K, Else, {seen_once, _}) -> Else;
- (_K, Else1, _Else2) -> Else1
- end, SeenVars0, AccSeenVars),
- {UpdatedSeenVars, St0}
- end, {SeenVars, St}, Args);
+check_type_2({type, _A, union, Args}=_F, SeenVars0, St) ->
+ lists:foldl(fun(T, {AccSeenVars0, AccSt}) ->
+ {SeenVars1, St0} = check_type_1(T, SeenVars0, AccSt),
+ AccSeenVars = maps:merge_with(
+ fun (K, {seen_once, Anno}, {seen_once, _}) ->
+ case SeenVars0 of
+ #{K := _} ->
+ %% Unused outside of this union.
+ {seen_once, Anno};
+ #{} ->
+ {seen_once_union, Anno}
+ end;
+ (_K, {seen_once, Anno}, {seen_once_union, _}) ->
+ {seen_once_union, Anno};
+ (_K, {seen_once_union, _}=R, {seen_once, _}) -> R;
+ (_K, {seen_once_union, _}=R, {seen_once_union, _}) -> R;
+ (_K, {seen_once_union, _}, Else) -> Else;
+ (_K, {seen_once, _}, Else) -> Else;
+ (_K, Else, {seen_once_union, _}) -> Else;
+ (_K, Else, {seen_once, _}) -> Else;
+ (_K, Else1, _Else2) -> Else1
+ end, AccSeenVars0, SeenVars1),
+ {AccSeenVars, St0}
+ end, {SeenVars0, St}, Args);
check_type_2({type, Anno, TypeName, Args}, SeenVars, St) ->
#lint{module = Module, types=Types} = St,
Arity = length(Args),
diff --git a/lib/stdlib/src/sets.erl b/lib/stdlib/src/sets.erl
index 816fb85a48..dccc6dcf3a 100644
--- a/lib/stdlib/src/sets.erl
+++ b/lib/stdlib/src/sets.erl
@@ -466,23 +466,12 @@ fold_1(Fun, Acc, Iter) ->
Set1 :: set(Element),
Set2 :: set(Element).
filter(F, #{}=D) when is_function(F, 1)->
- maps:from_keys(filter_1(F, maps:iterator(D)), ?VALUE);
+ %% For this purpose, it is more efficient to use
+ %% maps:from_keys than a map comprehension.
+ maps:from_keys([K || K := _ <- D, F(K)], ?VALUE);
filter(F, #set{}=D) when is_function(F, 1)->
filter_set(F, D).
-filter_1(Fun, Iter) ->
- case maps:next(Iter) of
- {K, _, NextIter} ->
- case Fun(K) of
- true ->
- [K | filter_1(Fun, NextIter)];
- false ->
- filter_1(Fun, NextIter)
- end;
- none ->
- []
- end.
-
%% get_slot(Hashdb, Key) -> Slot.
%% Get the slot. First hash on the new range, if we hit a bucket
%% which has not been split use the unsplit buddy bucket.
diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src
index 0cb84fd3dc..13efc74d85 100644
--- a/lib/stdlib/src/stdlib.appup.src
+++ b/lib/stdlib/src/stdlib.appup.src
@@ -54,7 +54,9 @@
{<<"^4\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^4\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
{<<"^4\\.2$">>,[restart_new_emulator]},
- {<<"^4\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}],
+ {<<"^4\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^4\\.3$">>,[restart_new_emulator]},
+ {<<"^4\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}],
[{<<"^3\\.13$">>,[restart_new_emulator]},
{<<"^3\\.13\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^3\\.13\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
@@ -81,4 +83,6 @@
{<<"^4\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^4\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
{<<"^4\\.2$">>,[restart_new_emulator]},
- {<<"^4\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}.
+ {<<"^4\\.2\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^4\\.3$">>,[restart_new_emulator]},
+ {<<"^4\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}]}.
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index 834eb23335..81bc3e9a0d 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -907,105 +907,121 @@ unused_import(Config) when is_list(Config) ->
%% Test singleton type variables
singleton_type_var_errors(Config) when is_list(Config) ->
- Ts = [ {singleton_error1
- , <<"-spec test_singleton_typevars_in_union(Opts) -> term() when
+ Ts = [{singleton_error1,
+ <<"-spec test_singleton_typevars_in_union(Opts) -> term() when
Opts :: {ok, Unknown} | {error, Unknown}.
test_singleton_typevars_in_union(_) ->
error.
- ">>
- , []
- , { errors
- , [{{2,36},erl_lint,{singleton_typevar,'Unknown'}}]
- , []
- }
- }
- , { singleton_error2
- , <<"-spec test_singleton_list_typevars_in_union([Opts]) -> term() when
+ ">>,
+ [],
+ {warnings,[{{2,36},erl_lint,{singleton_typevar,'Unknown'}}]}},
+
+ {singleton_error2,
+ <<"-spec test_singleton_list_typevars_in_union([Opts]) -> term() when
Opts :: {ok, Unknown} | {error, Unknown}.
test_singleton_list_typevars_in_union(_) ->
- error.">>
- , []
- , { errors
- , [{{2,36},erl_lint,{singleton_typevar,'Unknown'}}]
- , []
- }
- }
- , { singleton_error3
- , <<"-spec test_singleton_list_typevars_in_list([Opts]) -> term() when
+ error.">>,
+ [],
+ {warnings,[{{2,36},erl_lint,{singleton_typevar,'Unknown'}}]}},
+
+ {singleton_error3,
+ <<"-spec test_singleton_list_typevars_in_list([Opts]) -> term() when
Opts :: {ok, Unknown}.
test_singleton_list_typevars_in_list(_) ->
- error.">>
- , []
- , { errors
- , [{{2,36},erl_lint,{singleton_typevar,'Unknown'}}]
- , []
- }
- }
- , { singleton_error4
- , <<"-spec test_singleton_list_typevars_in_list_with_type_subst([{ok, Unknown}]) -> term().
+ error.">>,
+ [],
+ {errors,
+ [{{2,36},erl_lint,{singleton_typevar,'Unknown'}}],[]}},
+
+ {singleton_error4,
+ <<"-spec test_singleton_list_typevars_in_list_with_type_subst([{ok, Unknown}]) -> term().
test_singleton_list_typevars_in_list_with_type_subst(_) ->
- error.">>
- , []
- , { errors
- , [{{1,86},erl_lint,{singleton_typevar,'Unknown'}}]
- , []
- }
- }
- , { singleton_error5
- , <<"-spec test_singleton_buried_typevars_in_union(Opts) -> term() when
+ error.">>,
+ [],
+ {errors,[{{1,86},erl_lint,{singleton_typevar,'Unknown'}}],[]}},
+
+ {singleton_error5,
+ <<"-spec test_singleton_buried_typevars_in_union(Opts) -> term() when
Opts :: {ok, Foo} | {error, Foo},
Foo :: {true, X} | {false, X}.
test_singleton_buried_typevars_in_union(_) ->
- error.">>
- , []
- , { errors
- , [{{3,38},erl_lint,{singleton_typevar,'X'}}]
- , []
- }
- }
- , { singleton_error6
- , <<"-spec test_multiple_subtypes_to_same_typevar(Opts) -> term() when
+ error.">>,
+ [],
+ {warnings,[{{3,38},erl_lint,{singleton_typevar,'X'}}]}},
+
+ {singleton_error6,
+ <<"-spec test_multiple_subtypes_to_same_typevar(Opts) -> term() when
Opts :: {Foo, Bar} | Y,
Foo :: X,
Bar :: X,
Y :: Z.
test_multiple_subtypes_to_same_typevar(_) ->
- error.">>
- , []
- , { errors
- , [{{5,31},erl_lint,{singleton_typevar,'Z'}}]
- , []
- }
- }
- , { singleton_error7
- , <<"-spec test_duplicate_non_terminal_var_in_union(Opts) -> term() when
+ error.">>,
+ [],
+ {errors,[{{5,31},erl_lint,{singleton_typevar,'Z'}}],[]}},
+
+ {singleton_error7,
+ <<"-spec test_duplicate_non_terminal_var_in_union(Opts) -> term() when
Opts :: {ok, U, U} | {error, U, U},
U :: Foo.
test_duplicate_non_terminal_var_in_union(_) ->
- error.">>
- , []
- , { errors
- , [{{3,31},erl_lint,{singleton_typevar,'Foo'}}]
- , []
- }
- }
- , { singleton_ok1
- , <<"-spec test_multiple_occurrences_singleton(Opts) -> term() when
+ error.">>,
+ [],
+ {errors,[{{3,31},erl_lint,{singleton_typevar,'Foo'}}],[]}},
+
+ {singleton_error8,
+ <<"-spec test_unused_outside_union(Opts) -> term() when
+ Unused :: Unknown,
+ A :: Unknown,
+ Opts :: {Unknown | A}.
+ test_unused_outside_union(_) ->
+ error.">>,
+ [],
+ {errors,[{{2,21},erl_lint,{singleton_typevar,'Unused'}}],[]}},
+
+ {singleton_disabled_warning,
+ <<"-spec test_singleton_typevars_in_union(Opts) -> term() when
+ Opts :: {ok, Unknown} | {error, Unknown}.
+ test_singleton_typevars_in_union(_) ->
+ error.
+ ">>,
+ [nowarn_singleton_typevar],
+ []},
+
+ {singleton_ok1,
+ <<"-spec test_multiple_occurrences_singleton(Opts) -> term() when
Opts :: {Foo, Foo}.
test_multiple_occurrences_singleton(_) ->
- ok.">>
- , []
- , []
- }
- , { singleton_ok2
- , <<"-spec id(X) -> X.
+ ok.">>,
+ [],
+ []},
+
+ {singleton_ok2,
+ <<"-spec id(X) -> X.
id(X) ->
- X.">>
- , []
- , []
- }
+ X.">>,
+ [],
+ []},
+
+ {singleton_ok3,
+ <<"-spec ok(Opts) -> term() when
+ Opts :: {Unknown, {ok, Unknown} | {error, Unknown}}.
+ ok(_) ->
+ error.">>,
+ [],
+ []},
+
+ {singleton_ok4,
+ <<"-spec ok(Opts) -> term() when
+ Union :: {ok, Unknown} | {error, Unknown},
+ Opts :: {{tag, Unknown} | Union}.
+ ok(_) ->
+ error.">>,
+ [],
+ []}
+
+ ],
- ],
[] = run(Config, Ts),
ok.
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index cd81d52182..d6706e69bf 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 4.3
+STDLIB_VSN = 4.3.1
diff --git a/lib/syntax_tools/src/epp_dodger.erl b/lib/syntax_tools/src/epp_dodger.erl
index 2e0694c2cf..40f67b5660 100644
--- a/lib/syntax_tools/src/epp_dodger.erl
+++ b/lib/syntax_tools/src/epp_dodger.erl
@@ -517,6 +517,8 @@ quickscan_form([{'-', _Anno}, {'else', AnnoA} | _Ts]) ->
kill_form(AnnoA);
quickscan_form([{'-', _Anno}, {atom, AnnoA, endif} | _Ts]) ->
kill_form(AnnoA);
+quickscan_form([{'-', _Anno}, {atom, AnnoA, feature} | _Ts]) ->
+ kill_form(AnnoA);
quickscan_form([{'-', Anno}, {'?', _}, {Type, _, _}=N | [{'(', _} | _]=Ts])
when Type =:= atom; Type =:= var ->
%% minus, macro and open parenthesis at start of form - assume that
diff --git a/lib/wx/api_gen/gl_gen.erl b/lib/wx/api_gen/gl_gen.erl
index 641f21eccd..eef715b83a 100644
--- a/lib/wx/api_gen/gl_gen.erl
+++ b/lib/wx/api_gen/gl_gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2021. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2023. 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.
diff --git a/lib/wx/api_gen/gl_gen_erl.erl b/lib/wx/api_gen/gl_gen_erl.erl
index 7c9f97867c..06fc6c9e58 100644
--- a/lib/wx/api_gen/gl_gen_erl.erl
+++ b/lib/wx/api_gen/gl_gen_erl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2022. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2023. 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.
diff --git a/lib/wx/api_gen/gl_gen_nif.erl b/lib/wx/api_gen/gl_gen_nif.erl
index b8a6be3908..a84bf454a5 100644
--- a/lib/wx/api_gen/gl_gen_nif.erl
+++ b/lib/wx/api_gen/gl_gen_nif.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2021. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2023. 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.
diff --git a/lib/wx/api_gen/wx_gen_nif.erl b/lib/wx/api_gen/wx_gen_nif.erl
index fa2fd52fe4..e768f483fe 100644
--- a/lib/wx/api_gen/wx_gen_nif.erl
+++ b/lib/wx/api_gen/wx_gen_nif.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2022. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2023. 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.
diff --git a/lib/wx/api_gen/wxapi.conf b/lib/wx/api_gen/wxapi.conf
index 31bb522bc0..be9529d40c 100644
--- a/lib/wx/api_gen/wxapi.conf
+++ b/lib/wx/api_gen/wxapi.conf
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2022. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2023. 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.
diff --git a/lib/wx/c_src/egl_impl.c b/lib/wx/c_src/egl_impl.c
index 84e1601a7f..868b32ab79 100644
--- a/lib/wx/c_src/egl_impl.c
+++ b/lib/wx/c_src/egl_impl.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011-2022. All Rights Reserved.
+ * Copyright Ericsson AB 2011-2023. 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.
diff --git a/lib/wx/c_src/wxe_gl.cpp b/lib/wx/c_src/wxe_gl.cpp
index 7ad6abb659..e2327cfb54 100644
--- a/lib/wx/c_src/wxe_gl.cpp
+++ b/lib/wx/c_src/wxe_gl.cpp
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2022. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2023. 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.
diff --git a/lib/wx/c_src/wxe_gl.h b/lib/wx/c_src/wxe_gl.h
index 612432c22f..12aea9bb8c 100644
--- a/lib/wx/c_src/wxe_gl.h
+++ b/lib/wx/c_src/wxe_gl.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2021. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2023. 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.
diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp
index 52e9757d2e..5ea1371524 100644
--- a/lib/wx/c_src/wxe_impl.cpp
+++ b/lib/wx/c_src/wxe_impl.cpp
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2022. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2023. 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.
diff --git a/lib/wx/c_src/wxe_impl.h b/lib/wx/c_src/wxe_impl.h
index 45e80a77d1..a99c30a254 100644
--- a/lib/wx/c_src/wxe_impl.h
+++ b/lib/wx/c_src/wxe_impl.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2022. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2023. 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.
diff --git a/lib/wx/c_src/wxe_nif.c b/lib/wx/c_src/wxe_nif.c
index 6d9ed300ac..a7d3fea885 100644
--- a/lib/wx/c_src/wxe_nif.c
+++ b/lib/wx/c_src/wxe_nif.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2017-2022. All Rights Reserved.
+ * Copyright Ericsson AB 2017-2023. 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.
diff --git a/lib/wx/c_src/wxe_return.cpp b/lib/wx/c_src/wxe_return.cpp
index 621e39f16b..8728dafcf9 100644
--- a/lib/wx/c_src/wxe_return.cpp
+++ b/lib/wx/c_src/wxe_return.cpp
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2022. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2023. 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.
diff --git a/lib/wx/doc/src/gl.xml b/lib/wx/doc/src/gl.xml
index 865ce91bb9..1f35f8fa89 100644
--- a/lib/wx/doc/src/gl.xml
+++ b/lib/wx/doc/src/gl.xml
@@ -7,7 +7,7 @@
<erlref>
<header>
<copyright>
- <year>2020</year>
+ <year>2020</year><year>2023</year>
<holder>Ericsson AB. All Rights Reserved.</holder></copyright>
<legalnotice>
Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/lib/wx/doc/src/notes.xml b/lib/wx/doc/src/notes.xml
index f155b7a551..08e339e097 100644
--- a/lib/wx/doc/src/notes.xml
+++ b/lib/wx/doc/src/notes.xml
@@ -32,6 +32,22 @@
<p>This document describes the changes made to the wxErlang
application.</p>
+<section><title>Wx 2.2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improve debug prints from the nifs. Some minor fixes for
+ wxWidgets-3.2. Fixed OpenGL debug functions.</p>
+ <p>
+ Own Id: OTP-18512</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Wx 2.2.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/wx/src/wxe_master.erl b/lib/wx/src/wxe_master.erl
index dd6eb4f159..f0bb1e64e7 100644
--- a/lib/wx/src/wxe_master.erl
+++ b/lib/wx/src/wxe_master.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2022. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2023. 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.
diff --git a/lib/wx/src/wxe_util.erl b/lib/wx/src/wxe_util.erl
index 4f123ffc09..217e7118ff 100644
--- a/lib/wx/src/wxe_util.erl
+++ b/lib/wx/src/wxe_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2022. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2023. 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.
diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl
index 267ad4d336..5275defce6 100644
--- a/lib/wx/test/wx_class_SUITE.erl
+++ b/lib/wx/test/wx_class_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2022. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2023. 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.
diff --git a/lib/wx/test/wx_opengl_SUITE.erl b/lib/wx/test/wx_opengl_SUITE.erl
index fa4e456c42..fb3e5ba598 100644
--- a/lib/wx/test/wx_opengl_SUITE.erl
+++ b/lib/wx/test/wx_opengl_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2022. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2023. 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.
diff --git a/lib/wx/vsn.mk b/lib/wx/vsn.mk
index e7144bd6a2..78f0fd3395 100644
--- a/lib/wx/vsn.mk
+++ b/lib/wx/vsn.mk
@@ -1 +1 @@
-WX_VSN = 2.2.1
+WX_VSN = 2.2.2