diff options
Diffstat (limited to 'erts')
-rw-r--r-- | erts/doc/src/erl_ext_dist.xml | 251 | ||||
-rw-r--r-- | erts/doc/src/notes.xml | 218 | ||||
-rw-r--r-- | erts/emulator/beam/atom.c | 77 | ||||
-rw-r--r-- | erts/emulator/beam/atom.h | 8 | ||||
-rw-r--r-- | erts/emulator/beam/beam_emu.c | 35 | ||||
-rw-r--r-- | erts/emulator/beam/dist.c | 10 | ||||
-rw-r--r-- | erts/emulator/beam/erl_bif_trace.c | 29 | ||||
-rw-r--r-- | erts/emulator/beam/erl_proc_sig_queue.c | 18 | ||||
-rw-r--r-- | erts/emulator/beam/erl_process.c | 3 | ||||
-rw-r--r-- | erts/emulator/beam/erl_process.h | 5 | ||||
-rw-r--r-- | erts/emulator/beam/instrs.tab | 17 | ||||
-rw-r--r-- | erts/emulator/beam/msg_instrs.tab | 1 | ||||
-rw-r--r-- | erts/emulator/drivers/common/inet_drv.c | 190 | ||||
-rw-r--r-- | erts/emulator/sys/common/erl_check_io.c | 6 | ||||
-rw-r--r-- | erts/emulator/sys/unix/sys_drivers.c | 4 | ||||
-rw-r--r-- | erts/emulator/test/bif_SUITE.erl | 10 | ||||
-rw-r--r-- | erts/emulator/test/dirty_bif_SUITE.erl | 54 | ||||
-rw-r--r-- | erts/emulator/test/exception_SUITE.erl | 34 | ||||
-rw-r--r-- | erts/emulator/test/process_SUITE.erl | 86 | ||||
-rw-r--r-- | erts/preloaded/ebin/prim_inet.beam | bin | 82620 -> 83096 bytes | |||
-rw-r--r-- | erts/preloaded/src/prim_inet.erl | 97 | ||||
-rw-r--r-- | erts/vsn.mk | 2 |
22 files changed, 960 insertions, 195 deletions
diff --git a/erts/doc/src/erl_ext_dist.xml b/erts/doc/src/erl_ext_dist.xml index b7090d0472..5813af1d57 100644 --- a/erts/doc/src/erl_ext_dist.xml +++ b/erts/doc/src/erl_ext_dist.xml @@ -386,44 +386,6 @@ </section> <section> - <marker id="REFERENCE_EXT"/> - <title>REFERENCE_EXT</title> - <table align="left"> - <row> - <cell align="center">1</cell> - <cell align="center">N</cell> - <cell align="center">4</cell> - <cell align="center">1</cell> - </row> - <row> - <cell align="center"><c>101</c></cell> - <cell align="center"><c>Node</c></cell> - <cell align="center"><c>ID</c></cell> - <cell align="center"><c>Creation</c></cell> - </row> - <tcaption>REFERENCE_EXT</tcaption></table> - <p> - Encodes a reference object (an object generated with - <seealso marker="erlang:make_ref/0">erlang:make_ref/0</seealso>). - The <c>Node</c> term is an encoded atom, that is, - <seealso marker="#ATOM_UTF8_EXT"><c>ATOM_UTF8_EXT</c></seealso>, - <seealso marker="#SMALL_ATOM_UTF8_EXT"><c>SMALL_ATOM_UTF8_EXT</c></seealso>, or - <seealso marker="#ATOM_CACHE_REF"><c>ATOM_CACHE_REF</c></seealso>. - The <c>ID</c> field contains a big-endian unsigned integer, - but <em>is to be regarded as uninterpreted data</em>, - as this field is node-specific. - <c>Creation</c> is a byte containing a node serial number, which - makes it possible to separate old (crashed) nodes from a new one. - </p> - <p> - In <c>ID</c>, only 18 bits are significant; the rest are to be 0. - In <c>Creation</c>, only two bits are significant; the rest are to be 0. - See <seealso marker="#NEW_REFERENCE_EXT"> - <c>NEW_REFERENCE_EXT</c></seealso>. - </p> - </section> - - <section> <marker id="PORT_EXT"/> <title>PORT_EXT</title> <table align="left"> @@ -441,13 +403,46 @@ </row> <tcaption>PORT_EXT</tcaption></table> <p> - Encodes a port object (obtained from - <seealso marker="erlang:open_port/2"> - <c>erlang:open_port/2</c></seealso>). - The <c>ID</c> is a node-specific identifier for a local port. + Same as <seealso marker="#NEW_PORT_EXT"><c>NEW_PORT_EXT</c></seealso> + except the <c>Creation</c> field is only one byte and only two + bits are significant, the rest are to be 0. + </p> + </section> + + <section> + <marker id="NEW_PORT_EXT"/> + <title>NEW_PORT_EXT</title> + <table align="left"> + <row> + <cell align="center">1</cell> + <cell align="center">N</cell> + <cell align="center">4</cell> + <cell align="center">4</cell> + </row> + <row> + <cell align="center"><c>89</c></cell> + <cell align="center"><c>Node</c></cell> + <cell align="center"><c>ID</c></cell> + <cell align="center"><c>Creation</c></cell> + </row> + <tcaption>NEW_PORT_EXT</tcaption></table> + <p> + Encodes a port identifier (obtained from + <seealso marker="erlang#open_port/2"><c>erlang:open_port/2</c></seealso>). + <c>Node</c> is an encoded atom, that is, + <seealso marker="#ATOM_UTF8_EXT"><c>ATOM_UTF8_EXT</c></seealso>, + <seealso marker="#SMALL_ATOM_UTF8_EXT"><c>SMALL_ATOM_UTF8_EXT</c></seealso> + or <seealso marker="#ATOM_CACHE_REF"><c>ATOM_CACHE_REF</c></seealso>. + <c>ID</c> is a 32-bit big endian unsigned integer. Only 28 bits are + significant; the rest are to be 0. The <c>Creation</c> works just like in + <seealso marker="#NEW_PID_EXT"><c>NEW_PID_EXT</c></seealso>. Port operations are not allowed across node boundaries. - The <c>Creation</c> works just like in - <seealso marker="#REFERENCE_EXT"><c>REFERENCE_EXT</c></seealso>. + </p> + <p>Introduced in OTP 19, but only to be decoded and echoed back. Not + encoded for local ports. Planned to supersede <seealso marker="#PORT_EXT"> + <c>PORT_EXT</c></seealso> in OTP 23 when + <seealso marker="erl_dist_protocol#dflags"><c>DFLAG_BIG_CREATON</c></seealso> + becomes mandatory. </p> </section> @@ -471,12 +466,65 @@ </row> <tcaption>PID_EXT</tcaption></table> <p> - Encodes a process identifier object (obtained from - <seealso marker="erlang:spawn/3"><c>erlang:spawn/3</c></seealso> or - friends). The <c>ID</c> and <c>Creation</c> fields works just like in - <seealso marker="#REFERENCE_EXT"><c>REFERENCE_EXT</c></seealso>, while - the <c>Serial</c> field is used to improve safety. - In <c>ID</c>, only 15 bits are significant; the rest are to be 0. + Same as <seealso marker="#NEW_PID_EXT"><c>NEW_PID_EXT</c></seealso> + except the <c>Creation</c> field is only one byte and only two + bits are significant, the rest are to be 0. + </p> + </section> + + <section> + <marker id="NEW_PID_EXT"/> + <title>NEW_PID_EXT</title> + <table align="left"> + <row> + <cell align="center">1</cell> + <cell align="center">N</cell> + <cell align="center">4</cell> + <cell align="center">4</cell> + <cell align="center">4</cell> + </row> + <row> + <cell align="center"><c>88</c></cell> + <cell align="center"><c>Node</c></cell> + <cell align="center"><c>ID</c></cell> + <cell align="center"><c>Serial</c></cell> + <cell align="center"><c>Creation</c></cell> + </row> + <tcaption>NEW_PID_EXT</tcaption></table> + <p> + Encodes an Erlang process identifier object. + </p> + <taglist> + <tag><c>Node</c></tag> + <item><p>The name of the originating node, encoded using + <seealso marker="#ATOM_UTF8_EXT"><c>ATOM_UTF8_EXT</c></seealso>, + <seealso marker="#SMALL_ATOM_UTF8_EXT"><c>SMALL_ATOM_UTF8_EXT</c></seealso> + or <seealso + marker="#ATOM_CACHE_REF"><c>ATOM_CACHE_REF</c></seealso>.</p> + </item> + <tag><c>ID</c></tag> + <item><p>A 32-bit big endian unsigned integer. Only 15 bits are + significant; the rest are to be 0.</p> + </item> + <tag><c>Serial</c></tag> + <item><p>A 32-bit big endian unsigned integer. Only 13 bits are + significant; the rest are to be 0.</p> + </item> + <tag><c>Creation</c></tag> + <item><p>A 32-bit big endian unsigned integer. All identifiers + originating from the same node incarnation must have identical <c>Creation</c> + values. This makes it possible to separate identifiers from old + (crashed) nodes from a new one. The value zero should be avoided for + normal operations as it is used as a wild card for debug purpose + (like a pid returned by <seealso marker="erts:erlang#list_to_pid/1"> + erlang:list_to_pid/1</seealso>).</p> + </item> + </taglist> + <p>Introduced in OTP 19, but only to be decoded and echoed back. Not + encoded for local processes. Planned to supersede <seealso marker="#PID_EXT"> + <c>PID_EXT</c></seealso> in OTP 23 when + <seealso marker="erl_dist_protocol#dflags"><c>DFLAG_BIG_CREATON</c></seealso> + becomes mandatory. </p> </section> @@ -700,6 +748,30 @@ </section> <section> + <marker id="REFERENCE_EXT"/> + <title>REFERENCE_EXT (deprecated)</title> + <table align="left"> + <row> + <cell align="center">1</cell> + <cell align="center">N</cell> + <cell align="center">4</cell> + <cell align="center">1</cell> + </row> + <row> + <cell align="center"><c>101</c></cell> + <cell align="center"><c>Node</c></cell> + <cell align="center"><c>ID</c></cell> + <cell align="center"><c>Creation</c></cell> + </row> + <tcaption>REFERENCE_EXT</tcaption></table> + <p> + The same as <seealso marker="#NEW_REFERENCE_EXT"> + <c>NEW_REFERENCE_EXT</c></seealso> except <c>ID</c> is only one word + (<c>Len</c> = 1). + </p> + </section> + + <section> <marker id="NEW_REFERENCE_EXT"/> <title>NEW_REFERENCE_EXT</title> <table align="left"> @@ -719,29 +791,68 @@ </row> <tcaption>NEW_REFERENCE_EXT</tcaption></table> <p> - <c>Node</c> and <c>Creation</c> are as in - <seealso marker="#REFERENCE_EXT"><c>REFERENCE_EXT</c></seealso>. - </p> - <p> - <c>ID</c> contains a sequence of big-endian unsigned integers - (4 bytes each, so <c>N'</c> is a multiple of 4), - but is to be regarded as uninterpreted data. - </p> - <p> - <c>N'</c> = 4 * <c>Len</c>. - </p> - <p> - In the first word (4 bytes) of <c>ID</c>, only 18 bits are - significant, the rest are to be 0. - In <c>Creation</c>, only two bits are significant, - the rest are to be 0. + The same as <seealso marker="#NEWER_REFERENCE_EXT"> + <c>NEWER_REFERENCE_EXT</c></seealso> <em>except</em>: </p> + <taglist> + <tag><c>ID</c></tag> + <item><p>In the first word (4 bytes) of <c>ID</c>, only 18 bits are + significant, the rest must be 0.</p> + </item> + <tag><c>Creation</c></tag> + <item><p>Only one byte long and only two bits are significant, the rest must be 0.</p> + </item> + </taglist> + </section> + + <section> + <marker id="NEWER_REFERENCE_EXT"/> + <title>NEWER_REFERENCE_EXT</title> + <table align="left"> + <row> + <cell align="center">1</cell> + <cell align="center">2</cell> + <cell align="center">N</cell> + <cell align="center">4</cell> + <cell align="center">N'</cell> + </row> + <row> + <cell align="center"><c>90</c></cell> + <cell align="center"><c>Len</c></cell> + <cell align="center"><c>Node</c></cell> + <cell align="center"><c>Creation</c></cell> + <cell align="center"><c>ID ...</c></cell> + </row> + <tcaption>NEWER_REFERENCE_EXT</tcaption></table> <p> - <c>NEW_REFERENCE_EXT</c> was introduced with distribution version 4. - In version 4, <c>N'</c> is to be at most 12. + Encodes a reference term generated with + <seealso marker="erts:erlang#make_ref/0">erlang:make_ref/0</seealso>. </p> - <p> - See <seealso marker="#REFERENCE_EXT"><c>REFERENCE_EXT</c></seealso>. + <taglist> + <tag><c>Node</c></tag> + <item><p>The name of the originating node, encoded using + <seealso marker="#ATOM_UTF8_EXT"><c>ATOM_UTF8_EXT</c></seealso>, + <seealso marker="#SMALL_ATOM_UTF8_EXT"><c>SMALL_ATOM_UTF8_EXT</c></seealso> + or <seealso marker="#ATOM_CACHE_REF"><c>ATOM_CACHE_REF</c></seealso>.</p> + </item> + <tag><c>Len</c></tag> + <item><p>A 16-bit big endian unsigned integer not larger than 3.</p> + </item> + <tag><c>ID</c></tag> + <item><p>A sequence of <c>Len</c> big-endian unsigned integers + (4 bytes each, so <c>N'</c> = 4 * <c>Len</c>), + but is to be regarded as uninterpreted data.</p> + </item> + <tag><c>Creation</c></tag> + <item><p>Works just like in + <seealso marker="#NEW_PID_EXT"><c>NEW_PID_EXT</c></seealso>.</p> + </item> + </taglist> + <p>Introduced in OTP 19, but only to be decoded and echoed back. Not + encoded for local references. Planned to supersede <seealso marker="#NEW_REFERENCE_EXT"> + <c>NEW_REFERENCE_EXT</c></seealso> in OTP 23 when + <seealso marker="erl_dist_protocol#dflags"><c>DFLAG_BIG_CREATON</c></seealso> + becomes mandatory. </p> </section> diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index 5c45f8d83b..3c49853119 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -31,6 +31,224 @@ </header> <p>This document describes the changes made to the ERTS application.</p> +<section><title>Erts 10.3.5.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + If you set <c>{linger,{true,0}}</c> on a <c>gen_tcp</c> + listen socket, accept a connection on that socket, and + then close the accepted socket, now the linger zero + setting is transferred to the accepted socket. Before + this correction that information was lost and the close + behaviour on the accepted socket incorrect.</p> + <p> + Own Id: OTP-15370 Aux Id: ERIERL-353 </p> + </item> + <item> + <p> + Fixed <c>process_info(Pid,reductions)</c> to not + categorically increase reduction count of the measured + process <c>Pid</c>. Repeated reduction measure of an idle + process will most often (but not guaranteed) return the + same value, like it behaved before OTP 21.3.8.</p> + <p> + Own Id: OTP-15865 Aux Id: ERL-964 </p> + </item> + <item> + <p> + The runtime system disconnected a connection if it + received an <c>exit/2</c> signal where the recipient was + a process on an old incarnation of the current node. That + is, the receiving node had the same node name, but + another "creation" number. The signal will now just be + dropped since the receiving process no longer exists.</p> + <p> + Own Id: OTP-15867 Aux Id: ERIERL-373 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The possibility to send ancillary data, in particular the + TOS field, has been added to <c>gen_udp:send/4,5</c>.</p> + <p> + Own Id: OTP-15747 Aux Id: ERIERL-294 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 10.3.5.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>In nested use of <c>try</c>/<c>catch</c>, rethrowing + an exception using <c>erlang:raise/3</c> with a different + class would not always be able to change the class of the + exception.</p> + <p> + Own Id: OTP-15834 Aux Id: ERIERL-367 </p> + </item> + <item> + <p> + Fixed bug in <c>seq_trace:set_token(label,Term)</c> which + could cause VM crash if <c>Term</c> was heap allocated + (not an atom, small integer, local pid or port). Bug + exists since OTP 21.0 when terms other than small + integers were first allowed as labels.</p> + <p> + Own Id: OTP-15849 Aux Id: ERL-700 </p> + </item> + <item> + <p> + Fix <c>seq_trace:print/2</c> not to raise <c>badarg</c> + exception if label is not a small integer. Bug exists + since OTP 21.0.</p> + <p> + Own Id: OTP-15859 Aux Id: ERL-700 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 10.3.5.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>Fixed a buffer overflow when + <c>binary_to_existing_atom/2</c> and + <c>list_to_existing_atom/2</c> was used with the + <c>latin1</c> encoding.</p> + <p> + Own Id: OTP-15819 Aux Id: ERL-944 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 10.3.5</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed more bugs in <c>process_info(reductions)</c> + causing it to sometimes behave non-monotonic. That is, a + subsequent call toward the same process could return a + lower reduction value.</p> + <p> + Own Id: OTP-15793 Aux Id: ERIERL-337, OTP-15709 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 10.3.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>Add missing documentation of new external tags + <c>NEW_PID</c>, <c>NEW_PORT</c> and + <c>NEWER_REFERENCE</c> introduced in OTP 19.</p> <p>These + new tags are planned to be "activated" in OTP 23 when + distribution capability flag <c>DFLAG_BIG_CREATION</c> + becomes mandatory. Older nodes (>= 19) are able to decode + these new tags and send them back to the new node. Nodes + older than OTP 23 will however never encode their own + local pids, ports and references using the new tags.</p> + <p> + Own Id: OTP-15766</p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 10.3.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix <c>erlang:open_port/2</c> with the <c>fd</c> option + to correctly cleanup the pollset when the port is closed. + Before this fix there would be error printouts sent to + logger when the same fd was reused in a new port.</p> + <p> + Own Id: OTP-15753 Aux Id: ERL-900 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 10.3.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>Fixed a bug in <c>seq_trace:reset_trace/0</c> that + could crash the emulator.</p> + <p> + Own Id: OTP-15704</p> + </item> + <item> + <p> + Fixed bug in <c>process_info(reductions)</c> causing it + to sometimes return invalid results.</p> + <p> + Own Id: OTP-15709 Aux Id: ERIERL-337 </p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 10.3.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>If a suspend/resume signal pair was sent to a process + while it was executing dirty, the receiving process could + later end up in a suspended state indefinitely. This bug + was introduced in ERTS version 10.0 (OTP 21.0).</p> + <p>Suspend/resume signals are sent from <seealso + marker="erts:erlang#suspend_process/1"><c>erlang:suspend_process()</c></seealso>/<seealso + marker="erts:erlang#resume_process/1"><c>erlang:resume_process()</c></seealso>. + The <seealso + marker="runtime_tools:dbg"><c>dbg</c></seealso> trace + tool utilize this functionality and could thus trigger + this bug.</p> + <p> + Own Id: OTP-15688</p> + </item> + <item> + <p> + Fix a possible deadlock when terminating the ERTS caused + by a dirty scheduler not releasing it's run-queue lock + when terminating.</p> + <p> + Own Id: OTP-15690 Aux Id: PR-2172 </p> + </item> + </list> + </section> + +</section> + <section><title>Erts 10.3</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/erts/emulator/beam/atom.c b/erts/emulator/beam/atom.c index 59b51fd15e..5a70509ffd 100644 --- a/erts/emulator/beam/atom.c +++ b/erts/emulator/beam/atom.c @@ -200,11 +200,15 @@ atom_free(Atom* obj) ASSERT(obj->slot.index == atom_val(am_ErtsSecretAtom)); } -static void latin1_to_utf8(byte* conv_buf, const byte** srcp, int* lenp) +static void latin1_to_utf8(byte* conv_buf, Uint buf_sz, + const byte** srcp, Uint* lenp) { byte* dst; const byte* src = *srcp; - int i, len = *lenp; + Uint i, len = *lenp; + + ASSERT(len <= MAX_ATOM_CHARACTERS); + ASSERT(buf_sz >= MAX_ATOM_SZ_FROM_LATIN1); for (i=0 ; i < len; ++i) { if (src[i] & 0x80) { @@ -234,11 +238,11 @@ need_convertion: * erts_atom_put_index() may fail. Returns negative indexes for errors. */ int -erts_atom_put_index(const byte *name, int len, ErtsAtomEncoding enc, int trunc) +erts_atom_put_index(const byte *name, Sint len, ErtsAtomEncoding enc, int trunc) { byte utf8_copy[MAX_ATOM_SZ_FROM_LATIN1]; const byte *text = name; - int tlen = len; + Uint tlen; Sint no_latin1_chars; Atom a; int aix; @@ -247,13 +251,16 @@ erts_atom_put_index(const byte *name, int len, ErtsAtomEncoding enc, int trunc) erts_atomic_inc_nob(&atom_put_ops); #endif - if (tlen < 0) { - if (trunc) - tlen = 0; - else - return ATOM_MAX_CHARS_ERROR; + if (len < 0) { + if (trunc) { + len = 0; + } else { + return ATOM_MAX_CHARS_ERROR; + } } + tlen = len; + switch (enc) { case ERTS_ATOM_ENC_7BIT_ASCII: if (tlen > MAX_ATOM_CHARACTERS) { @@ -277,7 +284,7 @@ erts_atom_put_index(const byte *name, int len, ErtsAtomEncoding enc, int trunc) return ATOM_MAX_CHARS_ERROR; } no_latin1_chars = tlen; - latin1_to_utf8(utf8_copy, &text, &tlen); + latin1_to_utf8(utf8_copy, sizeof(utf8_copy), &text, &tlen); break; case ERTS_ATOM_ENC_UTF8: /* First sanity check; need to verify later */ @@ -338,7 +345,7 @@ erts_atom_put_index(const byte *name, int len, ErtsAtomEncoding enc, int trunc) * erts_atom_put() may fail. If it fails THE_NON_VALUE is returned! */ Eterm -erts_atom_put(const byte *name, int len, ErtsAtomEncoding enc, int trunc) +erts_atom_put(const byte *name, Sint len, ErtsAtomEncoding enc, int trunc) { int aix = erts_atom_put_index(name, len, enc, trunc); if (aix >= 0) @@ -348,7 +355,7 @@ erts_atom_put(const byte *name, int len, ErtsAtomEncoding enc, int trunc) } Eterm -am_atom_put(const char* name, int len) +am_atom_put(const char* name, Sint len) { /* Assumes 7-bit ascii; use erts_atom_put() for other encodings... */ return erts_atom_put((byte *) name, len, ERTS_ATOM_ENC_7BIT_ASCII, 1); @@ -379,23 +386,57 @@ int atom_table_sz(void) } int -erts_atom_get(const char *name, int len, Eterm* ap, ErtsAtomEncoding enc) +erts_atom_get(const char *name, Uint len, Eterm* ap, ErtsAtomEncoding enc) { byte utf8_copy[MAX_ATOM_SZ_FROM_LATIN1]; Atom a; int i; int res; - a.len = (Sint16) len; - a.name = (byte *)name; - if (enc == ERTS_ATOM_ENC_LATIN1) { - latin1_to_utf8(utf8_copy, (const byte**)&a.name, &len); - a.len = (Sint16) len; + switch (enc) { + case ERTS_ATOM_ENC_LATIN1: + if (len > MAX_ATOM_CHARACTERS) { + return 0; + } + + latin1_to_utf8(utf8_copy, sizeof(utf8_copy), (const byte**)&name, &len); + + a.name = (byte*)name; + a.len = (Sint16)len; + break; + case ERTS_ATOM_ENC_7BIT_ASCII: + if (len > MAX_ATOM_CHARACTERS) { + return 0; + } + + for (i = 0; i < len; i++) { + if (name[i] & 0x80) { + return 0; + } + } + + a.len = (Sint16)len; + a.name = (byte*)name; + break; + case ERTS_ATOM_ENC_UTF8: + if (len > MAX_ATOM_SZ_LIMIT) { + return 0; + } + + /* We don't need to check whether the encoding is legal as all atom + * names are stored as UTF-8 and we know a lookup with a badly encoded + * name will fail. */ + + a.len = (Sint16)len; + a.name = (byte*)name; + break; } + atom_read_lock(); i = index_get(&erts_atom_table, (void*) &a); res = i < 0 ? 0 : (*ap = make_atom(i), 1); atom_read_unlock(); + return res; } diff --git a/erts/emulator/beam/atom.h b/erts/emulator/beam/atom.h index ca920679c6..f51c5a8c62 100644 --- a/erts/emulator/beam/atom.h +++ b/erts/emulator/beam/atom.h @@ -133,14 +133,14 @@ typedef enum { int atom_table_size(void); /* number of elements */ int atom_table_sz(void); /* table size in bytes, excluding stored objects */ -Eterm am_atom_put(const char*, int); /* ONLY 7-bit ascii! */ -Eterm erts_atom_put(const byte *name, int len, ErtsAtomEncoding enc, int trunc); -int erts_atom_put_index(const byte *name, int len, ErtsAtomEncoding enc, int trunc); +Eterm am_atom_put(const char*, Sint); /* ONLY 7-bit ascii! */ +Eterm erts_atom_put(const byte *name, Sint len, ErtsAtomEncoding enc, int trunc); +int erts_atom_put_index(const byte *name, Sint len, ErtsAtomEncoding enc, int trunc); void init_atom_table(void); void atom_info(fmtfn_t, void *); void dump_atoms(fmtfn_t, void *); Uint erts_get_atom_limit(void); -int erts_atom_get(const char* name, int len, Eterm* ap, ErtsAtomEncoding enc); +int erts_atom_get(const char* name, Uint len, Eterm* ap, ErtsAtomEncoding enc); void erts_atom_get_text_space_sizes(Uint *reserved, Uint *used); #endif diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 4351dda5a7..ec4f9b4339 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -422,6 +422,7 @@ static Eterm add_stacktrace(Process* c_p, Eterm Value, Eterm exc); static void save_stacktrace(Process* c_p, BeamInstr* pc, Eterm* reg, ErtsCodeMFA *bif_mfa, Eterm args); static struct StackTrace * get_trace_from_exc(Eterm exc); +static Eterm *get_freason_ptr_from_exc(Eterm exc); static Eterm make_arglist(Process* c_p, Eterm* reg, int a); void @@ -1904,6 +1905,25 @@ static int is_raised_exc(Eterm exc) { } } +static Eterm *get_freason_ptr_from_exc(Eterm exc) { + static Eterm dummy_freason; + struct StackTrace* s; + + if (exc == NIL) { + /* + * Is is not exactly clear when exc can be NIL. Probably only + * when the exception has been generated from native code. + * Return a pointer to an Eterm that can be safely written and + * ignored. + */ + return &dummy_freason; + } else { + ASSERT(is_list(exc)); + s = (struct StackTrace *) big_val(CDR(list_val(exc))); + return &s->freason; + } +} + /* * Creating a list with the argument registers */ @@ -3261,20 +3281,23 @@ erts_is_builtin(Eterm Mod, Eterm Name, int arity) /* - * Return the current number of reductions for the given process. + * Return the current number of reductions consumed by the given process. * To get the total number of reductions, p->reds must be added. */ Uint -erts_current_reductions(Process *current, Process *p) +erts_current_reductions(Process *c_p, Process *p) { - if (current != p) { + Sint reds_left; + if (c_p != p || !(erts_atomic32_read_nob(&c_p->state) + & ERTS_PSFLG_RUNNING)) { return 0; - } else if (current->fcalls < 0 && ERTS_PROC_GET_SAVED_CALLS_BUF(current)) { - return current->fcalls + CONTEXT_REDS; + } else if (c_p->fcalls < 0 && ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) { + reds_left = c_p->fcalls + CONTEXT_REDS; } else { - return REDS_IN(current) - current->fcalls; + reds_left = c_p->fcalls; } + return REDS_IN(c_p) - reds_left - erts_proc_sched_data(p)->virtual_reds; } int diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index 0633bff3c2..bbe2fc31f3 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -1713,9 +1713,17 @@ int erts_net_message(Port *prt, token = tuple[4]; reason = tuple[5]; } - if (is_not_pid(from) || is_not_internal_pid(to)) { + if (is_not_pid(from)) { goto invalid_message; } + if (is_not_internal_pid(to)) { + if (is_external_pid(to)) { + DistEntry *dep = external_pid_dist_entry(to); + if (dep == erts_this_dist_entry) + break; /* Old incarnation of this node... */ + } + goto invalid_message; + } erts_proc_sig_send_exit(NULL, from, to, reason, token, 0); break; diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index 711e62c795..b31d5b86cb 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -74,7 +74,7 @@ static void smp_bp_finisher(void* arg); static BIF_RETTYPE system_monitor(Process *p, Eterm monitor_pid, Eterm list); -static void new_seq_trace_token(Process* p); /* help func for seq_trace_2*/ +static void new_seq_trace_token(Process* p, int); /* help func for seq_trace_2*/ static Eterm trace_info_pid(Process* p, Eterm pid_spec, Eterm key); static Eterm trace_info_func(Process* p, Eterm pid_spec, Eterm key); static Eterm trace_info_on_load(Process* p, Eterm key); @@ -1874,7 +1874,7 @@ Eterm erts_seq_trace(Process *p, Eterm arg1, Eterm arg2, if (current_flag && ( (arg2 == am_true) || (arg2 == am_false)) ) { /* Flags */ - new_seq_trace_token(p); + new_seq_trace_token(p, 0); flags = unsigned_val(SEQ_TRACE_TOKEN_FLAGS(p)); if (build_result) { old_value = flags & current_flag ? am_true : am_false; @@ -1889,11 +1889,11 @@ Eterm erts_seq_trace(Process *p, Eterm arg1, Eterm arg2, return old_value; } else if (arg1 == am_label) { - new_seq_trace_token(p); + new_seq_trace_token(p, is_not_immed(arg2)); if (build_result) { old_value = SEQ_TRACE_TOKEN_LABEL(p); } - SEQ_TRACE_TOKEN_LABEL(p) = arg2; + SEQ_TRACE_TOKEN_LABEL(p) = arg2; return old_value; } else if (arg1 == am_serial) { @@ -1905,7 +1905,7 @@ Eterm erts_seq_trace(Process *p, Eterm arg1, Eterm arg2, if ((*tp != make_arityval(2)) || is_not_small(*(tp+1)) || is_not_small(*(tp+2))) { return THE_NON_VALUE; } - new_seq_trace_token(p); + new_seq_trace_token(p, 0); if (build_result) { hp = HAlloc(p,3); old_value = TUPLE2(hp, SEQ_TRACE_TOKEN_LASTCNT(p), @@ -1940,8 +1940,8 @@ Eterm erts_seq_trace(Process *p, Eterm arg1, Eterm arg2, } } -void -new_seq_trace_token(Process* p) +static void +new_seq_trace_token(Process* p, int ensure_new_heap) { Eterm* hp; @@ -1953,6 +1953,16 @@ new_seq_trace_token(Process* p) p->common.id, /* Internal pid */ /* From */ make_small(p->seq_trace_lastcnt)); } + else if (ensure_new_heap) { + Eterm* tpl = tuple_val(SEQ_TRACE_TOKEN(p)); + ASSERT(arityval(tpl[0]) == 5); + if (ErtsInArea(tpl, OLD_HEAP(p), + (OLD_HEND(p) - OLD_HEAP(p))*sizeof(Eterm))) { + hp = HAlloc(p, 6); + sys_memcpy(hp, tpl, 6*sizeof(Eterm)); + SEQ_TRACE_TOKEN(p) = make_tuple(hp); + } + } } BIF_RETTYPE erl_seq_trace_info(Process *p, Eterm item) @@ -2050,10 +2060,7 @@ BIF_RETTYPE seq_trace_print_2(BIF_ALIST_2) if (have_no_seqtrace(SEQ_TRACE_TOKEN(BIF_P))) { BIF_RET(am_false); } - if (!(is_atom(BIF_ARG_1) || is_small(BIF_ARG_1))) { - BIF_ERROR(BIF_P, BADARG); - } - if (SEQ_TRACE_TOKEN_LABEL(BIF_P) != BIF_ARG_1) + if (!EQ(BIF_ARG_1, SEQ_TRACE_TOKEN_LABEL(BIF_P))) BIF_RET(am_false); seq_trace_update_send(BIF_P); seq_trace_output(SEQ_TRACE_TOKEN(BIF_P), BIF_ARG_2, diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c index 18418a76e1..d475a0a634 100644 --- a/erts/emulator/beam/erl_proc_sig_queue.c +++ b/erts/emulator/beam/erl_proc_sig_queue.c @@ -3247,9 +3247,15 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep, erts_nif_demonitored((ErtsResource *) tmon->other.ptr); cnt++; break; - case ERTS_MON_TYPE_SUSPEND: - erts_resume(c_p, ERTS_PROC_LOCK_MAIN); + case ERTS_MON_TYPE_SUSPEND: { + ErtsMonitorSuspend *msp; + erts_aint_t mstate; + msp = (ErtsMonitorSuspend *) erts_monitor_to_data(tmon); + mstate = erts_atomic_read_acqb(&msp->state); + if (mstate & ERTS_MSUSPEND_STATE_FLG_ACTIVE) + erts_resume(c_p, ERTS_PROC_LOCK_MAIN); break; + } default: break; } @@ -3784,6 +3790,9 @@ clear_seq_trace_token(ErtsMessage *sig) case ERTS_MON_TYPE_PROC: case ERTS_MON_TYPE_DIST_PROC: case ERTS_MON_TYPE_NODE: + case ERTS_MON_TYPE_NODES: + case ERTS_MON_TYPE_SUSPEND: + case ERTS_MON_TYPE_TIME_OFFSET: break; default: ERTS_INTERNAL_ERROR("Unexpected sig type"); @@ -3800,6 +3809,11 @@ clear_seq_trace_token(ErtsMessage *sig) case ERTS_SIG_Q_OP_LINK: case ERTS_SIG_Q_OP_UNLINK: case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE: + case ERTS_SIG_Q_OP_GROUP_LEADER: + case ERTS_SIG_Q_OP_IS_ALIVE: + case ERTS_SIG_Q_OP_PROCESS_INFO: + case ERTS_SIG_Q_OP_SYNC_SUSPEND: + case ERTS_SIG_Q_OP_RPC: break; default: diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index cc02fbad1e..1f464e2e5a 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -9474,6 +9474,7 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls) if (!is_normal_sched & !!(flags & ERTS_RUNQ_FLG_HALTING)) { /* Wait for emulator to terminate... */ + erts_runq_unlock(rq); while (1) erts_milli_sleep(1000*1000); } @@ -13081,10 +13082,10 @@ void erts_halt(int code) if (-1 == erts_atomic32_cmpxchg_acqb(&erts_halt_progress, erts_no_schedulers, -1)) { + notify_reap_ports_relb(); ERTS_RUNQ_FLGS_SET(ERTS_DIRTY_CPU_RUNQ, ERTS_RUNQ_FLG_HALTING); ERTS_RUNQ_FLGS_SET(ERTS_DIRTY_IO_RUNQ, ERTS_RUNQ_FLG_HALTING); erts_halt_code = code; - notify_reap_ports_relb(); } } diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index 43937f216c..86798df64e 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -1226,9 +1226,10 @@ void erts_check_for_holes(Process* p); /* The sequential tracing token is a tuple of size 5: * - * {Flags, Label, Serial, Sender} + * {Flags, Label, Serial, Sender, LastCnt} + * + * WARNING: The top 5-tuple is *MUTABLE* and thus INTERNAL ONLY. */ - #define SEQ_TRACE_TOKEN_ARITY(p) (arityval(*(tuple_val(SEQ_TRACE_TOKEN(p))))) #define SEQ_TRACE_TOKEN_FLAGS(p) (*(tuple_val(SEQ_TRACE_TOKEN(p)) + 1)) #define SEQ_TRACE_TOKEN_LABEL(p) (*(tuple_val(SEQ_TRACE_TOKEN(p)) + 2)) diff --git a/erts/emulator/beam/instrs.tab b/erts/emulator/beam/instrs.tab index 42c1168f85..999e9337ff 100644 --- a/erts/emulator/beam/instrs.tab +++ b/erts/emulator/beam/instrs.tab @@ -951,19 +951,30 @@ raw_raise() { Eterm class = x(0); Eterm value = x(1); Eterm stacktrace = x(2); + Eterm* freason_ptr; + + /* + * Note that the i_raise instruction will override c_p->freason + * with the freason field stored inside the StackTrace struct in + * ftrace. Therefore, we must take care to store the class both + * inside the StackTrace struct and in c_p->freason (important if + * the class is different from the class of the original + * exception). + */ + freason_ptr = get_freason_ptr_from_exc(stacktrace); if (class == am_error) { - c_p->freason = EXC_ERROR & ~EXF_SAVETRACE; + *freason_ptr = c_p->freason = EXC_ERROR & ~EXF_SAVETRACE; c_p->fvalue = value; c_p->ftrace = stacktrace; goto find_func_info; } else if (class == am_exit) { - c_p->freason = EXC_EXIT & ~EXF_SAVETRACE; + *freason_ptr = c_p->freason = EXC_EXIT & ~EXF_SAVETRACE; c_p->fvalue = value; c_p->ftrace = stacktrace; goto find_func_info; } else if (class == am_throw) { - c_p->freason = EXC_THROWN & ~EXF_SAVETRACE; + *freason_ptr = c_p->freason = EXC_THROWN & ~EXF_SAVETRACE; c_p->fvalue = value; c_p->ftrace = stacktrace; goto find_func_info; diff --git a/erts/emulator/beam/msg_instrs.tab b/erts/emulator/beam/msg_instrs.tab index 9bf3aefaca..a6a0dec451 100644 --- a/erts/emulator/beam/msg_instrs.tab +++ b/erts/emulator/beam/msg_instrs.tab @@ -105,6 +105,7 @@ i_loop_rec(Dest) { $SET_CP_I_ABS(I); c_p->arity = 0; c_p->current = NULL; + c_p->fcalls = FCALLS; FCALLS -= erts_proc_sig_receive_helper(c_p, FCALLS, neg_o_reds, &msgp, &get_out); SWAPIN; diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index b71ce0389d..d6ceab680b 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2018. All Rights Reserved. + * Copyright Ericsson AB 1997-2019. 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. @@ -3379,6 +3379,71 @@ static int udp_parse_ancillary_data(ErlDrvTermData *spec, int i, i = LOAD_NIL(spec, i); return LOAD_LIST(spec, i, n+1); } + +static int compile_ancillary_data(struct msghdr *mhdr, + char *ptr, ErlDrvSizeT anc_len) { + struct cmsghdr *cmsg; + size_t controllen = 0; + cmsg = CMSG_FIRSTHDR(mhdr); + for (;;) { + if (anc_len == 0) { + /* End of options to compile */ + mhdr->msg_controllen = controllen; + return 0; + } + if (cmsg == NULL) { + /* End of destination before end of options */ + return 1; + } + +#define COMPILE_ANCILLARY_DATA_ITEM(Level, Opt, Type, Get, Size) \ + do { \ + if (anc_len < (Size)) return 1; \ + sys_memset(cmsg, '\0', CMSG_SPACE(sizeof(Type))); \ + cmsg->cmsg_level = Level; \ + cmsg->cmsg_type = Opt; \ + cmsg->cmsg_len = CMSG_LEN(sizeof(Type)); \ + *((Type *) CMSG_DATA(cmsg)) = Get(ptr); \ + controllen += CMSG_SPACE(sizeof(Type)); \ + cmsg = CMSG_NXTHDR(mhdr, cmsg); \ + ptr += 4; \ + anc_len -= 4; \ + } while (0) +#define SIZEOF_ANCILLARY_DATA (2 * CMSG_SPACE(sizeof(int))) + /* (IP_TOS | IPV6_TCLASS) + IP_TTL */ + + switch (anc_len--, *ptr++) { + case INET_OPT_TOS: { +#if defined(IPPROTO_IP) && defined(IP_TOS) + COMPILE_ANCILLARY_DATA_ITEM(IPPROTO_IP, IP_TOS, int, get_int32, 4); +#else + return 1; /* Socket option not implemented */ +#endif + break; + } + case INET_OPT_TTL: { +#if defined(IPPROTO_IP) && defined(IP_TTL) + COMPILE_ANCILLARY_DATA_ITEM(IPPROTO_IP, IP_TTL, int, get_int32, 4); +#else + return 1; /* Socket option not implemented */ +#endif + break; + } + case INET_OPT_TCLASS: { +#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS) + COMPILE_ANCILLARY_DATA_ITEM(IPPROTO_IPV6, IPV6_TCLASS, int, get_int32, 4); +#else + return 1; /* Socket option not implemented */ +#endif + break; + } + default: + /* Unknow socket option */ + return 1; + } +#undef COMPILE_ANCILLARY_DATA_ITEM + } +} #endif /* ifndef __WIN32__ */ /* @@ -9846,10 +9911,8 @@ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s, copy_desc->send_timeout = desc->send_timeout; copy_desc->send_timeout_close = desc->send_timeout_close; - if (desc->tcp_add_flags & TCP_ADDF_SHOW_ECONNRESET) - copy_desc->tcp_add_flags |= TCP_ADDF_SHOW_ECONNRESET; - else - copy_desc->tcp_add_flags &= ~TCP_ADDF_SHOW_ECONNRESET; + copy_desc->tcp_add_flags = desc->tcp_add_flags + & (TCP_ADDF_SHOW_ECONNRESET | TCP_ADDF_LINGER_ZERO); /* The new port will be linked and connected to the original caller */ port = driver_create_port(port, owner, "tcp_inet", (ErlDrvData) copy_desc); @@ -11386,7 +11449,7 @@ static int tcp_shutdown_error(tcp_descriptor* desc, int err) static void tcp_inet_delay_send(ErlDrvData data, ErlDrvTermData dummy) { tcp_descriptor *desc = (tcp_descriptor*)data; - (void)tcp_inet_output(desc, INETP(desc)->s); + (void)tcp_inet_output(desc, (HANDLE) INETP(desc)->s); } /* @@ -12553,7 +12616,7 @@ static void packet_inet_timeout(ErlDrvData e) sock_select(desc, FD_READ, 0); async_error_am (desc, am_timeout); } else { - (void)packet_inet_input(udesc, desc->s); + (void)packet_inet_input(udesc, (HANDLE) desc->s); } } @@ -12597,11 +12660,8 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len) char ancd[CMSG_SPACE(sizeof(*sri))]; } cmsg; - if (len < SCTP_GET_SENDPARAMS_LEN) { - inet_reply_error(desc, EINVAL); - return; - } - + if (len < SCTP_GET_SENDPARAMS_LEN) goto return_einval; + /* The ancillary data */ sri = (struct sctp_sndrcvinfo *) (CMSG_DATA(&cmsg.hdr)); /* Get the "sndrcvinfo" from the buffer, advancing the "ptr": */ @@ -12634,28 +12694,85 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len) goto check_result_code; } #endif - /* UDP socket. Even if it is connected, there is an address prefix - here -- ignored for connected sockets: */ - sz = len; - qtr = ptr; - xerror = inet_set_faddress(desc->sfamily, &other, &qtr, &sz); - if (xerror != NULL) { - inet_reply_error_am(desc, driver_mk_atom(xerror)); - return; - } - len -= (qtr - ptr); - ptr = qtr; - /* Now "ptr" is the user data ptr, "len" is data length: */ - inet_output_count(desc, len); - - if (desc->state & INET_F_ACTIVE) { /* connected (ignore address) */ - code = sock_send(desc->s, ptr, len, 0); - } - else { - code = sock_sendto(desc->s, ptr, len, 0, &other.sa, sz); + { + ErlDrvSizeT anc_len; + + /* UDP socket. Even if it is connected, there is an address prefix + here -- ignored for connected sockets: */ + sz = len; + qtr = ptr; + xerror = inet_set_faddress(desc->sfamily, &other, &qtr, &sz); + if (xerror != NULL) { + inet_reply_error_am(desc, driver_mk_atom(xerror)); + return; + } + len -= (qtr - ptr); + ptr = qtr; + + /* Here comes ancillary data */ + if (len < 4) goto return_einval; + anc_len = get_int32(ptr); + len -= 4; ptr += 4; + if (len < anc_len) goto return_einval; + + if (anc_len == 0 && !!0/*XXX-short-circuit-for-testing*/) { + /* Empty ancillary data */ + /* Now "ptr" is the user data ptr, "len" is data length: */ + inet_output_count(desc, len); + if (desc->state & INET_F_ACTIVE) { + /* connected (ignore address) */ + code = sock_send(desc->s, ptr, len, 0); + } + else { + code = sock_sendto(desc->s, ptr, len, 0, &other.sa, sz); + } + } + else { +#ifdef __WIN32__ + goto return_einval; /* Can not send ancillary data on Windows */ +#else + struct iovec iov[1]; + struct msghdr mhdr; + union { /* For ancillary data */ + struct cmsghdr hdr; + char ancd[SIZEOF_ANCILLARY_DATA]; + } cmsg; + sys_memset(&iov, '\0', sizeof(iov)); + sys_memset(&mhdr, '\0', sizeof(mhdr)); + sys_memset(&cmsg, '\0', sizeof(cmsg)); + if (desc->state & INET_F_ACTIVE) { + /* connected (ignore address) */ + mhdr.msg_name = NULL; + mhdr.msg_namelen = 0; + } + else { + mhdr.msg_name = &other; + mhdr.msg_namelen = sz; + } + mhdr.msg_control = cmsg.ancd; + mhdr.msg_controllen = sizeof(cmsg.ancd); + if (compile_ancillary_data(&mhdr, ptr, anc_len) != 0) { + goto return_einval; + } + if (mhdr.msg_controllen == 0) { + /* XXX Testing - only possible for anc_len == 0 */ + mhdr.msg_control = NULL; + } + len -= anc_len; + ptr += anc_len; + /* Now "ptr" is the user data ptr, "len" is data length: */ + iov[0].iov_len = len; + iov[0].iov_base = ptr; + mhdr.msg_iov = iov; + mhdr.msg_iovlen = 1; + mhdr.msg_flags = 0; + inet_output_count(desc, len); + code = sock_sendmsg(desc->s, &mhdr, 0); +#endif + } } -#ifdef HAVE_SCTP +#ifdef HAVE_SCTP check_result_code: /* "code" analysis is the same for both SCTP and UDP cases above: */ #endif @@ -12665,8 +12782,15 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len) } else inet_reply_ok(desc); + return; + + return_einval: + inet_reply_error(desc, EINVAL); + return; } -#endif + +#endif /* HAVE_UDP */ + #ifdef __WIN32__ static void packet_inet_event(ErlDrvData e, ErlDrvEvent event) diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c index c39cd01e1c..c77a535105 100644 --- a/erts/emulator/sys/common/erl_check_io.c +++ b/erts/emulator/sys/common/erl_check_io.c @@ -752,6 +752,8 @@ driver_select(ErlDrvPort ix, ErlDrvEvent e, int mode, int on) ret = 0; goto done_unknown; } + /* For some reason (don't know why), we do not clean all + events when doing ERL_DRV_USE_NO_CALLBACK. */ else if ((mode&ERL_DRV_USE_NO_CALLBACK) == ERL_DRV_USE) { mode |= (ERL_DRV_READ | ERL_DRV_WRITE); } @@ -2439,6 +2441,10 @@ drvmode2str(int mode) { case ERL_DRV_WRITE|ERL_DRV_USE: return "WRITE|USE"; case ERL_DRV_READ|ERL_DRV_WRITE|ERL_DRV_USE: return "READ|WRITE|USE"; case ERL_DRV_USE: return "USE"; + case ERL_DRV_READ|ERL_DRV_USE_NO_CALLBACK: return "READ|USE_NO_CB"; + case ERL_DRV_WRITE|ERL_DRV_USE_NO_CALLBACK: return "WRITE|USE_NO_CB"; + case ERL_DRV_READ|ERL_DRV_WRITE|ERL_DRV_USE_NO_CALLBACK: return "READ|WRITE|USE_NO_CB"; + case ERL_DRV_USE_NO_CALLBACK: return "USE_NO_CB"; case ERL_DRV_READ: return "READ"; case ERL_DRV_WRITE: return "WRITE"; case ERL_DRV_READ|ERL_DRV_WRITE: return "READ|WRITE"; diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c index 042a091db1..664d677ebd 100644 --- a/erts/emulator/sys/unix/sys_drivers.c +++ b/erts/emulator/sys/unix/sys_drivers.c @@ -1006,10 +1006,8 @@ static void clear_fd_data(ErtsSysFdData *fdd) static void nbio_stop_fd(ErlDrvPort prt, ErtsSysFdData *fdd, int use) { - driver_select(prt, abs(fdd->fd), use ? ERL_DRV_USE_NO_CALLBACK : 0|DO_READ|DO_WRITE, 0); clear_fd_data(fdd); SET_BLOCKING(abs(fdd->fd)); - } static void fd_stop(ErlDrvData ev) /* Does not close the fds */ @@ -1026,10 +1024,12 @@ static void fd_stop(ErlDrvData ev) /* Does not close the fds */ if (dd->ifd) { sz += sizeof(ErtsSysFdData); + driver_select(prt, abs(dd->ifd->fd), ERL_DRV_USE_NO_CALLBACK|DO_READ|DO_WRITE, 0); nbio_stop_fd(prt, dd->ifd, 1); } if (dd->ofd && dd->ofd != dd->ifd) { sz += sizeof(ErtsSysFdData); + driver_select(prt, abs(dd->ofd->fd), ERL_DRV_USE_NO_CALLBACK|DO_WRITE, 0); nbio_stop_fd(prt, dd->ofd, 1); } diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl index 9e7bcd5255..9f6e1059b9 100644 --- a/erts/emulator/test/bif_SUITE.erl +++ b/erts/emulator/test/bif_SUITE.erl @@ -609,6 +609,16 @@ binary_to_existing_atom(Config) when is_list(Config) -> UnlikelyAtom = binary_to_atom(id(UnlikelyBin), latin1), UnlikelyAtom = binary_to_existing_atom(UnlikelyBin, latin1), + + %% ERL-944; a binary that was too large would overflow the latin1-to-utf8 + %% conversion buffer. + OverflowAtom = <<0:511/unit:8, + 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, + 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, + 196, 133, 196, 133, 196, 133, 196, 133, 196, 133, + 196, 133, 196, 133, 196, 133, 196, 133, 196, 133>>, + {'EXIT', _} = (catch binary_to_existing_atom(OverflowAtom, latin1)), + ok. diff --git a/erts/emulator/test/dirty_bif_SUITE.erl b/erts/emulator/test/dirty_bif_SUITE.erl index 46eb0cba58..4f5ad0295a 100644 --- a/erts/emulator/test/dirty_bif_SUITE.erl +++ b/erts/emulator/test/dirty_bif_SUITE.erl @@ -38,7 +38,8 @@ dirty_process_info/1, dirty_process_register/1, dirty_process_trace/1, - code_purge/1]). + code_purge/1, + otp_15688/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -64,7 +65,8 @@ all() -> dirty_process_info, dirty_process_register, dirty_process_trace, - code_purge]. + code_purge, + otp_15688]. init_per_suite(Config) -> case erlang:system_info(dirty_cpu_schedulers) of @@ -498,10 +500,58 @@ code_purge(Config) when is_list(Config) -> true = Time =< 1000, ok. +otp_15688(Config) when is_list(Config) -> + ImBack = make_ref(), + {See, SeeMon} = spawn_monitor(fun () -> + erts_debug:dirty_io(wait, 2000), + exit(ImBack) + end), + wait_until(fun () -> + [{current_function, {erts_debug, dirty_io, 2}}, + {status, running}] + == process_info(See, + [current_function, status]) + end), + {Ser1, Ser1Mon} = spawn_monitor(fun () -> + erlang:suspend_process(See, + [asynchronous]) + end), + erlang:suspend_process(See, [asynchronous]), + receive {'DOWN', Ser1Mon, process, Ser1, normal} -> ok end, + + %% Verify that we sent the suspend request while it was executing dirty... + [{current_function, {erts_debug, dirty_io, 2}}, + {status, running}] = process_info(See, [current_function, status]), + + wait_until(fun () -> + {status, suspended} == process_info(See, status) + end), + erlang:resume_process(See), + + receive + {'DOWN', SeeMon, process, See, Reason} -> + ImBack = Reason + after 4000 -> + %% Resume bug seems to have hit us... + PI = process_info(See), + exit(See, kill), + ct:fail({suspendee_stuck, PI}) + end. + + %% %% Internal... %% +wait_until(Fun) -> + case Fun() of + true -> + ok; + _ -> + receive after 100 -> ok end, + wait_until(Fun) + end. + access_dirty_process(Config, Start, Test, Finish) -> {ok, Node} = start_node(Config, ""), [ok] = mcall(Node, diff --git a/erts/emulator/test/exception_SUITE.erl b/erts/emulator/test/exception_SUITE.erl index aec66cb9a3..6e6f7d78ab 100644 --- a/erts/emulator/test/exception_SUITE.erl +++ b/erts/emulator/test/exception_SUITE.erl @@ -23,6 +23,7 @@ -export([all/0, suite/0, badmatch/1, pending_errors/1, nil_arith/1, top_of_stacktrace/1, stacktrace/1, nested_stacktrace/1, raise/1, gunilla/1, per/1, + change_exception_class/1, exception_with_heap_frag/1, backtrace_depth/1, line_numbers/1]). @@ -43,6 +44,7 @@ suite() -> all() -> [badmatch, pending_errors, nil_arith, top_of_stacktrace, stacktrace, nested_stacktrace, raise, gunilla, per, + change_exception_class, exception_with_heap_frag, backtrace_depth, line_numbers]. -define(try_match(E), @@ -507,6 +509,38 @@ t1(_,X,_) -> t2(_,X,_) -> (X bsl 1) + 1. +change_exception_class(_Config) -> + try + change_exception_class_1(fun() -> throw(arne) end) + catch + error:arne -> + ok; + Class:arne -> + ct:fail({wrong_exception_class,Class}) + end. + +change_exception_class_1(F) -> + try + change_exception_class_2(F) + after + %% The exception would be caught and rethrown using + %% an i_raise instruction. Before the correction + %% of the raw_raise instruction, the change of class + %% would not stick. + io:put_chars("Exception automatically rethrown here\n") + end. + +change_exception_class_2(F) -> + try + F() + catch + throw:Reason:Stack -> + %% Translated to a raw_raise instruction. + %% The change of exception class would not stick + %% if the i_raise instruction was later executed. + erlang:raise(error, Reason, Stack) + end. + %% %% Make sure that even if a BIF builds an heap fragment, then causes an exception, %% the stacktrace term will still be OK (specifically, that it does not contain diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index b23f77a0b2..cef1b79035 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -44,6 +44,7 @@ process_info_garbage_collection/1, process_info_smoke_all/1, process_info_status_handled_signal/1, + process_info_reductions/1, bump_reductions/1, low_prio/1, binary_owner/1, yield/1, yield2/1, otp_4725/1, bad_register/1, garbage_collect/1, otp_6237/1, process_info_messages/1, process_flag_badarg/1, process_flag_heap_size/1, @@ -84,6 +85,7 @@ all() -> process_info_garbage_collection, process_info_smoke_all, process_info_status_handled_signal, + process_info_reductions, bump_reductions, low_prio, yield, yield2, otp_4725, bad_register, garbage_collect, process_info_messages, process_flag_badarg, process_flag_heap_size, @@ -1084,6 +1086,90 @@ process_info_status_handled_signal(Config) when is_list(Config) -> false = erlang:is_process_alive(P), ok. +%% OTP-15709 +%% Provoke a bug where process_info(reductions) returned wrong result +%% because REDS_IN (def_arg_reg[5]) is read when the process in not running. +%% +%% And a bug where process_info(reductions) on a process which was releasing its +%% main lock during execution could result in negative reduction diffs. +process_info_reductions(Config) when is_list(Config) -> + {S1, S2} = case erlang:system_info(schedulers) of + 1 -> {1,1}; + _ -> {1,2} + end, + io:format("Run on schedulers ~p and ~p\n", [S1,S2]), + Boss = self(), + Doer = spawn_opt(fun () -> + pi_reductions_tester(true, 10, fun pi_reductions_spinnloop/0, S2), + pi_reductions_tester(true, 10, fun pi_reductions_recvloop/0, S2), + pi_reductions_tester(false, 100, fun pi_reductions_main_unlocker/0, S2), + Boss ! {self(), done} + end, + [link, {scheduler, S1}]), + + {Doer, done} = receive M -> M end, + ok. + +pi_reductions_tester(ForceSignal, MaxCalls, Fun, S2) -> + Pid = spawn_opt(Fun, [link, {scheduler,S2}]), + Extra = case ForceSignal of + true -> + %% Add another item that force sending the request + %% as a signal, like 'current_function'. + [current_function]; + false -> + [] + end, + LoopFun = fun Me(Calls, Prev, Acc0) -> + PI = process_info(Pid, [reductions | Extra]), + [{reductions,Reds} | _] = PI, + Diff = Reds - Prev, + %% Verify we get sane non-negative reduction diffs + {Diff, true} = {Diff, (Diff >= 0)}, + {Diff, true} = {Diff, (Diff =< 1000*1000)}, + Acc1 = [Diff | Acc0], + case Calls >= MaxCalls of + true -> Acc1; + false -> Me(Calls+1, Reds, Acc1) + end + end, + DiffList = LoopFun(0, 0, []), + unlink(Pid), + exit(Pid,kill), + io:format("Reduction diffs: ~p\n", [lists:reverse(DiffList)]), + ok. + +pi_reductions_spinnloop() -> + %% 6 args to make use of def_arg_reg[5] which is also used as REDS_IN + pi_reductions_spinnloop(999*1000, atom, "hej", self(), make_ref(), 3.14). + +pi_reductions_spinnloop(N,A,B,C,D,E) when N > 0 -> + pi_reductions_spinnloop(N-1,B,C,D,E,A); +pi_reductions_spinnloop(0,_,_,_,_,_) -> + %% Stop to limit max number of reductions consumed + pi_reductions_recvloop(). + +pi_reductions_recvloop() -> + receive + "a free lunch" -> false + end. + +pi_reductions_main_unlocker() -> + Other = spawn_link(fun() -> receive die -> ok end end), + pi_reductions_main_unlocker_loop(Other). + +pi_reductions_main_unlocker_loop(Other) -> + %% Assumption: register(OtherPid, Name) will unlock main lock of calling + %% process during execution. + register(pi_reductions_main_unlocker, Other), + unregister(pi_reductions_main_unlocker), + + %% Yield in order to increase probability of process_info sometimes probing + %% this process when it's not RUNNING. + erlang:yield(), + pi_reductions_main_unlocker_loop(Other). + + %% Tests erlang:bump_reductions/1. bump_reductions(Config) when is_list(Config) -> erlang:garbage_collect(), diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam Binary files differindex d3614d5f16..8833f9c77c 100644 --- a/erts/preloaded/ebin/prim_inet.beam +++ b/erts/preloaded/ebin/prim_inet.beam diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 2820a5bef4..77d4292ad0 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -553,34 +553,49 @@ send(S, Data) -> %% "sendto" is for UDP. IP and Port are set by the caller to 0 if the socket %% is known to be connected. -sendto(S, Addr, _, Data) when is_port(S), tuple_size(Addr) =:= 2 -> - case type_value(set, addr, Addr) of - true -> - ?DBG_FORMAT("prim_inet:sendto(~p, ~p, ~p)~n", [S,Addr,Data]), - try - erlang:port_command(S, [enc_value(set, addr, Addr),Data]) - of - true -> - receive - {inet_reply,S,Reply} -> - ?DBG_FORMAT( - "prim_inet:sendto() -> ~p~n", [Reply]), - Reply - end - catch - error:_ -> - ?DBG_FORMAT( - "prim_inet:sendto() -> {error,einval}~n", []), - {error,einval} - end; - false -> - ?DBG_FORMAT( - "prim_inet:sendto() -> {error,einval}~n", []), - {error,einval} - end; -sendto(S, IP, Port, Data) -> - sendto(S, {IP, Port}, 0, Data). - +sendto(S, {_, _} = Address, AncOpts, Data) + when is_port(S), is_list(AncOpts) -> + case encode_opt_val(AncOpts) of + {ok, AncData} -> + AncDataLen = iolist_size(AncData), + case + type_value(set, addr, Address) andalso + type_value(set, uint32, AncDataLen) + of + true -> + ?DBG_FORMAT("prim_inet:sendto(~p, ~p, ~p, ~p)~n", + [S,Address,AncOpts,Data]), + PortCommandData = + [enc_value(set, addr, Address), + enc_value(set, uint32, AncDataLen), AncData, + Data], + try erlang:port_command(S, PortCommandData) of + true -> + receive + {inet_reply,S,Reply} -> + ?DBG_FORMAT( + "prim_inet:sendto() -> ~p~n", [Reply]), + Reply + end + catch + _:_ -> + ?DBG_FORMAT( + "prim_inet:sendto() -> {error,einval}~n", []), + {error,einval} + end; + false -> + ?DBG_FORMAT( + "prim_inet:sendto() -> {error,einval}~n", []), + {error,einval} + end; + {error,_} -> + ?DBG_FORMAT( + "prim_inet:sendto() -> {error,einval}~n", []), + {error,einval} + end; +sendto(S, IP, Port, Data) + when is_port(S), is_integer(Port) -> + sendto(S, {IP, Port}, [], Data). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% @@ -1993,15 +2008,15 @@ enc_value_2(addr, {File,_}) when is_list(File); is_binary(File) -> [?INET_AF_LOCAL,iolist_size(File)|File]; %% enc_value_2(addr, {inet,{any,Port}}) -> - [?INET_AF_INET,?int16(Port),0,0,0,0]; + [?INET_AF_INET,?int16(Port)|ip4_to_bytes({0,0,0,0})]; enc_value_2(addr, {inet,{loopback,Port}}) -> - [?INET_AF_INET,?int16(Port),127,0,0,1]; + [?INET_AF_INET,?int16(Port)|ip4_to_bytes({127,0,0,1})]; enc_value_2(addr, {inet,{IP,Port}}) -> [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)]; enc_value_2(addr, {inet6,{any,Port}}) -> - [?INET_AF_INET6,?int16(Port),0,0,0,0,0,0,0,0]; + [?INET_AF_INET6,?int16(Port)|ip6_to_bytes({0,0,0,0,0,0,0,0})]; enc_value_2(addr, {inet6,{loopback,Port}}) -> - [?INET_AF_INET6,?int16(Port),0,0,0,0,0,0,0,1]; + [?INET_AF_INET6,?int16(Port)|ip6_to_bytes({0,0,0,0,0,0,0,1})]; enc_value_2(addr, {inet6,{IP,Port}}) -> [?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)]; enc_value_2(addr, {local,Addr}) -> @@ -2149,10 +2164,10 @@ enum_name(_, []) -> false. %% encode opt/val REVERSED since options are stored in reverse order %% i.e. the recent options first (we must process old -> new) encode_opt_val(Opts) -> - try - enc_opt_val(Opts, []) + try + {ok, enc_opt_val(Opts, [])} catch - Reason -> {error,Reason} + throw:Reason -> {error,Reason} end. %% {active, once} and {active, N} are specially optimized because they will @@ -2171,17 +2186,21 @@ enc_opt_val([binary|Opts], Acc) -> enc_opt_val(Opts, Acc, mode, binary); enc_opt_val([list|Opts], Acc) -> enc_opt_val(Opts, Acc, mode, list); -enc_opt_val([_|_], _) -> {error,einval}; -enc_opt_val([], Acc) -> {ok,Acc}. +enc_opt_val([_|_], _) -> + throw(einval); +enc_opt_val([], Acc) -> + Acc. enc_opt_val(Opts, Acc, Opt, Val) when is_atom(Opt) -> Type = type_opt(set, Opt), case type_value(set, Type, Val) of true -> enc_opt_val(Opts, [enc_opt(Opt),enc_value(set, Type, Val)|Acc]); - false -> {error,einval} + false -> + throw(einval) end; -enc_opt_val(_, _, _, _) -> {error,einval}. +enc_opt_val(_, _, _, _) -> + throw(einval). diff --git a/erts/vsn.mk b/erts/vsn.mk index fac608ed4e..8b159b1c1f 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% # -VSN = 10.3 +VSN = 10.3.5.3 # Port number 4365 in 4.2 # Port number 4366 in 4.3 |