diff options
-rw-r--r-- | OTP_VERSION | 2 | ||||
-rw-r--r-- | erts/doc/src/notes.xml | 131 | ||||
-rw-r--r-- | erts/emulator/beam/erl_process.c | 2 | ||||
-rw-r--r-- | erts/emulator/drivers/common/inet_drv.c | 7 | ||||
-rw-r--r-- | erts/etc/win32/nsis/erlang20.nsi | 8 | ||||
-rw-r--r-- | erts/etc/win32/wsl_tools/SetupWSLcross.bat | 10 | ||||
-rw-r--r-- | erts/vsn.mk | 2 | ||||
-rw-r--r-- | lib/compiler/doc/src/notes.xml | 23 | ||||
-rw-r--r-- | lib/compiler/src/beam_ssa_bool.erl | 78 | ||||
-rw-r--r-- | lib/compiler/test/guard_SUITE.erl | 166 | ||||
-rw-r--r-- | lib/compiler/vsn.mk | 2 | ||||
-rw-r--r-- | lib/crypto/test/crypto_SUITE.erl | 482 | ||||
-rw-r--r-- | lib/crypto/test/crypto_property_test_SUITE.erl | 1 | ||||
-rw-r--r-- | lib/kernel/doc/src/notes.xml | 17 | ||||
-rw-r--r-- | lib/kernel/test/gen_sctp_SUITE.erl | 152 | ||||
-rw-r--r-- | lib/kernel/test/gen_udp_SUITE.erl | 84 | ||||
-rw-r--r-- | lib/megaco/doc/src/notes.xml | 16 | ||||
-rw-r--r-- | lib/stdlib/src/digraph.erl | 4 | ||||
-rw-r--r-- | lib/stdlib/test/digraph_SUITE.erl | 51 | ||||
-rw-r--r-- | lib/stdlib/test/gen_statem_SUITE.erl | 107 | ||||
-rw-r--r-- | make/otp_version_tickets | 202 | ||||
-rw-r--r-- | make/otp_version_tickets_in_merge | 6 | ||||
-rw-r--r-- | otp_versions.table | 3 | ||||
-rwxr-xr-x | scripts/pre-push | 6 |
24 files changed, 1029 insertions, 533 deletions
diff --git a/OTP_VERSION b/OTP_VERSION index 919c868b57..c471f62163 100644 --- a/OTP_VERSION +++ b/OTP_VERSION @@ -1 +1 @@ -23.0 +23.0.1 diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index 698d044bfb..cdee14a460 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -31,6 +31,39 @@ </header> <p>This document describes the changes made to the ERTS application.</p> +<section><title>Erts 11.0.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The functionality utilized by BIFs for temporary + disabling of garbage collection while yielding could + cause system task queues to become inconsistent on a + process executing such a BIF. Process system tasks are + for example utilized when purging code, garbage + collecting literal data, and when issuing an ordinary + garbage collection from another process.</p> + <p> + The bug does not trigger frequently. Multiple code purges + in direct sequence makes it more likely that this bug is + triggered. In the cases observed, this has resulted in a + hanging code purge operation.</p> + <p> + Own Id: OTP-16639 Aux Id: ERL-1236 </p> + </item> + <item> + <p> + SCTP and UDP recv/2,3 hangs indefinitely if socket is + closed while recv is called (socket in passive mode).</p> + <p> + Own Id: OTP-16654 Aux Id: ERL-1242 </p> + </item> + </list> + </section> + +</section> + <section><title>Erts 11.0</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -627,6 +660,46 @@ </section> +<section><title>Erts 10.7.2.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed bug in erl_crash.dump generation that could cause a + SEGV core dump if a recently cancelled timer was found.</p> + <p> + Own Id: OTP-16596 Aux Id: ERL-1105, PR-2606 </p> + </item> + <item> + <p> + The functionality utilized by BIFs for temporary + disabling of garbage collection while yielding could + cause system task queues to become inconsistent on a + process executing such a BIF. Process system tasks are + for example utilized when purging code, garbage + collecting literal data, and when issuing an ordinary + garbage collection from another process.</p> + <p> + The bug does not trigger frequently. Multiple code purges + in direct sequence makes it more likely that this bug is + triggered. In the cases observed, this has resulted in a + hanging code purge operation.</p> + <p> + Own Id: OTP-16639 Aux Id: ERL-1236 </p> + </item> + <item> + <p> + SCTP and UDP recv/2,3 hangs indefinitely if socket is + closed while recv is called (socket in passive mode).</p> + <p> + Own Id: OTP-16654 Aux Id: ERL-1242 </p> + </item> + </list> + </section> + +</section> + <section><title>Erts 10.7.2</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -2388,6 +2461,64 @@ </section> +<section><title>Erts 10.3.5.12</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The functionality utilized by BIFs for temporary + disabling of garbage collection while yielding could + cause system task queues to become inconsistent on a + process executing such a BIF. Process system tasks are + for example utilized when purging code, garbage + collecting literal data, and when issuing an ordinary + garbage collection from another process.</p> + <p> + The bug does not trigger frequently. Multiple code purges + in direct sequence makes it more likely that this bug is + triggered. In the cases observed, this has resulted in a + hanging code purge operation.</p> + <p> + Own Id: OTP-16639 Aux Id: ERL-1236 </p> + </item> + <item> + <p> + A literal area could prematurely be released before all + uses of it had been removed. This occurred either when a + terminating process had a complex exit reason referring + to a literal that concurrently was removed, or when a + terminating process continued executing a dirty NIF + accessing a literal (via the heap) that concurrently was + removed.</p> + <p> + Own Id: OTP-16640 Aux Id: OTP-16193 </p> + </item> + <item> + <p> + The VM could potentially crash when checking process code + of a process that terminated while executing a dirty NIF. + The checking of process code is part of a code purge + operation.</p> + <p> + Own Id: OTP-16641</p> + </item> + <item> + <p> + System tasks of <c>low</c> priority were not interleaved + with <c>normal</c> priority system tasks as they should. + This could potentially delay garbage collection of + another process longer than intended if the garbage + collection was requested from a <c>low</c> priority + process.</p> + <p> + Own Id: OTP-16642</p> + </item> + </list> + </section> + +</section> + <section><title>Erts 10.3.5.11</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 0a1e274396..6c83693df8 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -11188,7 +11188,7 @@ erts_set_gc_state(Process *c_p, int enable) first1 = dgc_tsk_qs->q[prio]; last1 = first1->prev; first2 = stsk_qs->q[prio]; - last2 = first1->prev; + last2 = first2->prev; last1->next = first2; first2->prev = last1; diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 42a5936513..6797b5d32f 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -12254,14 +12254,15 @@ static void packet_inet_stop(ErlDrvData e) into "udp_descriptor*" or "inet_descriptor*": */ udp_descriptor * udesc = (udp_descriptor*) e; - inet_descriptor* descr = INETP(udesc); + inet_descriptor* desc = INETP(udesc); if (udesc->i_buf != NULL) { release_buffer(udesc->i_buf); udesc->i_buf = NULL; } - ASSERT(NO_SUBSCRIBERS(&(descr->empty_out_q_subs))); - inet_stop(descr); + ASSERT(NO_SUBSCRIBERS(&(desc->empty_out_q_subs))); + async_error_am_all(desc, am_closed); + inet_stop(desc); } static int packet_error(udp_descriptor* udesc, int err) diff --git a/erts/etc/win32/nsis/erlang20.nsi b/erts/etc/win32/nsis/erlang20.nsi index 63e63a06cb..950f3ec0a3 100644 --- a/erts/etc/win32/nsis/erlang20.nsi +++ b/erts/etc/win32/nsis/erlang20.nsi @@ -52,7 +52,7 @@ Var STARTMENU_FOLDER !define MY_STARTMENUPAGE_REGISTRY_VALUENAME "Start Menu Folder"
;General
- OutFile "${OUTFILEDIR}\otp_${WINTYPE}_${OTP_VERSION}.exe"
+ OutFile "${OUTFILEDIR}\otp_${WINTYPE}_${OTP_RELEASE_VERSION}.exe"
;Folder selection page
!if ${WINTYPE} == "win64"
@@ -68,7 +68,7 @@ Var STARTMENU_FOLDER !if ${WINTYPE} == "win64"
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "${OTP_PRODUCT} ${OTP_VERSION} (x64)"
!else
- !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${OTP_PRODUCT} ${OTP_VERSION}"
+ !define MUI_STARTMENUPAGE_DEFAULTFOLDER "${OTP_PRODUCT} ${OTP_VERSION} (i386)"
!endif
;--------------------------------
@@ -201,7 +201,7 @@ done_startmenu: WriteRegStr HKLM \
"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
- "DisplayName" "Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})"
+ "DisplayName" "Erlang OTP ${OTP_RELEASE_VERSION} (${ERTS_VERSION})"
WriteRegStr HKLM \
"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
"UninstallString" "$INSTDIR\Uninstall.exe"
@@ -225,7 +225,7 @@ done_startmenu: WriteRegStr HKCU \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
- "DisplayName" "Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})"
+ "DisplayName" "Erlang OTP ${OTP_RELEASE_VERSION} (${ERTS_VERSION})"
WriteRegStr HKCU \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\Erlang OTP ${OTP_VERSION} (${ERTS_VERSION})" \
"UninstallString" "$INSTDIR\Uninstall.exe"
diff --git a/erts/etc/win32/wsl_tools/SetupWSLcross.bat b/erts/etc/win32/wsl_tools/SetupWSLcross.bat index 860a7d5e60..5de4cd8bb1 100644 --- a/erts/etc/win32/wsl_tools/SetupWSLcross.bat +++ b/erts/etc/win32/wsl_tools/SetupWSLcross.bat @@ -8,11 +8,6 @@ IF "%~1"=="x64" GOTO search GOTO badarg :search -IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat". ( - call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" %~1 > nul - goto continue -) - IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvarsall.bat". ( call "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" %~1 > nul goto continue @@ -33,6 +28,11 @@ IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat". goto continue ) +IF EXIST "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat". ( + call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" %~1 > nul + goto continue +) + GOTO no_vcvars :continue diff --git a/erts/vsn.mk b/erts/vsn.mk index 75d621458e..1f9796c5cd 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% # -VSN = 11.0 +VSN = 11.0.1 # Port number 4365 in 4.2 # Port number 4366 in 4.3 diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml index d460de2bcd..a37ac251de 100644 --- a/lib/compiler/doc/src/notes.xml +++ b/lib/compiler/doc/src/notes.xml @@ -32,6 +32,29 @@ <p>This document describes the changes made to the Compiler application.</p> +<section><title>Compiler 7.6.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + In rare circumstances, a guard using 'not' could evaluate + to the wrong boolean value.</p> + <p> + Own Id: OTP-16652 Aux Id: ERL-1246 </p> + </item> + <item> + <p>A guard expression that referenced a variable bound to + a boolean expression could evaluate to the wrong + value.</p> + <p> + Own Id: OTP-16657 Aux Id: ERL-1253 </p> + </item> + </list> + </section> + +</section> + <section><title>Compiler 7.6</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/compiler/src/beam_ssa_bool.erl b/lib/compiler/src/beam_ssa_bool.erl index 7ae9070df2..5b81ca2be1 100644 --- a/lib/compiler/src/beam_ssa_bool.erl +++ b/lib/compiler/src/beam_ssa_bool.erl @@ -922,9 +922,11 @@ opt_digraph_instr(#b_set{dst=Dst}=I, G0, St) -> %% Rewriting 'xor' is not practical. Fortunately, %% 'xor' is almost never used in practice. not_possible(); - #b_set{op={bif,'not'},args=[#b_var{}=Bool]} -> - G = convert_to_br_node(I, Fail, G1, St), - redirect_test(Bool, {fail,Succ}, G, St); + #b_set{op={bif,'not'}} -> + %% This is suprisingly rare. The previous attempt to + %% optimize it was broken, which wasn't noticed because + %% very few test cases triggered this code. + not_possible(); #b_set{op=phi,dst=Bool} -> Vtx = get_vertex(Bool, St), G2 = del_out_edges(Vtx, G1), @@ -1070,7 +1072,60 @@ redirect_phi(Phi, Args, SuccFail, G0, St) -> redirect_phi_1(PhiVtx, [{#b_literal{val=false},FalseExit}, {#b_var{}=SuccBool,_BoolExit}], SuccFail, G0, St) -> + %% This was most likely an `andalso` in the source code. BoolVtx = get_vertex(SuccBool, St), + + %% We must be careful when rewriting guards that reference boolean + %% expressions defined before the guard. Here is an example: + %% + %% Bool = Z =:= false, + %% if + %% X =:= Y andalso Bool -> ok; + %% true -> error + %% end. + %% + %% Slightly simplified, the SSA code will look like this: + %% + %% 10: Bool = bif:'=:=' _2, `false` + %% br ^11 + %% + %% 11: B = bif:'=:=' X, Y + %% br B, ^20, ^30 + %% + %% 20: br ^40 + %% 30: br ^40 + %% + %% 40: Phi = phi { `true`, ^20 }, { Bool, ^30 } + %% br Phi, ^100, ^200 + %% + %% 100: ret `ok` + %% 200: ret `error' + %% + %% The usual rewriting of the phi node will result in the following + %% SSA code: + %% + %% 10: Bool = bif:'=:=' _2, `false` + %% br Bool, ^100, ^200 + %% + %% 11: B = bif:'=:=' X, Y + %% br B, ^100, ^200 + %% + %% 20: br ^40 + %% 30: br ^40 + %% + %% 40: Phi = phi { `true`, ^20 }, { Bool, ^30 } + %% br Phi, ^100, ^200 + %% + %% 100: ret `ok` + %% 200: ret `error' + %% + %% Block 11 is no longer reachable; thus, the X =:= Y test has been dropped. + %% To avoid dropping tests, we should check whether if there is a path from + %% 10 to block 20. If there is, the optimization in its current form is not + %% safe. + %% + ensure_disjoint_paths(G0, BoolVtx, FalseExit), + [FalseOut] = beam_digraph:out_edges(G0, FalseExit), G1 = beam_digraph:del_edge(G0, FalseOut), case SuccFail of @@ -1088,6 +1143,11 @@ redirect_phi_1(PhiVtx, [{#b_literal{val=true},TrueExit}, {fail,Fail}, G0, St) -> %% This was probably an `orelse` in the source code. BoolVtx = get_vertex(SuccBool, St), + + %% See the previous clause for an explanation of why we + %% must ensure that paths are disjoint. + ensure_disjoint_paths(G0, BoolVtx, TrueExit), + [TrueOut] = beam_digraph:out_edges(G0, TrueExit), G1 = beam_digraph:del_edge(G0, TrueOut), G2 = beam_digraph:add_edge(G1, TrueExit, PhiVtx, next), @@ -1117,6 +1177,18 @@ digraph_bool_def(G) -> Ds = [{Dst,Vtx} || {Vtx,#b_set{dst=Dst}} <- Vs], maps:from_list(Ds). + +%% ensure_disjoint_paths(G, Vertex1, Vertex2) -> ok. +%% Ensure that there is no path from Vertex1 to Vertex2 in +%% either direction. (It is probably overkill to test both +%% directions, but better safe than sorry.) + +ensure_disjoint_paths(G, V1, V2) -> + case beam_digraph:is_path(G, V1, V2) orelse beam_digraph:is_path(G, V2, V1) of + true -> not_possible(); + false -> ok + end. + %%% %%% Shortcut branches that branch to other branches. %%% diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl index 4a53698e15..0558b8f300 100644 --- a/lib/compiler/test/guard_SUITE.erl +++ b/lib/compiler/test/guard_SUITE.erl @@ -2300,6 +2300,8 @@ beam_bool_SUITE(_Config) -> in_catch(), recv_semi(), andalso_repeated_var(), + erl1246(), + erl1253(), ok. before_and_inside_if() -> @@ -2597,6 +2599,170 @@ andalso_repeated_var() -> andalso_repeated_var(B) when B andalso B -> ok; andalso_repeated_var(_) -> error. +-record(erl1246, {tran_stat = 0}). + +erl1246() -> + false = erl1246(#erl1246{tran_stat = 0}, #{cid => 1131}), + false = erl1246(#erl1246{tran_stat = 12}, #{cid => 1131}), + false = erl1246(#erl1246{tran_stat = 12}, #{cid => 9502}), + true = erl1246(#erl1246{tran_stat = 0}, #{cid => 9502}), + ok. + +erl1246(Rec, #{cid := CollID}) -> + {GiftCollID, _} = erl1246_conf(gift_coll), + IsTranStat = Rec#erl1246.tran_stat =:= erl1246_conf(transform_id), + if + %% Optimization of 'not' in a guard was broken. + CollID =:= GiftCollID andalso not IsTranStat -> + true; + true -> + false + end. + +erl1246_conf(gift_coll) -> {9502, {112, 45}}; +erl1246_conf(transform_id) -> 12; +erl1246_conf(_) -> undefined. + +erl1253() -> + ok = erl1253_orelse_false(a, a, any), + ok = erl1253_orelse_false(a, a, true), + ok = erl1253_orelse_false(a, a, false), + error = erl1253_orelse_false(a, b, any), + error = erl1253_orelse_false(a, b, true), + ok = erl1253_orelse_false(a, b, false), + + ok = erl1253_orelse_true(a, a, any), + ok = erl1253_orelse_true(a, a, true), + ok = erl1253_orelse_true(a, a, false), + error = erl1253_orelse_true(a, b, any), + ok = erl1253_orelse_true(a, b, true), + error = erl1253_orelse_true(a, b, false), + + error = erl1253_andalso_false(a, a, any), + error = erl1253_andalso_false(a, a, true), + ok = erl1253_andalso_false(a, a, false), + error = erl1253_andalso_false(a, b, any), + error = erl1253_andalso_false(a, b, true), + error = erl1253_andalso_false(a, b, false), + + error = erl1253_andalso_true(a, a, any), + ok = erl1253_andalso_true(a, a, true), + error = erl1253_andalso_true(a, a, false), + error = erl1253_andalso_true(a, b, any), + error = erl1253_andalso_true(a, b, true), + error = erl1253_andalso_true(a, b, false), + + ok. + +erl1253_orelse_false(X, Y, Z) -> + Res = erl1253_orelse_false_1(X, Y, Z), + Res = erl1253_orelse_false_2(X, Y, Z), + Res = erl1253_orelse_false_3(X, Y, Z). + +erl1253_orelse_false_1(X, Y, Z) -> + Bool = Z =:= false, + if + X =:= Y orelse Bool -> ok; + true -> error + end. + +erl1253_orelse_false_2(X, Y, Z) -> + Bool = Z =:= false, + if + Bool orelse X =:= Y -> ok; + true -> error + end. + +erl1253_orelse_false_3(X, Y, Z) -> + Bool1 = X =:= Y, + Bool2 = Z =:= false, + if + Bool1 orelse Bool2 -> ok; + true -> error + end. + +erl1253_orelse_true(X, Y, Z) -> + Res = erl1253_orelse_true_1(X, Y, Z), + Res = erl1253_orelse_true_2(X, Y, Z), + Res = erl1253_orelse_true_3(X, Y, Z). + +erl1253_orelse_true_1(X, Y, Z) -> + Bool = Z =:= true, + if + X =:= Y orelse Bool -> ok; + true -> error + end. + +erl1253_orelse_true_2(X, Y, Z) -> + Bool = Z =:= true, + if + Bool orelse X =:= Y -> ok; + true -> error + end. + +erl1253_orelse_true_3(X, Y, Z) -> + Bool1 = X =:= Y, + Bool2 = Z =:= true, + if + Bool1 orelse Bool2 -> ok; + true -> error + end. + +erl1253_andalso_false(X, Y, Z) -> + Res = erl1253_andalso_false_1(X, Y, Z), + Res = erl1253_andalso_false_2(X, Y, Z), + Res = erl1253_andalso_false_3(X, Y, Z). + +erl1253_andalso_false_1(X, Y, Z) -> + Bool = Z =:= false, + if + X =:= Y andalso Bool -> ok; + true -> error + end. + +erl1253_andalso_false_2(X, Y, Z) -> + Bool1 = X =:= Y, + Bool2 = Z =:= false, + if + Bool1 andalso Bool2 -> ok; + true -> error + end. + +erl1253_andalso_false_3(X, Y, Z) -> + Bool1 = X =:= Y, + Bool2 = Z =:= false, + if + Bool1 andalso Bool2 -> ok; + true -> error + end. + +erl1253_andalso_true(X, Y, Z) -> + Res = erl1253_andalso_true_1(X, Y, Z), + Res = erl1253_andalso_true_2(X, Y, Z), + Res = erl1253_andalso_true_3(X, Y, Z). + +erl1253_andalso_true_1(X, Y, Z) -> + Bool = Z =:= true, + if + X =:= Y andalso Bool -> ok; + true -> error + end. + +erl1253_andalso_true_2(X, Y, Z) -> + Bool = Z =:= true, + if + Bool andalso X =:= Y-> ok; + true -> error + end. + +erl1253_andalso_true_3(X, Y, Z) -> + Bool1 = X =:= Y, + Bool2 = Z =:= true, + if + Bool1 andalso Bool2 -> ok; + true -> error + end. + %%% %%% End of beam_bool_SUITE tests. %%% diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk index 9a2f1d1919..e167c63a7d 100644 --- a/lib/compiler/vsn.mk +++ b/lib/compiler/vsn.mk @@ -1 +1 @@ -COMPILER_VSN = 7.6 +COMPILER_VSN = 7.6.1 diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index ca72601bef..df830b32f6 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -135,6 +135,7 @@ groups() -> {group, dh}, {group, ecdh}, + {group, eddh}, {group, srp}, {group, chacha20_poly1305}, @@ -217,7 +218,7 @@ groups() -> {dss, [], [sign_verify %% Does not work yet: ,public_encrypt, private_encrypt ]}, - {ecdsa, [], [sign_verify + {ecdsa, [], [sign_verify, use_all_ec_sign_verify %% Does not work yet: ,public_encrypt, private_encrypt ]}, {ed25519, [], [sign_verify, @@ -229,7 +230,8 @@ groups() -> generate ]}, {dh, [], [generate_compute, compute_bug]}, - {ecdh, [], [use_all_elliptic_curves, compute, generate]}, + {ecdh, [], [compute, generate, use_all_ecdh_generate_compute]}, + {eddh, [], [compute, generate, use_all_eddh_generate_compute]}, {srp, [], [generate_compute]}, {des_cbc, [], [block, api_ng, api_ng_one_shot, api_ng_tls]}, {des_cfb, [], [block, api_ng, api_ng_one_shot, api_ng_tls]}, @@ -330,7 +332,7 @@ init_per_suite(Config) -> {ok, _} = zip:unzip("cmactestvectors.zip"), {ok, _} = zip:unzip("gcmtestvectors.zip"), - try crypto:start() of + try is_ok(crypto:start()) of ok -> catch ct:comment("~s",[element(3,hd(crypto:info_lib()))]), catch ct:log("crypto:info_lib() -> ~p~n" @@ -353,10 +355,18 @@ init_per_suite(Config) -> crypto:rand_seed(<< <<Bin/binary>> || _ <- lists:seq(1,16) >>), Config end - catch _:_ -> + + catch C:E:S -> + ct:log("~p ~p~n~p", [C,E,S]), {fail, "Crypto did not start"} end. +is_ok(ok) -> ok; +is_ok({error, already_started}) -> ok; +is_ok({error,{already_started,crypto}}) -> ok. + + + end_per_suite(_Config) -> application:stop(crypto). @@ -471,8 +481,7 @@ hmac() -> [{doc, "Test hmac function"}]. hmac(Config) when is_list(Config) -> Tuples = lazy_eval(proplists:get_value(hmac, Config)), - lists:foreach(fun hmac_check/1, Tuples), - lists:foreach(fun hmac_check/1, mac_listify(Tuples)). + do_cipher_tests(fun hmac_check/1, Tuples++mac_listify(Tuples)). %%-------------------------------------------------------------------- no_hmac() -> @@ -500,8 +509,7 @@ cmac() -> [{doc, "Test all different cmac functions"}]. cmac(Config) when is_list(Config) -> Pairs = lazy_eval(proplists:get_value(cmac, Config)), - lists:foreach(fun cmac_check/1, Pairs), - lists:foreach(fun cmac_check/1, mac_listify(Pairs)). + do_cipher_tests(fun cmac_check/1, Pairs ++ mac_listify(Pairs)). %%-------------------------------------------------------------------- poly1305() -> @@ -531,8 +539,7 @@ block() -> [{doc, "Test block ciphers"}]. block(Config) when is_list(Config) -> [_|_] = Blocks = lazy_eval(proplists:get_value(cipher, Config)), - lists:foreach(fun block_cipher/1, Blocks), - lists:foreach(fun block_cipher/1, block_iolistify(Blocks)), + do_cipher_tests(fun block_cipher/1, Blocks++block_iolistify(Blocks)), lists:foreach(fun block_cipher_increment/1, block_iolistify(Blocks)). %%-------------------------------------------------------------------- @@ -604,7 +611,7 @@ api_ng_cipher_increment_loop(Ref, InTexts) -> Bin catch error:Error -> - ct:pal("Txt = ~p",[Txt]), + ct:log("Txt = ~p",[Txt]), ct:fail("~p",[Error]) end end, InTexts). @@ -676,17 +683,16 @@ api_ng_tls(Config) when is_list(Config) -> lists:foreach(fun do_api_ng_tls/1, Ciphers). -do_api_ng_tls({Type, Key, PlainTexts}=_X) -> - ct:log("~p",[_X]), +do_api_ng_tls({Type, Key, PlainTexts}) -> do_api_ng_tls({Type, Key, <<>>, PlainTexts}); -do_api_ng_tls({Type, Key, IV, PlainTexts}=_X) -> - ct:log("~p",[_X]), +do_api_ng_tls({Type, Key, IV, PlainTexts}) -> do_api_ng_tls({Type, Key, IV, PlainTexts, undefined}); -do_api_ng_tls({Type, Key, IV, PlainText0, ExpectedEncText}=_X) -> - ct:log("~p",[_X]), +do_api_ng_tls({Type, Key, IV, PlainText0, ExpectedEncText}) -> PlainText = iolist_to_binary(lazy_eval(PlainText0)), + ct:log("Type = ~p~nKey = ~p~nIV = ~p~nPlainText = ~p~nExpectedEncText = ~p", + [Type, Key, IV, PlainText, ExpectedEncText]), Renc = crypto:crypto_dyn_iv_init(Type, Key, true), Rdec = crypto:crypto_dyn_iv_init(Type, Key, false), EncTxt = crypto:crypto_dyn_iv_update(Renc, PlainText, IV), @@ -832,8 +838,6 @@ no_stream_ivec(Config) when is_list(Config) -> notsup(fun crypto:stream_init/3, [Type, <<"Key">>, <<"Ivec">>]). %%-------------------------------------------------------------------- -aead() -> - [{doc, "Test AEAD ciphers"}]. aead(Config) when is_list(Config) -> [_|_] = AEADs = lazy_eval(proplists:get_value(cipher, Config)), FilteredAEADs = @@ -848,7 +852,7 @@ aead(Config) when is_list(Config) -> IVLen >= 12 end, AEADs) end, - lists:foreach(fun aead_cipher/1, FilteredAEADs). + do_cipher_tests(fun aead_cipher/1, FilteredAEADs). %%-------------------------------------------------------------------- aead_ng(Config) when is_list(Config) -> @@ -865,7 +869,7 @@ aead_ng(Config) when is_list(Config) -> IVLen >= 12 end, AEADs) end, - lists:foreach(fun aead_cipher_ng/1, FilteredAEADs ++ spec_0_bytes(Config)). + do_cipher_tests(fun aead_cipher_ng/1, FilteredAEADs ++ spec_0_bytes(Config)). %%-------------------------------------------------------------------- aead_bad_tag(Config) -> @@ -882,7 +886,7 @@ aead_bad_tag(Config) -> IVLen >= 12 end, AEADs) end, - lists:foreach(fun aead_cipher_bad_tag/1, FilteredAEADs). + do_cipher_tests(fun aead_cipher_bad_tag/1, FilteredAEADs). %%-------------------------------------------------------------------- sign_verify() -> @@ -902,6 +906,7 @@ no_sign_verify(Config) when is_list(Config) -> public_encrypt() -> [{doc, "Test public_encrypt/decrypt "}]. public_encrypt(Config) when is_list(Config) -> + ct:log("public_encrypt", []), Params = proplists:get_value(pub_pub_encrypt, Config, []), lists:foreach(fun do_public_encrypt/1, Params). @@ -961,9 +966,7 @@ compute(Config) when is_list(Config) -> Gen = proplists:get_value(compute, Config), lists:foreach(fun do_compute/1, Gen). %%-------------------------------------------------------------------- -use_all_elliptic_curves() -> - [{doc, " Test that all curves from crypto:ec_curves/0"}]. -use_all_elliptic_curves(_Config) -> +use_all_ec_sign_verify(_Config) -> Msg = <<"hello world!">>, Sups = crypto:supports(), Curves = proplists:get_value(curves, Sups), @@ -975,6 +978,7 @@ use_all_elliptic_curves(_Config) -> Results = [{{Curve,Hash}, try + ct:log("~p ~p",[Curve,Hash]), {Pub,Priv} = crypto:generate_key(ecdh, Curve), true = is_binary(Pub), true = is_binary(Priv), @@ -1000,6 +1004,57 @@ use_all_elliptic_curves(_Config) -> end. %%-------------------------------------------------------------------- +use_all_ecdh_generate_compute(Config) -> + Curves = crypto:supports(curves) -- [ed25519, ed448, x25519, x448], + do_dh_curves(Config, Curves). + +use_all_eddh_generate_compute(Config) -> + AllCurves = crypto:supports(curves), + Curves = [C || C <- [x25519, x448], + lists:member(C, AllCurves)], + do_dh_curves(Config, Curves). + +do_dh_curves(_Config, Curves) -> + ct:log("Lib: ~p~nFIPS: ~p~nCurves:~n~p~n", [crypto:info_lib(), + crypto:info_fips(), + Curves]), + Results = + [{Curve, + try + ct:log("~p",[Curve]), + {APub,APriv} = crypto:generate_key(ecdh, Curve), + {BPub,BPriv} = crypto:generate_key(ecdh, Curve), + true = is_binary(APub), + true = is_binary(APriv), + true = is_binary(BPub), + true = is_binary(BPriv), + + ACommonSecret = crypto:compute_key(ecdh, BPub, APriv, Curve), + BCommonSecret = crypto:compute_key(ecdh, APub, BPriv, Curve), + ACommonSecret == BCommonSecret + catch + C:E -> + {C,E} + end} + || Curve <- Curves + ], + + Fails = + lists:filter(fun({_,true}) -> false; + (_) -> true + end, Results), + + case Fails of + [] -> + ct:comment("All ~p passed",[length(Results)]), + ok; + _ -> + ct:comment("passed: ~p, failed: ~p",[length(Results),length(Fails)]), + ct:log("Fails:~n~p",[Fails]), + ct:fail("Bad curve(s)",[]) + end. + +%%-------------------------------------------------------------------- generate() -> [{doc, " Test crypto:generate_key"}]. generate(Config) when is_list(Config) -> @@ -1065,13 +1120,14 @@ cipher_info(Config) when is_list(Config) -> of _ -> Ok catch Cls:Exc -> - ct:pal("~p:~p ~p",[Cls,Exc,C]), + ct:log("~p:~p ~p",[Cls,Exc,C]), false end end, true, -crypto:supports(ciphers)) of -%% proplists:get_value(ciphers, crypto:supports())) of + crypto:supports(ciphers) + ) + of true -> ok; false -> @@ -1175,76 +1231,49 @@ hmac_increment(State0, [Increment | Rest]) -> hmac_increment(State, Rest). %%%---------------------------------------------------------------- -cmac_check({cmac, Type, Key, Text, CMac}) -> +cmac_check({cmac, Type, Key, Text, CMac}=T) -> ExpCMac = iolist_to_binary(CMac), - case crypto:cmac(Type, Key, Text) of - ExpCMac -> - ok; - Other -> - ct:fail({{crypto, cmac, [Type, Key, Text]}, {expected, ExpCMac}, {got, Other}}) - end; -cmac_check({cmac, Type, Key, Text, Size, CMac}) -> + cipher_test(T, + fun() -> crypto:cmac(Type, Key, Text) end, + ExpCMac); +cmac_check({cmac, Type, Key, Text, Size, CMac}=T) -> ExpCMac = iolist_to_binary(CMac), - case crypto:cmac(Type, Key, Text, Size) of - ExpCMac -> - ok; - Other -> - ct:fail({{crypto, cmac, [Type, Key, Text, Size]}, {expected, ExpCMac}, {got, Other}}) - end. - + cipher_test(T, + fun() -> crypto:cmac(Type, Key, Text, Size) end, + ExpCMac). -mac_check({MacType, SubType, Key, Text, Mac}) -> +mac_check({MacType, SubType, Key, Text, Mac}=T) -> ExpMac = iolist_to_binary(Mac), - case crypto:mac(MacType, SubType, Key, Text) of - ExpMac -> - ok; - Other -> - ct:fail({{crypto, mac, [MacType, SubType, Key, Text]}, {expected, ExpMac}, {got, Other}}) - end; -mac_check({MacType, SubType, Key, Text, Size, Mac}) -> + cipher_test(T, + fun() -> crypto:mac(MacType, SubType, Key, Text) end, + ExpMac); +mac_check({MacType, SubType, Key, Text, Size, Mac}=T) -> ExpMac = iolist_to_binary(Mac), - case crypto:mac(MacType, SubType, Key, Text, Size) of - ExpMac -> - ok; - Other -> - ct:fail({{crypto, mac, [MacType, SubType, Key, Text]}, {expected, ExpMac}, {got, Other}}) - end. + cipher_test(T, + fun() -> crypto:mac(MacType, SubType, Key, Text, Size) end, + ExpMac). - -block_cipher({Type, Key, PlainText}) -> +block_cipher({Type, Key, PlainText}=T) -> Plain = iolist_to_binary(PlainText), CipherText = crypto:block_encrypt(Type, Key, PlainText), - case crypto:block_decrypt(Type, Key, CipherText) of - Plain -> - ok; - Other -> - ct:fail({{crypto, block_decrypt, [Type, Key, CipherText]}, {expected, Plain}, {got, Other}}) - end; + cipher_test(T, + fun() -> crypto:block_decrypt(Type, Key, CipherText) end, + Plain); -block_cipher({Type, Key, IV, PlainText}) -> +block_cipher({Type, Key, IV, PlainText}=T) -> Plain = iolist_to_binary(PlainText), CipherText = crypto:block_encrypt(Type, Key, IV, PlainText), - case crypto:block_decrypt(Type, Key, IV, CipherText) of - Plain -> - ok; - Other -> - ct:fail({{crypto, block_decrypt, [Type, Key, IV, CipherText]}, {expected, Plain}, {got, Other}}) - end; + cipher_test(T, + fun() -> crypto:block_decrypt(Type, Key, IV, CipherText) end, + Plain); -block_cipher({Type, Key, IV, PlainText, CipherText}) -> +block_cipher({Type, Key, IV, PlainText, CipherText}=T) -> Plain = iolist_to_binary(PlainText), - case crypto:block_encrypt(Type, Key, IV, Plain) of - CipherText -> - ok; - Other0 -> - ct:fail({{crypto, block_encrypt, [Type, Key, IV, Plain]}, {expected, CipherText}, {got, Other0}}) - end, - case crypto:block_decrypt(Type, Key, IV, CipherText) of - Plain -> - ok; - Other1 -> - ct:fail({{crypto, block_decrypt, [Type, Key, IV, CipherText]}, {expected, Plain}, {got, Other1}}) - end. + cipher_test(T, + fun() -> crypto:block_encrypt(Type, Key, IV, Plain) end, + CipherText, + fun() -> crypto:block_decrypt(Type, Key, IV, CipherText) end, + Plain). block_cipher_increment({Type, Key, IV, PlainTexts}) when Type == des_cbc ; Type == des3_cbc ; @@ -1365,124 +1394,99 @@ stream_cipher_incment_loop(State0, OrigState, [PlainText | PlainTexts], Acc, Pla {State, CipherText} = crypto:stream_encrypt(State0, PlainText), stream_cipher_incment_loop(State, OrigState, PlainTexts, [CipherText | Acc], Plain). -aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, Info}) -> +aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, _Info}=T) -> Plain = iolist_to_binary(PlainText), - case crypto:block_encrypt(Type, Key, IV, {AAD, Plain}) of - {CipherText, CipherTag} -> - ok; - Other0 -> - ct:fail({{crypto, - block_encrypt, - [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}]}, - {expected, {CipherText, CipherTag}}, - {got, Other0}}) - end, - case crypto:block_decrypt(Type, Key, IV, {AAD, CipherText, CipherTag}) of - Plain -> - ok; - Other1 -> - ct:fail({{crypto, - block_decrypt, - [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}]}, - {expected, Plain}, - {got, Other1}}) - end; -aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, Info}) -> + cipher_test(T, + fun() -> crypto:block_encrypt(Type, Key, IV, {AAD, Plain}) end, + {CipherText, CipherTag}, + fun() -> crypto:block_decrypt(Type, Key, IV, {AAD, CipherText, CipherTag}) end, + Plain); +aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, _Info}=T) -> <<TruncatedCipherTag:TagLen/binary, _/binary>> = CipherTag, Plain = iolist_to_binary(PlainText), - try crypto:block_encrypt(Type, Key, IV, {AAD, Plain, TagLen}) of - {CipherText, TruncatedCipherTag} -> - ok; - Other0 -> - ct:fail({{crypto, - block_encrypt, - [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}, {taglen,TagLen}]}, - {expected, {CipherText, TruncatedCipherTag}}, - {got, Other0}}) - catch - error:E -> - ct:log("~p",[{Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, Info}]), - try crypto:crypto_one_time_aead(Type, Key, IV, PlainText, AAD, TagLen, true) - of - RR -> - ct:log("Works: ~p",[RR]) - catch - CC:EE -> - ct:log("~p:~p", [CC,EE]) - end, - ct:fail("~p",[E]) - end, - case crypto:block_decrypt(Type, Key, IV, {AAD, CipherText, TruncatedCipherTag}) of - Plain -> - ok; - Other1 -> - ct:fail({{crypto, - block_decrypt, - [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}, - {truncated,TruncatedCipherTag}]}, - {expected, Plain}, - {got, Other1}}) - end. + cipher_test(T, + fun() -> crypto:block_encrypt(Type, Key, IV, {AAD, Plain, TagLen}) end, + {CipherText, TruncatedCipherTag}, + fun() -> crypto:block_decrypt(Type, Key, IV, {AAD, CipherText, TruncatedCipherTag}) end, + Plain). -aead_cipher_ng({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, Info}) -> +aead_cipher_ng({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, _Info}=T) -> Plain = iolist_to_binary(PlainText), - case crypto:crypto_one_time_aead(Type, Key, IV, PlainText, AAD, true) of - {CipherText, CipherTag} -> - ok; - Other0 -> - ct:fail({{crypto, - block_encrypt, - [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}]}, - {expected, {CipherText, CipherTag}}, - {got, Other0}}) - end, - case crypto:crypto_one_time_aead(Type, Key, IV, CipherText, AAD, CipherTag, false) of - Plain -> - ok; - Other1 -> - ct:fail({{crypto, - block_decrypt, - [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}]}, - {expected, Plain}, - {got, Other1}}) - end; -aead_cipher_ng({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, Info}) -> + cipher_test(T, + fun() -> crypto:crypto_one_time_aead(Type, Key, IV, PlainText, AAD, true) end, + {CipherText, CipherTag}, + fun() -> crypto:crypto_one_time_aead(Type, Key, IV, CipherText, AAD, CipherTag, false) end, + Plain); +aead_cipher_ng({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, _Info}=T) -> <<TruncatedCipherTag:TagLen/binary, _/binary>> = CipherTag, Plain = iolist_to_binary(PlainText), - try crypto:crypto_one_time_aead(Type, Key, IV, PlainText, AAD, TagLen, true) of - {CipherText, TruncatedCipherTag} -> - ok; - Other0 -> - ct:fail({{crypto, - block_encrypt, - [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}, {taglen,TagLen}]}, - {expected, {CipherText, TruncatedCipherTag}}, - {got, Other0}}) + cipher_test(T, + fun() -> crypto:crypto_one_time_aead(Type, Key, IV, PlainText, AAD, TagLen, true) end, + {CipherText, TruncatedCipherTag}, + fun() -> crypto:crypto_one_time_aead(Type, Key, IV, CipherText, AAD, TruncatedCipherTag, false) end, + Plain). + +aead_cipher_bad_tag({Type, Key, _PlainText, IV, AAD, CipherText, CipherTag, _Info}=T) -> + BadTag = mk_bad_tag(CipherTag), + cipher_test(T, + fun() -> crypto:crypto_one_time_aead(Type, Key, IV, CipherText, AAD, BadTag, false) end, + error); +aead_cipher_bad_tag({Type, Key, _PlainText, IV, AAD, CipherText, CipherTag, TagLen, _Info}=T) -> + <<TruncatedCipherTag:TagLen/binary, _/binary>> = CipherTag, + BadTruncatedTag = mk_bad_tag(TruncatedCipherTag), + cipher_test(T, + fun() -> crypto:crypto_one_time_aead(Type, Key, IV, CipherText, AAD, BadTruncatedTag, false) end, + error). + + +cipher_test(T, Fe, Ee, Fd, Ed) -> + %% Test encrypt + Re = cipher_test(encrypt, T, Fe, Ee), + %% Test decrypt + Rd = cipher_test(decrypt, T, Fd, Ed), + case {Re, Rd} of + {ok,ok} -> ok; + {ok,_} -> Rd; + {_,ok} -> Re; + _ -> {Re,Rd} + end. + +cipher_test(T, F, E) -> + cipher_test(notag, T, F, E). + +cipher_test(Tag, T, F, E) -> + try F() of + E -> ok; + Other -> {other, {Tag,T,Other}} catch - error:E -> - ct:log("~p",[{Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, Info}]), - try crypto:crypto_one_time_aead(Type, Key, IV, PlainText, AAD, TagLen, true) - of - RR -> - ct:log("Works: ~p",[RR]) - catch - CC:EE -> - ct:log("~p:~p", [CC,EE]) - end, - ct:fail("~p",[E]) - end, - case crypto:crypto_one_time_aead(Type, Key, IV, CipherText, AAD, TruncatedCipherTag, false) of - Plain -> - ok; - Other1 -> - ct:fail({{crypto, - block_decrypt, - [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}, - {truncated,TruncatedCipherTag}]}, - {expected, Plain}, - {got, Other1}}) + error:Error -> {error, {Tag,T,Error}} + end. + +do_cipher_tests(F, TestVectors) when is_function(F,1) -> + {Passed,Failed} = + lists:partition( + fun(R) -> R == ok end, + lists:map(F, TestVectors) + ), + BothFailed = lists:filter(fun({ok,_}) -> false; + ({_,ok}) -> false; + (ok) -> false; + (_) -> true + end, + Failed), + ct:log("Passed: ~p, BothFailed: ~p OnlyOneFailed: ~p", + [length(Passed), length(BothFailed), length(Failed)-length(BothFailed)]), + case Failed of + [] -> + ct:comment("All ~p passed", [length(Passed)]); + _ -> + ct:log("~p",[hd(Failed)]), + ct:comment("Passed: ~p, BothFailed: ~p OnlyOneFailed: ~p", + [length(Passed), length(BothFailed), length(Failed)-length(BothFailed)]), + ct:fail("Failed", []) end. + mk_bad_tag(CipherTag) -> case <<0:(size(CipherTag))/unit:8>> of CipherTag -> % The correct tag may happen to be a suite of zeroes @@ -1491,30 +1495,6 @@ mk_bad_tag(CipherTag) -> X end. -aead_cipher_bad_tag({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, Info}) -> - Plain = iolist_to_binary(PlainText), - BadTag = mk_bad_tag(CipherTag), - case crypto:crypto_one_time_aead(Type, Key, IV, CipherText, AAD, BadTag, false) of - error -> - ok; - Plain -> - ct:log("~p:~p~n info: ~p~n key: ~p~n pt: ~p~n iv: ~p~n aad: ~p~n ct: ~p~n tag: ~p~n bad tag: ~p~n", - [?MODULE,?LINE,Info, Key, PlainText, IV, AAD, CipherText, CipherTag, BadTag]), - ct:fail("Didn't fail on bad tag") - end; -aead_cipher_bad_tag({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, Info}) -> - Plain = iolist_to_binary(PlainText), - <<TruncatedCipherTag:TagLen/binary, _/binary>> = CipherTag, - BadTruncatedTag = mk_bad_tag(TruncatedCipherTag), - case crypto:crypto_one_time_aead(Type, Key, IV, CipherText, AAD, BadTruncatedTag, false) of - error -> - ok; - Plain -> - ct:log("~p:~p~n info: ~p~n key: ~p~n pt: ~p~n iv: ~p~n aad: ~p~n ct: ~p~n tag: ~p~n bad tag: ~p~n", - [Info, Key, PlainText, IV, AAD, CipherText, TruncatedCipherTag, BadTruncatedTag]), - ct:fail("Didn't fail on bad tag") - end. - do_sign_verify({Type, undefined=Hash, Private, Public, Msg, Signature}) -> case crypto:sign(eddsa, Hash, Msg, [Private,Type]) of Signature -> @@ -1598,45 +1578,65 @@ negative_verify(Type, Hash, Msg, Signature, Public, Options) -> end. do_public_encrypt({Type, Public, Private, Msg, Padding}) -> + ct:log("do_public_encrypt Type=~p, Padding=~p,~nPublic = ~p,~nPrivate = ~p,~nMsg = ~p.", + [Type, Padding, Public, Private, Msg]), + timer:sleep(100), try crypto:public_encrypt(Type, Msg, Public, Padding) of PublicEcn -> + ct:log("private_decrypt~nPublicEcn = ~p.", [PublicEcn]), + timer:sleep(100), try crypto:private_decrypt(Type, PublicEcn, Private, Padding) of Msg -> + ct:log("~p:~p ok", [?MODULE,?LINE]), + timer:sleep(100), ok; Other -> + ct:log("~p:~p Other = ~p", [?MODULE,?LINE,Other]), + timer:sleep(100), ct:fail({{crypto, private_decrypt, [Type, PublicEcn, Private, Padding]}, {expected, Msg}, {got, Other}}) catch CC:EE -> + ct:log("~p:~p EXC. ~p:~p", [?MODULE,?LINE,CC,EE]), + timer:sleep(100), ct:fail({{crypto, private_decrypt, [Type, PublicEcn, Private, Padding]}, {expected, Msg}, {got, {CC,EE}}}) end catch CC:EE -> + ct:log("~p:~p EXC 2. ~p:~p", [?MODULE,?LINE,CC,EE]), + timer:sleep(100), ct:fail({{crypto, public_encrypt, [Type, Msg, Public, Padding]}, {got, {CC,EE}}}) end. do_private_encrypt({Type, Public, Private, Msg, Padding}) -> + ct:log("do_private_encrypt Type=~p, Padding=~p,~nPublic = ~p,~nPrivate = ~p,~nMsg = ~p.", + [Type, Padding, Public, Private, Msg]), try crypto:private_encrypt(Type, Msg, Private, Padding) of PrivEcn -> try + ct:log("public_decrypt~nPrivEcn = ~p.", [PrivEcn]), crypto:public_decrypt(Type, PrivEcn, Public, Padding) of Msg -> + ct:log("~p:~p ok", [?MODULE,?LINE]), ok; Other -> + ct:log("~p:~p Other = ~p", [?MODULE,?LINE,Other]), ct:fail({{crypto, public_decrypt, [Type, PrivEcn, Public, Padding]}, {expected, Msg}, {got, Other}}) catch CC:EE -> + ct:log("~p:~p EXC. ~p:~p", [?MODULE,?LINE,CC,EE]), ct:fail({{crypto, public_decrypt, [Type, PrivEcn, Public, Padding]}, {expected, Msg}, {got, {CC,EE}}}) end catch CC:EE -> + ct:log("~p:~p EXC 2. ~p:~p", [?MODULE,?LINE,CC,EE]), ct:fail({{crypto, private_encrypt, [Type, Msg, Private, Padding]}, {got, {CC,EE}}}) end. @@ -1648,6 +1648,9 @@ do_generate_compute({srp = Type, UserPrivate, UserGenParams, UserComParams, UserComParams), SessionKey = crypto:compute_key(Type, UserPublic, {HostPublic, HostPrivate}, HostComParam); + + + do_generate_compute({dh, P, G}) -> {UserPub, UserPriv} = crypto:generate_key(dh, [P, G]), {HostPub, HostPriv} = crypto:generate_key(dh, [P, G]), @@ -1655,6 +1658,7 @@ do_generate_compute({dh, P, G}) -> SharedSecret = crypto:compute_key(dh, UserPub, HostPriv, [P, G]). do_compute({ecdh = Type, Pub, Priv, Curve, SharedSecret}) -> + ct:log("~p ~p", [Type,Curve]), Secret = crypto:compute_key(Type, Pub, Priv, Curve), case Secret of SharedSecret -> @@ -1664,6 +1668,7 @@ do_compute({ecdh = Type, Pub, Priv, Curve, SharedSecret}) -> end. do_generate({Type, Curve, Priv, Pub}) when Type == ecdh ; Type == eddsa -> + ct:log("~p ~p", [Type,Curve]), case crypto:generate_key(Type, Curve, Priv) of {Pub, _} -> ok; @@ -1671,6 +1676,7 @@ do_generate({Type, Curve, Priv, Pub}) when Type == ecdh ; Type == eddsa -> ct:fail({{crypto, generate_key, [Type, Priv, Curve]}, {expected, Pub}, {got, Other}}) end; do_generate({rsa = Type, Mod, Exp}) -> + ct:log("~p", [Type]), case crypto:info_fips() of enabled when Mod < 3072 -> ct:log("SKIP do_generate ~p FIPS=~p, Mod=~p Exp=~p", [Type, enabled, Mod, Exp]), @@ -2101,6 +2107,8 @@ group_config(ecdh, Config) -> Compute = ecdh(), Generate = ecc(), [{compute, Compute}, {generate, Generate} | Config]; +group_config(eddh, Config) -> + [{compute, []}, {generate, []} | Config]; group_config(dh, Config) -> GenerateCompute = [dh()], [{generate_compute, GenerateCompute} | Config]; @@ -2239,12 +2247,13 @@ gen_rsa_sign_verify_tests(Hashs, Msg, Public, Private, Opts) -> gen_rsa_pub_priv_tests(Public, Private, Msg, OptsToTry) -> - SupOpts = proplists:get_value(rsa_opts, crypto:supports(), []), + SupOpts = proplists:get_value(rsa_opts, crypto:supports(), []) -- + [rsa_x931_padding], lists:foldr(fun(Opt, Acc) -> case rsa_opt_is_supported(Opt, SupOpts) of true -> [{rsa, Public, Private, Msg, Opt} | Acc]; - false -> + false -> Acc end end, [], OptsToTry). @@ -3975,11 +3984,13 @@ eddsa(ed448) -> ecdh() -> %% http://csrc.nist.gov/groups/STM/cavp/ - Curves = crypto:ec_curves() ++ - [X || X <- proplists:get_value(curves, crypto:supports(), []), - lists:member(X, [x25519,x448])], - TestCases = - [{ecdh, hexstr2point("42ea6dd9969dd2a61fea1aac7f8e98edcc896c6e55857cc0", "dfbe5d7c61fac88b11811bde328e8a0d12bf01a9d204b523"), + Curves = crypto:supports(curves), + lists:filter( + fun ({_Type, _Pub, _Priv, Curve, _SharedSecret}) -> + lists:member(Curve, Curves) + end, + + [{ecdh, hexstr2point("42ea6dd9969dd2a61fea1aac7f8e98edcc896c6e55857cc0", "dfbe5d7c61fac88b11811bde328e8a0d12bf01a9d204b523"), hexstr2bin("f17d3fea367b74d340851ca4270dcb24c271f445bed9d527"), secp192r1, hexstr2bin("803d8ab2e5b6e6fca715737c3a82f7ce3c783124f6d51cd0")}, @@ -4085,11 +4096,8 @@ ecdh() -> 16#9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b, x448, hexstr2bin("07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d")} - ], - lists:filter(fun ({_Type, _Pub, _Priv, Curve, _SharedSecret}) -> - lists:member(Curve, Curves) - end, - TestCases). + ] + ). dh() -> {dh, 90970053988169282502023478715631717259407236400413906591937635666709823903223997309250405131675572047545403771567755831138144089197560332757755059848492919215391041119286178688014693040542889497092308638580104031455627238700168892909539193174537248629499995652186913900511641708112112482297874449292467498403, 2}. @@ -4143,8 +4151,11 @@ ecc() -> %% information about the curves see %% http://csrc.nist.gov/encryption/dss/ecdsa/NISTReCur.pdf %% - Curves = crypto:ec_curves(), - TestCases = + Curves = crypto:supports(curves), + lists:filter( + fun ({_Type, Curve, _Priv, _Pub}) -> + lists:member(Curve, Curves) + end, [{ecdh,secp192r1,1, hexstr2point("188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811")}, @@ -4174,12 +4185,9 @@ ecc() -> hexstr2bin("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a")}, {ecdh, x25519, hexstr2bin("5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb"), - hexstr2bin("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f")}], - lists:filter(fun ({_Type, Curve, _Priv, _Pub}) -> - lists:member(Curve, Curves) - end, - TestCases). - + hexstr2bin("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f")} + ] + ). int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []); int_to_bin(X) -> int_to_bin_pos(X, []). diff --git a/lib/crypto/test/crypto_property_test_SUITE.erl b/lib/crypto/test/crypto_property_test_SUITE.erl index bf137363e8..9c958007c7 100644 --- a/lib/crypto/test/crypto_property_test_SUITE.erl +++ b/lib/crypto/test/crypto_property_test_SUITE.erl @@ -35,6 +35,7 @@ init_per_suite(Config) -> try crypto:start() of ok -> true; {error, already_started} -> true; + {error,{already_started,crypto}} -> true; _ -> false catch _:_ -> false diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml index 1e8e52cfb2..478607d0c8 100644 --- a/lib/kernel/doc/src/notes.xml +++ b/lib/kernel/doc/src/notes.xml @@ -414,6 +414,23 @@ </section> +<section><title>Kernel 6.5.2.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix bug in <c>application:loaded_applications/0</c> that + could cause it to fail with <c>badarg</c> if for example + a concurrent upgrade/downgrade is running.</p> + <p> + Own Id: OTP-16627 Aux Id: PR-2601 </p> + </item> + </list> + </section> + +</section> + <section><title>Kernel 6.5.2</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index 65183d83cc..55109a5178 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -41,7 +41,8 @@ peeloff_active_once/1, peeloff_active_true/1, peeloff_active_n/1, buffers/1, names_unihoming_ipv4/1, names_unihoming_ipv6/1, - names_multihoming_ipv4/1, names_multihoming_ipv6/1]). + names_multihoming_ipv4/1, names_multihoming_ipv6/1, + recv_close/1]). suite() -> [{ct_hooks,[ts_install_cth]}, @@ -56,10 +57,25 @@ all() -> {group,G}]. groups() -> - [{smoke,[],[basic,basic_stream]}, - {old_solaris,[],[skip_old_solaris]}, - {extensive,[], - [api_open_close, api_listen, api_connect_init, + [ + {smoke, [], smoke_cases()}, + {old_solaris, [], old_solaris_cases()}, + {extensive, [], extensive_cases()} + ]. + +smoke_cases() -> + [ + basic, + basic_stream + ]. + +old_solaris_cases() -> + [ + skip_old_solaris + ]. + +extensive_cases() -> + [api_open_close, api_listen, api_connect_init, api_opts, xfer_min, xfer_active, def_sndrcvinfo, implicit_inet6, open_multihoming_ipv4_socket, open_unihoming_ipv6_socket, @@ -68,7 +84,8 @@ groups() -> xfer_stream_min, peeloff_active_once, peeloff_active_true, peeloff_active_n, buffers, names_unihoming_ipv4, names_unihoming_ipv6, - names_multihoming_ipv4, names_multihoming_ipv6]}]. + names_multihoming_ipv4, names_multihoming_ipv6, + recv_close]. init_per_suite(_Config) -> case gen_sctp:open() of @@ -1511,6 +1528,111 @@ recv_comm_up_eventually(S) -> recv_comm_up_eventually(S) end. + +%% +recv_close(Config) when is_list(Config) -> + p("create server socket (and listen)"), + {ok, S} = gen_sctp:open(), + gen_sctp:listen(S, true), + {ok, SPort} = inet:port(S), + + p("create client socket (and connect)"), + {ok, C} = gen_sctp:open(), + {ok, _} = gen_sctp:connect(C, localhost, SPort, []), + + TC = self(), + RECV = fun() -> + p("try setup recv(s)"), + ok = recv_close_setup_recv(S), + p("announce ready"), + TC ! {self(), ready}, + p("try data recv"), + Res = gen_sctp:recv(S), + p("recv res: " + "~n ~p", [Res]), + exit(Res) + end, + p("spawn reader - then await reader ready"), + {Pid, MRef} = spawn_monitor(RECV), + receive + {'DOWN', MRef, process, Pid, PreReason} -> + %% Make sure it does not die for some other reason... + p("unexpected reader termination:" + "~n ~p", [PreReason]), + (catch gen_sctp:close(S)), + (catch gen_sctp:close(C)), + ?line ct:fail("Unexpected pre close from reader (~p): ~p", + [Pid, PreReason]); + {Pid, ready} -> + p("reader ready"), + ok + after 30000 -> % Just in case... + %% This is **extreme**, but there is no way to know + %% how long it will take to iterate through all the + %% addresses of a host... + p("reader ready timeout"), + (catch gen_sctp:close(S)), + (catch gen_sctp:close(C)), + ?line ct:fail("Unexpected pre close timeout (~p)", [Pid]) + end, + + p("\"ensure\" reader reading..."), + receive + Any -> + p("Received unexpected message: " + "~n ~p", [Any]), + (catch gen_sctp:close(S)), + (catch gen_sctp:close(C)), + ?line ct:fail("Unexpected message: ~p", [Any]) + after 5000 -> + ok + end, + + p("close server socket"), + ok = gen_sctp:close(S), + p("await reader termination"), + receive + {'DOWN', MRef, process, Pid, {error, closed}} -> + p("expected reader termination result"), + (catch gen_sctp:close(C)), + ok; + {'DOWN', MRef, process, Pid, PostReason} -> + p("unexpected reader termination: " + "~n ~p", [PostReason]), + (catch gen_sctp:close(C)), + ?line ct:fail("Unexpected post close from reader (~p): ~p", + [Pid, PostReason]) + after 5000 -> + p("unexpected reader termination timeout"), + demonitor(MRef, [flush]), + (catch gen_sctp:close(C)), + exit(Pid, kill), + ?line ct:fail("Reader (~p) termination timeout", [Pid]) + end, + p("close client socket"), + (catch gen_sctp:close(C)), + p("done"), + ok. + + +recv_close_setup_recv(S) -> + recv_close_setup_recv(S, 1). + +recv_close_setup_recv(S, N) -> + p("try setup recv ~w", [N]), + case gen_sctp:recv(S, 5000) of + {ok, {Addr, + Port, + _AncData, + Data}} when is_tuple(Addr) andalso is_integer(Port) -> + p("setup recv ~w: " + "~n ~p", [N, Data]), + recv_close_setup_recv(S, N+1); + {error, timeout} -> + ok + end. + + %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% socket gen_server ultra light @@ -1745,3 +1867,21 @@ match_unless_solaris(A, B) -> timestamp() -> erlang:monotonic_time(). + +formated_timestamp() -> + format_timestamp(os:timestamp()). + +format_timestamp({_N1, _N2, N3} = TS) -> + {_Date, Time} = calendar:now_to_local_time(TS), + {Hour, Min, Sec} = Time, + FormatTS = io_lib:format("~.2.0w:~.2.0w:~.2.0w.~.3.0w", + [Hour, Min, Sec, N3 div 1000]), + lists:flatten(FormatTS). + +p(F) -> + p(F, []). + +p(F, A) -> + io:format("~s ~p " ++ F ++ "~n", [formated_timestamp(), self() | A]). + + diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl index 2720d3cc77..7ec553ec51 100644 --- a/lib/kernel/test/gen_udp_SUITE.erl +++ b/lib/kernel/test/gen_udp_SUITE.erl @@ -40,25 +40,45 @@ recvtos/1, recvtosttl/1, recvttl/1, recvtclass/1, sendtos/1, sendtosttl/1, sendttl/1, sendtclass/1, local_basic/1, local_unbound/1, - local_fdopen/1, local_fdopen_unbound/1, local_abstract/1]). + local_fdopen/1, local_fdopen_unbound/1, local_abstract/1, + recv_close/1]). suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap,{minutes,1}}]. all() -> - [send_to_closed, buffer_size, binary_passive_recv, max_buffer_size, - bad_address, read_packets, recv_poll_after_active_once, - open_fd, connect, - implicit_inet6, active_n, + [ + send_to_closed, + buffer_size, + binary_passive_recv, + max_buffer_size, + bad_address, + read_packets, + recv_poll_after_active_once, + open_fd, + connect, + implicit_inet6, + active_n, recvtos, recvtosttl, recvttl, recvtclass, sendtos, sendtosttl, sendttl, sendtclass, - {group, local}]. + {group, local}, + recv_close + ]. groups() -> - [{local, [], - [local_basic, local_unbound, - local_fdopen, local_fdopen_unbound, local_abstract]}]. + [ + {local, [], local_cases()} + ]. + +local_cases() -> + [ + local_basic, + local_unbound, + local_fdopen, + local_fdopen_unbound, + local_abstract + ]. init_per_suite(Config) -> Config. @@ -969,6 +989,52 @@ local_handshake(S, SAddr, C, CAddr) -> end. + + +%%------------------------------------------------------------- +%% Open a passive socket. Create a socket that reads from it. +%% Then close the socket. +recv_close(Config) when is_list(Config) -> + {ok, Sock} = gen_udp:open(0, [{active, false}]), + RECV = fun() -> + io:format("~p try recv~n", [self()]), + Res = gen_udp:recv(Sock, 0), + io:format("~p recv res: ~p~n", [self(), Res]), + exit(Res) + end, + io:format("~p spawn reader", [self()]), + {Pid, MRef} = spawn_monitor(RECV), + receive + {'DOWN', MRef, process, Pid, PreReason} -> + %% Make sure id does not die for some other reason... + ?line ct:fail("Unexpected pre close from reader (~p): ~p", + [Pid, PreReason]) + after 5000 -> % Just in case... + ok + end, + io:format("~p close socket", [self()]), + ok = gen_udp:close(Sock), + io:format("~p await reader termination", [self()]), + receive + {'DOWN', MRef, process, Pid, {error, closed}} -> + io:format("~p expected reader termination result", [self()]), + ok; + {'DOWN', MRef, process, Pid, PostReason} -> + io:format("~p unexpected reader termination: ~p", + [self(), PostReason]), + ?line ct:fail("Unexpected post close from reader (~p): ~p", + [Pid, PostReason]) + after 5000 -> + io:format("~p unexpected reader termination timeout", [self()]), + demonitor(MRef, [flush]), + exit(Pid, kill), + ?line ct:fail("Reader (~p) termination timeout", [Pid]) + end, + ok. + + + + %% %% Utils %% diff --git a/lib/megaco/doc/src/notes.xml b/lib/megaco/doc/src/notes.xml index 44a820fc7c..c2f72e8b2f 100644 --- a/lib/megaco/doc/src/notes.xml +++ b/lib/megaco/doc/src/notes.xml @@ -61,6 +61,22 @@ </section> + <section><title>Megaco 3.18.8.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The mini parser could not properly decode some IPv6 + addresses.</p> + <p> + Own Id: OTP-16631 Aux Id: ERIERL-491 </p> + </item> + </list> + </section> + +</section> + <section><title>Megaco 3.18.8</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/stdlib/src/digraph.erl b/lib/stdlib/src/digraph.erl index 8a4df95027..58d493cf54 100644 --- a/lib/stdlib/src/digraph.erl +++ b/lib/stdlib/src/digraph.erl @@ -230,7 +230,7 @@ in_neighbours(G, V) -> Edges :: [edge()]. in_edges(G, V) -> - ets:select(G#digraph.ntab, [{{{in, V}, '$1'}, [], ['$1']}]). + [E || {{in, _}, E} <- ets:lookup(G#digraph.ntab, {in, V})]. -spec out_degree(G, V) -> non_neg_integer() when G :: graph(), @@ -255,7 +255,7 @@ out_neighbours(G, V) -> Edges :: [edge()]. out_edges(G, V) -> - ets:select(G#digraph.ntab, [{{{out, V}, '$1'}, [], ['$1']}]). + [E || {{out, _}, E} <- ets:lookup(G#digraph.ntab, {out, V})]. -spec add_edge(G, V1, V2) -> edge() | {'error', add_edge_err_rsn()} when G :: graph(), diff --git a/lib/stdlib/test/digraph_SUITE.erl b/lib/stdlib/test/digraph_SUITE.erl index b5d3452616..ce0bc90f1c 100644 --- a/lib/stdlib/test/digraph_SUITE.erl +++ b/lib/stdlib/test/digraph_SUITE.erl @@ -31,7 +31,7 @@ init_per_group/2,end_per_group/2]). -export([opts/1, degree/1, path/1, cycle/1, vertices/1, - edges/1, data/1, otp_3522/1, otp_3630/1, otp_8066/1]). + edges/1, data/1, otp_3522/1, otp_3630/1, otp_8066/1, vertex_names/1]). -export([spawn_graph/2]). @@ -41,10 +41,10 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [opts, degree, path, cycle, {group, misc}, - {group, tickets}]. + {group, tickets}, vertex_names]. groups() -> - [{misc, [], [vertices, edges, data]}, + [{misc, [], [vertices, edges, data, vertex_names]}, {tickets, [], [otp_3522, otp_3630, otp_8066]}]. init_per_suite(Config) -> @@ -337,6 +337,51 @@ otp_8066(Config) when is_list(Config) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +vertex_names(Config) when is_list(Config) -> + %% Check that a node named '_' does not lead to wildcard matches + %% in ets. + + G = digraph:new([acyclic]), + A = digraph:add_vertex(G, 'A'), + B = digraph:add_vertex(G, '_'), + AB = digraph:add_edge(G, A, B), + + %% Link A -> B + 1 = digraph:out_degree(G, A), + 1 = digraph:in_degree(G, B), + 0 = digraph:out_degree(G, B), + 0 = digraph:in_degree(G, A), + [B] = digraph:out_neighbours(G, A), + [A] = digraph:in_neighbours(G, B), + [] = digraph:out_neighbours(G, B), + [] = digraph:in_neighbours(G, A), + [AB] = digraph:out_edges(G, A), + [AB] = digraph:in_edges(G, B), + [] = digraph:out_edges(G, B), + [] = digraph:in_edges(G, A), + + %% Reverse the edge + digraph:del_edge(G, AB), + BA = digraph:add_edge(G, B, A), + + 1 = digraph:out_degree(G, B), + 1 = digraph:in_degree(G, A), + 0 = digraph:out_degree(G, A), + 0 = digraph:in_degree(G, B), + [A] = digraph:out_neighbours(G, B), + [B] = digraph:in_neighbours(G, A), + [] = digraph:out_neighbours(G, A), + [] = digraph:in_neighbours(G, B), + [BA] = digraph:out_edges(G, B), + [BA] = digraph:in_edges(G, A), + [] = digraph:out_edges(G, A), + [] = digraph:in_edges(G, B), + + digraph:delete(G), + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + sane(G) -> sane1(G), erase(sane) =:= undefined. diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl index f40dce5d7a..76dee868e9 100644 --- a/lib/stdlib/test/gen_statem_SUITE.erl +++ b/lib/stdlib/test/gen_statem_SUITE.erl @@ -534,10 +534,10 @@ abnormal1(Config) -> gen_statem:start(LocalSTM, ?MODULE, start_arg(Config, []), []), %% timeout call. - delayed = gen_statem:call(Name, {delayed_answer,1}, 100), + delayed = gen_statem:call(Name, {delayed_answer,100}, 2000), {timeout,_} = ?EXPECT_FAILURE( - gen_statem:call(Name, {delayed_answer,1000}, 10), + gen_statem:call(Name, {delayed_answer,2000}, 100), Reason), ok = gen_statem:stop(Name), ?t:sleep(1100), @@ -1437,7 +1437,7 @@ hibernate(Config) -> {ok,Pid0} = gen_statem:start_link( ?MODULE, start_arg(Config, hiber_now), []), - is_in_erlang_hibernate(Pid0), + wait_erlang_hibernate(Pid0), stop_it(Pid0), receive {'EXIT',Pid0,normal} -> ok @@ -1450,23 +1450,23 @@ hibernate(Config) -> true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid,current_function)), hibernating = gen_statem:call(Pid, hibernate_sync), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), good_morning = gen_statem:call(Pid, wakeup_sync), is_not_in_erlang_hibernate(Pid), hibernating = gen_statem:call(Pid, hibernate_sync), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), please_just_five_more = gen_statem:call(Pid, snooze_sync), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), good_morning = gen_statem:call(Pid, wakeup_sync), is_not_in_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, hibernate_async), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, wakeup_async), is_not_in_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, hibernate_async), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, snooze_async), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, wakeup_async), is_not_in_erlang_hibernate(Pid), @@ -1474,14 +1474,14 @@ hibernate(Config) -> true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid, current_function)), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), 'alive!' = gen_statem:call(Pid, 'alive?'), true = ({current_function,{erlang,hibernate,3}} =/= erlang:process_info(Pid, current_function)), Pid ! hibernate_now, - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), 'alive!' = gen_statem:call(Pid, 'alive?'), true = @@ -1489,34 +1489,34 @@ hibernate(Config) -> erlang:process_info(Pid, current_function)), hibernating = gen_statem:call(Pid, hibernate_sync), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), good_morning = gen_statem:call(Pid, wakeup_sync), is_not_in_erlang_hibernate(Pid), hibernating = gen_statem:call(Pid, hibernate_sync), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), please_just_five_more = gen_statem:call(Pid, snooze_sync), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), good_morning = gen_statem:call(Pid, wakeup_sync), is_not_in_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, hibernate_async), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, wakeup_async), is_not_in_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, hibernate_async), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, snooze_async), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), ok = gen_statem:cast(Pid, wakeup_async), is_not_in_erlang_hibernate(Pid), hibernating = gen_statem:call(Pid, hibernate_sync), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), sys:suspend(Pid), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), sys:resume(Pid), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), receive after 1000 -> ok end, - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), good_morning = gen_statem:call(Pid, wakeup_sync), is_not_in_erlang_hibernate(Pid), @@ -1532,15 +1532,16 @@ hibernate(Config) -> %% Auto-hibernation timeout auto_hibernate(Config) -> OldFl = process_flag(trap_exit, true), - HibernateAfterTimeout = 100, + HibernateAfterTimeout = 1000, {ok,Pid} = gen_statem:start_link( - ?MODULE, start_arg(Config, []), [{hibernate_after, HibernateAfterTimeout}]), + ?MODULE, start_arg(Config, []), + [{hibernate_after, HibernateAfterTimeout}]), %% After init test is_not_in_erlang_hibernate(Pid), timer:sleep(HibernateAfterTimeout), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), %% After info test Pid ! {hping, self()}, receive @@ -1551,7 +1552,7 @@ auto_hibernate(Config) -> end, is_not_in_erlang_hibernate(Pid), timer:sleep(HibernateAfterTimeout), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), %% After cast test ok = gen_statem:cast(Pid, {hping, self()}), receive @@ -1562,42 +1563,42 @@ auto_hibernate(Config) -> end, is_not_in_erlang_hibernate(Pid), timer:sleep(HibernateAfterTimeout), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), %% After call test hpong = gen_statem:call(Pid, hping), is_not_in_erlang_hibernate(Pid), timer:sleep(HibernateAfterTimeout), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), %% Timer test 1 - TimerTimeout1 = 50, - ok = gen_statem:call(Pid, {arm_htimer, self(), TimerTimeout1}), + TimerTimeout1 = HibernateAfterTimeout div 2, + ok = gen_statem:call(Pid, {start_htimer, self(), TimerTimeout1}), is_not_in_erlang_hibernate(Pid), timer:sleep(TimerTimeout1), is_not_in_erlang_hibernate(Pid), receive - {Pid, htimer_armed} -> + {Pid, htimer_timeout} -> ok after 1000 -> ct:fail(timer1) end, is_not_in_erlang_hibernate(Pid), timer:sleep(HibernateAfterTimeout), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), %% Timer test 2 - TimerTimeout2 = 150, - ok = gen_statem:call(Pid, {arm_htimer, self(), TimerTimeout2}), + TimerTimeout2 = HibernateAfterTimeout * 2, + ok = gen_statem:call(Pid, {start_htimer, self(), TimerTimeout2}), is_not_in_erlang_hibernate(Pid), timer:sleep(HibernateAfterTimeout), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), receive - {Pid, htimer_armed} -> + {Pid, htimer_timeout} -> ok - after 1000 -> + after TimerTimeout2 -> ct:fail(timer2) end, is_not_in_erlang_hibernate(Pid), timer:sleep(HibernateAfterTimeout), - is_in_erlang_hibernate(Pid), + wait_erlang_hibernate(Pid), stop_it(Pid), process_flag(trap_exit, OldFl), receive @@ -1607,38 +1608,38 @@ auto_hibernate(Config) -> end, ok = verify_empty_msgq(). -is_in_erlang_hibernate(Pid) -> + +wait_erlang_hibernate(Pid) -> receive after 1 -> ok end, - is_in_erlang_hibernate_1(200, Pid). + wait_erlang_hibernate_1(200, Pid). -is_in_erlang_hibernate_1(0, Pid) -> +wait_erlang_hibernate_1(0, Pid) -> ct:log("~p\n", [erlang:process_info(Pid, current_function)]), - ct:fail(not_in_erlang_hibernate_3); -is_in_erlang_hibernate_1(N, Pid) -> + ct:fail(should_be_in_erlang_hibernate_3); +wait_erlang_hibernate_1(N, Pid) -> {current_function,MFA} = erlang:process_info(Pid, current_function), case MFA of {erlang,hibernate,3} -> ok; _ -> receive after 10 -> ok end, - is_in_erlang_hibernate_1(N-1, Pid) + wait_erlang_hibernate_1(N-1, Pid) end. is_not_in_erlang_hibernate(Pid) -> receive after 1 -> ok end, is_not_in_erlang_hibernate_1(200, Pid). -is_not_in_erlang_hibernate_1(0, Pid) -> - ct:log("~p\n", [erlang:process_info(Pid, current_function)]), - ct:fail(not_in_erlang_hibernate_3); +is_not_in_erlang_hibernate_1(0, _Pid) -> + ct:fail(should_not_be_in_erlang_hibernate_3); is_not_in_erlang_hibernate_1(N, Pid) -> {current_function,MFA} = erlang:process_info(Pid, current_function), case MFA of - {erlang,hibernate,3} -> + {erlang,hibernate,3} -> receive after 10 -> ok end, is_not_in_erlang_hibernate_1(N-1, Pid); - _ -> - ok + _ -> + ok end. @@ -2430,10 +2431,10 @@ idle(cast, {hping,Pid}, Data) -> {keep_state, Data}; idle({call, From}, hping, _Data) -> {keep_state_and_data, [{reply, From, hpong}]}; -idle({call, From}, {arm_htimer, Pid, Timeout}, _Data) -> - {keep_state_and_data, [{reply, From, ok}, {timeout, Timeout, {arm_htimer, Pid}}]}; -idle(timeout, {arm_htimer, Pid}, _Data) -> - Pid ! {self(), htimer_armed}, +idle({call, From}, {start_htimer, Pid, Timeout}, _Data) -> + {keep_state_and_data, [{reply, From, ok}, {timeout, Timeout, {htimer, Pid}}]}; +idle(timeout, {htimer, Pid}, _Data) -> + Pid ! {self(), htimer_timeout}, keep_state_and_data; idle(cast, {connect,Pid}, Data) -> Pid ! accept, diff --git a/make/otp_version_tickets b/make/otp_version_tickets index 055b8075da..b8220e1a87 100644 --- a/make/otp_version_tickets +++ b/make/otp_version_tickets @@ -1,201 +1 @@ -OTP-10278 -OTP-11688 -OTP-13450 -OTP-13812 -OTP-14708 -OTP-14734 -OTP-14790 -OTP-15077 -OTP-15232 -OTP-15247 -OTP-15251 -OTP-15299 -OTP-15434 -OTP-15517 -OTP-15589 -OTP-15603 -OTP-15618 -OTP-15695 -OTP-15744 -OTP-15792 -OTP-15800 -OTP-15812 -OTP-15835 -OTP-15837 -OTP-15840 -OTP-15842 -OTP-15866 -OTP-15868 -OTP-15892 -OTP-15896 -OTP-15914 -OTP-15915 -OTP-15925 -OTP-15948 -OTP-15950 -OTP-15956 -OTP-15967 -OTP-15995 -OTP-15998 -OTP-15999 -OTP-16005 -OTP-16007 -OTP-16008 -OTP-16014 -OTP-16026 -OTP-16029 -OTP-16055 -OTP-16072 -OTP-16073 -OTP-16105 -OTP-16110 -OTP-16112 -OTP-16120 -OTP-16127 -OTP-16128 -OTP-16148 -OTP-16155 -OTP-16160 -OTP-16168 -OTP-16171 -OTP-16189 -OTP-16210 -OTP-16214 -OTP-16215 -OTP-16222 -OTP-16229 -OTP-16232 -OTP-16237 -OTP-16244 -OTP-16250 -OTP-16251 -OTP-16252 -OTP-16260 -OTP-16264 -OTP-16270 -OTP-16273 -OTP-16275 -OTP-16276 -OTP-16283 -OTP-16284 -OTP-16289 -OTP-16312 -OTP-16327 -OTP-16328 -OTP-16329 -OTP-16345 -OTP-16346 -OTP-16347 -OTP-16362 -OTP-16363 -OTP-16367 -OTP-16368 -OTP-16369 -OTP-16370 -OTP-16386 -OTP-16389 -OTP-16391 -OTP-16394 -OTP-16395 -OTP-16398 -OTP-16400 -OTP-16402 -OTP-16406 -OTP-16407 -OTP-16408 -OTP-16419 -OTP-16429 -OTP-16431 -OTP-16432 -OTP-16453 -OTP-16454 -OTP-16455 -OTP-16463 -OTP-16469 -OTP-16470 -OTP-16474 -OTP-16478 -OTP-16480 -OTP-16482 -OTP-16483 -OTP-16484 -OTP-16487 -OTP-16489 -OTP-16490 -OTP-16492 -OTP-16494 -OTP-16495 -OTP-16496 -OTP-16497 -OTP-16499 -OTP-16500 -OTP-16501 -OTP-16502 -OTP-16503 -OTP-16504 -OTP-16505 -OTP-16506 -OTP-16508 -OTP-16509 -OTP-16510 -OTP-16511 -OTP-16512 -OTP-16513 -OTP-16516 -OTP-16519 -OTP-16521 -OTP-16523 -OTP-16530 -OTP-16531 -OTP-16532 -OTP-16533 -OTP-16534 -OTP-16535 -OTP-16540 -OTP-16541 -OTP-16543 -OTP-16544 -OTP-16545 -OTP-16547 -OTP-16549 -OTP-16550 -OTP-16551 -OTP-16552 -OTP-16554 -OTP-16557 -OTP-16561 -OTP-16562 -OTP-16563 -OTP-16570 -OTP-16571 -OTP-16573 -OTP-16576 -OTP-16579 -OTP-16583 -OTP-16584 -OTP-16585 -OTP-16589 -OTP-16594 -OTP-16596 -OTP-16597 -OTP-16598 -OTP-16601 -OTP-16602 -OTP-16603 -OTP-16604 -OTP-16607 -OTP-16615 -OTP-16616 -OTP-16617 -OTP-16620 -OTP-16622 -OTP-16623 -OTP-16624 -OTP-16626 -OTP-16627 -OTP-16630 -OTP-16632 -OTP-16633 -OTP-16634 -OTP-16635 -OTP-16638 +DEVELOPMENT diff --git a/make/otp_version_tickets_in_merge b/make/otp_version_tickets_in_merge index e69de29bb2..1c9a3e3bb9 100644 --- a/make/otp_version_tickets_in_merge +++ b/make/otp_version_tickets_in_merge @@ -0,0 +1,6 @@ +OTP-16582 +OTP-16607 +OTP-16639 +OTP-16652 +OTP-16654 +OTP-16657 diff --git a/otp_versions.table b/otp_versions.table index ec9b448191..82506466b6 100644 --- a/otp_versions.table +++ b/otp_versions.table @@ -1,4 +1,6 @@ +OTP-23.0.1 : compiler-7.6.1 erts-11.0.1 # asn1-5.0.13 common_test-1.19 crypto-4.7 debugger-5.0 dialyzer-4.2 diameter-2.2.3 edoc-0.12 eldap-1.2.8 erl_docgen-1.0 erl_interface-4.0 et-1.6.4 eunit-2.5 ftp-1.0.4 hipe-4.0 inets-7.2 jinterface-1.11 kernel-7.0 megaco-3.19 mnesia-4.17 observer-2.9.4 odbc-2.13 os_mon-2.5.2 parsetools-2.2 public_key-1.8 reltool-0.8 runtime_tools-1.15 sasl-4.0 snmp-5.6 ssh-4.10 ssl-10.0 stdlib-3.13 syntax_tools-2.3 tftp-1.0.2 tools-3.4 wx-1.9.1 xmerl-1.3.25 : OTP-23.0 : asn1-5.0.13 common_test-1.19 compiler-7.6 crypto-4.7 debugger-5.0 dialyzer-4.2 edoc-0.12 erl_docgen-1.0 erl_interface-4.0 erts-11.0 eunit-2.5 hipe-4.0 inets-7.2 jinterface-1.11 kernel-7.0 megaco-3.19 mnesia-4.17 observer-2.9.4 odbc-2.13 os_mon-2.5.2 parsetools-2.2 public_key-1.8 runtime_tools-1.15 sasl-4.0 snmp-5.6 ssh-4.10 ssl-10.0 stdlib-3.13 syntax_tools-2.3 tools-3.4 wx-1.9.1 xmerl-1.3.25 # diameter-2.2.3 eldap-1.2.8 et-1.6.4 ftp-1.0.4 reltool-0.8 tftp-1.0.2 : +OTP-22.3.4.1 : erts-10.7.2.1 kernel-6.5.2.1 megaco-3.18.8.1 # asn1-5.0.12 common_test-1.18.2 compiler-7.5.4 crypto-4.6.5 debugger-4.2.8 dialyzer-4.1.1 diameter-2.2.3 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.2 et-1.6.4 eunit-2.4.1 ftp-1.0.4 hipe-3.19.3 inets-7.1.3 jinterface-1.10.1 mnesia-4.16.3 observer-2.9.3 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 public_key-1.7.2 reltool-0.8 runtime_tools-1.14 sasl-3.4.2 snmp-5.5 ssh-4.9.1 ssl-9.6.2 stdlib-3.12.1 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3.1 wx-1.9 xmerl-1.3.24 : OTP-22.3.4 : asn1-5.0.12 erts-10.7.2 # common_test-1.18.2 compiler-7.5.4 crypto-4.6.5 debugger-4.2.8 dialyzer-4.1.1 diameter-2.2.3 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.2 et-1.6.4 eunit-2.4.1 ftp-1.0.4 hipe-3.19.3 inets-7.1.3 jinterface-1.10.1 kernel-6.5.2 megaco-3.18.8 mnesia-4.16.3 observer-2.9.3 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 public_key-1.7.2 reltool-0.8 runtime_tools-1.14 sasl-3.4.2 snmp-5.5 ssh-4.9.1 ssl-9.6.2 stdlib-3.12.1 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3.1 wx-1.9 xmerl-1.3.24 : OTP-22.3.3 : ssh-4.9.1 ssl-9.6.2 # asn1-5.0.11 common_test-1.18.2 compiler-7.5.4 crypto-4.6.5 debugger-4.2.8 dialyzer-4.1.1 diameter-2.2.3 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.2 erts-10.7.1 et-1.6.4 eunit-2.4.1 ftp-1.0.4 hipe-3.19.3 inets-7.1.3 jinterface-1.10.1 kernel-6.5.2 megaco-3.18.8 mnesia-4.16.3 observer-2.9.3 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 public_key-1.7.2 reltool-0.8 runtime_tools-1.14 sasl-3.4.2 snmp-5.5 stdlib-3.12.1 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3.1 wx-1.9 xmerl-1.3.24 : OTP-22.3.2 : asn1-5.0.11 # common_test-1.18.2 compiler-7.5.4 crypto-4.6.5 debugger-4.2.8 dialyzer-4.1.1 diameter-2.2.3 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.2 erts-10.7.1 et-1.6.4 eunit-2.4.1 ftp-1.0.4 hipe-3.19.3 inets-7.1.3 jinterface-1.10.1 kernel-6.5.2 megaco-3.18.8 mnesia-4.16.3 observer-2.9.3 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 public_key-1.7.2 reltool-0.8 runtime_tools-1.14 sasl-3.4.2 snmp-5.5 ssh-4.9 ssl-9.6.1 stdlib-3.12.1 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3.1 wx-1.9 xmerl-1.3.24 : @@ -31,6 +33,7 @@ OTP-22.0.3 : compiler-7.4.2 dialyzer-4.0.1 erts-10.4.2 ssl-9.3.2 stdlib-3.9.2 # OTP-22.0.2 : compiler-7.4.1 crypto-4.5.1 erts-10.4.1 stdlib-3.9.1 # asn1-5.0.9 common_test-1.17.3 debugger-4.2.7 dialyzer-4.0 diameter-2.2.1 edoc-0.11 eldap-1.2.8 erl_docgen-0.9.1 erl_interface-3.12 et-1.6.4 eunit-2.3.7 ftp-1.0.2 hipe-3.19 inets-7.0.8 jinterface-1.10 kernel-6.4 megaco-3.18.5 mnesia-4.16 observer-2.9.1 odbc-2.12.4 os_mon-2.5 parsetools-2.1.8 public_key-1.6.7 reltool-0.8 runtime_tools-1.13.3 sasl-3.4 snmp-5.3 ssh-4.7.7 ssl-9.3.1 syntax_tools-2.2 tftp-1.0.1 tools-3.2 wx-1.8.8 xmerl-1.3.21 : OTP-22.0.1 : ssl-9.3.1 # asn1-5.0.9 common_test-1.17.3 compiler-7.4 crypto-4.5 debugger-4.2.7 dialyzer-4.0 diameter-2.2.1 edoc-0.11 eldap-1.2.8 erl_docgen-0.9.1 erl_interface-3.12 erts-10.4 et-1.6.4 eunit-2.3.7 ftp-1.0.2 hipe-3.19 inets-7.0.8 jinterface-1.10 kernel-6.4 megaco-3.18.5 mnesia-4.16 observer-2.9.1 odbc-2.12.4 os_mon-2.5 parsetools-2.1.8 public_key-1.6.7 reltool-0.8 runtime_tools-1.13.3 sasl-3.4 snmp-5.3 ssh-4.7.7 stdlib-3.9 syntax_tools-2.2 tftp-1.0.1 tools-3.2 wx-1.8.8 xmerl-1.3.21 : OTP-22.0 : asn1-5.0.9 common_test-1.17.3 compiler-7.4 crypto-4.5 debugger-4.2.7 dialyzer-4.0 edoc-0.11 eldap-1.2.8 erl_docgen-0.9.1 erl_interface-3.12 erts-10.4 hipe-3.19 inets-7.0.8 jinterface-1.10 kernel-6.4 megaco-3.18.5 mnesia-4.16 observer-2.9.1 odbc-2.12.4 os_mon-2.5 public_key-1.6.7 reltool-0.8 runtime_tools-1.13.3 sasl-3.4 snmp-5.3 ssh-4.7.7 ssl-9.3 stdlib-3.9 syntax_tools-2.2 tools-3.2 wx-1.8.8 xmerl-1.3.21 # diameter-2.2.1 et-1.6.4 eunit-2.3.7 ftp-1.0.2 parsetools-2.1.8 tftp-1.0.1 : +OTP-21.3.8.16 : erts-10.3.5.12 # asn1-5.0.8 common_test-1.17.2.1 compiler-7.3.2 crypto-4.4.2.2 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2.1 edoc-0.10 eldap-1.2.7 erl_docgen-0.9 erl_interface-3.11.3 et-1.6.4 eunit-2.3.7 ftp-1.0.2.2 hipe-3.18.3 inets-7.0.7.2 jinterface-1.9.1 kernel-6.3.1.3 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.6.1 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssh-4.7.6.4 ssl-9.2.3.6 stdlib-3.8.2.4 syntax_tools-2.1.7.1 tftp-1.0.1 tools-3.1.0.1 wx-1.8.7 xmerl-1.3.20.1 : OTP-21.3.8.15 : erts-10.3.5.11 ssh-4.7.6.4 ssl-9.2.3.6 stdlib-3.8.2.4 # asn1-5.0.8 common_test-1.17.2.1 compiler-7.3.2 crypto-4.4.2.2 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2.1 edoc-0.10 eldap-1.2.7 erl_docgen-0.9 erl_interface-3.11.3 et-1.6.4 eunit-2.3.7 ftp-1.0.2.2 hipe-3.18.3 inets-7.0.7.2 jinterface-1.9.1 kernel-6.3.1.3 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.6.1 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 syntax_tools-2.1.7.1 tftp-1.0.1 tools-3.1.0.1 wx-1.8.7 xmerl-1.3.20.1 : OTP-21.3.8.14 : erts-10.3.5.10 # asn1-5.0.8 common_test-1.17.2.1 compiler-7.3.2 crypto-4.4.2.2 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2.1 edoc-0.10 eldap-1.2.7 erl_docgen-0.9 erl_interface-3.11.3 et-1.6.4 eunit-2.3.7 ftp-1.0.2.2 hipe-3.18.3 inets-7.0.7.2 jinterface-1.9.1 kernel-6.3.1.3 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.6.1 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssh-4.7.6.3 ssl-9.2.3.5 stdlib-3.8.2.3 syntax_tools-2.1.7.1 tftp-1.0.1 tools-3.1.0.1 wx-1.8.7 xmerl-1.3.20.1 : OTP-21.3.8.13 : erts-10.3.5.9 stdlib-3.8.2.3 # asn1-5.0.8 common_test-1.17.2.1 compiler-7.3.2 crypto-4.4.2.2 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2.1 edoc-0.10 eldap-1.2.7 erl_docgen-0.9 erl_interface-3.11.3 et-1.6.4 eunit-2.3.7 ftp-1.0.2.2 hipe-3.18.3 inets-7.0.7.2 jinterface-1.9.1 kernel-6.3.1.3 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.6.1 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssh-4.7.6.3 ssl-9.2.3.5 syntax_tools-2.1.7.1 tftp-1.0.1 tools-3.1.0.1 wx-1.8.7 xmerl-1.3.20.1 : diff --git a/scripts/pre-push b/scripts/pre-push index 7da1f575db..6689daf03a 100755 --- a/scripts/pre-push +++ b/scripts/pre-push @@ -23,14 +23,14 @@ # # Bump this version to give users an update notification. -PRE_PUSH_SCRIPT_VERSION=1 +PRE_PUSH_SCRIPT_VERSION=2 -NEW_RELEASES="22 21 20 19 18 17" +NEW_RELEASES="23 22 21 20 19 18 17" OLD_RELEASES="r16 r15 r14 r13" RELEASES="$NEW_RELEASES $OLD_RELEASES" # First commit on master, not allowed in other branches -MASTER_ONLY=f633fe962ea7078c32f8c81d34950c0ebce0f472 +MASTER_ONLY=740b29ecc21c73a4bf4ebfc494490865d3c31978 # Number of commits and files allowed in one push by this script NCOMMITS_MAX=100 |