diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2020-12-31 00:56:19 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2020-12-31 00:56:19 -0800 |
commit | 28e985b35d918a51d0bc1b7fa459e43447c88e4a (patch) | |
tree | 05a6f828cca8092dc221d93f473114f1f8bdf304 /gc.c | |
parent | 5b1896c4098f71da3eeb88b8f45adaa10c3f0f5d (diff) | |
download | txr-28e985b35d918a51d0bc1b7fa459e43447c88e4a.tar.gz txr-28e985b35d918a51d0bc1b7fa459e43447c88e4a.tar.bz2 txr-28e985b35d918a51d0bc1b7fa459e43447c88e4a.zip |
gc: bug: finalization logic causing gc assert
This problem was introduced on Feb 18, 2019 in commit
3931df5cba3d826511503ad1c0a5b84c1363765e.
Explicit finalization of objects outside of GC can
trigger an assertion in a later GC pass.
* gc.c (call_finalizers_impl): We simply must not have
duplicate entries in fresh_obj; this causes problems for
sweep_one. Under Valgrind debugging, sweep_one protects the
memory of processed entries, so a duplicate visit triggers bad
accesses. A more serious issue is that this function can be
called outside of gc, explicitly, since it is available as an
API function. So that is to say, non-garbage objects can have
their finalizers called ouside of GC. If this function is
called explicitly, outside of GC, it can end up doing
something stupid, like adding a generation 1 object into the
freshobj array, triggering an assert. We address this by not
doing any of that processing if GC is not taking place.
Diffstat (limited to 'gc.c')
-rw-r--r-- | gc.c | 24 |
1 files changed, 17 insertions, 7 deletions
@@ -783,16 +783,26 @@ static val call_finalizers_impl(val ctx, while (found) { struct fin_reg *next = found->next; + int dup, i, freshobj_idx_start = freshobj_idx; val obj = found->obj; funcall1(found->fun, obj); #if CONFIG_GEN_GC - /* Note: here an object may be added to freshobj more than once, since - * multiple finalizers can be registered. - */ - if (freshobj_idx < FRESHOBJ_VEC_SIZE && obj->t.gen == 0) - freshobj[freshobj_idx++] = obj; - else - full_gc = 1; + if (inprogress) { + for (dup = 0, i = freshobj_idx_start; i < freshobj_idx; i++) { + if (freshobj[i] == obj) { + dup = 1; + break; + } + } + + if (!dup) { + if (freshobj_idx < FRESHOBJ_VEC_SIZE && obj->t.gen == 0) { + freshobj[freshobj_idx++] = obj; + } else { + full_gc = 1; + } + } + } #endif free(found); found = next; |