aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/beam/atom.c77
-rw-r--r--erts/emulator/beam/atom.h8
-rw-r--r--erts/emulator/test/bif_SUITE.erl10
-rw-r--r--lib/tools/src/cover.erl42
-rw-r--r--lib/tools/test/cover_SUITE.erl29
5 files changed, 129 insertions, 37 deletions
diff --git a/erts/emulator/beam/atom.c b/erts/emulator/beam/atom.c
index 38e02c386f..8c7d04e1fd 100644
--- a/erts/emulator/beam/atom.c
+++ b/erts/emulator/beam/atom.c
@@ -202,11 +202,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) {
@@ -236,11 +240,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;
@@ -249,13 +253,16 @@ erts_atom_put_index(const byte *name, int len, ErtsAtomEncoding enc, int trunc)
erts_smp_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) {
@@ -279,7 +286,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 */
@@ -340,7 +347,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)
@@ -350,7 +357,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);
@@ -389,23 +396,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 385120a8d9..bc8219120c 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/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl
index 04b7f2de15..b9d078ff99 100644
--- a/erts/emulator/test/bif_SUITE.erl
+++ b/erts/emulator/test/bif_SUITE.erl
@@ -592,6 +592,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/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index 4e64d7aa4e..3565f8ba70 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -167,6 +167,8 @@ start() ->
receive
{?SERVER,started} ->
{ok,Pid};
+ {?SERVER,{error,Error}} ->
+ {error,Error};
{'DOWN', Ref, _Type, _Object, Info} ->
{error,Info}
end,
@@ -628,21 +630,33 @@ remote_reply(MainNode,Reply) ->
%%%----------------------------------------------------------------------
init_main(Starter) ->
- register(?SERVER,self()),
- %% Having write concurrancy here gives a 40% performance boost
- %% when collect/1 is called.
- ?COVER_TABLE = ets:new(?COVER_TABLE, [set, public, named_table,
- {write_concurrency, true}]),
- ?COVER_CLAUSE_TABLE = ets:new(?COVER_CLAUSE_TABLE, [set, public,
+ try register(?SERVER,self()) of
+ true ->
+ %% Having write concurrancy here gives a 40% performance boost
+ %% when collect/1 is called.
+ ?COVER_TABLE = ets:new(?COVER_TABLE, [set, public, named_table,
+ {write_concurrency, true}]),
+ ?COVER_CLAUSE_TABLE = ets:new(?COVER_CLAUSE_TABLE, [set, public,
+ named_table]),
+ ?BINARY_TABLE = ets:new(?BINARY_TABLE, [set, public, named_table]),
+ ?COLLECTION_TABLE = ets:new(?COLLECTION_TABLE, [set, public,
named_table]),
- ?BINARY_TABLE = ets:new(?BINARY_TABLE, [set, public, named_table]),
- ?COLLECTION_TABLE = ets:new(?COLLECTION_TABLE, [set, public,
- named_table]),
- ?COLLECTION_CLAUSE_TABLE = ets:new(?COLLECTION_CLAUSE_TABLE, [set, public,
- named_table]),
- ok = net_kernel:monitor_nodes(true),
- Starter ! {?SERVER,started},
- main_process_loop(#main_state{}).
+ ?COLLECTION_CLAUSE_TABLE = ets:new(?COLLECTION_CLAUSE_TABLE,
+ [set, public, named_table]),
+ ok = net_kernel:monitor_nodes(true),
+ Starter ! {?SERVER,started},
+ main_process_loop(#main_state{})
+ catch
+ error:badarg ->
+ %% The server's already registered; either report that it's already
+ %% started or try again if it died before we could find its pid.
+ case whereis(?SERVER) of
+ undefined ->
+ init_main(Starter);
+ Pid ->
+ Starter ! {?SERVER, {error, {already_started, Pid}}}
+ end
+ end.
main_process_loop(State) ->
receive
diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl
index 161b0105b9..806297abdd 100644
--- a/lib/tools/test/cover_SUITE.erl
+++ b/lib/tools/test/cover_SUITE.erl
@@ -35,7 +35,8 @@ all() ->
distribution, reconnect, die_and_reconnect,
dont_reconnect_after_stop, stop_node_after_disconnect,
export_import, otp_5031, otp_6115,
- otp_8270, otp_10979_hanging_node, otp_14817],
+ otp_8270, otp_10979_hanging_node, otp_14817,
+ startup_race],
case whereis(cover_server) of
undefined ->
[coverage,StartStop ++ NoStartStop];
@@ -1742,6 +1743,32 @@ otp_13289(Config) ->
ok = file:delete(File),
ok.
+%% ERL-943; We should not crash on startup when multiple servers race to
+%% register the server name.
+startup_race(Config) when is_list(Config) ->
+ PidRefs = [spawn_monitor(fun() ->
+ case cover:start() of
+ {error, {already_started, _Pid}} ->
+ ok;
+ {ok, _Pid} ->
+ ok
+ end
+ end) || _<- lists:seq(1,8)],
+ startup_race_1(PidRefs).
+
+startup_race_1([{Pid, Ref} | PidRefs]) ->
+ receive
+ {'DOWN', Ref, process, Pid, normal} ->
+ startup_race_1(PidRefs);
+ {'DOWN', Ref, process, Pid, _Other} ->
+ ct:fail("Cover server crashed on startup.")
+ after 5000 ->
+ ct:fail("Timed out.")
+ end;
+startup_race_1([]) ->
+ cover:stop(),
+ ok.
+
%%--Auxiliary------------------------------------------------------------
analyse_expr(Expr, Config) ->