summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErlang/OTP <otp@erlang.org>2021-09-02 12:15:40 +0200
committerErlang/OTP <otp@erlang.org>2021-09-02 12:15:40 +0200
commit0054a4beee1d977bb2adbb8b10af4edcec37b225 (patch)
treeb1f304531300482c81889c6faad1536638e91274
parent9154460788fa1c71b4f3ed8ed0cd0fbf0f2458b1 (diff)
parentfcd81a3c4ce7b1ceceb73d030723d2d4a0985873 (diff)
downloaderlang-0054a4beee1d977bb2adbb8b10af4edcec37b225.tar.gz
Merge branch 'sverker/22/dist-auto-connect-crash/GH-4964/OTP-17513' into maint-22
* sverker/22/dist-auto-connect-crash/GH-4964/OTP-17513: erts: Fix write-after-free bug for DistEntry (AGAIN)
-rw-r--r--erts/emulator/beam/erl_bif_unique.h14
-rw-r--r--erts/emulator/beam/erl_node_tables.c7
-rw-r--r--erts/emulator/test/distribution_SUITE.erl45
3 files changed, 62 insertions, 4 deletions
diff --git a/erts/emulator/beam/erl_bif_unique.h b/erts/emulator/beam/erl_bif_unique.h
index 41fce533d6..bda9a50d25 100644
--- a/erts/emulator/beam/erl_bif_unique.h
+++ b/erts/emulator/beam/erl_bif_unique.h
@@ -87,6 +87,7 @@ ERTS_GLB_INLINE void erts_sched_make_magic_ref_in_array(ErtsSchedulerData *esdp,
Uint32 ref[ERTS_REF_NUMBERS]);
ERTS_GLB_INLINE Eterm erts_sched_make_ref_in_buffer(ErtsSchedulerData *esdp,
Eterm buffer[ERTS_REF_THING_SIZE]);
+ERTS_GLB_INLINE Eterm erts_mk_magic_ref_get_refc(Eterm * *hpp, ErlOffHeap * ohp, Binary*, erts_aint_t*);
ERTS_GLB_INLINE Eterm erts_mk_magic_ref(Eterm **hpp, ErlOffHeap *ohp, Binary *mbp);
ERTS_GLB_INLINE Binary *erts_magic_ref2bin(Eterm mref);
ERTS_GLB_INLINE void erts_magic_ref_save_bin(Eterm ref);
@@ -175,17 +176,26 @@ erts_sched_make_ref_in_buffer(ErtsSchedulerData *esdp,
}
ERTS_GLB_INLINE Eterm
-erts_mk_magic_ref(Eterm **hpp, ErlOffHeap *ohp, Binary *bp)
+erts_mk_magic_ref_get_refc(Eterm **hpp, ErlOffHeap *ohp, Binary *bp, erts_aint_t* refcp)
{
Eterm *hp = *hpp;
ASSERT(bp->intern.flags & BIN_FLAG_MAGIC);
write_magic_ref_thing(hp, ohp, (ErtsMagicBinary *) bp);
*hpp += ERTS_MAGIC_REF_THING_SIZE;
- erts_refc_inc(&bp->intern.refc, 1);
+ if (refcp)
+ *refcp = erts_refc_inctest(&bp->intern.refc, 1);
+ else
+ erts_refc_inc(&bp->intern.refc, 1);
OH_OVERHEAD(ohp, bp->orig_size / sizeof(Eterm));
return make_internal_ref(hp);
}
+ERTS_GLB_INLINE Eterm
+erts_mk_magic_ref(Eterm **hpp, ErlOffHeap *ohp, Binary *bp)
+{
+ return erts_mk_magic_ref_get_refc(hpp, ohp, bp, NULL);
+}
+
ERTS_GLB_INLINE Binary *
erts_magic_ref2bin(Eterm mref)
{
diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c
index b8c36f4ecd..3c806944eb 100644
--- a/erts/emulator/beam/erl_node_tables.c
+++ b/erts/emulator/beam/erl_node_tables.c
@@ -394,10 +394,13 @@ erts_build_dhandle(Eterm **hpp, ErlOffHeap* ohp,
{
Binary *bin = ErtsDistEntry2Bin(dep);
Eterm mref, dhandle;
+ erts_aint_t refc;
ASSERT(bin);
ASSERT(ERTS_MAGIC_BIN_DESTRUCTOR(bin) == erts_dist_entry_destructor);
- erts_refc_inc_if(&bin->intern.refc, 0, 0); /* inc for pending delete */
- mref = erts_mk_magic_ref(hpp, ohp, bin);
+ mref = erts_mk_magic_ref_get_refc(hpp, ohp, bin, &refc);
+ if (refc < 2) {
+ erts_refc_inc(&bin->intern.refc, 2); /* inc for pending delete */
+ }
dhandle = TUPLE2(*hpp, make_small(conn_id), mref);
*hpp += 3;
return dhandle;
diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl
index 25e6ea89c8..2b8f69b2b9 100644
--- a/erts/emulator/test/distribution_SUITE.erl
+++ b/erts/emulator/test/distribution_SUITE.erl
@@ -68,6 +68,7 @@
message_latency_large_link_exit/1,
message_latency_large_monitor_exit/1,
message_latency_large_exit2/1,
+ dist_entry_refc_race/1,
system_limit/1]).
%% Internal exports.
@@ -76,6 +77,7 @@
optimistic_dflags_echo/0, optimistic_dflags_sender/1,
roundtrip/1, bounce/1, do_dist_auto_connect/1, inet_rpc_server/1,
dist_parallel_sender/3, dist_parallel_receiver/0,
+ derr_run/1,
dist_evil_parallel_receiver/0, make_busy/2]).
%% epmd_module exports
@@ -97,6 +99,7 @@ all() ->
contended_atom_cache_entry, contended_unicode_atom_cache_entry,
{group, message_latency},
{group, bad_dist}, {group, bad_dist_ext},
+ dist_entry_refc_race,
start_epmd_false, epmd_module, system_limit].
groups() ->
@@ -2567,6 +2570,48 @@ address_please(_Name, _Address, _AddressFamily) ->
IP = {127,0,0,1},
{ok, IP}.
+%% Try provoke DistEntry refc bugs (OTP-17513).
+dist_entry_refc_race(_Config) ->
+ {ok, Node} = start_node(dist_entry_refc_race, "+zdntgc 1"),
+ Pid = spawn_link(Node, ?MODULE, derr_run, [self()]),
+ {Pid, done} = receive M -> M end,
+ stop_node(Node),
+ ok.
+
+derr_run(Papa) ->
+ inet_db:set_lookup([file]), % make connection attempt fail fast
+ NScheds = erlang:system_info(schedulers_online),
+ SeqList = lists:seq(1, 25 * NScheds),
+ Nodes = [list_to_atom("none@host" ++ integer_to_list(Seq))
+ || Seq <- SeqList],
+ Self = self(),
+ Pids = [spawn_link(fun () -> derr_sender(Self, Nodes) end)
+ || _ <- SeqList],
+ derr_count(1, 8000),
+ [begin unlink(P), exit(P,kill) end || P <- Pids],
+ Papa ! {self(), done},
+ ok.
+
+derr_count(Max, Max) ->
+ done;
+derr_count(N, Max) ->
+ receive
+ count -> ok
+ end,
+ case N rem 1000 of
+ 0 ->
+ io:format("Total attempts: ~bk~n", [N div 1000]);
+ _ -> ok
+ end,
+ derr_count(N+1, Max).
+
+
+derr_sender(Main, Nodes) ->
+ [{none, Node} ! msg || Node <- Nodes],
+ Main ! count,
+ derr_sender(Main, Nodes).
+
+
%%% Utilities
timestamp() ->