summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErlang/OTP <otp@erlang.org>2020-02-27 11:53:57 +0100
committerErlang/OTP <otp@erlang.org>2020-02-27 11:53:57 +0100
commit63bd6be692381ac6d62bd4aed79c4488db44055a (patch)
tree0ab6dc17008e656dc42094c3f8f97ec1a69318ae
parent6a99831ae3c5c7962929108480323792af6cbc61 (diff)
parent6ec79f11513982c1e93495c6ee35ea3ccfb56035 (diff)
downloaderlang-63bd6be692381ac6d62bd4aed79c4488db44055a.tar.gz
Merge branch 'sverker/list_to_ref-fix/OTP-16438' into maint-20
* sverker/list_to_ref-fix/OTP-16438: erts: Fix bug in erlang:list_to_ref/1 for external refs
-rw-r--r--erts/emulator/beam/bif.c8
-rw-r--r--erts/emulator/test/list_bif_SUITE.erl53
2 files changed, 59 insertions, 2 deletions
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index d7a25adccb..e5854d6002 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -4420,12 +4420,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) ->