summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Larsson <lukas@erlang.org>2021-02-05 18:19:13 +0100
committerLukas Larsson <lukas@erlang.org>2021-02-08 10:09:25 +0100
commit754f0f22dc7221208242c39860dbf2e48022951e (patch)
tree55d2acd4b169a5356772716d6bacaf0d72596b39
parent74d045d62e283948247e03a93d22171802997804 (diff)
downloaderlang-754f0f22dc7221208242c39860dbf2e48022951e.tar.gz
erts: Fix seq_trace token gc
If the seq_trace tuple is on the mature side of the young heap we need to make a copy as otherwise the tuple will be promited to the old heap before the token which will lead to all kinds of issues.
-rw-r--r--erts/emulator/beam/erl_bif_trace.c5
-rw-r--r--lib/kernel/test/seq_trace_SUITE.erl22
2 files changed, 24 insertions, 3 deletions
diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c
index 7708e0755c..36cad53ce4 100644
--- a/erts/emulator/beam/erl_bif_trace.c
+++ b/erts/emulator/beam/erl_bif_trace.c
@@ -1841,10 +1841,13 @@ new_seq_trace_token(Process* p, int ensure_new_heap)
make_small(p->seq_trace_lastcnt));
}
else if (ensure_new_heap) {
+ Eterm *mature = p->abandoned_heap ? p->abandoned_heap : p->heap;
+ Uint mature_size = p->high_water - mature;
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))) {
+ (OLD_HEND(p) - OLD_HEAP(p))*sizeof(Eterm)) ||
+ ErtsInArea(tpl, mature, mature_size*sizeof(Eterm))) {
hp = HAlloc(p, 6);
sys_memcpy(hp, tpl, 6*sizeof(Eterm));
SEQ_TRACE_TOKEN(p) = make_tuple(hp);
diff --git a/lib/kernel/test/seq_trace_SUITE.erl b/lib/kernel/test/seq_trace_SUITE.erl
index f8efd1ffea..df1ad00a80 100644
--- a/lib/kernel/test/seq_trace_SUITE.erl
+++ b/lib/kernel/test/seq_trace_SUITE.erl
@@ -26,7 +26,7 @@
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2]).
-export([token_set_get/1, tracer_set_get/1, print/1,
- old_heap_token/1,
+ old_heap_token/1,mature_heap_token/1,
send/1, distributed_send/1, recv/1, distributed_recv/1,
trace_exit/1, distributed_exit/1, call/1, port/1,
port_clean_token/1,
@@ -54,7 +54,7 @@ suite() ->
all() ->
[token_set_get, tracer_set_get, print, send, send_literal,
distributed_send, recv, distributed_recv, trace_exit,
- old_heap_token,
+ old_heap_token, mature_heap_token,
distributed_exit, call, port, match_set_seq_token,
port_clean_token,
gc_seq_token, label_capability_mismatch,
@@ -971,6 +971,24 @@ old_heap_token(Config) when is_list(Config) ->
{label,NewLabel} = seq_trace:get_token(label),
ok.
+%% Verify changing label on existing token when it resides on mature heap.
+%% Bug caused faulty ref from old to new heap.
+mature_heap_token(Config) when is_list(Config) ->
+
+ seq_trace:set_token(label, 1),
+ erlang:garbage_collect(self(), [{type, minor}]),
+ %% Now token should be on mature heap
+ %% Set a new non-literal label which should reside on new-heap.
+ NewLabel = {self(), "new label"},
+ seq_trace:set_token(label, NewLabel),
+
+ %% If bug, we now have a ref from mature to new heap. If we now GC
+ %% twice the token will refer to deallocated memory.
+ erlang:garbage_collect(self(), [{type, minor}]),
+ erlang:garbage_collect(self(), [{type, minor}]),
+ {label,NewLabel} = seq_trace:get_token(label),
+ ok.
+
match_set_seq_token(doc) ->
["Tests that match spec function set_seq_token does not "