diff options
author | Rickard Green <rickard@erlang.org> | 2021-04-22 13:15:45 +0200 |
---|---|---|
committer | Rickard Green <rickard@erlang.org> | 2021-04-22 13:29:25 +0200 |
commit | bc3dd429b94b6bde3bc6de1000e6b37ddd0d0697 (patch) | |
tree | 593bac0be91c238ecc8b6632d0c470a0ac9b0906 | |
parent | 7fe7fa3dde556b5b92522f8279d465bb52baf1f6 (diff) | |
download | erlang-bc3dd429b94b6bde3bc6de1000e6b37ddd0d0697.tar.gz |
Fix literal collection of messages
The literal GC missed copying literals in messages where the whole
message consisted of a literal.
-rw-r--r-- | erts/emulator/beam/beam_bif_load.c | 34 | ||||
-rw-r--r-- | erts/emulator/test/persistent_term_SUITE.erl | 46 |
2 files changed, 74 insertions, 6 deletions
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index bb1b2e5b27..6bd38823f5 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -922,7 +922,7 @@ msg_copy_literal_area(ErtsMessage *msgp, int *redsp, *redsp += 1; - if (!ERTS_SIG_IS_INTERNAL_MSG(msgp) || !msgp->data.attached) + if (!ERTS_SIG_IS_INTERNAL_MSG(msgp)) return; if (msgp->data.attached == ERTS_MSG_COMBINED_HFRAG) @@ -930,6 +930,23 @@ msg_copy_literal_area(ErtsMessage *msgp, int *redsp, else hfrag = msgp->data.heap_frag; + /* + * Literals should only be able to appear in the + * first message reference, i.e., the message + * itself... + */ + if (ErtsInArea(msgp->m[0], literals, lit_bsize)) + lit_sz += size_object(msgp->m[0]); + +#ifdef DEBUG + { + int i; + for (i = 1; i < ERL_MESSAGE_REF_ARRAY_SZ; i++) { + ASSERT(!ErtsInArea(msgp->m[i], literals, lit_bsize)); + } + } +#endif + for (hf = hfrag; hf; hf = hf->next) { lit_sz += hfrag_literal_size(&hf->mem[0], &hf->mem[hf->used_size], @@ -942,6 +959,11 @@ msg_copy_literal_area(ErtsMessage *msgp, int *redsp, ErlHeapFragment *bp = new_message_buffer(lit_sz); Eterm *hp = bp->mem; + if (ErtsInArea(msgp->m[0], literals, lit_bsize)) { + Uint sz = size_object(msgp->m[0]); + msgp->m[0] = copy_struct(msgp->m[0], sz, &hp, &bp->off_heap); + } + for (hf = hfrag; hf; hf = hf->next) { hfrag_literal_copy(&hp, &bp->off_heap, &hf->mem[0], @@ -950,10 +972,14 @@ msg_copy_literal_area(ErtsMessage *msgp, int *redsp, hfrag = hf; } - /* link new hfrag last */ - ASSERT(hfrag->next == NULL); - hfrag->next = bp; bp->next = NULL; + /* link new hfrag last */ + if (!hfrag) + msgp->data.heap_frag = bp; + else { + ASSERT(hfrag->next == NULL); + hfrag->next = bp; + } } } diff --git a/erts/emulator/test/persistent_term_SUITE.erl b/erts/emulator/test/persistent_term_SUITE.erl index 93eb026ced..7c0b1ab3db 100644 --- a/erts/emulator/test/persistent_term_SUITE.erl +++ b/erts/emulator/test/persistent_term_SUITE.erl @@ -25,7 +25,7 @@ basic/1,purging/1,sharing/1,get_trapping/1, info/1,info_trapping/1,killed_while_trapping/1, off_heap_values/1,keys/1,collisions/1, - init_restart/1]). + init_restart/1,whole_message/1]). %% -export([test_init_restart_cmd/1]). @@ -37,7 +37,7 @@ suite() -> all() -> [basic,purging,sharing,get_trapping,info,info_trapping, killed_while_trapping,off_heap_values,keys,collisions, - init_restart]. + init_restart,whole_message]. init_per_suite(Config) -> %% Put a term in the dict so that we know that the testcases handle @@ -596,6 +596,48 @@ do_test_init_restart_cmd(File) -> init:stop() end. +%% Test that the literal is copied when removed also when +%% the whole message is a literal... + +whole_message(Config) when is_list(Config) -> + whole_message_test(on_heap), + whole_message_test(off_heap), + ok. + +whole_message_test(MQD) -> + io:format("Testing on ~p~n", [MQD]), + Go = make_ref(), + Done = make_ref(), + TestRef = make_ref(), + Tester = self(), + persistent_term:put(test_ref, TestRef), + Pid = spawn_opt(fun () -> + receive Go -> ok end, + receive TestRef -> ok end, + receive TestRef -> ok end, + receive TestRef -> ok end, + receive [TestRef] -> ok end, + receive [TestRef] -> ok end, + receive [TestRef] -> ok end, + Tester ! Done + end, [link, {message_queue_data, MQD}]), + Pid ! persistent_term:get(test_ref), + Pid ! persistent_term:get(test_ref), + Pid ! persistent_term:get(test_ref), + %% Throw in some messages with a reference from the heap + %% while we're at it... + Pid ! [persistent_term:get(test_ref)], + Pid ! [persistent_term:get(test_ref)], + Pid ! [persistent_term:get(test_ref)], + persistent_term:erase(test_ref), + receive after 1000 -> ok end, + Pid ! Go, + receive Done -> ok end, + unlink(Pid), + exit(Pid, kill), + false = is_process_alive(Pid), + ok. + %% Check that there is the same number of persistents terms before %% and after each test case. |