summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErlang/OTP <otp@erlang.org>2020-04-06 12:45:13 +0200
committerErlang/OTP <otp@erlang.org>2020-04-06 12:45:13 +0200
commit3bdb81e2d8f609b24fb06f14c1cbdf9ba56c2ffa (patch)
tree4f8a470664d10ec9f4c5fd1e2153e552f350ec2f
parent7162fa04faca0e0aa8ad78bf0e00f77820643965 (diff)
parent8a71d0f980d734fdb09f9ac34a90fbffb4bd601e (diff)
downloaderlang-3bdb81e2d8f609b24fb06f14c1cbdf9ba56c2ffa.tar.gz
Merge branch 'john/erts/fix-cla-disable-gc/OTP-16555/ERL-1088' into maint-22
* john/erts/fix-cla-disable-gc/OTP-16555/ERL-1088: erts: Delay copying literal area when GC is disabled
-rw-r--r--erts/emulator/beam/beam_bif_load.c11
-rw-r--r--erts/emulator/beam/erl_bif_info.c34
-rw-r--r--erts/emulator/test/code_SUITE.erl42
3 files changed, 82 insertions, 5 deletions
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index a168c52006..a965f157ba 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -955,6 +955,14 @@ erts_proc_copy_literal_area(Process *c_p, int *redsp, int fcalls, int gc_allowed
if (!la)
goto return_ok;
+ /* The heap may be in an inconsistent state when the GC is disabled, for
+ * example when we're in the middle of building a record in
+ * binary_to_term/1, so we have to delay scanning until the GC is enabled
+ * again. */
+ if (c_p->flags & F_DISABLE_GC) {
+ return THE_NON_VALUE;
+ }
+
oh = la->off_heap;
literals = (char *) &la->start[0];
lit_bsize = (char *) la->end - literals;
@@ -1075,9 +1083,6 @@ literal_gc:
if (!gc_allowed)
return am_need_gc;
- if (c_p->flags & F_DISABLE_GC)
- return THE_NON_VALUE;
-
*redsp += erts_garbage_collect_literals(c_p, (Eterm *) literals, lit_bsize,
oh, fcalls);
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 9af5f3ea38..aee097840f 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -4543,6 +4543,40 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2)
erts_set_gc_state(BIF_P, enable);
BIF_RET(res);
}
+ else if (ERTS_IS_ATOM_STR("inconsistent_heap", BIF_ARG_1)) {
+ /* Used by code_SUITE (emulator) */
+ if (am_start == BIF_ARG_2) {
+ Eterm broken_term;
+ Eterm *hp;
+
+ ERTS_ASSERT(!(BIF_P->flags & F_DISABLE_GC));
+ erts_set_gc_state(BIF_P, 0);
+
+ hp = HAlloc(BIF_P, 2);
+ hp[0] = make_arityval(1234);
+ hp[1] = THE_NON_VALUE;
+
+ broken_term = make_tuple(hp);
+
+ BIF_RET(broken_term);
+ } else {
+ Eterm broken_term;
+ Eterm *hp;
+
+ broken_term = BIF_ARG_2;
+
+ hp = tuple_val(broken_term);
+ ERTS_ASSERT(hp[0] == make_arityval(1234));
+ ERTS_ASSERT(hp[1] == THE_NON_VALUE);
+ hp[0] = make_arityval(1);
+ hp[1] = am_ok;
+
+ ERTS_ASSERT(BIF_P->flags & F_DISABLE_GC);
+ erts_set_gc_state(BIF_P, 1);
+
+ BIF_RET(am_ok);
+ }
+ }
else if (ERTS_IS_ATOM_STR("colliding_names", BIF_ARG_1)) {
/* Used by ets_SUITE (stdlib) */
if (is_tuple(BIF_ARG_2)) {
diff --git a/erts/emulator/test/code_SUITE.erl b/erts/emulator/test/code_SUITE.erl
index bb4880b150..5fbb5d5a9c 100644
--- a/erts/emulator/test/code_SUITE.erl
+++ b/erts/emulator/test/code_SUITE.erl
@@ -348,8 +348,25 @@ constant_pools(Config) when is_list(Config) ->
receive
{'EXIT',NoOldHeap,{A,B,C,D}} ->
ok;
- Other ->
- ct:fail({unexpected,Other})
+ Other_NoOldHeap ->
+ ct:fail({unexpected,Other_NoOldHeap})
+ end,
+ {module,literals} = erlang:load_module(literals, Code),
+
+ %% Have a process with an inconsistent heap (legal while GC is disabled)
+ %% that references the literals in the 'literals' module.
+ InconsistentHeap = spawn_link(fun() -> inconsistent_heap(Self) end),
+ receive go -> ok end,
+ true = erlang:delete_module(literals),
+ false = erlang:check_process_code(InconsistentHeap, literals),
+ erlang:check_process_code(self(), literals),
+ true = erlang:purge_module(literals),
+ InconsistentHeap ! done,
+ receive
+ {'EXIT',InconsistentHeap,{A,B,C}} ->
+ ok;
+ Other_InconsistentHeap ->
+ ct:fail({unexpected,Other_InconsistentHeap})
end,
{module,literals} = erlang:load_module(literals, Code),
@@ -424,6 +441,27 @@ old_heap(Parent) ->
exit(Res)
end.
+inconsistent_heap(Parent) ->
+ A = literals:a(),
+ B = literals:b(),
+ C = literals:huge_bignum(),
+ Res = {A,B,C},
+ Parent ! go,
+
+ %% Disable the GC and return a tuple whose arity and contents are broken
+ BrokenTerm = erts_debug:set_internal_state(inconsistent_heap, start),
+ receive
+ after 5000 ->
+ %% Fix the tuple and enable the GC again
+ ok = erts_debug:set_internal_state(inconsistent_heap, BrokenTerm),
+ erlang:garbage_collect()
+ end,
+
+ receive
+ done ->
+ exit(Res)
+ end.
+
hibernated(Parent) ->
A = literals:a(),
B = literals:b(),