From aa8e490fd54bc7c62e591edc349c0dcb5cc572a9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 25 Apr 2017 17:25:48 +0900 Subject: Prevent GC during `each_object`; fix #3616 --- src/gc.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index da84ca3ad..cef0b33e8 100644 --- a/src/gc.c +++ b/src/gc.c @@ -17,6 +17,7 @@ #include #include #include +#include /* = Tri-color Incremental Garbage Collection @@ -1162,7 +1163,7 @@ mrb_incremental_gc(mrb_state *mrb) { mrb_gc *gc = &mrb->gc; - if (gc->disabled) return; + if (gc->disabled || gc->iterating) return; GC_INVOKE_TIME_REPORT("mrb_incremental_gc()"); GC_TIME_START; @@ -1202,7 +1203,7 @@ mrb_full_gc(mrb_state *mrb) { mrb_gc *gc = &mrb->gc; - if (gc->disabled) return; + if (gc->disabled || gc->iterating) return; GC_INVOKE_TIME_REPORT("mrb_full_gc()"); GC_TIME_START; @@ -1508,7 +1509,32 @@ gc_each_objects(mrb_state *mrb, mrb_gc *gc, mrb_each_object_callback *callback, void mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data) { - gc_each_objects(mrb, &mrb->gc, callback, data); + mrb_bool iterating = mrb->gc.iterating; + + mrb_full_gc(mrb); + mrb->gc.iterating = TRUE; + if (iterating) { + gc_each_objects(mrb, &mrb->gc, callback, data); + } + else { + struct mrb_jmpbuf *prev_jmp = mrb->jmp; + struct mrb_jmpbuf c_jmp; + + MRB_TRY(&c_jmp) { + mrb->jmp = &c_jmp; + gc_each_objects(mrb, &mrb->gc, callback, data); + mrb->jmp = prev_jmp; + mrb->gc.iterating = iterating; + } MRB_CATCH(&c_jmp) { + mrb->jmp = prev_jmp; + mrb->gc.iterating = iterating; + if (mrb->exc) { + mrb_value exc = mrb_obj_value(mrb->exc); + mrb->exc = NULL; + mrb_exc_raise(mrb, exc); + } + } MRB_END_EXC(&c_jmp); + } } #ifdef GC_TEST -- cgit v1.2.3