diff options
author | Sverker Eriksson <sverker@erlang.org> | 2020-01-27 19:49:01 +0100 |
---|---|---|
committer | Sverker Eriksson <sverker@erlang.org> | 2020-01-29 14:58:54 +0100 |
commit | 6ec79f11513982c1e93495c6ee35ea3ccfb56035 (patch) | |
tree | 63eab80a41c8e035bae58df3c31436be137ce217 /erts/emulator | |
parent | 040bdce67f88d833bfb59adae130a4ffb4c180f0 (diff) | |
download | erlang-6ec79f11513982c1e93495c6ee35ea3ccfb56035.tar.gz |
erts: Fix bug in erlang:list_to_ref/1 for external refs
Diffstat (limited to 'erts/emulator')
-rw-r--r-- | erts/emulator/beam/bif.c | 8 | ||||
-rw-r--r-- | erts/emulator/test/list_bif_SUITE.erl | 53 |
2 files changed, 59 insertions, 2 deletions
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 40dd4129d2..34ffa014e9 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -4421,12 +4421,16 @@ BIF_RETTYPE list_to_ref_1(BIF_ALIST_1) #endif etp = (ExternalThing *) HAlloc(BIF_P, hsz); - etp->header = make_external_ref_header(n/2); +#if defined(ARCH_64) + etp->header = make_external_ref_header(n/2 + 1); +#else + etp->header = make_external_ref_header(n); +#endif etp->next = BIF_P->off_heap.first; etp->node = enp; i = 0; #if defined(ARCH_64) - etp->data.ui32[i] = n; + etp->data.ui32[i++] = n; #endif for (j = 0; j < n; j++) { etp->data.ui32[i] = refn[j]; diff --git a/erts/emulator/test/list_bif_SUITE.erl b/erts/emulator/test/list_bif_SUITE.erl index f95251943d..b35ba0ff77 100644 --- a/erts/emulator/test/list_bif_SUITE.erl +++ b/erts/emulator/test/list_bif_SUITE.erl @@ -23,6 +23,7 @@ -export([all/0, suite/0]). -export([hd_test/1,tl_test/1,t_length/1,t_list_to_pid/1, + t_list_to_ref/1, t_list_to_ext_pidportref/1, t_list_to_port/1,t_list_to_float/1,t_list_to_integer/1]). @@ -33,6 +34,7 @@ suite() -> all() -> [hd_test, tl_test, t_length, t_list_to_pid, t_list_to_port, + t_list_to_ref, t_list_to_ext_pidportref, t_list_to_float, t_list_to_integer]. %% Tests list_to_integer and string:to_integer @@ -126,6 +128,57 @@ t_list_to_port(Config) when is_list(Config) -> end, ok. +t_list_to_ref(Config) when is_list(Config) -> + Ref = make_ref(), + RefStr = ref_to_list(Ref), + Ref = list_to_ref(RefStr), + case catch list_to_ref(id("Incorrect list")) of + {'EXIT', {badarg, _}} -> + ok; + Res -> + ct:fail("list_to_ref/1 with incorrect arg succeeded.~n" + "Result: ~p", [Res]) + end, + ok. + +%% Test list_to_pid/port/ref for external pids/ports/refs. +t_list_to_ext_pidportref(Config) when is_list(Config) -> + {ok, Node} = slave:start(net_adm:localhost(), t_list_to_ext_pidportref), + Pid = rpc:call(Node, erlang, self, []), + Port = hd(rpc:call(Node, erlang, ports, [])), + Ref = rpc:call(Node, erlang, make_ref, []), + + PidStr = pid_to_list(Pid), + PortStr = port_to_list(Port), + RefStr = ref_to_list(Ref), + + Pid2 = list_to_pid(PidStr), + Port2 = list_to_port(PortStr), + Ref2 = list_to_ref(RefStr), + + %% No, the local roundtrips of externals does not work + %% as 'creation' is missing in the string formats and we don't know + %% the 'creation' of the connected node. + false = (Pid =:= Pid2), + false = (Pid == Pid2), + false = (Port =:= Port2), + false = (Port == Port2), + false = (Ref =:= Ref2), + false = (Ref == Ref2), + + %% But it works when sent back to matching node name, as 0-creations + %% will be converted to the local node creation. + true = rpc:call(Node, erlang, '=:=', [Pid, Pid2]), + true = rpc:call(Node, erlang, '==', [Pid, Pid2]), + true = rpc:call(Node, erlang, '=:=', [Port, Port2]), + true = rpc:call(Node, erlang, '==', [Port, Port2]), + true = rpc:call(Node, erlang, '=:=', [Ref, Ref2]), + true = rpc:call(Node, erlang, '==', [Ref, Ref2]), + + slave:stop(Node), + ok. + + %% Test list_to_float/1 with correct and incorrect arguments. t_list_to_float(Config) when is_list(Config) -> |