diff options
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 |