aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/beam/erl_sched_spec_pre_alloc.h2
-rw-r--r--erts/etc/unix/etp-commands.in98
-rw-r--r--erts/preloaded/ebin/atomics.beambin3292 -> 3292 bytes
-rw-r--r--erts/preloaded/ebin/counters.beambin3092 -> 3092 bytes
-rw-r--r--erts/preloaded/ebin/erl_init.beambin2312 -> 2260 bytes
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin52636 -> 52540 bytes
-rw-r--r--erts/preloaded/ebin/erl_tracer.beambin2200 -> 2200 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin100196 -> 100200 bytes
-rw-r--r--erts/preloaded/ebin/erts_code_purger.beambin11204 -> 10976 bytes
-rw-r--r--erts/preloaded/ebin/erts_dirty_process_signal_handler.beambin2764 -> 2760 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin17788 -> 17760 bytes
-rw-r--r--erts/preloaded/ebin/erts_literal_area_collector.beambin3268 -> 3248 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin50304 -> 50208 bytes
-rw-r--r--erts/preloaded/ebin/net.beambin6140 -> 6096 bytes
-rw-r--r--erts/preloaded/ebin/persistent_term.beambin1836 -> 1844 bytes
-rw-r--r--erts/preloaded/ebin/prim_buffer.beambin3596 -> 3592 bytes
-rw-r--r--erts/preloaded/ebin/prim_eval.beambin1496 -> 1496 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin28084 -> 27984 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin81012 -> 80932 bytes
-rw-r--r--erts/preloaded/ebin/prim_zip.beambin22644 -> 22436 bytes
-rw-r--r--erts/preloaded/ebin/socket.beambin70300 -> 70248 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin19716 -> 19700 bytes
-rw-r--r--lib/compiler/src/beam_except.erl7
-rw-r--r--lib/compiler/src/beam_ssa_codegen.erl15
-rw-r--r--lib/compiler/src/beam_ssa_dead.erl30
-rw-r--r--lib/compiler/src/beam_ssa_type.erl62
-rw-r--r--lib/compiler/src/beam_validator.erl12
-rw-r--r--lib/compiler/test/beam_except_SUITE.erl20
-rw-r--r--lib/compiler/test/beam_ssa_SUITE.erl60
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl11
-rw-r--r--lib/compiler/test/core_SUITE.erl7
-rw-r--r--lib/compiler/test/core_SUITE_data/get_map_element.core18
-rw-r--r--lib/compiler/test/guard_SUITE.erl25
-rw-r--r--lib/kernel/src/code.erl18
-rw-r--r--lib/kernel/src/kernel.erl2
-rw-r--r--lib/kernel/test/code_SUITE.erl29
-rw-r--r--lib/public_key/src/pubkey_pbe.erl4
-rw-r--r--lib/ssl/src/ssl.erl9
-rw-r--r--lib/ssl/src/ssl_alert.erl31
-rw-r--r--lib/ssl/src/ssl_connection.erl66
-rw-r--r--lib/ssl/test/ssl_test_lib.erl30
-rw-r--r--system/doc/system_principles/system_principles.xml3
42 files changed, 392 insertions, 167 deletions
diff --git a/erts/emulator/beam/erl_sched_spec_pre_alloc.h b/erts/emulator/beam/erl_sched_spec_pre_alloc.h
index 74cc966cbe..6f715ae80d 100644
--- a/erts/emulator/beam/erl_sched_spec_pre_alloc.h
+++ b/erts/emulator/beam/erl_sched_spec_pre_alloc.h
@@ -49,7 +49,7 @@ do { \
#endif
#ifdef DEBUG
-extern Uint erts_no_schedulers;
+extern Uint ERTS_WRITE_UNLIKELY(erts_no_schedulers);
#endif
#define ERTS_SSPA_FORCE_THR_CHECK_PROGRESS 10
diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in
index 66d6d20c4e..730f0a0c64 100644
--- a/erts/etc/unix/etp-commands.in
+++ b/erts/etc/unix/etp-commands.in
@@ -132,14 +132,14 @@ define etp-1
if (($arg0) & 0x3) == 1
# Cons pointer
if $etp_flat
- printf "<etpf-cons %#x>", ($arg0)
+ printf "<etpf-cons %p>", (($arg0)-1)
else
etp-list-1 ($arg0) ($arg1)
end
else
if (($arg0) & 0x3) == 2
if $etp_flat
- printf "<etpf-boxed %#x>", ($arg0)
+ printf "<etpf-boxed %p>", (($arg0)-2)
else
etp-boxed-1 ($arg0) ($arg1)
end
@@ -187,7 +187,7 @@ define etp-list-1
# Reentrant
#
if (($arg0) & 0x3) != 0x1
- printf "#NotCons<%#x>", ($arg0)
+ printf "#NotCons<%p>", ($arg0)
else
# Cons pointer
if $etp_chart
@@ -210,7 +210,7 @@ define etp-list-printable-1
# Returns: $etp_list_printable
#
if (($arg0) & 0x3) != 0x1
- printf "#NotCons<%#x>", ($arg0)
+ printf "#NotCons<%p>", ($arg0)
else
# Loop to check if it is a printable string
set $etp_list_p = ($arg0)
@@ -272,7 +272,7 @@ define etp-list-2
# Reentrant
#
if (($arg0) & 0x3) != 0x1
- printf "#NotCons<%#x>", ($arg0)
+ printf "#NotCons<%p>", ($arg0)
else
# Cons pointer
if ($arg1) >= $etp_max_depth
@@ -307,7 +307,7 @@ define etpf-cons
# Reentrant capable
#
if ((Eterm)($arg0) & 0x3) != 0x1
- printf "#NotCons<%#x>", ($arg0)
+ printf "#NotCons<%p>", ($arg0)
else
# Cons pointer
set $etp_flat = 1
@@ -336,13 +336,13 @@ define etp-boxed-1
# Reentrant
#
if (($arg0) & 0x3) != 0x2
- printf "#NotBoxed<%#x>", ($arg0)
+ printf "#NotBoxed<%p>", ($arg0)
else
if (((Eterm*)(($arg0) & ~0x3))[0] & 0x3) != 0x0
if $etp_chart
etp-chart-entry-1 (($arg0)&~0x3) ($arg1) 1
end
- printf "#BoxedError<%#x>", ($arg0)
+ printf "#BoxedError<%p>", ($arg0)
else
if $etp_chart
etp-chart-entry-1 (($arg0)&~0x3) ($arg1) \
@@ -390,10 +390,10 @@ define etp-boxed-immediate-1
# Non-reentrant
#
if (($arg0) & 0x3) != 0x2
- printf "#NotBoxed<%#x>", ($arg0)
+ printf "#NotBoxed<%p>", ($arg0)
else
if (((Eterm*)(($arg0) & ~0x3))[0] & 0x3) != 0x0
- printf "#BoxedError<%#x>", ($arg0)
+ printf "#BoxedError<%p>", ($arg0)
else
set $etp_boxed_immediate_p = (Eterm*)(($arg0) & ~0x3)
set $etp_boxed_immediate_h = ($etp_boxed_immediate_p[0] >> 2) & 0xF
@@ -438,12 +438,12 @@ define etp-boxed-immediate-1
while $etp_boxed_immediate_arity > 0
set $etp_boxed_immediate_p++
if $etp_boxed_immediate_arity > 1
- printf "%#x,", *$etp_boxed_immediate_p
+ printf "%p,", *$etp_boxed_immediate_p
else
- printf "%#x", *$etp_boxed_immediate_p
+ printf "%p", *$etp_boxed_immediate_p
if ($etp_boxed_immediate_h == 0xA)
set $etp_boxed_immediate_p++
- printf ":%#x", *$etp_boxed_immediate_p
+ printf ":%p", *$etp_boxed_immediate_p
end
printf ">"
end
@@ -558,7 +558,7 @@ define etp-immediate-1
# Reentrant capable
#
if (($arg0) & 0x3) != 0x3
- printf "#NotImmediate<%#x>", ($arg0)
+ printf "#NotImmediate<%p>", ($arg0)
else
if (($arg0) & 0xF) == 0x3
etp-pid-1 ($arg0)
@@ -580,7 +580,7 @@ define etp-immediate-1
if (($arg0) == $etp_nil)
printf "[]"
else
- printf "#UnknownImmediate<%#x>", ($arg0)
+ printf "#UnknownImmediate<%p>", ($arg0)
end
end
end
@@ -598,7 +598,7 @@ define etp-atom-1
# Non-reentrant
#
if ((Eterm)($arg0) & 0x3f) != 0xb
- printf "#NotAtom<%#x>", ($arg0)
+ printf "#NotAtom<%p>", ($arg0)
else
set $etp_atom_1_ap = (Atom*)erts_atom_table.seg_table[(Eterm)($arg0)>>16][((Eterm)($arg0)>>6)&0x3FF]
set $etp_atom_1_i = ($etp_atom_1_ap)->len
@@ -652,7 +652,7 @@ define etp-char-1
# Non-reentrant
#
if (($arg0) < 0) || (0377 < ($arg0))
- printf "#NotChar<%#x>", ($arg0)
+ printf "#NotChar<%p>", ($arg0)
else
if ($arg0) == ($arg1)
printf "\\%c", ($arg0)
@@ -787,7 +787,7 @@ define etp-pid-1
# Internal pid
printf "<0.%u.%u>", $etp_pid_data & 0x7fff, ($etp_pid_data >> 15) & 0x1fff
else
- printf "#NotPid<%#x>", ($arg0)
+ printf "#NotPid<%p>", ($arg0)
end
end
@@ -797,11 +797,11 @@ define etp-extpid-1
# Non-reentrant
#
if ((Eterm)($arg0) & 0x3) != 0x2
- printf "#NotBoxed<%#x>", (Eterm)($arg0)
+ printf "#NotBoxed<%p>", (Eterm)($arg0)
else
set $etp_extpid_1_p = (ExternalThing*)((Eterm)($arg0) & ~0x3)
if ($etp_extpid_1_p->header & 0x3f) != 0x30
- printf "#NotExternalPid<%#x>", $etp_extpid_1_p->header
+ printf "#NotExternalPid<%p>", $etp_extpid_1_p->header
else
## External pid
set $etp_extpid_1_number = $etp_extpid_1_p->data.ui[0]&0x7fff
@@ -812,7 +812,7 @@ define etp-extpid-1
set $etp_extpid_1_node = $etp_extpid_1_np->sysname
if ($etp_extpid_1_node & 0x3f) != 0xb
# Should be an atom
- printf "#ExternalPidError<%#x>", ($arg0)
+ printf "#ExternalPidError<%p>", ($arg0)
else
if $etp_extpid_1_dep == erts_this_dist_entry
printf "<0:"
@@ -847,7 +847,7 @@ define etp-port-1
# Internal port
printf "#Port<0.%u>", $etp_port_data
else
- printf "#NotPort<%#x>", ($arg0)
+ printf "#NotPort<%p>", ($arg0)
end
end
@@ -857,11 +857,11 @@ define etp-extport-1
# Non-reentrant
#
if ((Eterm)($arg0) & 0x3) != 0x2
- printf "#NotBoxed<%#x>", (Eterm)($arg0)
+ printf "#NotBoxed<%p>", (Eterm)($arg0)
else
set $etp_extport_1_p = (ExternalThing*)((Eterm)($arg0) & ~0x3)
if ($etp_extport_1_p->header & 0x3F) != 0x34
- printf "#NotExternalPort<%#x>", $etp_extport_1->header
+ printf "#NotExternalPort<%p>", $etp_extport_1->header
else
## External port
set $etp_extport_1_number = $etp_extport_1_p->data.ui[0]&0x3ffff
@@ -871,7 +871,7 @@ define etp-extport-1
set $etp_extport_1_node = $etp_extport_1_np->sysname
if ($etp_extport_1_node & 0x3f) != 0xb
# Should be an atom
- printf "#ExternalPortError<%#x>", ($arg0)
+ printf "#ExternalPortError<%p>", ($arg0)
else
if $etp_extport_1_dep == erts_this_dist_entry
printf "#Port<0:"
@@ -893,15 +893,15 @@ define etp-bignum-1
# Non-reentrant
#
if ((Eterm)($arg0) & 0x3) != 0x2
- printf "#NotBoxed<%#x>", (Eterm)($arg0)
+ printf "#NotBoxed<%p>", (Eterm)($arg0)
else
set $etp_bignum_1_p = (Eterm*)((Eterm)($arg0) & ~0x3)
if ($etp_bignum_1_p[0] & 0x3b) != 0x08
- printf "#NotBignum<%#x>", $etp_bignum_1_p[0]
+ printf "#NotBignum<%p>", $etp_bignum_1_p[0]
else
set $etp_bignum_1_i = ($etp_bignum_1_p[0] >> 6)
if $etp_bignum_1_i < 1
- printf "#BignumError<%#x>", (Eterm)($arg0)
+ printf "#BignumError<%p>", (Eterm)($arg0)
else
if $etp_bignum_1_p[0] & 0x04
printf "-"
@@ -932,11 +932,11 @@ define etp-float-1
# Non-reentrant
#
if ((Eterm)($arg0) & 0x3) != 0x2
- printf "#NotBoxed<%#x>", (Eterm)($arg0)
+ printf "#NotBoxed<%p>", (Eterm)($arg0)
else
set $etp_float_1_p = (Eterm*)((Eterm)($arg0) & ~0x3)
if ($etp_float_1_p[0] & 0x3f) != 0x18
- printf "#NotFloat<%#x>", $etp_float_1_p[0]
+ printf "#NotFloat<%p>", $etp_float_1_p[0]
else
printf "%f", *(double*)($etp_float_1_p+1)
end
@@ -951,14 +951,14 @@ define etp-ref-1
# Non-reentrant
#
if ((Eterm)($arg0) & 0x3) != 0x2
- printf "#NotBoxed<%#x>", (Eterm)($arg0)
+ printf "#NotBoxed<%p>", (Eterm)($arg0)
else
set $etp_ref_1_p = (ErtsORefThing *)((Eterm)($arg0) & ~0x3)
if ($etp_ref_1_p->header & 0x3b) != 0x10
- printf "#NotRef<%#x>", $etp_ref_1_p->header
+ printf "#NotRef<%p>", $etp_ref_1_p->header
else
if $etp_ref_1_p->header != etp_ref_header && $etp_ref_1_p->header != etp_magic_ref_header
- printf "#InternalRefError<%#x>", ($arg0)
+ printf "#InternalRefError<%p>", ($arg0)
else
set $etp_magic_ref = 0
set $etp_ref_1_i = 3
@@ -998,11 +998,11 @@ define etp-extref-1
# Non-reentrant
#
if ((Eterm)($arg0) & 0x3) != 0x2
- printf "#NotBoxed<%#x>", (Eterm)($arg0)
+ printf "#NotBoxed<%p>", (Eterm)($arg0)
else
set $etp_extref_1_p = (ExternalThing*)((Eterm)($arg0) & ~0x3)
if ($etp_extref_1_p->header & 0x3F) != 0x38
- printf "#NotExternalRef<%#x>", $etp_extref_1->header
+ printf "#NotExternalRef<%p>", $etp_extref_1->header
else
## External ref
set $etp_extref_1_nump = (Uint32 *) 0
@@ -1041,7 +1041,7 @@ define etp-extref-1
end
end
if $etp_extref_1_error
- printf "#ExternalRefError<%#x>", ($arg0)
+ printf "#ExternalRefError<%p>", ($arg0)
else
set $etp_extref_1_i--
while $etp_extref_1_i >= 0
@@ -1166,7 +1166,7 @@ define etp-cp-1
if *(Eterm*)($etp_cp) == beam_return_to_trace[0]
printf "#Cp<return to trace>"
else
- printf "#Cp<%#x>", $etp_cp
+ printf "#Cp<%p>", $etp_cp
end
end
end
@@ -1743,7 +1743,7 @@ define etp-term-dump-pid
# Internal pid
printf "| <0.%04u.%03u> ", $etp_pid_data & 0x7fff, ($etp_pid_data >> 15) & 0x1fff
else
- printf "| #NotPid<%#x> ", ($arg0)
+ printf "| #NotPid<%p> ", ($arg0)
end
end
@@ -3324,7 +3324,7 @@ define etp-offheapdump
set $etp_offheapdump_p = $etp_offheapdump_p->next
set $etp_offheapdump_i++
else
- printf "#TaggedPtr<%#x>", $etp_offheapdump_p
+ printf "#TaggedPtr<%p>", $etp_offheapdump_p
set $etp_offheapdump_p = 0
end
end
@@ -3363,12 +3363,12 @@ define etp-search-heaps
#
# Non-reentrant
#
- printf "%% Search all (<%u) process heaps for ", erts_max_processes
+ printf "%% Search all (<%u) process heaps for ", erts_proc.r.o.max
set $etp_flat = 1
etp-1 ($arg0) 0
set $etp_flat = 0
printf ":...\n"
- etp-search-heaps-1 ((Eterm*)((Eterm)($arg0)&~3))
+ etp-search-heaps-1 ((Eterm*)((Eterm)($arg0)&~(Eterm)3))
end
define etp-search-heaps-1
@@ -3376,8 +3376,8 @@ define etp-search-heaps-1
#
# Non-reentrant
#
- set $etp_search_heaps_q = erts_max_processes / 10
- set $etp_search_heaps_r = erts_max_processes % 10
+ set $etp_search_heaps_q = erts_proc.r.o.max / 10
+ set $etp_search_heaps_r = erts_proc.r.o.max % 10
set $etp_search_heaps_t = 10
set $etp_search_heaps_m = $etp_search_heaps_q
if $etp_search_heaps_r > 0
@@ -3387,7 +3387,7 @@ define etp-search-heaps-1
set $etp_search_heaps_i = 0
set $etp_search_heaps_found = 0
while $etp_search_heaps_i < erts_proc.r.o.max
- set $proc = (Process *) *((UWord *) &erts_proc.r.o.tab[$proc_ix])
+ set $proc = (Process *) *((UWord *) &erts_proc.r.o.tab[$etp_search_heaps_i])
if $proc
if ($proc->heap <= ($arg0)) && \
(($arg0) < $proc->hend)
@@ -3404,7 +3404,7 @@ define etp-search-heaps-1
while $etp_search_heaps_p && ($etp_search_heaps_cnt < $etp_max_depth)
set $etp_search_heaps_cnt++
if (&($etp_search_heaps_p->mem) <= ($arg0)) && \
- (($arg0) < &($etp_search_heaps_p->mem)+$etp_search_heaps_p->size)
+ (($arg0) < &($etp_search_heaps_p->mem)+$etp_search_heaps_p->used_size)
printf "process_tab[%d]->mbuf(%d)+%d\n", \
$etp_search_heaps_i, $etp_search_heaps_cnt, \
($arg0)-&($etp_search_heaps_p->mem)
@@ -3700,8 +3700,8 @@ define etp-overlapped-heaps
# Non-reentrant
#
printf "%% Dumping heap addresses to \"etp-commands.bin\"\n"
- set $etp_overlapped_heaps_q = erts_max_processes / 10
- set $etp_overlapped_heaps_r = erts_max_processes % 10
+ set $etp_overlapped_heaps_q = erts_proc.r.o.max / 10
+ set $etp_overlapped_heaps_r = erts_proc.r.o.max % 10
set $etp_overlapped_heaps_t = 10
set $etp_overlapped_heaps_m = $etp_overlapped_heaps_q
if $etp_overlapped_heaps_r > 0
@@ -3727,7 +3727,7 @@ define etp-overlapped-heaps
append binary value etp-commands.bin 'p'
append binary value etp-commands.bin 's'
append binary value etp-commands.bin '\0'
- while $etp_overlapped_heaps_i < erts_max_processes
+ while $etp_overlapped_heaps_i < erts_proc.r.o.max
if process_tab[$etp_overlapped_heaps_i]
append binary value etp-commands.bin \
(Eterm)$etp_overlapped_heaps_i
@@ -3868,7 +3868,7 @@ define etp-chart-entry-1
append binary value etp-commands.bin (Eterm)(($arg2)*sizeof(Eterm))
append binary value etp-commands.bin (Eterm)$etp_chart_id
append binary value etp-commands.bin (Eterm)($arg1)
-# printf "<dumped %#x %lu %lu %lu>", ($arg0)&~0x3, \
+# printf "<dumped %p %lu %lu %lu>", ($arg0)&~0x3, \
# (Eterm)(($arg2)*sizeof(Eterm)), (Eterm)$etp_chart_id, (Eterm)($arg1)
end
diff --git a/erts/preloaded/ebin/atomics.beam b/erts/preloaded/ebin/atomics.beam
index ef402b5fee..c74ce3ce2d 100644
--- a/erts/preloaded/ebin/atomics.beam
+++ b/erts/preloaded/ebin/atomics.beam
Binary files differ
diff --git a/erts/preloaded/ebin/counters.beam b/erts/preloaded/ebin/counters.beam
index 674d0d27fa..2aec433bcb 100644
--- a/erts/preloaded/ebin/counters.beam
+++ b/erts/preloaded/ebin/counters.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erl_init.beam b/erts/preloaded/ebin/erl_init.beam
index 0313988e3e..0c032e8e91 100644
--- a/erts/preloaded/ebin/erl_init.beam
+++ b/erts/preloaded/ebin/erl_init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index 661bcd8413..13fdd7908b 100644
--- a/erts/preloaded/ebin/erl_prim_loader.beam
+++ b/erts/preloaded/ebin/erl_prim_loader.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erl_tracer.beam b/erts/preloaded/ebin/erl_tracer.beam
index ec4d6153d1..16e17b870b 100644
--- a/erts/preloaded/ebin/erl_tracer.beam
+++ b/erts/preloaded/ebin/erl_tracer.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 62dc8702e7..866f9df79f 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam
index 669149df82..d81bc08282 100644
--- a/erts/preloaded/ebin/erts_code_purger.beam
+++ b/erts/preloaded/ebin/erts_code_purger.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam b/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam
index 6d3528c2dc..a8d492dfa5 100644
--- a/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam
+++ b/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
index b3af713809..dd08111aad 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_literal_area_collector.beam b/erts/preloaded/ebin/erts_literal_area_collector.beam
index fc2bf6f6bd..0f7dd6efbe 100644
--- a/erts/preloaded/ebin/erts_literal_area_collector.beam
+++ b/erts/preloaded/ebin/erts_literal_area_collector.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index 1d89174b25..942f29a11c 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/net.beam b/erts/preloaded/ebin/net.beam
index f61b2b4a69..88d546a3af 100644
--- a/erts/preloaded/ebin/net.beam
+++ b/erts/preloaded/ebin/net.beam
Binary files differ
diff --git a/erts/preloaded/ebin/persistent_term.beam b/erts/preloaded/ebin/persistent_term.beam
index c882e4fad4..7871b64991 100644
--- a/erts/preloaded/ebin/persistent_term.beam
+++ b/erts/preloaded/ebin/persistent_term.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_buffer.beam b/erts/preloaded/ebin/prim_buffer.beam
index cf671bf8f4..90d9596fe6 100644
--- a/erts/preloaded/ebin/prim_buffer.beam
+++ b/erts/preloaded/ebin/prim_buffer.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam
index 24911123f9..19935eeee3 100644
--- a/erts/preloaded/ebin/prim_eval.beam
+++ b/erts/preloaded/ebin/prim_eval.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index 0efd954e50..a2c5f2f336 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index ff9268ad38..b7c4cbe0a8 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam
index d319d7a343..bd51c3b271 100644
--- a/erts/preloaded/ebin/prim_zip.beam
+++ b/erts/preloaded/ebin/prim_zip.beam
Binary files differ
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index 558a886565..27efe10f38 100644
--- a/erts/preloaded/ebin/socket.beam
+++ b/erts/preloaded/ebin/socket.beam
Binary files differ
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index 9610c94ac2..8b7c5fe2ef 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/lib/compiler/src/beam_except.erl b/lib/compiler/src/beam_except.erl
index 28c89782c9..2305502800 100644
--- a/lib/compiler/src/beam_except.erl
+++ b/lib/compiler/src/beam_except.erl
@@ -140,8 +140,11 @@ fix_block_1([{set,[],[],{alloc,Live,{F1,F2,Needed0,F3}}}|Is], Words) ->
[{set,[],[],{alloc,Live,{F1,F2,Needed,F3}}}|Is]
end;
fix_block_1([I|Is], Words) ->
- [I|fix_block_1(Is, Words)].
-
+ [I|fix_block_1(Is, Words)];
+fix_block_1([], _Words) ->
+ %% Rare. The heap allocation was probably done by a binary
+ %% construction instruction.
+ [].
dig_out_fc(Arity, Is0) ->
Regs0 = maps:from_list([{{x,X},{arg,X}} || X <- seq(0, Arity-1)]),
diff --git a/lib/compiler/src/beam_ssa_codegen.erl b/lib/compiler/src/beam_ssa_codegen.erl
index c2d5035b19..07f4c8b461 100644
--- a/lib/compiler/src/beam_ssa_codegen.erl
+++ b/lib/compiler/src/beam_ssa_codegen.erl
@@ -1016,6 +1016,14 @@ bif_fail({catch_tag,_}) -> {f,0}.
next_block([]) -> none;
next_block([{Next,_}|_]) -> Next.
+%% Certain instructions (such as get_map_element or is_nonempty_list)
+%% are only used in guards and **must** have a non-zero label;
+%% otherwise, the loader will refuse to load the
+%% module. ensure_label/2 replaces a zero label with the "ultimate
+%% failure" label to make the module loadable. The instruction that
+%% have had the zero label replaced is **not** supposed to ever fail
+%% and actually jump to the label.
+
ensure_label(Fail0, #cg{ultimate_fail=Lbl}) ->
case bif_fail(Fail0) of
{f,0} -> {f,Lbl};
@@ -1160,6 +1168,11 @@ cg_block([#cg_set{op=call}=I,
#cg_set{op=succeeded,dst=Bool}], {Bool,_Fail}, St) ->
%% A call in try/catch block.
cg_block([I], none, St);
+cg_block([#cg_set{op=get_map_element,dst=Dst0,args=Args0},
+ #cg_set{op=succeeded,dst=Bool}], {Bool,Fail0}, St) ->
+ [Dst,Map,Key] = beam_args([Dst0|Args0], St),
+ Fail = ensure_label(Fail0, St),
+ {[{get_map_elements,Fail,Map,{list,[Key,Dst]}}],St};
cg_block([#cg_set{op=Op,dst=Dst0,args=Args0}=I,
#cg_set{op=succeeded,dst=Bool}], {Bool,Fail}, St) ->
[Dst|Args] = beam_args([Dst0|Args0], St),
@@ -1606,8 +1619,6 @@ cg_test({float,Op0}, Fail, Args, Dst, #cg_set{anno=Anno}) ->
'/' -> fdiv
end,
[line(Anno),{bif,Op,Fail,Args,Dst}];
-cg_test(get_map_element, Fail, [Map,Key], Dst, _I) ->
- [{get_map_elements,Fail,Map,{list,[Key,Dst]}}];
cg_test(peek_message, Fail, [], Dst, _I) ->
[{loop_rec,Fail,{x,0}}|copy({x,0}, Dst)];
cg_test(put_map, Fail, [{atom,exact},SrcMap|Ss], Dst, Set) ->
diff --git a/lib/compiler/src/beam_ssa_dead.erl b/lib/compiler/src/beam_ssa_dead.erl
index bb43a550ae..64b9b3e222 100644
--- a/lib/compiler/src/beam_ssa_dead.erl
+++ b/lib/compiler/src/beam_ssa_dead.erl
@@ -436,8 +436,22 @@ get_phi_arg([{Val,From}|_], From) -> Val;
get_phi_arg([_|As], From) -> get_phi_arg(As, From).
eval_terminator(#b_br{bool=#b_var{}=Bool}=Br, Bs, _St) ->
- Val = get_value(Bool, Bs),
- beam_ssa:normalize(Br#b_br{bool=Val});
+ case get_value(Bool, Bs) of
+ #b_literal{val=Val}=Lit ->
+ case is_boolean(Val) of
+ true ->
+ beam_ssa:normalize(Br#b_br{bool=Lit});
+ false ->
+ %% Non-boolean literal. This means that this `br`
+ %% terminator will never actually be reached with
+ %% these bindings. (There must be a previous two-way
+ %% branch that branches the other way when Bool
+ %% is bound to a non-boolean literal.)
+ none
+ end;
+ #b_var{}=Var ->
+ beam_ssa:normalize(Br#b_br{bool=Var})
+ end;
eval_terminator(#b_br{bool=#b_literal{}}=Br, _Bs, _St) ->
beam_ssa:normalize(Br);
eval_terminator(#b_switch{arg=Arg,fail=Fail,list=List}=Sw, Bs, St) ->
@@ -680,11 +694,8 @@ will_succeed_test(is_list, is_nonempty_list) ->
maybe;
will_succeed_test(is_nonempty_list, is_list) ->
yes;
-will_succeed_test(T1, T2) ->
- case is_numeric_test(T1) andalso is_numeric_test(T2) of
- true -> maybe;
- false -> no
- end.
+will_succeed_test(_T1, _T2) ->
+ maybe.
will_succeed_1('=:=', A, '<', B) ->
if
@@ -769,11 +780,6 @@ will_succeed_vars('==', Val1, '/=', Val2) when Val1 == Val2 -> no;
will_succeed_vars(_, _, _, _) -> maybe.
-is_numeric_test(is_float) -> true;
-is_numeric_test(is_integer) -> true;
-is_numeric_test(is_number) -> true;
-is_numeric_test(_) -> false.
-
eval_type_test(Test, Arg) ->
case eval_type_test_1(Test, Arg) of
true -> yes;
diff --git a/lib/compiler/src/beam_ssa_type.erl b/lib/compiler/src/beam_ssa_type.erl
index 2ea7e89dfa..57fd7fec60 100644
--- a/lib/compiler/src/beam_ssa_type.erl
+++ b/lib/compiler/src/beam_ssa_type.erl
@@ -23,7 +23,7 @@
-include("beam_ssa_opt.hrl").
-import(lists, [all/2,any/2,droplast/1,foldl/3,last/1,member/2,
- keyfind/3,partition/2,reverse/1,reverse/2,
+ keyfind/3,reverse/1,reverse/2,
sort/1,split/2]).
-define(UNICODE_INT, #t_integer{elements={0,16#10FFFF}}).
@@ -896,11 +896,15 @@ type(call, [#b_remote{mod=#b_literal{val=Mod},
{_,_} ->
#t_tuple{}
end;
- {erlang,'++',[List1,List2]} ->
- case get_type(List1, Ts) =:= cons orelse
- get_type(List2, Ts) =:= cons of
- true -> cons;
- false -> list
+ {erlang,'++',[LHS,RHS]} ->
+ LType = get_type(LHS, Ts),
+ RType = get_type(RHS, Ts),
+ case LType =:= cons orelse RType =:= cons of
+ true ->
+ cons;
+ false ->
+ %% `[] ++ RHS` yields RHS, even if RHS is not a list.
+ join(list, RType)
end;
{erlang,'--',[_,_]} ->
list;
@@ -1388,24 +1392,11 @@ get_type(#b_literal{val=Val}, _Ts) ->
%% type for L. For example, if L was known to be 'list', subtracting
%% 'cons' would give 'nil' as the only possible type. The result of the
%% subtraction for L will be added to FailTypes.
-%%
-%% Here is another example, asking about the variable Bool:
-%%
-%% Head = bif:hd L
-%% Bool = succeeded Head
-%%
-%% 'succeeded Head' will evaluate to 'true' if the instrution that
-%% defined Head succeeded. In this case, it is the 'bif:hd L'
-%% instruction, which will succeed if L is 'cons'. Thus, the meet of
-%% the previous type for L and 'cons' will be added to SuccTypes.
-%%
-%% If 'succeeded Head' evaluates to 'false', it means that 'bif:hd L'
-%% failed and that L is not 'cons'. 'cons' can be subtracted from the
-%% previously known type for L and the result put in FailTypes.
infer_types_br(#b_var{}=V, Ts, #d{ds=Ds}) ->
#{V:=#b_set{op=Op,args=Args}} = Ds,
- Types0 = infer_type(Op, Args, Ds),
+ PosTypes0 = infer_type(Op, Args, Ds),
+ NegTypes0 = infer_type_negative(Op, Args, Ds),
%% We must be careful with types inferred from '=:='.
%%
@@ -1416,13 +1407,17 @@ infer_types_br(#b_var{}=V, Ts, #d{ds=Ds}) ->
%%
%% However, it is safe to subtract a type inferred from '=:=' if
%% it is single-valued, e.g. if it is [] or the atom 'true'.
- EqTypes0 = infer_eq_type(Op, Args, Ts, Ds),
- {Types1,EqTypes} = partition(fun({_,T}) ->
- is_singleton_type(T)
- end, EqTypes0),
- Types = Types1 ++ Types0,
- {meet_types(EqTypes++Types, Ts),subtract_types(Types, Ts)}.
+ EqTypes = infer_eq_type(Op, Args, Ts, Ds),
+ NegTypes1 = [P || {_,T}=P <- EqTypes, is_singleton_type(T)],
+
+ PosTypes = EqTypes ++ PosTypes0,
+ SuccTs = meet_types(PosTypes, Ts),
+
+ NegTypes = NegTypes0 ++ NegTypes1,
+ FailTs = subtract_types(NegTypes, Ts),
+
+ {SuccTs,FailTs}.
infer_types_switch(V, Lit, Ts, #d{ds=Ds}) ->
Types = infer_eq_type({bif,'=:='}, [V, Lit], Ts, Ds),
@@ -1457,6 +1452,19 @@ infer_eq_lit(#b_set{op=get_tuple_element,
[{Tuple,#t_tuple{size=Index,elements=Es}}];
infer_eq_lit(_, _) -> [].
+infer_type_negative(Op, Args, Ds) ->
+ case is_negative_inference_safe(Op, Args) of
+ true ->
+ infer_type(Op, Args, Ds);
+ false ->
+ []
+ end.
+
+%% Conservative list of instructions for which negative
+%% inference is safe.
+is_negative_inference_safe(is_nonempty_list, _Args) -> true;
+is_negative_inference_safe(_, _) -> false.
+
infer_type({bif,element}, [#b_literal{val=Pos},#b_var{}=Tuple], _Ds) ->
if
is_integer(Pos), 1 =< Pos ->
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 09a5a6c104..ebe9631e09 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -2844,10 +2844,14 @@ call_return_type_1(erlang, setelement, 3, Vst) ->
setelement(3, TupleType, #{})
end;
call_return_type_1(erlang, '++', 2, Vst) ->
- case get_term_type({x,0}, Vst) =:= cons orelse
- get_term_type({x,1}, Vst) =:= cons of
- true -> cons;
- false -> list
+ LType = get_term_type({x,0}, Vst),
+ RType = get_term_type({x,1}, Vst),
+ case LType =:= cons orelse RType =:= cons of
+ true ->
+ cons;
+ false ->
+ %% `[] ++ RHS` yields RHS, even if RHS is not a list
+ join(list, RType)
end;
call_return_type_1(erlang, '--', 2, _Vst) ->
list;
diff --git a/lib/compiler/test/beam_except_SUITE.erl b/lib/compiler/test/beam_except_SUITE.erl
index 8e3b373d29..67947dc292 100644
--- a/lib/compiler/test/beam_except_SUITE.erl
+++ b/lib/compiler/test/beam_except_SUITE.erl
@@ -21,7 +21,8 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
- multiple_allocs/1,bs_get_tail/1,coverage/1]).
+ multiple_allocs/1,bs_get_tail/1,coverage/1,
+ binary_construction_allocation/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -32,7 +33,8 @@ groups() ->
[{p,[parallel],
[multiple_allocs,
bs_get_tail,
- coverage]}].
+ coverage,
+ binary_construction_allocation]}].
init_per_suite(Config) ->
test_lib:recompile(?MODULE),
@@ -118,6 +120,20 @@ coverage(_) ->
fake_function_clause(A) -> error(function_clause, [A,42.0]).
+
+binary_construction_allocation(_Config) ->
+ ok = do_binary_construction_allocation("PUT"),
+ ok.
+
+do_binary_construction_allocation(Req) ->
+ %% Allocation for building the error term was done by the
+ %% bs_init2 instruction. beam_except crashed because it expected
+ %% an explicit allocation instruction.
+ ok = case Req of
+ "POST" -> {error, <<"BAD METHOD ", Req/binary>>, Req};
+ _ -> ok
+ end.
+
id(I) -> I.
-file("fake.erl", 1).
diff --git a/lib/compiler/test/beam_ssa_SUITE.erl b/lib/compiler/test/beam_ssa_SUITE.erl
index 15cf9bcbf3..a741ebbdf9 100644
--- a/lib/compiler/test/beam_ssa_SUITE.erl
+++ b/lib/compiler/test/beam_ssa_SUITE.erl
@@ -22,7 +22,8 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
calls/1,tuple_matching/1,recv/1,maps/1,
- cover_ssa_dead/1,combine_sw/1,share_opt/1]).
+ cover_ssa_dead/1,combine_sw/1,share_opt/1,
+ beam_ssa_dead_crash/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -37,7 +38,8 @@ groups() ->
maps,
cover_ssa_dead,
combine_sw,
- share_opt
+ share_opt,
+ beam_ssa_dead_crash
]}].
init_per_suite(Config) ->
@@ -492,6 +494,60 @@ do_share_opt(A) ->
end,
receive after 1 -> ok end.
+beam_ssa_dead_crash(_Config) ->
+ not_A_B = do_beam_ssa_dead_crash(id(false), id(true)),
+ not_A_not_B = do_beam_ssa_dead_crash(false, false),
+ neither = do_beam_ssa_dead_crash(true, false),
+ neither = do_beam_ssa_dead_crash(true, true),
+ ok.
+
+do_beam_ssa_dead_crash(A, B) ->
+ %% beam_ssa_dead attempts to shortcut branches that branch other
+ %% branches. When a two-way branch is encountered, beam_ssa_dead
+ %% will simulate execution along both paths, in the hope that both
+ %% paths happens to end up in the same place.
+ %%
+ %% During the simulated execution of this function, the boolean
+ %% varible for a `br` instruction would be replaced with the
+ %% literal atom `nil`, which is not allowed, and would crash the
+ %% compiler. In practice, during the actual execution, control
+ %% would never be transferred to that `br` instruction when the
+ %% variable in question had the value `nil`.
+ %%
+ %% beam_ssa_dead has been updated to immediately abort the search
+ %% along the current path if there is an attempt to substitute a
+ %% non-boolean value into a `br` instruction.
+
+ case
+ case not A of
+ false ->
+ false;
+ true ->
+ B
+ end
+ of
+ V
+ when
+ V /= nil
+ andalso
+ V /= false ->
+ not_A_B;
+ _ ->
+ case
+ case not A of
+ false ->
+ false;
+ true ->
+ not B
+ end
+ of
+ true ->
+ not_A_not_B;
+ false ->
+ neither
+ end
+ end.
+
%% The identity function.
id(I) -> I.
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
index 0d1680fb15..2297c2e0f5 100644
--- a/lib/compiler/test/beam_type_SUITE.erl
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -24,7 +24,7 @@
integers/1,numbers/1,coverage/1,booleans/1,setelement/1,
cons/1,tuple/1,record_float/1,binary_float/1,float_compare/1,
arity_checks/1,elixir_binaries/1,find_best/1,
- test_size/1,cover_lists_functions/1]).
+ test_size/1,cover_lists_functions/1,list_append/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -47,7 +47,8 @@ groups() ->
elixir_binaries,
find_best,
test_size,
- cover_lists_functions
+ cover_lists_functions,
+ list_append
]}].
init_per_suite(Config) ->
@@ -501,5 +502,11 @@ cover_lists_functions(Config) ->
true = is_list(Zipped),
ok.
+list_append(_Config) ->
+ %% '++'/2 has a quirk where it returns the right-hand argument as-is when
+ %% the left-hand is [].
+ hello = id([]) ++ id(hello),
+ ok.
+
id(I) ->
I.
diff --git a/lib/compiler/test/core_SUITE.erl b/lib/compiler/test/core_SUITE.erl
index e5611e99d1..72016c6d76 100644
--- a/lib/compiler/test/core_SUITE.erl
+++ b/lib/compiler/test/core_SUITE.erl
@@ -29,7 +29,8 @@
bs_shadowed_size_var/1,
cover_v3_kernel_1/1,cover_v3_kernel_2/1,cover_v3_kernel_3/1,
cover_v3_kernel_4/1,cover_v3_kernel_5/1,
- non_variable_apply/1,name_capture/1,fun_letrec_effect/1]).
+ non_variable_apply/1,name_capture/1,fun_letrec_effect/1,
+ get_map_element/1]).
-include_lib("common_test/include/ct.hrl").
@@ -57,7 +58,8 @@ groups() ->
bs_shadowed_size_var,
cover_v3_kernel_1,cover_v3_kernel_2,cover_v3_kernel_3,
cover_v3_kernel_4,cover_v3_kernel_5,
- non_variable_apply,name_capture,fun_letrec_effect
+ non_variable_apply,name_capture,fun_letrec_effect,
+ get_map_element
]}].
@@ -95,6 +97,7 @@ end_per_group(_GroupName, Config) ->
?comp(non_variable_apply).
?comp(name_capture).
?comp(fun_letrec_effect).
+?comp(get_map_element).
try_it(Mod, Conf) ->
Src = filename:join(proplists:get_value(data_dir, Conf),
diff --git a/lib/compiler/test/core_SUITE_data/get_map_element.core b/lib/compiler/test/core_SUITE_data/get_map_element.core
new file mode 100644
index 0000000000..092b5e71eb
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/get_map_element.core
@@ -0,0 +1,18 @@
+module 'get_map_element' ['get_map_element'/0]
+attributes []
+
+'get_map_element'/0 =
+ fun () ->
+ apply 'match_map'/1(~{'foo'=>'bar'}~)
+
+'match_map'/1 =
+ fun (_0) ->
+ case _0 of
+ <~{'foo':='bar'}~> when 'true' ->
+ 'ok'
+ %% It will be undefined behaviour at runtime if no
+ %% clause of the case can be selected. That can't
+ %% happen for this module, because match_map/1 is
+ %% always called with a matching map argument.
+ end
+end
diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl
index ed0a56f064..cea7a374cd 100644
--- a/lib/compiler/test/guard_SUITE.erl
+++ b/lib/compiler/test/guard_SUITE.erl
@@ -35,7 +35,8 @@
basic_andalso_orelse/1,traverse_dcd/1,
check_qlc_hrl/1,andalso_semi/1,t_tuple_size/1,binary_part/1,
bad_constants/1,bad_guards/1,
- guard_in_catch/1,beam_bool_SUITE/1]).
+ guard_in_catch/1,beam_bool_SUITE/1,
+ repeated_type_tests/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -53,7 +54,8 @@ groups() ->
rel_ops,rel_op_combinations,
literal_type_tests,basic_andalso_orelse,traverse_dcd,
check_qlc_hrl,andalso_semi,t_tuple_size,binary_part,
- bad_constants,bad_guards,guard_in_catch,beam_bool_SUITE]}].
+ bad_constants,bad_guards,guard_in_catch,beam_bool_SUITE,
+ repeated_type_tests]}].
init_per_suite(Config) ->
test_lib:recompile(?MODULE),
@@ -2261,6 +2263,25 @@ maps() ->
evidence(#{0 := Charge}) when 0; #{[] => Charge} == #{[] => 42} ->
ok.
+repeated_type_tests(_Config) ->
+ binary = repeated_type_test(<<42>>),
+ bitstring = repeated_type_test(<<1:1>>),
+ other = repeated_type_test(atom),
+ ok.
+
+repeated_type_test(T) ->
+ %% Test for a bug in beam_ssa_dead.
+ if is_bitstring(T) ->
+ if is_binary(T) -> %This test would be optimized away.
+ binary;
+ true ->
+ bitstring
+ end;
+ true ->
+ other
+ end.
+
+
%% Call this function to turn off constant propagation.
id(I) -> I.
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index 7faef93609..964ede9bc9 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -19,6 +19,8 @@
%%
-module(code).
+-include_lib("kernel/include/logger.hrl").
+
%% This is the interface module to the code server. It also contains
%% some implementation details. See also related modules: code_*.erl
%% in this directory.
@@ -707,8 +709,20 @@ do_s(Lib) ->
start_get_mode() ->
case init:get_argument(mode) of
- {ok,[["embedded"]]} ->
- embedded;
+ {ok, [FirstMode | Rest]} ->
+ case Rest of
+ [] ->
+ ok;
+ _ ->
+ ?LOG_WARNING("Multiple -mode given to erl, using the first, ~p",
+ [FirstMode])
+ end,
+ case FirstMode of
+ ["embedded"] ->
+ embedded;
+ _ ->
+ interactive
+ end;
_ ->
interactive
end.
diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl
index bc4f09a023..c8c631ab23 100644
--- a/lib/kernel/src/kernel.erl
+++ b/lib/kernel/src/kernel.erl
@@ -141,7 +141,7 @@ init([]) ->
modules => [logger_sup]},
case init:get_argument(mode) of
- {ok, [["minimal"]]} ->
+ {ok, [["minimal"]|_]} ->
{ok, {SupFlags,
[Code, File, StdError, User, LoggerSup, Config, RefC, SafeSup]}};
_ ->
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 4f0847084f..6b133f8d6b 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -41,7 +41,7 @@
big_boot_embedded/1,
module_status/1,
native_early_modules/1, get_mode/1,
- normalized_paths/1]).
+ normalized_paths/1, mult_embedded_flags/1]).
-export([init_per_testcase/2, end_per_testcase/2,
init_per_suite/1, end_per_suite/1]).
@@ -72,7 +72,8 @@ all() ->
on_load_purge, on_load_self_call, on_load_pending,
on_load_deleted,
module_status,
- big_boot_embedded, native_early_modules, get_mode, normalized_paths].
+ big_boot_embedded, native_early_modules, get_mode, normalized_paths,
+ mult_embedded_flags].
%% These need to run in order
groups() -> [{sequence, [sequence], [on_load_update,
@@ -354,7 +355,7 @@ load_abs(Config) when is_list(Config) ->
ensure_loaded(Config) when is_list(Config) ->
{module, lists} = code:ensure_loaded(lists),
case init:get_argument(mode) of
- {ok, [["embedded"]]} ->
+ {ok, [["embedded"] | _]} ->
{error, embedded} = code:ensure_loaded(code_b_test),
{error, badarg} = code:ensure_loaded(34),
ok;
@@ -1836,6 +1837,28 @@ do_normalized_paths([M|Ms]) ->
do_normalized_paths([]) ->
ok.
+%% Make sure that the extra -mode flags are ignored
+mult_embedded_flags(_Config) ->
+ Modes = [{" -mode embedded", embedded},
+ {" -mode interactive", interactive},
+ {" -mode invalid", interactive}],
+
+ [ begin
+ {ArgMode, ExpectedMode} = Mode,
+ {ok, Node} = start_node(mode_test, ArgMode),
+ ExpectedMode = rpc:call(Node, code, get_mode, []),
+ true = stop_node(Node)
+ end || Mode <- Modes],
+
+ [ begin
+ {ArgIgnoredMode, _} = IgnoredMode,
+ {ArgRelevantMode, ExpectedMode} = RelevantMode,
+ {ok, Node} = start_node(mode_test, ArgRelevantMode ++ ArgIgnoredMode),
+ ExpectedMode = rpc:call(Node, code, get_mode, []),
+ true = stop_node(Node)
+ end || IgnoredMode <- Modes, RelevantMode <- Modes],
+ ok.
+
%% Test that module_status/1 behaves as expected
module_status(_Config) ->
case test_server:is_cover() of
diff --git a/lib/public_key/src/pubkey_pbe.erl b/lib/public_key/src/pubkey_pbe.erl
index e6bcedd1b1..38b5c93521 100644
--- a/lib/public_key/src/pubkey_pbe.erl
+++ b/lib/public_key/src/pubkey_pbe.erl
@@ -74,7 +74,7 @@ decode(Data, Password,"AES-256-CBC"= Cipher, KeyDevParams) ->
%%--------------------------------------------------------------------
--spec pbdkdf1(string(), iodata(), integer(), atom()) -> binary().
+-spec pbdkdf1(iodata(), iodata(), integer(), atom()) -> binary().
%%
%% Description: Implements password based decryption key derive function 1.
%% Exported mainly for testing purposes.
@@ -86,7 +86,7 @@ pbdkdf1(Password, Salt, Count, Hash) ->
do_pbdkdf1(Result, Count-1, Result, Hash).
%%--------------------------------------------------------------------
--spec pbdkdf2(string(), iodata(), integer(), integer(), fun(), atom(), integer())
+-spec pbdkdf2(iodata(), iodata(), integer(), integer(), fun(), atom(), integer())
-> binary().
%%
%% Description: Implements password based decryption key derive function 2.
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 6af65e09f2..f99c0e2b7a 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -125,7 +125,9 @@
protocol_extensions/0,
session_id/0,
error_alert/0,
- srp_param_type/0]).
+ tls_alert/0,
+ srp_param_type/0,
+ named_curve/0]).
%% -------------------------------------------------------------------------------------------------------
@@ -192,6 +194,7 @@
| rsa_pss_pss_sha512
| rsa_pkcs1_sha1
| ecdsa_sha1.
+
-type kex_algo() :: rsa |
dhe_rsa | dhe_dss |
ecdhe_ecdsa | ecdh_ecdsa | ecdh_rsa |
@@ -236,7 +239,7 @@
sect163r2 |
secp160k1 |
secp160r1 |
- secp160r2.
+ secp160r2. % exported
-type group() :: secp256r1 | secp384r1 | secp521r1 | ffdhe2048 |
ffdhe3072 | ffdhe4096 | ffdhe6144 | ffdhe8192.
@@ -279,7 +282,7 @@
bad_certificate_status_response |
bad_certificate_hash_value |
unknown_psk_identity |
- no_application_protocol.
+ no_application_protocol. % exported
%% -------------------------------------------------------------------------------------------------------
-type common_option() :: {protocol, protocol()} |
diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl
index 06b1b005a5..2d57b72f7b 100644
--- a/lib/ssl/src/ssl_alert.erl
+++ b/lib/ssl/src/ssl_alert.erl
@@ -32,7 +32,11 @@
-include("ssl_record.hrl").
-include("ssl_internal.hrl").
--export([decode/1, own_alert_txt/1, alert_txt/1, reason_code/2]).
+-export([decode/1,
+ own_alert_txt/1,
+ alert_txt/1,
+ alert_txt/4,
+ reason_code/4]).
%%====================================================================
%% Internal application API
@@ -48,20 +52,29 @@ decode(Bin) ->
decode(Bin, [], 0).
%%--------------------------------------------------------------------
-%% -spec reason_code(#alert{}, client | server) ->
-%% {tls_alert, unicode:chardata()} | closed.
-%-spec reason_code(#alert{}, client | server) -> closed | {essl, string()}.
+-spec reason_code(#alert{}, client | server, ProtocolName::string(), StateName::atom()) ->
+ {tls_alert, {atom(), unicode:chardata()}} | closed.
%%
%% Description: Returns the error reason that will be returned to the
%% user.
%%--------------------------------------------------------------------
-reason_code(#alert{description = ?CLOSE_NOTIFY}, _) ->
+reason_code(#alert{description = ?CLOSE_NOTIFY}, _, _, _) ->
closed;
-reason_code(#alert{description = Description, role = Role} = Alert, Role) ->
- {tls_alert, {description_atom(Description), own_alert_txt(Alert)}};
-reason_code(#alert{description = Description} = Alert, Role) ->
- {tls_alert, {description_atom(Description), alert_txt(Alert#alert{role = Role})}}.
+reason_code(#alert{description = Description, role = Role} = Alert, Role, ProtocolName, StateName) ->
+ Txt = lists:flatten(alert_txt(ProtocolName, Role, StateName, own_alert_txt(Alert))),
+ {tls_alert, {description_atom(Description), Txt}};
+reason_code(#alert{description = Description} = Alert, Role, ProtocolName, StateName) ->
+ Txt = lists:flatten(alert_txt(ProtocolName, Role, StateName, alert_txt(Alert))),
+ {tls_alert, {description_atom(Description), Txt}}.
+
+%%--------------------------------------------------------------------
+-spec alert_txt(string(), server | client, StateNam::atom(), string()) -> string().
+%%
+%% Description: Generates alert text for log or string part of error return.
+%%--------------------------------------------------------------------
+alert_txt(ProtocolName, Role, StateName, Txt) ->
+ io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]).
%%--------------------------------------------------------------------
-spec own_alert_txt(#alert{}) -> string().
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 345db7510f..7047c01657 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -328,34 +328,33 @@ prf(ConnectionPid, Secret, Label, Seed, WantedLength) ->
%%====================================================================
%% Alert and close handling
%%====================================================================
-handle_own_alert(Alert, _, StateName,
+handle_own_alert(Alert0, _, StateName,
#state{static_env = #static_env{role = Role,
protocol_cb = Connection},
ssl_options = SslOpts} = State) ->
try %% Try to tell the other side
- send_alert(Alert, StateName, State)
+ send_alert(Alert0, StateName, State)
catch _:_ -> %% Can crash if we are in a uninitialized state
ignore
end,
try %% Try to tell the local user
- log_alert(SslOpts#ssl_options.log_level, Role,
- Connection:protocol_name(), StateName,
- Alert#alert{role = Role}),
+ Alert = Alert0#alert{role = Role},
+ log_alert(SslOpts#ssl_options.log_level, Role, Connection:protocol_name(), StateName, Alert),
handle_normal_shutdown(Alert,StateName, State)
catch _:_ ->
ok
end,
{stop, {shutdown, own_alert}, State}.
-handle_normal_shutdown(Alert, _, #state{static_env = #static_env{role = Role,
- socket = Socket,
- transport_cb = Transport,
- protocol_cb = Connection,
- tracker = Tracker},
- handshake_env = #handshake_env{renegotiation = {false, first}},
- start_or_recv_from = StartFrom} = State) ->
+handle_normal_shutdown(Alert, StateName, #state{static_env = #static_env{role = Role,
+ socket = Socket,
+ transport_cb = Transport,
+ protocol_cb = Connection,
+ tracker = Tracker},
+ handshake_env = #handshake_env{renegotiation = {false, first}},
+ start_or_recv_from = StartFrom} = State) ->
Pids = Connection:pids(State),
- alert_user(Pids, Transport, Tracker,Socket, StartFrom, Alert, Role, Connection);
+ alert_user(Pids, Transport, Tracker,Socket, StartFrom, Alert, Role, StateName, Connection);
handle_normal_shutdown(Alert, StateName, #state{static_env = #static_env{role = Role,
socket = Socket,
@@ -366,9 +365,9 @@ handle_normal_shutdown(Alert, StateName, #state{static_env = #static_env{role =
socket_options = Opts,
start_or_recv_from = RecvFrom} = State) ->
Pids = Connection:pids(State),
- alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, RecvFrom, Alert, Role, Connection).
+ alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, RecvFrom, Alert, Role, StateName, Connection).
-handle_alert(#alert{level = ?FATAL} = Alert, StateName,
+handle_alert(#alert{level = ?FATAL} = Alert0, StateName,
#state{static_env = #static_env{role = Role,
socket = Socket,
host = Host,
@@ -382,11 +381,11 @@ handle_alert(#alert{level = ?FATAL} = Alert, StateName,
session = Session,
socket_options = Opts} = State) ->
invalidate_session(Role, Host, Port, Session),
+ Alert = Alert0#alert{role = opposite_role(Role)},
log_alert(SslOpts#ssl_options.log_level, Role, Connection:protocol_name(),
- StateName, Alert#alert{role = opposite_role(Role)}),
+ StateName, Alert),
Pids = Connection:pids(State),
- alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, From, Alert,
- opposite_role(Role), Connection),
+ alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, From, Alert, Role, StateName, Connection),
{stop, {shutdown, normal}, State};
handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
@@ -396,13 +395,14 @@ handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
StateName, State) ->
handle_normal_shutdown(Alert, StateName, State),
{stop,{shutdown, peer_close}, State};
-handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
+handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert0, StateName,
#state{static_env = #static_env{role = Role,
protocol_cb = Connection},
handshake_env = #handshake_env{renegotiation = {true, internal}},
ssl_options = SslOpts} = State) ->
+ Alert = Alert0#alert{role = opposite_role(Role)},
log_alert(SslOpts#ssl_options.log_level, Role,
- Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}),
+ Connection:protocol_name(), StateName, Alert),
handle_normal_shutdown(Alert, StateName, State),
{stop,{shutdown, peer_close}, State};
@@ -1445,7 +1445,7 @@ handle_info({ErrorTag, Socket, econnaborted}, StateName,
} = State) when StateName =/= connection ->
Pids = Connection:pids(State),
alert_user(Pids, Transport, Tracker,Socket,
- StartFrom, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role, Connection),
+ StartFrom, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role, StateName, Connection),
{stop, {shutdown, normal}, State};
handle_info({ErrorTag, Socket, Reason}, StateName, #state{static_env = #static_env{socket = Socket,
@@ -2907,22 +2907,22 @@ send_user(Pid, Msg) ->
Pid ! Msg,
ok.
-alert_user(Pids, Transport, Tracker, Socket, connection, Opts, Pid, From, Alert, Role, Connection) ->
- alert_user(Pids, Transport, Tracker, Socket, Opts#socket_options.active, Pid, From, Alert, Role, Connection);
-alert_user(Pids, Transport, Tracker, Socket,_, _, _, From, Alert, Role, Connection) ->
- alert_user(Pids, Transport, Tracker, Socket, From, Alert, Role, Connection).
+alert_user(Pids, Transport, Tracker, Socket, connection, Opts, Pid, From, Alert, Role, StateName, Connection) ->
+ alert_user(Pids, Transport, Tracker, Socket, Opts#socket_options.active, Pid, From, Alert, Role, StateName, Connection);
+alert_user(Pids, Transport, Tracker, Socket,_, _, _, From, Alert, Role, StateName, Connection) ->
+ alert_user(Pids, Transport, Tracker, Socket, From, Alert, Role, StateName, Connection).
-alert_user(Pids, Transport, Tracker, Socket, From, Alert, Role, Connection) ->
- alert_user(Pids, Transport, Tracker, Socket, false, no_pid, From, Alert, Role, Connection).
+alert_user(Pids, Transport, Tracker, Socket, From, Alert, Role, StateName, Connection) ->
+ alert_user(Pids, Transport, Tracker, Socket, false, no_pid, From, Alert, Role, StateName, Connection).
-alert_user(_, _, _, _, false = Active, Pid, From, Alert, Role, _) when From =/= undefined ->
+alert_user(_, _, _, _, false = Active, Pid, From, Alert, Role, StateName, Connection) when From =/= undefined ->
%% If there is an outstanding ssl_accept | recv
%% From will be defined and send_or_reply will
%% send the appropriate error message.
- ReasonCode = ssl_alert:reason_code(Alert, Role),
+ ReasonCode = ssl_alert:reason_code(Alert, Role, Connection:protocol_name(), StateName),
send_or_reply(Active, Pid, From, {error, ReasonCode});
-alert_user(Pids, Transport, Tracker, Socket, Active, Pid, From, Alert, Role, Connection) ->
- case ssl_alert:reason_code(Alert, Role) of
+alert_user(Pids, Transport, Tracker, Socket, Active, Pid, From, Alert, Role, StateName, Connection) ->
+ case ssl_alert:reason_code(Alert, Role, Connection:protocol_name(), StateName) of
closed ->
send_or_reply(Active, Pid, From,
{ssl_closed, Connection:socket(Pids, Transport, Socket, Tracker)});
@@ -2933,11 +2933,11 @@ alert_user(Pids, Transport, Tracker, Socket, Active, Pid, From, Alert, Role, Con
log_alert(Level, Role, ProtocolName, StateName, #alert{role = Role} = Alert) ->
Txt = ssl_alert:own_alert_txt(Alert),
- Report = io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]),
+ Report = ssl_alert:alert_txt(ProtocolName, Role, StateName, Txt),
ssl_logger:notice(Level, Report);
log_alert(Level, Role, ProtocolName, StateName, Alert) ->
Txt = ssl_alert:alert_txt(Alert),
- Report = io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]),
+ Report = ssl_alert:alert_txt(ProtocolName, Role, StateName, Txt),
ssl_logger:notice(Level, Report).
invalidate_session(client, Host, Port, Session) ->
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 3b161a0c8a..733ee993a8 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -429,14 +429,17 @@ check_result(Pid, Msg) ->
end.
check_server_alert(Pid, Alert) ->
receive
- {Pid, {error, {tls_alert, {Alert, _}}}} ->
+ {Pid, {error, {tls_alert, {Alert, STxt}}}} ->
+ check_server_txt(STxt),
ok
end.
check_server_alert(Server, Client, Alert) ->
receive
- {Server, {error, {tls_alert, {Alert, _}}}} ->
+ {Server, {error, {tls_alert, {Alert, STxt}}}} ->
+ check_server_txt(STxt),
receive
- {Client, {error, {tls_alert, {Alert, _}}}} ->
+ {Client, {error, {tls_alert, {Alert, CTxt}}}} ->
+ check_client_txt(CTxt),
ok;
{Client, {error, closed}} ->
ok
@@ -444,20 +447,35 @@ check_server_alert(Server, Client, Alert) ->
end.
check_client_alert(Pid, Alert) ->
receive
- {Pid, {error, {tls_alert, {Alert, _}}}} ->
+ {Pid, {error, {tls_alert, {Alert, CTxt}}}} ->
+ check_client_txt(CTxt),
ok
end.
check_client_alert(Server, Client, Alert) ->
receive
- {Client, {error, {tls_alert, {Alert, _}}}} ->
+ {Client, {error, {tls_alert, {Alert, CTxt}}}} ->
+ check_client_txt(CTxt),
receive
- {Server, {error, {tls_alert, {Alert, _}}}} ->
+ {Server, {error, {tls_alert, {Alert, STxt}}}} ->
+ check_server_txt(STxt),
ok;
{Server, {error, closed}} ->
ok
end
end.
+check_server_txt("TLS server" ++ _) ->
+ ok;
+check_server_txt("DTLS server" ++ _) ->
+ ok;
+check_server_txt(Txt) ->
+ ct:fail({expected_server, {got, Txt}}).
+check_client_txt("TLS client" ++ _) ->
+ ok;
+check_client_txt("DTLS client" ++ _) ->
+ ok;
+check_client_txt(Txt) ->
+ ct:fail({expected_server, {got, Txt}}).
wait_for_result(Server, ServerMsg, Client, ClientMsg) ->
receive
diff --git a/system/doc/system_principles/system_principles.xml b/system/doc/system_principles/system_principles.xml
index 500522d778..6986d93ed9 100644
--- a/system/doc/system_principles/system_principles.xml
+++ b/system/doc/system_principles/system_principles.xml
@@ -156,7 +156,8 @@ init:stop()</pre>
command-line flag <c>-mode</c>.</p>
<pre>
% <input>erl -mode embedded</input></pre>
- <p>Default mode is <c>interactive</c>.</p>
+ <p>Default mode is <c>interactive</c> and extra <c>-mode</c> flags are
+ ignored.</p>
<p>The mode properties are as follows:</p>
<list type="bulleted">
<item>In embedded mode, all code is loaded during system startup