From 28e985b35d918a51d0bc1b7fa459e43447c88e4a Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Thu, 31 Dec 2020 00:56:19 -0800 Subject: 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. --- gc.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/gc.c b/gc.c index bec066e8..05cf55dc 100644 --- a/gc.c +++ b/gc.c @@ -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; -- cgit v1.2.3