diff options
author | Lukas Larsson <lukas@erlang.org> | 2021-02-05 18:19:13 +0100 |
---|---|---|
committer | Lukas Larsson <lukas@erlang.org> | 2021-02-08 10:09:25 +0100 |
commit | 754f0f22dc7221208242c39860dbf2e48022951e (patch) | |
tree | 55d2acd4b169a5356772716d6bacaf0d72596b39 | |
parent | 74d045d62e283948247e03a93d22171802997804 (diff) | |
download | erlang-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.c | 5 | ||||
-rw-r--r-- | lib/kernel/test/seq_trace_SUITE.erl | 22 |
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 " |