summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xerts/configure28
-rw-r--r--erts/configure.ac21
-rw-r--r--erts/emulator/beam/bif.c1
-rw-r--r--erts/emulator/beam/code_ix.c23
-rw-r--r--erts/emulator/beam/erl_bif_unique.c11
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c1
-rw-r--r--erts/emulator/beam/io.c44
-rw-r--r--erts/emulator/beam/jit/arm/ops.tab8
-rw-r--r--erts/emulator/beam/jit/beam_jit_main.cpp6
-rw-r--r--erts/emulator/beam/jit/x86/instr_guard_bifs.cpp24
-rw-r--r--erts/emulator/beam/jit/x86/ops.tab14
-rw-r--r--erts/emulator/test/process_SUITE.erl50
-rw-r--r--lib/compiler/src/beam_validator.erl2
-rw-r--r--lib/compiler/src/sys_core_fold.erl28
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl19
-rw-r--r--lib/compiler/test/bif_SUITE.erl28
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl20
-rw-r--r--lib/crypto/c_src/dh.c4
-rw-r--r--lib/eldap/doc/src/eldap.xml12
-rw-r--r--lib/eldap/src/eldap.erl23
-rw-r--r--lib/eldap/test/eldap_basic_SUITE.erl39
-rwxr-xr-xlib/erl_interface/configure6
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl46
-rw-r--r--lib/snmp/doc/src/snmp_app.xml38
-rw-r--r--lib/snmp/doc/src/snmp_config.xml38
-rw-r--r--lib/snmp/src/agent/snmpa_agent.erl73
-rw-r--r--lib/snmp/src/agent/snmpa_agent_sup.erl12
-rw-r--r--lib/snmp/src/agent/snmpa_net_if.erl38
-rw-r--r--lib/snmp/src/agent/snmpa_supervisor.erl43
-rw-r--r--lib/snmp/src/app/snmp_app.erl11
-rw-r--r--lib/snmp/src/app/snmp_app_sup.erl16
-rw-r--r--lib/ssl/src/ssl_cipher.erl4
-rw-r--r--lib/ssl/src/ssl_gen_statem.erl32
-rw-r--r--lib/ssl/src/tls_sender.erl7
-rw-r--r--lib/ssl/test/ssl_cipher_SUITE.erl9
-rw-r--r--lib/ssl/test/ssl_key_update_SUITE.erl111
-rw-r--r--lib/ssl/test/ssl_session_SUITE.erl22
-rw-r--r--lib/stdlib/src/erl_parse.yrl12
-rw-r--r--make/autoconf/otp.m46
39 files changed, 679 insertions, 251 deletions
diff --git a/erts/configure b/erts/configure
index a84ffe4342..fbdb6baba8 100755
--- a/erts/configure
+++ b/erts/configure
@@ -13973,7 +13973,7 @@ int
main (void)
{
- __asm__ __volatile__("isb sy" : : : "memory");
+ __asm__ __volatile__("isb sy\n" : : : "memory");
;
return 0;
@@ -14007,7 +14007,7 @@ int
main (void)
{
- char data[512]; __asm__ __volatile__("dc cvau, %0" : "r" (data) : : "memory");
+ char data[512]; __asm__ __volatile__("dc cvau, %0\n" :: "r" (data) : "memory");
;
return 0;
@@ -14041,7 +14041,7 @@ int
main (void)
{
- char data[512]; __asm__ __volatile__("ic ivau, %0" : "r" (data) : : "memory");
+ char data[512]; __asm__ __volatile__("ic ivau, %0\n" :: "r" (data) : "memory");
;
return 0;
@@ -24313,7 +24313,27 @@ then :
JIT_ARCH=x86
;;
arm64)
- JIT_ARCH=arm
+ case "$OPSYS" in
+ win32|darwin)
+ # These platforms have dedicated system calls for clearing
+ # instruction cache, and don't require us to manually issue
+ # instruction barriers on all threads.
+ JIT_ARCH=arm
+ ;;
+ *)
+ # We need to use `DC CVAU`, `IC IVAU`, and `ISB SY` to clear
+ # instruction cache. These have already been tested as part of
+ # ETHR_CHK_GCC_ATOMIC_OPS([]).
+
+ if test "$ethr_arm_isb_sy_instr_val$ethr_arm_dc_cvau_instr_val$ethr_arm_ic_ivau_instr_val" = "111"; then
+ JIT_ARCH=arm
+ else
+ enable_jit=no
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: JIT disabled due to lack of cache-clearing instructions" >&5
+printf "%s\n" "$as_me: WARNING: JIT disabled due to lack of cache-clearing instructions" >&2;}
+ fi
+ ;;
+ esac
;;
*)
if test ${enable_jit} = yes; then
diff --git a/erts/configure.ac b/erts/configure.ac
index ab2ee78acd..a052c319ba 100644
--- a/erts/configure.ac
+++ b/erts/configure.ac
@@ -2855,7 +2855,26 @@ AS_IF([test ${enable_jit} != no],
JIT_ARCH=x86
;;
arm64)
- JIT_ARCH=arm
+ case "$OPSYS" in
+ win32|darwin)
+ # These platforms have dedicated system calls for clearing
+ # instruction cache, and don't require us to manually issue
+ # instruction barriers on all threads.
+ JIT_ARCH=arm
+ ;;
+ *)
+ # We need to use `DC CVAU`, `IC IVAU`, and `ISB SY` to clear
+ # instruction cache. These have already been tested as part of
+ # ETHR_CHK_GCC_ATOMIC_OPS([]).
+
+ if test "$ethr_arm_isb_sy_instr_val$ethr_arm_dc_cvau_instr_val$ethr_arm_ic_ivau_instr_val" = "111"; then
+ JIT_ARCH=arm
+ else
+ enable_jit=no
+ AC_MSG_WARN([JIT disabled due to lack of cache-clearing instructions])
+ fi
+ ;;
+ esac
;;
*)
if test ${enable_jit} = yes; then
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index c4687f04b8..fe3dbb4c48 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -370,6 +370,7 @@ demonitor(Process *c_p, Eterm ref, Eterm *multip)
NIL,
THE_NON_VALUE);
amdp->origin.flags = mon->flags & ERTS_ML_STATE_ALIAS_MASK;
+ mon->flags &= ~ERTS_ML_STATE_ALIAS_MASK;
erts_monitor_tree_replace(&ERTS_P_MONITORS(c_p), mon, &amdp->origin);
break;
}
diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c
index 607f3c82c6..8f393f92cf 100644
--- a/erts/emulator/beam/code_ix.c
+++ b/erts/emulator/beam/code_ix.c
@@ -347,7 +347,17 @@ static ErtsThrPrgrLaterOp global_code_barrier_lop;
static void decrement_blocking_code_barriers(void *ignored) {
(void)ignored;
- erts_atomic32_dec_nob(&outstanding_blocking_code_barriers);
+
+ if (erts_atomic32_dec_read_nob(&outstanding_blocking_code_barriers) > 0) {
+ /* We had more than one barrier in the same tick, and can't tell
+ * whether the later ones were issued before any of the managed threads
+ * were woken. Keep telling all managed threads to execute an
+ * instruction barrier on wake-up for one more tick. */
+ erts_atomic32_set_nob(&outstanding_blocking_code_barriers, 1);
+ erts_schedule_thr_prgr_later_op(decrement_blocking_code_barriers,
+ NULL,
+ &global_code_barrier_lop);
+ }
}
static void schedule_blocking_code_barriers(void *ignored) {
@@ -358,11 +368,12 @@ static void schedule_blocking_code_barriers(void *ignored) {
* counter.
*
* Note that we increment and decrement instead of setting and clearing
- * since we might execute several blocking barriers in the same tick. */
- erts_atomic32_inc_nob(&outstanding_blocking_code_barriers);
- erts_schedule_thr_prgr_later_op(decrement_blocking_code_barriers,
- NULL,
- &global_code_barrier_lop);
+ * since we might schedule several blocking barriers in the same tick. */
+ if (erts_atomic32_inc_read_nob(&outstanding_blocking_code_barriers) == 1) {
+ erts_schedule_thr_prgr_later_op(decrement_blocking_code_barriers,
+ NULL,
+ &global_code_barrier_lop);
+ }
}
#endif
diff --git a/erts/emulator/beam/erl_bif_unique.c b/erts/emulator/beam/erl_bif_unique.c
index 7b3b3746b1..e1686c6f93 100644
--- a/erts/emulator/beam/erl_bif_unique.c
+++ b/erts/emulator/beam/erl_bif_unique.c
@@ -591,14 +591,15 @@ erts_pid_ref_delete(Eterm ref)
erts_rwmtx_rwlock(&tblp->rwmtx);
tep = hash_remove(&tblp->hash, &tmpl);
- ASSERT(tep);
erts_rwmtx_rwunlock(&tblp->rwmtx);
- if (tblp != &pid_ref_table[0].u.table)
- erts_free(ERTS_ALC_T_PREF_NSCHED_ENT, (void *) tep);
- else
- erts_free(ERTS_ALC_T_PREF_ENT, (void *) tep);
+ if (tep) {
+ if (tblp != &pid_ref_table[0].u.table)
+ erts_free(ERTS_ALC_T_PREF_NSCHED_ENT, (void *) tep);
+ else
+ erts_free(ERTS_ALC_T_PREF_ENT, (void *) tep);
+ }
}
}
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index d2799bdb91..79d661675e 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -5628,6 +5628,7 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep,
mdp->ref, c_p->common.id,
NIL, NIL, THE_NON_VALUE);
amdp->origin.flags = ERTS_ML_STATE_ALIAS_UNALIAS;
+ omon->flags &= ~ERTS_ML_STATE_ALIAS_MASK;
erts_monitor_tree_replace(&ERTS_P_MONITORS(c_p),
omon,
&amdp->origin);
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index dfdbe475b3..2ef5bc4d01 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -4659,6 +4659,7 @@ erts_port_call(Process* c_p,
unsigned ret_flags = 0U;
Eterm term;
Eterm* hp;
+ ErtsPortOpResult result;
res = call_driver_call(c_p->common.id,
prt,
@@ -4672,25 +4673,36 @@ erts_port_call(Process* c_p,
finalize_imm_drv_call(&try_call_state);
if (bufp != &input_buf[0])
erts_free(ERTS_ALC_T_TMP, bufp);
- if (res == ERTS_PORT_OP_BADARG)
- return ERTS_PORT_OP_BADARG;
- hsz = erts_decode_ext_size((byte *) resp_bufp, resp_size);
- if (hsz < 0)
- return ERTS_PORT_OP_BADARG;
- hsz += 3;
- erts_factory_proc_prealloc_init(&factory, c_p, hsz);
- endp = (byte *) resp_bufp;
- term = erts_decode_ext(&factory, (const byte**)&endp, 0);
- if (term == THE_NON_VALUE)
- return ERTS_PORT_OP_BADARG;
- hp = erts_produce_heap(&factory,3,0);
- *retvalp = TUPLE2(hp, am_ok, term);
- erts_factory_close(&factory);
+ if (res == ERTS_PORT_OP_BADARG) {
+ result = ERTS_PORT_OP_BADARG;
+ }
+ else {
+ hsz = erts_decode_ext_size((byte *) resp_bufp, resp_size);
+ if (hsz < 0) {
+ result = ERTS_PORT_OP_BADARG;
+ }
+ else {
+ hsz += 3;
+ erts_factory_proc_prealloc_init(&factory, c_p, hsz);
+ endp = (byte *) resp_bufp;
+ term = erts_decode_ext(&factory, (const byte**)&endp, 0);
+ if (term == THE_NON_VALUE) {
+ result = ERTS_PORT_OP_BADARG;
+ }
+ else {
+ hp = erts_produce_heap(&factory,3,0);
+ *retvalp = TUPLE2(hp, am_ok, term);
+ result = ERTS_PORT_OP_DONE;
+ }
+ erts_factory_close(&factory);
+ }
+ }
if (resp_bufp != &resp_buf[0]
- && !(ret_flags & DRIVER_CALL_KEEP_BUFFER))
+ && !(ret_flags & DRIVER_CALL_KEEP_BUFFER)) {
driver_free(resp_bufp);
+ }
BUMP_REDS(c_p, ERTS_PORT_REDS_CALL);
- return ERTS_PORT_OP_DONE;
+ return result;
}
case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
if (bufp != &input_buf[0])
diff --git a/erts/emulator/beam/jit/arm/ops.tab b/erts/emulator/beam/jit/arm/ops.tab
index cc0bfeccf0..9cfce18e58 100644
--- a/erts/emulator/beam/jit/arm/ops.tab
+++ b/erts/emulator/beam/jit/arm/ops.tab
@@ -666,18 +666,14 @@ i_perf_counter
bif0 u$bif:erlang:self/0 Dst=d => self Dst
bif0 u$bif:erlang:node/0 Dst=d => node Dst
-bif1 Fail=f Bif=u$bif:erlang:hd/1 Src=n Dst =>
- jump Fail
-bif1 Fail=f Bif=u$bif:erlang:hd/1 Src Dst =>
+bif1 Fail=f Bif=u$bif:erlang:hd/1 Src=xy Dst =>
is_nonempty_list Fail Src | get_hd Src Dst
bif1 Fail=p Bif=u$bif:erlang:hd/1 Src Dst =>
bif_hd Src Dst
bif_hd s d
-bif1 Fail=f Bif=u$bif:erlang:tl/1 Src=n Dst =>
- jump Fail
-bif1 Fail=f Bif=u$bif:erlang:tl/1 Src Dst =>
+bif1 Fail=f Bif=u$bif:erlang:tl/1 Src=xy Dst =>
is_nonempty_list Fail Src | get_tl Src Dst
bif1 Fail=p Bif=u$bif:erlang:tl/1 Src Dst =>
bif_tl Src Dst
diff --git a/erts/emulator/beam/jit/beam_jit_main.cpp b/erts/emulator/beam/jit/beam_jit_main.cpp
index 2ddde35511..ef0ad6943a 100644
--- a/erts/emulator/beam/jit/beam_jit_main.cpp
+++ b/erts/emulator/beam/jit/beam_jit_main.cpp
@@ -377,9 +377,9 @@ extern "C"
/* Issues full memory/instruction barriers on all threads for us. */
sys_icache_invalidate((char *)address, size);
#elif defined(__aarch64__) && defined(__GNUC__) && \
- defined(ETHR_HAVE_GCC_ASM_ARM_IC_IVAU_INSTRUCTION) && \
- defined(ETHR_HAVE_GCC_ASM_ARM_DC_CVAU_INSTRUCTION) && \
- defined(ERTS_THR_INSTRUCTION_BARRIER)
+ defined(ERTS_THR_INSTRUCTION_BARRIER) && \
+ ETHR_HAVE_GCC_ASM_ARM_IC_IVAU_INSTRUCTION && \
+ ETHR_HAVE_GCC_ASM_ARM_DC_CVAU_INSTRUCTION
/* Note that we do not issue any barriers here, whether instruction or
* memory. This is on purpose as we must issue those on all schedulers
* and not just the calling thread, and the chances of us forgetting to
diff --git a/erts/emulator/beam/jit/x86/instr_guard_bifs.cpp b/erts/emulator/beam/jit/x86/instr_guard_bifs.cpp
index 4dfe39cb98..26133d5ac0 100644
--- a/erts/emulator/beam/jit/x86/instr_guard_bifs.cpp
+++ b/erts/emulator/beam/jit/x86/instr_guard_bifs.cpp
@@ -60,24 +60,22 @@ void BeamGlobalAssembler::emit_handle_hd_error() {
* The code size for this specialization of hd/1 is 21 bytes,
* while the code size for the bif1 instruction is 24 bytes.
*/
-void BeamModuleAssembler::emit_bif_hd(const ArgLabel &Fail,
- const ArgSource &Src,
+void BeamModuleAssembler::emit_bif_hd(const ArgSource &Src,
const ArgRegister &Hd) {
+ Label good_cons = a.newLabel();
+
mov_arg(RET, Src);
a.test(RETb, imm(_TAG_PRIMARY_MASK - TAG_PRIMARY_LIST));
- if (Fail.get() != 0) {
- a.jne(resolve_beam_label(Fail));
- } else {
- Label next = a.newLabel();
- a.short_().je(next);
- safe_fragment_call(ga->get_handle_hd_error());
- a.bind(next);
- }
+ a.short_().je(good_cons);
+ safe_fragment_call(ga->get_handle_hd_error());
- x86::Gp boxed_ptr = emit_ptr_val(RET, RET);
- a.mov(ARG2, getCARRef(boxed_ptr));
- mov_arg(Hd, ARG2);
+ a.bind(good_cons);
+ {
+ x86::Gp boxed_ptr = emit_ptr_val(RET, RET);
+ a.mov(ARG2, getCARRef(boxed_ptr));
+ mov_arg(Hd, ARG2);
+ }
}
void BeamGlobalAssembler::emit_handle_element_error() {
diff --git a/erts/emulator/beam/jit/x86/ops.tab b/erts/emulator/beam/jit/x86/ops.tab
index 1ce0d6f9c2..5481fff2d8 100644
--- a/erts/emulator/beam/jit/x86/ops.tab
+++ b/erts/emulator/beam/jit/x86/ops.tab
@@ -660,18 +660,14 @@ i_perf_counter
bif0 u$bif:erlang:self/0 Dst=d => self Dst
bif0 u$bif:erlang:node/0 Dst=d => node Dst
-bif1 Fail=f Bif=u$bif:erlang:hd/1 Src=n Dst =>
- jump Fail
-bif1 Fail=f Bif=u$bif:erlang:hd/1 Src Dst =>
+bif1 Fail=f Bif=u$bif:erlang:hd/1 Src=xy Dst =>
is_nonempty_list Fail Src | get_hd Src Dst
-bif1 Fail Bif=u$bif:erlang:hd/1 Src Dst =>
- bif_hd Fail Src Dst
+bif1 Fail=p Bif=u$bif:erlang:hd/1 Src Dst =>
+ bif_hd Src Dst
-bif_hd j s d
+bif_hd s d
-bif1 Fail=f Bif=u$bif:erlang:tl/1 Src=n Dst =>
- jump Fail
-bif1 Fail=f Bif=u$bif:erlang:tl/1 Src Dst =>
+bif1 Fail=f Bif=u$bif:erlang:tl/1 Src=xy Dst =>
is_nonempty_list Fail Src | get_tl Src Dst
bif1 Fail Bif=u$bif:erlang:get/1 Src=s Dst=d => get(Src, Dst)
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index 114fa42da8..080b63c5f6 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -96,6 +96,8 @@
monitor_alias/1,
spawn_monitor_alias/1,
alias_process_exit/1,
+ demonitor_aliasmonitor/1,
+ down_aliasmonitor/1,
monitor_tag/1]).
-export([prio_server/2, prio_client/2, init/1, handle_event/2]).
@@ -183,7 +185,8 @@ groups() ->
gc_request_when_gc_disabled, gc_request_blast_when_gc_disabled,
otp_16436, otp_16642]},
{alias, [],
- [alias_bif, monitor_alias, spawn_monitor_alias, alias_process_exit]}].
+ [alias_bif, monitor_alias, spawn_monitor_alias, alias_process_exit,
+ demonitor_aliasmonitor, down_aliasmonitor]}].
init_per_suite(Config) ->
A0 = case application:start(sasl) of
@@ -5017,6 +5020,51 @@ alias_process_exit(Config) when is_list(Config) ->
check_pid_ref_table_size(PRTSz),
ok.
+demonitor_aliasmonitor(Config) when is_list(Config) ->
+ {ok, Peer, Node} = ?CT_PEER(),
+ Fun = fun () ->
+ receive
+ {alias, Alias} ->
+ Alias ! {alias_reply, Alias, self()}
+ end
+ end,
+ LPid = spawn(Fun),
+ RPid = spawn(Node, Fun),
+ AliasMonitor = erlang:monitor(process, LPid, [{alias, explicit_unalias}]),
+ erlang:demonitor(AliasMonitor),
+ LPid ! {alias, AliasMonitor},
+ receive {alias_reply, AliasMonitor, LPid} -> ok end,
+ %% Demonitor signal has been received and cleaned up. Cleanup of
+ %% it erroneously removed it from the alias table which caused
+ %% remote use of the alias to stop working...
+ RPid ! {alias, AliasMonitor},
+ receive {alias_reply, AliasMonitor, RPid} -> ok end,
+ exit(LPid, kill),
+ peer:stop(Peer),
+ false = is_process_alive(LPid),
+ ok.
+
+down_aliasmonitor(Config) when is_list(Config) ->
+ {ok, Peer, Node} = ?CT_PEER(),
+ LPid = spawn(fun () -> receive infinty -> ok end end),
+ RPid = spawn(Node,
+ fun () ->
+ receive
+ {alias, Alias} ->
+ Alias ! {alias_reply, Alias, self()}
+ end
+ end),
+ AliasMonitor = erlang:monitor(process, LPid, [{alias, explicit_unalias}]),
+ exit(LPid, bye),
+ receive {'DOWN', AliasMonitor, process, LPid, bye} -> ok end,
+ %% Down signal has been received and cleaned up. Cleanup of
+ %% it erroneously removed it from the alias table which caused
+ %% remote use of the alias to stop working...
+ RPid ! {alias, AliasMonitor},
+ receive {alias_reply, AliasMonitor, RPid} -> ok end,
+ peer:stop(Peer),
+ ok.
+
monitor_tag(Config) when is_list(Config) ->
%% Exit signals with immediate exit reasons are sent
%% in a different manner than compound exit reasons, and
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 98eacce0fc..b38d288f99 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -2299,6 +2299,8 @@ update_type(Merge, With, #value_ref{}=Ref, Vst0) ->
case Merge(Current, With) of
none ->
throw({type_conflict, Current, With});
+ Current ->
+ Vst0;
Type ->
Vst = update_container_type(Type, Ref, Vst0),
set_type(Type, Ref, Vst)
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index d79753068f..d96f3a6ae0 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -215,15 +215,15 @@ expr(#c_tuple{anno=Anno,es=Es0}=Tuple, Ctxt, Sub) ->
ann_c_tuple(Anno, Es)
end;
expr(#c_map{anno=Anno,arg=V0,es=Es0}=Map, Ctxt, Sub) ->
- Es = pair_list(Es0, Ctxt, descend(Map, Sub)),
+ %% Warn for useless building, but always build the map
+ %% anyway to preserve a possible exception.
case Ctxt of
- effect ->
- warn_useless_building(Map, Sub),
- make_effect_seq(Es, Sub);
- value ->
- V = expr(V0, Ctxt, Sub),
- ann_c_map(Anno,V,Es)
- end;
+ effect -> warn_useless_building(Map, Sub);
+ value -> ok
+ end,
+ Es = pair_list(Es0, descend(Map, Sub)),
+ V = expr(V0, value, Sub),
+ ann_c_map(Anno, V, Es);
expr(#c_binary{segments=Ss}=Bin0, Ctxt, Sub) ->
%% Warn for useless building, but always build the binary
%% anyway to preserve a possible exception.
@@ -490,14 +490,12 @@ ifes_list(_FVar, [], _Safe) ->
expr_list(Es, Ctxt, Sub) ->
[expr(E, Ctxt, Sub) || E <- Es].
-pair_list(Es, Ctxt, Sub) ->
- [pair(E, Ctxt, Sub) || E <- Es].
+pair_list(Es, Sub) ->
+ [pair(E, Sub) || E <- Es].
-pair(#c_map_pair{key=K,val=V}, effect, Sub) ->
- make_effect_seq([K,V], Sub);
-pair(#c_map_pair{key=K0,val=V0}=Pair, value=Ctxt, Sub) ->
- K = expr(K0, Ctxt, Sub),
- V = expr(V0, Ctxt, Sub),
+pair(#c_map_pair{key=K0,val=V0}=Pair, Sub) ->
+ K = expr(K0, value, Sub),
+ V = expr(V0, value, Sub),
Pair#c_map_pair{key=K,val=V}.
bitstr_list(Es, Sub) ->
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index 64a356c7e4..aba3b8dfe2 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -41,7 +41,8 @@
missing_return_type/1,will_succeed/1,
bs_saved_position_units/1,parent_container/1,
container_performance/1,
- not_equal_inference/1]).
+ not_equal_inference/1,
+ inert_update_type/1]).
-include_lib("common_test/include/ct.hrl").
@@ -77,7 +78,8 @@ groups() ->
missing_return_type,will_succeed,
bs_saved_position_units,parent_container,
container_performance,
- not_equal_inference]}].
+ not_equal_inference,
+ inert_update_type]}].
init_per_suite(Config) ->
test_lib:recompile(?MODULE),
@@ -1045,5 +1047,18 @@ not_equal_inference(_Config) ->
not_equal_inference_1(X) when (X /= []) /= is_port(0 div 0) ->
[X || _ <- []].
+%% GH-6969: A type was made concrete even though that added no additional
+%% information.
+inert_update_type(_Config) ->
+ hello(<<"string">>, id(42)).
+
+hello(A, B) ->
+ mike([{sys_period, {A, B}}, {some_atom, B}]).
+
+mike([Head | _Rest]) -> joe(Head).
+
+joe({Name, 42}) -> Name;
+joe({sys_period, {A, _B}}) -> {41, 42, A}.
+
id(I) ->
I.
diff --git a/lib/compiler/test/bif_SUITE.erl b/lib/compiler/test/bif_SUITE.erl
index 8480569507..34bf54a871 100644
--- a/lib/compiler/test/bif_SUITE.erl
+++ b/lib/compiler/test/bif_SUITE.erl
@@ -24,7 +24,8 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
beam_validator/1,trunc_and_friends/1,cover_safe_and_pure_bifs/1,
- cover_trim/1]).
+ cover_trim/1,
+ head_tail/1]).
suite() ->
[{ct_hooks,[ts_install_cth]}].
@@ -37,7 +38,8 @@ groups() ->
[beam_validator,
trunc_and_friends,
cover_safe_and_pure_bifs,
- cover_trim
+ cover_trim,
+ head_tail
]}].
init_per_suite(Config) ->
@@ -167,6 +169,28 @@ cover_trim_3(Header, N)->
false
end.
+%% GH-7024: The loader transformations for hd/1 and tl/1 were incorrect and
+%% failed when certain optimizations were turned off.
+head_tail(_Config) ->
+ {1, ok} = head_case(),
+ {1, ok} = tail_case(),
+
+ 1 = hd(id([1])),
+ [] = tl(id([1])),
+
+ ok.
+
+head_case() ->
+ case 1 of
+ X when hd(X) -> blurf;
+ X -> {X, ok}
+ end.
+
+tail_case() ->
+ case 1 of
+ X when tl(X) -> blurf;
+ X -> {X, ok}
+ end.
id(I) ->
I.
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index 4da55bed2e..0bdcfab5b7 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -29,7 +29,7 @@
no_no_file/1,configuration/1,supplies/1,
redundant_stack_frame/1,export_from_case/1,
empty_values/1,cover_letrec_effect/1,
- receive_effect/1]).
+ receive_effect/1,map_effect/1]).
-export([foo/0,foo/1,foo/2,foo/3]).
@@ -50,7 +50,7 @@ groups() ->
no_no_file,configuration,supplies,
redundant_stack_frame,export_from_case,
empty_values,cover_letrec_effect,
- receive_effect]}].
+ receive_effect,map_effect]}].
init_per_suite(Config) ->
@@ -700,4 +700,20 @@ receive_effect(_Config) ->
do_receive_effect() ->
{} = receive _ -> {} = {} end.
+map_effect(_Config) ->
+ {'EXIT',{{badkey,key},_}} = catch map_effect_1(),
+
+ {'EXIT',{{badkey,key},_}} = catch map_effect_2(#{}),
+ {'EXIT',{{badmap,no_map},_}} = catch map_effect_2(no_map),
+
+ ok.
+
+map_effect_1() ->
+ #{}#{key := value},
+ ok.
+
+map_effect_2(Map) ->
+ Map#{key := value},
+ ok.
+
id(I) -> I.
diff --git a/lib/crypto/c_src/dh.c b/lib/crypto/c_src/dh.c
index 4bcab0ec6e..92a339ab5f 100644
--- a/lib/crypto/c_src/dh.c
+++ b/lib/crypto/c_src/dh.c
@@ -41,7 +41,7 @@ ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg
/* Has 3_0 */
ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (PrivKey|undefined, DHParams=[P,G], 0, Len|0) */
- unsigned long len = 0;
+ ErlNifUInt64 len = 0;
int i = 0;
OSSL_PARAM params[8];
EVP_PKEY *pkey = NULL, *pkey_gen = NULL;
@@ -84,7 +84,7 @@ ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
*/
/* argv[3] is the length of the private key that is to be generated */
- if (!enif_get_ulong(env, argv[3], &len) ||
+ if (!enif_get_uint64(env, argv[3], &len) ||
(len > LONG_MAX) ) {
ret = EXCP_BADARG_N(env, 3, "Bad value of length element");
goto done;
diff --git a/lib/eldap/doc/src/eldap.xml b/lib/eldap/doc/src/eldap.xml
index 4d9ec96a70..b3b8dc0a9b 100644
--- a/lib/eldap/doc/src/eldap.xml
+++ b/lib/eldap/doc/src/eldap.xml
@@ -548,6 +548,18 @@ Control2 = eldap:paged_result_control(PageSize, Cookie1),
the series.</p>
</desc>
</func>
+ <func>
+ <name since="OTP @OTP-18480@">info(Handle) -> connection_info()</name>
+ <fsummary>Returns information about the LDAP connection.
+ </fsummary>
+ <type>
+ <v>connection_info() = #{socket := Socket, socket_type := tcp | ssl}</v>
+ <v>Socket = ssl:sslsocket() | gen_tcp:socket()</v>
+ </type>
+ <desc><p>Currently available information reveals the socket and the transport
+ protocol, TCP or TLS (SSL), used by the LDAP connection.</p>
+ </desc>
+ </func>
</funcs>
diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl
index 22d816c8c8..7edd012263 100644
--- a/lib/eldap/src/eldap.erl
+++ b/lib/eldap/src/eldap.erl
@@ -30,7 +30,8 @@
parse_ldap_url/1,
paged_result_control/1,
paged_result_control/2,
- paged_result_cookie/1]).
+ paged_result_cookie/1,
+ info/1]).
-export([neverDerefAliases/0, derefInSearching/0,
derefFindingBaseObj/0, derefAlways/0]).
@@ -155,6 +156,13 @@ controlling_process(Handle, Pid) when is_pid(Handle), is_pid(Pid) ->
recv(Handle).
%%% --------------------------------------------------------------------
+%%% Return LDAP socket information
+%%% --------------------------------------------------------------------
+info(Handle) when is_pid(Handle) ->
+ send(Handle, info),
+ recv(Handle).
+
+%%% --------------------------------------------------------------------
%%% Authenticate ourselves to the Directory
%%% using simple authentication.
%%%
@@ -608,6 +616,18 @@ loop(Cpid, Data) ->
send(From, Result),
?MODULE:loop(Cpid, Data);
+ {From, info} ->
+ SocketType =
+ case Data#eldap.ldaps of
+ true ->
+ ssl;
+ false ->
+ tcp
+ end,
+ Res = #{socket => Data#eldap.fd, socket_type => SocketType},
+ send(From, Res),
+ ?MODULE:loop(Cpid, Data);
+
{Cpid, 'EXIT', Reason} ->
?PRINT("Got EXIT from Cpid, reason=~p~n",[Reason]),
exit(Reason);
@@ -618,7 +638,6 @@ loop(Cpid, Data) ->
end.
-
%%% --------------------------------------------------------------------
%%% startTLS Request
%%% --------------------------------------------------------------------
diff --git a/lib/eldap/test/eldap_basic_SUITE.erl b/lib/eldap/test/eldap_basic_SUITE.erl
index 5fa6d4ca69..2b26ed52bd 100644
--- a/lib/eldap/test/eldap_basic_SUITE.erl
+++ b/lib/eldap/test/eldap_basic_SUITE.erl
@@ -46,6 +46,7 @@
more_add/1,
open_ret_val_error/1,
open_ret_val_success/1,
+ plain_ldap_socket_info/1,
search_filter_and/1,
search_filter_and_not/1,
search_filter_equalityMatch/1,
@@ -63,6 +64,7 @@
search_extensible_match_without_dn/1,
search_paged_results/1,
ssl_connection/1,
+ ssl_conn_socket_info/1,
start_tls_on_ssl_should_fail/1,
start_tls_twice_should_fail/1,
tcp_connection/1,
@@ -81,8 +83,8 @@
suite/0
]).
-%%-include_lib("common_test/include/ct.hrl").
-include_lib("common_test/include/ct.hrl").
+-include_lib("stdlib/include/assert.hrl").
-include_lib("eldap/include/eldap.hrl").
-include_lib("eldap/ebin/ELDAPv3.hrl").
@@ -159,7 +161,9 @@ connection_tests() ->
client_side_bind_timeout,
client_side_add_timeout,
client_side_search_timeout,
- close_after_tcp_error
+ close_after_tcp_error,
+ ssl_conn_socket_info,
+ plain_ldap_socket_info
].
@@ -259,7 +263,7 @@ end_per_group(start_tls_api, Config) -> clear_db(Config);
end_per_group(_Group, Config) -> Config.
-init_per_testcase(ssl_connection, Config) ->
+init_per_testcase(TC, Config) when TC == ssl_connection; TC == ssl_conn_socket_info ->
case proplists:get_value(ssl_available,Config) of
true ->
SSL_Port = 9999,
@@ -423,6 +427,35 @@ ssl_connection(Config) ->
end.
%%%----------------------------------------------------------------
+ssl_conn_socket_info(Config) ->
+ Host = proplists:get_value(listen_host, Config),
+ Port = proplists:get_value(ssl_listen_port, Config),
+ Opts = proplists:get_value(tcp_connect_opts, Config),
+ SSLOpts = proplists:get_value(ssl_connect_opts, Config),
+ case eldap:open([Host], [{port,Port},
+ {ssl,true},
+ {timeout,5000},
+ {sslopts,SSLOpts}|Opts]) of
+ {ok,H} ->
+ #{socket := Socket, socket_type := ssl} = eldap:info(H),
+ ?assertMatch({ok, _Data}, ssl:connection_information(Socket));
+ Other -> ct:fail("eldap:open failed: ~p",[Other])
+ end.
+
+%%%----------------------------------------------------------------
+plain_ldap_socket_info(Config) ->
+ Host = proplists:get_value(listen_host, Config),
+ Port = proplists:get_value(listen_port, Config),
+ Opts = proplists:get_value(tcp_connect_opts, Config),
+ T = 1000,
+ case eldap:open([Host], [{timeout,T},{port,Port}|Opts]) of
+ {ok,H} ->
+ ?assertMatch(#{socket := _, socket_type := tcp},
+ eldap:info(H));
+ Other -> ct:fail("eldap:open failed: ~p",[Other])
+ end.
+
+%%%----------------------------------------------------------------
client_side_add_timeout(Config) ->
client_timeout(
fun(H) ->
diff --git a/lib/erl_interface/configure b/lib/erl_interface/configure
index acfd569e30..049c3371fc 100755
--- a/lib/erl_interface/configure
+++ b/lib/erl_interface/configure
@@ -8718,7 +8718,7 @@ int
main (void)
{
- __asm__ __volatile__("isb sy" : : : "memory");
+ __asm__ __volatile__("isb sy\n" : : : "memory");
;
return 0;
@@ -8752,7 +8752,7 @@ int
main (void)
{
- char data[512]; __asm__ __volatile__("dc cvau, %0" : "r" (data) : : "memory");
+ char data[512]; __asm__ __volatile__("dc cvau, %0\n" :: "r" (data) : "memory");
;
return 0;
@@ -8786,7 +8786,7 @@ int
main (void)
{
- char data[512]; __asm__ __volatile__("ic ivau, %0" : "r" (data) : : "memory");
+ char data[512]; __asm__ __volatile__("ic ivau, %0\n" :: "r" (data) : "memory");
;
return 0;
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index 63e26f5266..2dee200291 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -305,8 +305,9 @@ terminate(normal,
%% Socket closed remotely
terminate(normal,
#state{session = #session{socket = {remote_close, Socket},
- socket_type = SocketType,
- id = Id},
+ socket_type = SocketType,
+ type = Type,
+ id = Id},
profile_name = ProfileName,
request = Request,
timers = Timers,
@@ -315,21 +316,26 @@ terminate(normal,
%% Clobber session
(catch httpc_manager:delete_session(Id, ProfileName)),
- maybe_retry_queue(Pipeline, State),
- maybe_retry_queue(KeepAlive, State),
+ case Type of
+ pipeline ->
+ maybe_retry_queue(Pipeline, State);
+ _ ->
+ maybe_retry_queue(KeepAlive, State)
+ end,
%% Cancel timers
cancel_timers(Timers),
%% Maybe deliver answers to requests
- deliver_answer(Request),
+ maybe_deliver_answer(Request, State),
%% And, just in case, close our side (**really** overkill)
http_transport:close(SocketType, Socket);
terminate(_Reason, #state{session = #session{id = Id,
- socket = Socket,
- socket_type = SocketType},
+ socket = Socket,
+ type = Type,
+ socket_type = SocketType},
request = undefined,
profile_name = ProfileName,
timers = Timers,
@@ -339,8 +345,12 @@ terminate(_Reason, #state{session = #session{id = Id,
%% Clobber session
(catch httpc_manager:delete_session(Id, ProfileName)),
- maybe_retry_queue(Pipeline, State),
- maybe_retry_queue(KeepAlive, State),
+ case Type of
+ pipeline ->
+ maybe_retry_queue(Pipeline, State);
+ _ ->
+ maybe_retry_queue(KeepAlive, State)
+ end,
cancel_timer(Timers#timers.queue_timer, timeout_queue),
http_transport:close(SocketType, Socket);
@@ -706,24 +716,26 @@ call(Msg, Pid) ->
cast(Msg, Pid) ->
gen_server:cast(Pid, Msg).
-maybe_retry_queue(Q, State) ->
- case queue:is_empty(Q) of
- false ->
+maybe_retry_queue(Q, #state{status = new} = State) ->
+ retry_pipeline(queue:to_list(Q), State);
+maybe_retry_queue(Q, #state{request = Request} = State) ->
+ case Request of
+ undefined ->
retry_pipeline(queue:to_list(Q), State);
- true ->
- ok
+ _ ->
+ retry_pipeline(queue:to_list(queue:cons(Request, Q)), State)
end.
-
+
maybe_send_answer(#request{from = answer_sent}, _Reason, State) ->
State;
maybe_send_answer(Request, Answer, State) ->
answer_request(Request, Answer, State).
-deliver_answer(#request{from = From} = Request)
+maybe_deliver_answer(#request{from = From} = Request, #state{status = new})
when From =/= answer_sent ->
Response = httpc_response:error(Request, socket_closed_remotely),
httpc_response:send(From, Response);
-deliver_answer(_Request) ->
+maybe_deliver_answer(_,_) ->
ok.
%%%--------------------------------------------------------------------
diff --git a/lib/snmp/doc/src/snmp_app.xml b/lib/snmp/doc/src/snmp_app.xml
index 0613de3158..1400e7bf32 100644
--- a/lib/snmp/doc/src/snmp_app.xml
+++ b/lib/snmp/doc/src/snmp_app.xml
@@ -4,7 +4,7 @@
<appref>
<header>
<copyright>
- <year>1997</year><year>2021</year>
+ <year>1997</year><year>2023</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -295,14 +295,15 @@ in the snmp_config file!
<c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag>
<item>
<p><c>agent_net_if_option() =
- {bind_to, bind_to()} |
- {sndbuf, sndbuf()} |
- {recbuf, recbuf()} |
- {no_reuse, no_reuse()} |
- {req_limit, req_limit()} |
- {filter, agent_net_if_filter_options()} |
- {extra_sock_opts, extra_socket_options()} |
- {inet_backend, inet | socket}</c></p>
+ {bind_to, bind_to()} |
+ {sndbuf, sndbuf()} |
+ {recbuf, recbuf()} |
+ {no_reuse, no_reuse()} |
+ {req_limit, req_limit()} |
+ {filter, agent_net_if_filter_options()} |
+ {open_err_filters, agent_net_if_open_err_filters()} |
+ {extra_sock_opts, extra_socket_options()} |
+ {inet_backend, inet | socket}</c></p>
<p>These options are actually specific to the used module.
The ones shown here are applicable to the default
<c>agent_net_if_module()</c>.</p>
@@ -343,6 +344,25 @@ in the snmp_config file!
<p>Default is <c>snmpa_net_if_filter</c>.</p>
</item>
+ <tag><marker id="agent_ni_open_err_filters"></marker>
+ <c><![CDATA[agent_net_if_open_err_filters() = [agent_net_if_open_err_filter()] <optional>]]></c></tag>
+ <item>
+ <p><c>agent_net_if_open_err_filter() = atom()</c></p>
+ <p>During agent initiation, the transports UDP sockets are opened.
+ If this operation fails, the net-if (and the agent) fails to start
+ (crash). This (filter) list contains error (reasons) that will
+ make net-if fail "nicely".
+ This (filter) list, is supposed to contain errors that can be
+ returned by
+ <seemfa marker="kernel:gen_udp#open/1">gen_udp:open/1,2</seemfa>.
+ The effect is that any error returned by
+ <seemfa marker="kernel:gen_udp#open/1">gen_udp:open</seemfa>
+ which *are* in this list, will be considered
+ "non-fatal" and will only result in an info message, rather than
+ an error message. Net If, and the agent, will still crash,
+ but will produce a less obnoxious message. </p>
+ </item>
+
<tag><marker id="agent_mibs"></marker>
<c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag>
<item>
diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml
index 0b8d786a2d..99324ed400 100644
--- a/lib/snmp/doc/src/snmp_config.xml
+++ b/lib/snmp/doc/src/snmp_config.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2021</year>
+ <year>1997</year><year>2023</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -281,14 +281,15 @@
<c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag>
<item>
<p><c>agent_net_if_option() =
- {bind_to, bind_to()} |
- {sndbuf, sndbuf()} |
- {recbuf, recbuf()} |
- {no_reuse, no_reuse()} |
- {req_limit, req_limit()} |
- {filter, agent_net_if_filter_options()} |
- {extra_sock_opts, extra_socket_options()} |
- {inet_backend, inet | socket}</c></p>
+ {bind_to, bind_to()} |
+ {sndbuf, sndbuf()} |
+ {recbuf, recbuf()} |
+ {no_reuse, no_reuse()} |
+ {req_limit, req_limit()} |
+ {filter, agent_net_if_filter_options()} |
+ {extra_sock_opts, extra_socket_options()} |
+ {open_err_filters, agent_net_if_open_err_filters()} |
+ {inet_backend, inet | socket}</c></p>
<p>These options are actually specific to the used module.
The ones shown here are applicable to the default
<c>agent_net_if_module()</c>.</p>
@@ -329,6 +330,25 @@
<p>Default is <c>snmpa_net_if_filter</c>.</p>
</item>
+ <tag><marker id="agent_ni_open_err_filters"></marker>
+ <c><![CDATA[agent_net_if_open_err_filters() = [agent_net_if_open_err_filter()] <optional>]]></c></tag>
+ <item>
+ <p><c>agent_net_if_open_err_filter() = atom()</c></p>
+ <p>During agent initiation, the transports UDP sockets are opened.
+ If this operation fails, the net-if (and the agent) fails to start
+ (crash). This (filter) list contains error (reasons) that will
+ make net-if fail "nicely".
+ This (filter) list, is supposed to contain errors that can be
+ returned by
+ <seemfa marker="kernel:gen_udp#open/1">gen_udp:open/1,2</seemfa>.
+ The effect is that any error returned by
+ <seemfa marker="kernel:gen_udp#open/1">gen_udp:open</seemfa>
+ which *are* in this list, will be considered
+ "non-fatal" and will only result in an info message, rather than
+ an error message. Net If, and the agent, will still crash,
+ but will produce a less obnoxious message. </p>
+ </item>
+
<tag><marker id="agent_mibs"></marker>
<c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag>
<item>
diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl
index 736b2907fa..8c24440efc 100644
--- a/lib/snmp/src/agent/snmpa_agent.erl
+++ b/lib/snmp/src/agent/snmpa_agent.erl
@@ -340,10 +340,16 @@ init([Prio, Parent, Ref, Options]) ->
"~n Options: ~p", [Prio, Parent, Ref, Options]),
case (catch do_init(Prio, Parent, Ref, Options)) of
{ok, State} ->
- ?vdebug("started",[]),
+ ?vdebug("started"),
{ok, State};
+ {error, {net_if, info, Reason}} ->
+ info_msg("Failed starting agent: "
+ "~n Net If error: ~p", [Reason]),
+ %% {shutdown, Reason};
+ exit(Reason);
{error, Reason} ->
- config_err("failed starting agent: ~n~p", [Reason]),
+ config_err("Failed starting agent: "
+ "~n ~p", [Reason]),
{stop, Reason}
end.
@@ -410,15 +416,18 @@ start_note_store(Prio, Ref, Options) ->
{ok, Pid} ->
?vdebug("start_note_store -> Pid: ~p", [Pid]),
Pid;
- {error, Reason} ->
- ?vinfo("error starting note store: ~n~p",[Reason]),
- throw({error, {note_store_error, Reason}});
- {'EXIT', Reason} ->
- ?vinfo("exit starting note store: ~n~p",[Reason]),
- throw({error, {note_store_exit, Reason}});
+ {error, {Reason, _ChildSpec}} ->
+ ?vinfo("error starting note store: "
+ "~n ~p", [Reason]),
+ throw({error, {note_store, error, Reason}});
+ {'EXIT', {Reason, _ChildSpec}} ->
+ ?vinfo("exit starting note store: "
+ "~n ~p", [Reason]),
+ throw({error, {note_store, exit, Reason}});
Error ->
- ?vinfo("failed starting note store: ~n~p",[Error]),
- throw({error, {note_store_failed, Error}})
+ ?vinfo("failed starting note store: "
+ "~n ~p", [Error]),
+ throw({error, {note_store, failed, Error}})
end.
@@ -437,18 +446,25 @@ start_net_if(none, Prio, Ref, Vsns, NoteStore, Options) ->
case (catch snmpa_misc_sup:start_net_if(Prio, NoteStore, Ref, self(),
Mod, NiOpts)) of
- {ok, Pid} ->
+ {ok, Pid} ->
?vdebug("start_net_if -> Pid: ~p", [Pid]),
{master_agent, Pid, Mod};
- {error, Reason} ->
- ?vinfo("error starting net if: ~n~p",[Reason]),
- throw({error, {net_if_error, Reason}});
+ {error, {{Class, udp_open, PortNo, Reason}, _ChildSpec}} ->
+ ?vinfo("error starting net if: "
+ "~n ~p", [Reason]),
+ throw({error, {net_if, Class, {udp_open, PortNo, Reason}}});
+ {error, {Reason, _ChildSpec}} ->
+ ?vinfo("error starting net if: "
+ "~n ~p", [Reason]),
+ throw({error, {net_if, error, Reason}});
{'EXIT', Reason} ->
- ?vinfo("exit starting net if: ~n~p",[Reason]),
- throw({error, {net_if_exit, Reason}});
+ ?vinfo("exit starting net if: "
+ "~n ~p", [Reason]),
+ throw({error, {net_if, exit, Reason}});
Error ->
- ?vinfo("failed starting net if: ~n~p",[Error]),
- throw({error, {net_if_failed, Error}})
+ ?vinfo("failed starting net if: "
+ "~n ~p", [Error]),
+ throw({error, {net_if, failed, Error}})
end;
start_net_if(Parent, _Prio, _Ref, _Vsns, _NoteStore, _Options)
when is_pid(Parent) ->
@@ -470,15 +486,18 @@ start_mib_server(Prio, Ref, Mibs, Options) ->
{ok, Pid} ->
?vdebug("start_mib_server -> Pid: ~p", [Pid]),
Pid;
- {error, Reason} ->
- ?vinfo("error starting mib server: ~n~p",[Reason]),
- throw({error, {mib_server_error, Reason}});
+ {error, {Reason, _ChildSpec}} ->
+ ?vinfo("error starting mib server: "
+ "~n ~p", [Reason]),
+ throw({error, {mib_server, error, Reason}});
{'EXIT', Reason} ->
- ?vinfo("exit starting mib server: ~n~p",[Reason]),
- throw({error, {mib_server_exit, Reason}});
+ ?vinfo("exit starting mib server: "
+ "~n ~p", [Reason]),
+ throw({error, {mib_server, exit, Reason}});
Error ->
- ?vinfo("failed starting mib server: ~n~p",[Error]),
- throw({error, {mib_server_failed, Error}})
+ ?vinfo("failed starting mib server: "
+ "~n ~p", [Error]),
+ throw({error, {mib_server, failed, Error}})
end.
@@ -3204,8 +3223,8 @@ get_stats_counters([Counter|Counters], Acc) ->
%% ---------------------------------------------------------------------
-%% info_msg(F, A) ->
-%% ?snmpa_info(F, A).
+info_msg(F, A) ->
+ ?snmpa_info(F, A).
warning_msg(F, A) ->
?snmpa_warning(F, A).
diff --git a/lib/snmp/src/agent/snmpa_agent_sup.erl b/lib/snmp/src/agent/snmpa_agent_sup.erl
index 0a5116b2d0..b1eeaba988 100644
--- a/lib/snmp/src/agent/snmpa_agent_sup.erl
+++ b/lib/snmp/src/agent/snmpa_agent_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
@@ -24,7 +24,9 @@
-behaviour(supervisor).
%% External exports
--export([start_link/0, start_link/1, start_subagent/3, stop_subagent/1]).
+-export([start_link/0, start_link/1,
+ start_master_agent/1,
+ start_subagent/3, stop_subagent/1]).
%% Internal exports
-export([init/1]).
@@ -40,8 +42,7 @@
%%%-----------------------------------------------------------------
-%%% This is a supervisor for the mib processes. Each agent has one
-%%% mib process.
+%%% This is a supervisor for the agent processes (master and sub).
%%%-----------------------------------------------------------------
start_link() ->
?d("start_link -> entry", []),
@@ -52,6 +53,9 @@ start_link(AgentSpec) ->
"~n AgentSpec: ~p", [AgentSpec]),
supervisor:start_link({local, ?SERVER}, ?MODULE, [[AgentSpec]]).
+start_master_agent(MasterAgentSpec) ->
+ supervisor:start_child(snmpa_agent_sup, MasterAgentSpec).
+
start_subagent(ParentAgent, Subtree, Mibs) ->
?d("start_subagent -> entry with"
"~n ParentAgent: ~p"
diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl
index d37aa6c28a..72e3ac3e41 100644
--- a/lib/snmp/src/agent/snmpa_net_if.erl
+++ b/lib/snmp/src/agent/snmpa_net_if.erl
@@ -235,11 +235,21 @@ init(Prio, NoteStore, MasterAgent, Parent, Opts) ->
end,
erlang:raise(C, E, S)
end;
- {error, Reason} ->
- config_err("failed starting net-if: ~n~p", [Reason]),
- proc_lib:init_ack({error, Reason});
+ {error, {udp_open, {open, PortNo, Reason}}} ->
+ OEFilters = get_open_err_filters(Opts),
+ Class =
+ case lists:member(Reason, OEFilters) of
+ false ->
+ error;
+ true ->
+ info
+ end,
+ proc_lib:init_ack({error, {Class, udp_open, PortNo, Reason}});
+ {error, Reason} ->
+ %% config_err("failed starting net-if: ~n~p", [Reason]),
+ proc_lib:init_ack({error, Reason});
Error ->
- config_err("failed starting net-if: ~n~p", [Error]),
+ %% config_err("failed starting net-if: ~n~p", [Error]),
proc_lib:init_ack({error, Error})
end.
@@ -256,7 +266,7 @@ do_init(Prio, NoteStore, MasterAgent, Parent, Opts) ->
Vsns = get_vsns(Opts),
?vdebug("vsns: ~w",[Vsns]),
- %% Flow control --
+ %% -- Flow control --
Limit = get_req_limit(Opts),
?vdebug("Limit: ~w", [Limit]),
FilterOpts = get_filter_opts(Opts),
@@ -475,7 +485,7 @@ gen_udp_open(system, Opts) ->
throw({udp_open, {port, PReason}})
end;
{error, OReason} ->
- throw({udp_open, {open, OReason}})
+ throw({udp_open, {open, 0, OReason}})
end;
%% This is for "future compat" since we cannot actually config '0'...
gen_udp_open(IpPort, Opts) when (IpPort =:= 0) ->
@@ -533,7 +543,7 @@ gen_udp_range_open(Min, Max, Opts) ->
gen_udp_range_open(Min+1, Max, Opts);
{error, Reason} ->
?vdebug("gen_udp_range_open(~w,~w) -> ~w", [Reason]),
- throw({udp_open, {open, Reason}})
+ throw({udp_open, {open, Min, Reason}})
catch
C:E:S ->
?vinfo("gen_udp_range_open(~w,~w) -> failed open socket: "
@@ -2101,6 +2111,16 @@ get_filter_opts(O) ->
get_filter_module(O) ->
snmp_misc:get_option(module, O, ?DEFAULT_FILTER_MODULE).
+get_open_err_filters(O) ->
+ case snmp_misc:get_option(open_err_filters, O, []) of
+ Filters when is_list(Filters) ->
+ Filters;
+ Filter when is_atom(Filter) ->
+ [Filter];
+ _ ->
+ []
+ end.
+
get_recbuf(Opts, DefaultOpts) ->
get_socket_opt(recbuf, Opts, DefaultOpts, use_default).
@@ -2153,8 +2173,8 @@ info_msg(F,A) ->
user_err(F, A) ->
snmpa_error:user_err(F, A).
-config_err(F, A) ->
- snmpa_error:config_err(F, A).
+%% config_err(F, A) ->
+%% snmpa_error:config_err(F, A).
%% ----------------------------------------------------------------
diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl
index 215851f23c..26c61579d5 100644
--- a/lib/snmp/src/agent/snmpa_supervisor.erl
+++ b/lib/snmp/src/agent/snmpa_supervisor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2022. All Rights Reserved.
+%% Copyright Ericsson AB 1996-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.
@@ -29,6 +29,7 @@
%% Internal exports
-export([init/1, config/2]).
+-compile({no_auto_import,[erase/1]}).
-define(SERVER, ?MODULE).
@@ -41,6 +42,10 @@
%% Process structure
%% =================
%%
+%% "application"
+%% |
+%% app-sup
+%% |
%% ___________________ supervisor __________________
%% / | | \ \
%% ___misc_sup___ target_cache symbolic_store local_db agent_sup
@@ -176,7 +181,23 @@ start_master_sup(Opts) ->
do_start_master_sup(Opts) ->
verify_mandatory([db_dir], Opts),
- supervisor:start_link({local, ?SERVER}, ?MODULE, [master, Opts]).
+ case supervisor:start_link({local, ?SERVER}, ?MODULE, [master, Opts]) of
+ {ok, Pid} = OK ->
+ %% <HACKETI-HACK-HACK>
+ Key = master_agent_child_spec,
+ MasterAgentSpec = lookup(Key),
+ case snmpa_agent_sup:start_master_agent(MasterAgentSpec) of
+ {ok, MPid} when is_pid(MPid) ->
+ erase(Key),
+ OK;
+ {error, {Reason, _ChildSpec}} ->
+ stop(Pid, 0),
+ {error, Reason}
+ end;
+ %% </HACKETI-HACK-HACK>
+ Else ->
+ Else
+ end.
verify_mandatory([], _) ->
ok;
@@ -503,9 +524,18 @@ init([AgentType, Opts]) ->
worker_spec(snmpa_agent,
[Prio, snmp_master_agent, none, Ref, AgentOpts],
Restart, 15000),
+ %% <HACKETI-HACK-HACK>
+ %% The point is to make start failure more quiet
+ %% Often the failure happens in the master agent,
+ %% so we move the start of that out of this function
+ %% and into the 'do_start_master_sup' function.
+ %% At some point we should rewrite this. Maybe start all
+ %% children the same way (explicitly).
+ store(master_agent_child_spec, AgentSpec),
AgentSupSpec =
- sup_spec(snmpa_agent_sup, [AgentSpec],
+ sup_spec(snmpa_agent_sup, [],
Restart, infinity),
+ %% </HACKETI-HACK-HACK>
[ConfigSpec, AgentSupSpec];
_ ->
?vdebug("[sub agent] spec for the agent supervisor",[]),
@@ -521,6 +551,13 @@ init([AgentType, Opts]) ->
store(Key, Value) ->
ets:insert(snmp_agent_table, {Key, Value}).
+lookup(Key) ->
+ [{Key, Value}] = ets:lookup(snmp_agent_table, Key),
+ Value.
+
+erase(Key) ->
+ ets:delete(snmp_agent_table, Key).
+
get_mibs(Mibs, Vsns) ->
MibDir = filename:join(code:priv_dir(snmp), "mibs"),
StdMib =
diff --git a/lib/snmp/src/app/snmp_app.erl b/lib/snmp/src/app/snmp_app.erl
index 486b276383..7ba3c659f0 100644
--- a/lib/snmp/src/app/snmp_app.erl
+++ b/lib/snmp/src/app/snmp_app.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2021. All Rights Reserved.
+%% Copyright Ericsson AB 2003-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.
@@ -38,8 +38,13 @@ start(Type, []) ->
%% First start the (new) central supervisor,
{ok, Pid} = snmp_app_sup:start_link(),
Entities = entities(),
- ok = start_entities(Type, Entities),
- {ok, Pid}.
+ case start_entities(Type, Entities) of
+ ok ->
+ {ok, Pid};
+ Error ->
+ snmp_app_sup:stop(),
+ Error
+ end.
entities() ->
entities([agent, manager], []).
diff --git a/lib/snmp/src/app/snmp_app_sup.erl b/lib/snmp/src/app/snmp_app_sup.erl
index eb89cc5b6d..bb6faa18cb 100644
--- a/lib/snmp/src/app/snmp_app_sup.erl
+++ b/lib/snmp/src/app/snmp_app_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-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.
@@ -64,7 +64,12 @@ start_agent(Type, Opts) ->
"~n Type: ~p"
"~n Opts: ~p", [Type, Opts]),
Restart = get_restart(Opts, permanent),
- start_sup_child(snmpa_supervisor, Restart, [Type, Opts]).
+ case start_sup_child(snmpa_supervisor, Restart, [Type, Opts]) of
+ {ok, Pid} = OK when is_pid(Pid) ->
+ OK;
+ {error, {Reason, _ChildSpec}} ->
+ {error, Reason}
+ end.
start_manager(Type, Opts) ->
@@ -72,7 +77,12 @@ start_manager(Type, Opts) ->
"~n Type: ~p"
"~n Opts: ~p", [Type, Opts]),
Restart = get_restart(Opts, transient),
- start_sup_child(snmpm_supervisor, Restart, [Type, Opts]).
+ case start_sup_child(snmpm_supervisor, Restart, [Type, Opts]) of
+ {ok, Pid} = OK when is_pid(Pid) ->
+ OK;
+ {error, {Reason, _ChildSpec}} ->
+ {error, Reason}
+ end.
%%%-------------------------------------------------------------------
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 87dd624306..6e952a4584 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -647,7 +647,7 @@ signature_scheme(SignAlgo) when is_integer(SignAlgo) ->
signature_scheme(_) -> unassigned.
signature_schemes_1_2(SigAlgs) ->
- lists:foldl(fun(Alg, Acc) when is_atom(Alg) ->
+ lists:reverse(lists:foldl(fun(Alg, Acc) when is_atom(Alg) ->
case scheme_to_components(Alg) of
{Hash, Sign = rsa_pss_pss,_} ->
[{Hash, Sign} | Acc];
@@ -658,7 +658,7 @@ signature_schemes_1_2(SigAlgs) ->
end;
(Alg, Acc) ->
[Alg| Acc]
- end, [], SigAlgs).
+ end, [], SigAlgs)).
%% TODO: reserved code points?
diff --git a/lib/ssl/src/ssl_gen_statem.erl b/lib/ssl/src/ssl_gen_statem.erl
index 36768ab6c7..62c09c60ae 100644
--- a/lib/ssl/src/ssl_gen_statem.erl
+++ b/lib/ssl/src/ssl_gen_statem.erl
@@ -1897,7 +1897,8 @@ connection_info(#state{handshake_env = #handshake_env{sni_hostname = SNIHostname
security_info(#state{connection_states = ConnectionStates,
static_env = #static_env{role = Role},
- ssl_options = #{keep_secrets := KeepSecrets}}) ->
+ ssl_options = #{keep_secrets := KeepSecrets},
+ protocol_specific = ProtocolSpecific}) ->
ReadState = ssl_record:current_connection_state(ConnectionStates, read),
#{security_parameters :=
#security_parameters{client_random = ClientRand,
@@ -1911,10 +1912,12 @@ security_info(#state{connection_states = ConnectionStates,
BaseSecurityInfo;
true ->
#{security_parameters :=
- #security_parameters{application_traffic_secret = AppTrafSecretWrite,
- client_early_data_secret = ClientEarlyData
- }} =
+ #security_parameters{
+ application_traffic_secret = AppTrafSecretWrite0,
+ client_early_data_secret = ClientEarlyData}} =
ssl_record:current_connection_state(ConnectionStates, write),
+ Sender = maps:get(sender, ProtocolSpecific, undefined),
+ AppTrafSecretWrite = {Sender, AppTrafSecretWrite0},
if Role == server ->
if ServerEarlyData =/= undefined ->
[{server_traffic_secret_0, AppTrafSecretWrite},
@@ -2118,8 +2121,25 @@ maybe_add_keylog({_, 'tlsv1.2'}, Info) ->
maybe_add_keylog({_, 'tlsv1.3'}, Info) ->
try
{client_random, ClientRandomBin} = lists:keyfind(client_random, 1, Info),
- {client_traffic_secret_0, ClientTrafficSecret0Bin} = lists:keyfind(client_traffic_secret_0, 1, Info),
- {server_traffic_secret_0, ServerTrafficSecret0Bin} = lists:keyfind(server_traffic_secret_0, 1, Info),
+ %% after traffic key update current traffic secret
+ %% is stored in tls_sender process state
+ MaybeUpdateTrafficSecret =
+ fun({Direction, {Sender, TrafficSecret0}}) ->
+ TrafficSecret =
+ case call(Sender, get_application_traffic_secret) of
+ {ok, SenderAppTrafSecretWrite} ->
+ SenderAppTrafSecretWrite;
+ _ ->
+ TrafficSecret0
+ end,
+ {Direction, TrafficSecret};
+ (TrafficSecret0) ->
+ TrafficSecret0
+ end,
+ {client_traffic_secret_0, ClientTrafficSecret0Bin} =
+ MaybeUpdateTrafficSecret(lists:keyfind(client_traffic_secret_0, 1, Info)),
+ {server_traffic_secret_0, ServerTrafficSecret0Bin} =
+ MaybeUpdateTrafficSecret(lists:keyfind(server_traffic_secret_0, 1, Info)),
{client_handshake_traffic_secret, ClientHSecretBin} = lists:keyfind(client_handshake_traffic_secret, 1, Info),
{server_handshake_traffic_secret, ServerHSecretBin} = lists:keyfind(server_handshake_traffic_secret, 1, Info),
{selected_cipher_suite, #{prf := Prf}} = lists:keyfind(selected_cipher_suite, 1, Info),
diff --git a/lib/ssl/src/tls_sender.erl b/lib/ssl/src/tls_sender.erl
index b53a801b90..b531b51819 100644
--- a/lib/ssl/src/tls_sender.erl
+++ b/lib/ssl/src/tls_sender.erl
@@ -313,6 +313,13 @@ connection({call, From}, {dist_handshake_complete, _Node, DHandle},
{next_event, internal,
{application_packets, {self(),undefined}, Data}}]}
end;
+connection({call, From}, get_application_traffic_secret, State) ->
+ CurrentWrite = maps:get(current_write, State#data.connection_states),
+ SecurityParams = maps:get(security_parameters, CurrentWrite),
+ ApplicationTrafficSecret =
+ SecurityParams#security_parameters.application_traffic_secret,
+ hibernate_after(?FUNCTION_NAME, State,
+ [{reply, From, {ok, ApplicationTrafficSecret}}]);
connection(internal, {application_packets, From, Data}, StateData) ->
send_application_data(Data, From, ?FUNCTION_NAME, StateData);
connection(internal, {post_handshake_data, From, HSData}, StateData) ->
diff --git a/lib/ssl/test/ssl_cipher_SUITE.erl b/lib/ssl/test/ssl_cipher_SUITE.erl
index def13d0860..70c0b50d4a 100644
--- a/lib/ssl/test/ssl_cipher_SUITE.erl
+++ b/lib/ssl/test/ssl_cipher_SUITE.erl
@@ -41,7 +41,8 @@
aes_decipher_good/1,
aes_decipher_fail/0,
aes_decipher_fail/1,
- padding_test/1
+ padding_test/1,
+ sign_algorithms/1
]).
@@ -49,7 +50,7 @@
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
all() ->
- [aes_decipher_good, aes_decipher_fail, padding_test].
+ [aes_decipher_good, aes_decipher_fail, padding_test, sign_algorithms].
groups() ->
[].
@@ -122,6 +123,10 @@ padding_test(Config) when is_list(Config) ->
pad_test(HashSz, CipherState, {3,2}),
pad_test(HashSz, CipherState, {3,3}).
+%%--------------------------------------------------------------------
+sign_algorithms(Config) when is_list(Config) ->
+ [{sha256,rsa_pss_pss},{rsa,sha256}] = ssl_cipher:signature_schemes_1_2([rsa_pss_pss_sha256, {rsa, sha256}]).
+
%%--------------------------------------------------------------------
% Internal functions --------------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/ssl_key_update_SUITE.erl b/lib/ssl/test/ssl_key_update_SUITE.erl
index baa408dbc5..0ac3228f85 100644
--- a/lib/ssl/test/ssl_key_update_SUITE.erl
+++ b/lib/ssl/test/ssl_key_update_SUITE.erl
@@ -42,7 +42,6 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("ssl/src/ssl_api.hrl").
-include_lib("ssl/src/ssl_connection.hrl").
-
all() ->
[{group, 'tlsv1.3'}].
@@ -107,24 +106,22 @@ key_update_at_server(Config) ->
key_update_at(Config, Role) ->
Data = "123456789012345", %% 15 bytes
Server = ssl_test_lib:start_server(erlang,
- [{options, [{key_update_at, 14}]}],
+ [{options, [{keep_secrets, true},
+ {key_update_at, 14}]}],
Config),
Port = ssl_test_lib:inet_port(Server),
- {Client,
- #sslsocket{pid =
- [ClientReceiverPid, ClientSenderPid]}} =
- ssl_test_lib:start_client(erlang,
- [return_socket, {port, Port},
- {options, [{key_update_at, 14}]}],
- Config),
+ ClientResult = ssl_test_lib:start_client(erlang,
+ [return_socket, {port, Port},
+ {options, [{keep_secrets, true},
+ {key_update_at, 14}]}],
+ Config),
+ {Client, ClientSocket} = ClientResult,
Server ! get_socket,
- #sslsocket{pid =
- [ServerReceiverPid, ServerSenderPid]} =
- receive
- {Server, {socket, S}} -> S
- end,
- Keys0 = get_keys(ClientReceiverPid, ClientSenderPid,
- ServerReceiverPid, ServerSenderPid),
+ ServerSocket = receive
+ {Server, {socket, S}} -> S
+ end,
+ Keys0 = get_traffic_secrets(ClientSocket, ServerSocket),
+ ct:log("connected", []),
{Sender, Receiver} = case Role of
client -> {Client, Server};
server -> {Server, Client}
@@ -134,53 +131,67 @@ key_update_at(Config, Role) ->
Data = ssl_test_lib:check_active_receive(Receiver, Data),
%% TODO check if key has been updated (needs debug logging of secrets)
ct:sleep(500),
- Keys1 = get_keys(ClientReceiverPid, ClientSenderPid,
- ServerReceiverPid, ServerSenderPid),
+ ct:log("sent and waited", []),
+ Keys1 = get_traffic_secrets(ClientSocket, ServerSocket),
verify_key_update(Keys0, Keys1),
%% Test mechanism to prevent infinite loop of key updates
BigData = binary:copy(<<"1234567890">>, 10), %% 100 bytes
ok = ssl_test_lib:send(Sender, BigData),
ct:sleep(500),
- Keys2 = get_keys(ClientReceiverPid, ClientSenderPid,
- ServerReceiverPid, ServerSenderPid),
+ ct:log("sent and waited 2", []),
+ Keys2 = get_traffic_secrets(ClientSocket, ServerSocket),
verify_key_update(Keys1, Keys2),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-get_keys(ClientReceiverPid, ClientSenderPid,
- ServerReceiverPid, ServerSenderPid) ->
- F = fun(Pid) ->
- {connection, D} = sys:get_state(Pid),
- M0 = element(3, D),
- Cr = maps:get(current_write, M0),
- {Pid, {maps:get(security_parameters, Cr),
- maps:get(cipher_state, Cr)}}
+get_traffic_secrets(ClientSocket, ServerSocket) ->
+ ProcessSocket =
+ fun(Socket, Role) ->
+ {ok, [{keylog, KeyLog}]} = ssl:connection_information(Socket, [keylog]),
+ Interesting =
+ fun(S) ->
+ Patterns = ["CLIENT_TRAFFIC_SECRET", "SERVER_TRAFFIC_SECRET"],
+ SearchResults = [string:find(S, P) || P <- Patterns],
+ lists:any(fun(I) -> I /= nomatch end, SearchResults)
+ end,
+ TrafficSecrets = lists:filter(Interesting, KeyLog),
+ Print = fun(Secret) ->
+ [Name, _A, B] = string:lexemes(Secret, " "),
+ [Key] = io_lib:format("~s", [B]),
+ {Name, {Role, Key}}
+ end,
+ [Print(Scr) || Scr <- TrafficSecrets]
end,
- SendersKeys = [F(P) || P <- [ClientSenderPid, ServerSenderPid]],
-
- G = fun(Pid) ->
- {connection, D} = sys:get_state(Pid),
- #state{connection_states = Cs} = D,
- Cr = maps:get(current_read, Cs),
- {Pid, {maps:get(security_parameters,Cr),
- maps:get(cipher_state, Cr)}}
+ Secrets = lists:flatten(
+ [ProcessSocket(S, R) ||
+ {S, R} <-
+ [{ClientSocket, client}, {ServerSocket, server}]]),
+ P = fun(Direction) ->
+ Vals = proplists:get_all_values(Direction, Secrets),
+ ct:log("~30s ~10s(c) ~10s(s)",
+ [Direction, proplists:get_value(client, Vals),
+ proplists:get_value(server, Vals)]),
+ {Direction, [proplists:get_value(client, Vals),
+ proplists:get_value(server, Vals)]}
end,
- ReceiversKeys = [G(P) || P <- [ClientReceiverPid, ServerReceiverPid]],
- maps:from_list(SendersKeys ++ ReceiversKeys).
+ [P(Direction) ||
+ Direction <-
+ ["CLIENT_TRAFFIC_SECRET_0", "SERVER_TRAFFIC_SECRET_0"]].
verify_key_update(Keys0, Keys1) ->
- V = fun(Pid, CurrentKeys) ->
- BaseKeys = maps:get(Pid, Keys0),
- ct:log("Pid = ~p~nBaseKeys = ~p~nCurrentKeys = ~p",
- [Pid, BaseKeys, CurrentKeys], [esc_chars]),
- case BaseKeys == CurrentKeys of
- true ->
- ct:fail("Keys don't differ for ~w", [Pid]);
- false ->
- ok
- end
- end,
- maps:foreach(V, Keys1).
+ CTS0 = proplists:get_value("CLIENT_TRAFFIC_SECRET_0", Keys0),
+ CTS1 = proplists:get_value("CLIENT_TRAFFIC_SECRET_0", Keys1),
+ STS0 = proplists:get_value("SERVER_TRAFFIC_SECRET_0", Keys0),
+ STS1 = proplists:get_value("SERVER_TRAFFIC_SECRET_0", Keys1),
+ CTS = lists:zip(CTS0, CTS1),
+ STS = lists:zip(STS0, STS1),
+ Pred = fun({A, B}) when A == B ->
+ ct:fail(no_key_update),
+ false;
+ (_) ->
+ true
+ end,
+ [true = lists:all(Pred, X) || X <- [CTS, STS]].
explicit_key_update() ->
[{doc,"Test ssl:update_key/2 between erlang client and erlang server."}].
diff --git a/lib/ssl/test/ssl_session_SUITE.erl b/lib/ssl/test/ssl_session_SUITE.erl
index 40fff3bbbd..f597c78bb5 100644
--- a/lib/ssl/test/ssl_session_SUITE.erl
+++ b/lib/ssl/test/ssl_session_SUITE.erl
@@ -464,8 +464,11 @@ no_reuses_session_server_restart_new_cert() ->
no_reuses_session_server_restart_new_cert(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_der_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_der_verify_opts, Config),
- RSA1024ServerOpts = ssl_test_lib:ssl_options(server_rsa_1024_der_opts, Config),
- RSA1024ClientOpts = ssl_test_lib:ssl_options(client_rsa_1024_der_opts, Config),
+ #{client_config := NewCOpts,
+ server_config := NewSOpts} = ssl_test_lib:make_cert_chains_der(rsa,
+ [[{key, ssl_test_lib:hardcode_rsa_key(4)}],
+ [{key, ssl_test_lib:hardcode_rsa_key(5)}],
+ [{key, ssl_test_lib:hardcode_rsa_key(6)}]]),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -490,12 +493,12 @@ no_reuses_session_server_restart_new_cert(Config) when is_list(Config) ->
Server1 = ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
{from, self()},
{mfa, {ssl_test_lib, session_info_result, []}},
- {options, [{reuseaddr, true} | RSA1024ServerOpts]}]),
+ {options, [{reuseaddr, true} | NewSOpts]}]),
Client1 = ssl_test_lib:start_client([{node, ClientNode},
{port, Port}, {host, Hostname},
{mfa, {ssl_test_lib, session_info_result, []}},
- {from, self()}, {options, RSA1024ClientOpts}]),
+ {from, self()}, {options, NewCOpts}]),
Info1 = receive {Server1, Info10} -> Info10 end,
receive
@@ -517,7 +520,12 @@ no_reuses_session_server_restart_new_cert_file() ->
no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- RSA1024ServerOpts = ssl_test_lib:ssl_options(server_rsa_1024_verify_opts, Config),
+ #{client_config := NewCOpts,
+ server_config := NewSOpts} = ssl_test_lib:make_cert_chains_pem(rsa,
+ [[{key, ssl_test_lib:hardcode_rsa_key(4)}],
+ [{key, ssl_test_lib:hardcode_rsa_key(5)}],
+ [{key, ssl_test_lib:hardcode_rsa_key(6)}]],
+ Config, "ssl_session_new_rsa"),
PrivDir = proplists:get_value(priv_dir, Config),
NewServerOpts0 = ssl_test_lib:new_config(PrivDir, ServerOpts),
@@ -548,7 +556,7 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
ssl:clear_pem_cache(),
- NewServerOpts1 = ssl_test_lib:new_config(PrivDir, RSA1024ServerOpts),
+ NewServerOpts1 = ssl_test_lib:new_config(PrivDir, NewSOpts),
Server1 =
ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
@@ -559,7 +567,7 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
ssl_test_lib:start_client([{node, ClientNode},
{port, Port}, {host, Hostname},
{mfa, {ssl_test_lib, session_info_result, []}},
- {from, self()}, {options, ClientOpts}]),
+ {from, self()}, {options, NewCOpts}]),
receive
{Client1, SessionInfo} ->
ct:fail(session_reused_when_server_has_new_cert);
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index f97ea99e60..6228c5857a 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -661,6 +661,7 @@ Erlang code.
-type abstract_expr() :: af_literal()
| af_match(abstract_expr())
+ | af_maybe_match()
| af_variable()
| af_tuple(abstract_expr())
| af_nil()
@@ -687,7 +688,9 @@ Erlang code.
| af_local_fun()
| af_remote_fun()
| af_fun()
- | af_named_fun().
+ | af_named_fun()
+ | af_maybe()
+ | af_maybe_else().
-type af_record_update(T) :: {'record',
anno(),
@@ -830,6 +833,9 @@ Erlang code.
-type af_map_pattern() ::
{'map', anno(), [af_assoc_exact(af_pattern())]}.
+-type af_maybe() :: {'maybe', anno(), af_body()}.
+-type af_maybe_else() :: {'maybe', anno(), af_body(), {'else', anno(), af_clause_seq()}}.
+
-type abstract_type() :: af_annotated_type()
| af_atom()
| af_bitstring_type()
@@ -940,6 +946,8 @@ Erlang code.
-type af_match(T) :: {'match', anno(), af_pattern(), T}.
+-type af_maybe_match() :: {'maybe_match', anno(), af_pattern(), abstract_expr()}.
+
-type af_variable() :: {'var', anno(), atom()}. % | af_anon_variable()
%-type af_anon_variable() :: {'var', anno(), '_'}.
@@ -965,7 +973,7 @@ Erlang code.
-type binary_op() :: '/' | '*' | 'div' | 'rem' | 'band' | 'and' | '+' | '-'
| 'bor' | 'bxor' | 'bsl' | 'bsr' | 'or' | 'xor' | '++'
| '--' | '==' | '/=' | '=<' | '<' | '>=' | '>' | '=:='
- | '=/='.
+ | '=/=' | '!'.
-type af_unary_op(T) :: {'op', anno(), unary_op(), T}.
diff --git a/make/autoconf/otp.m4 b/make/autoconf/otp.m4
index 98b8ea5f61..a522fae3bd 100644
--- a/make/autoconf/otp.m4
+++ b/make/autoconf/otp.m4
@@ -1458,7 +1458,7 @@ AC_DEFUN(ETHR_CHK_GCC_ATOMIC_OPS,
[
ethr_cv_arm_isb_sy_instr=no
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[
- __asm__ __volatile__("isb sy" : : : "memory");
+ __asm__ __volatile__("isb sy\n" : : : "memory");
]])],[ethr_cv_arm_isb_sy_instr=yes],[])
])
if test $ethr_cv_arm_isb_sy_instr = yes; then
@@ -1468,7 +1468,7 @@ AC_DEFUN(ETHR_CHK_GCC_ATOMIC_OPS,
[
ethr_cv_arm_dc_cvau_instr=no
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[
- char data[512]; __asm__ __volatile__("dc cvau, %0" : "r" (data) : : "memory");
+ char data[512]; __asm__ __volatile__("dc cvau, %0\n" :: "r" (data) : "memory");
]])],[ethr_cv_arm_dc_cvau_instr=yes],[])
])
if test $ethr_cv_arm_dc_cvau_instr = yes; then
@@ -1478,7 +1478,7 @@ AC_DEFUN(ETHR_CHK_GCC_ATOMIC_OPS,
[
ethr_cv_arm_ic_ivau_instr=no
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[
- char data[512]; __asm__ __volatile__("ic ivau, %0" : "r" (data) : : "memory");
+ char data[512]; __asm__ __volatile__("ic ivau, %0\n" :: "r" (data) : "memory");
]])],[ethr_cv_arm_ic_ivau_instr=yes],[])
])
if test $ethr_cv_arm_ic_ivau_instr = yes; then