summaryrefslogtreecommitdiffstats
path: root/gc.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2020-12-31 00:56:19 -0800
committerKaz Kylheku <kaz@kylheku.com>2020-12-31 00:56:19 -0800
commit28e985b35d918a51d0bc1b7fa459e43447c88e4a (patch)
tree05a6f828cca8092dc221d93f473114f1f8bdf304 /gc.c
parent5b1896c4098f71da3eeb88b8f45adaa10c3f0f5d (diff)
downloadtxr-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.c24
1 files 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;