From 3531fe179c0d58125e13dd08c53fe1ab084339c0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 31 Dec 2015 00:11:37 +0900 Subject: GC must scan env from fibers even when it's not yet copied to heap; fix #3063 --- include/mruby/proc.h | 2 ++ src/gc.c | 26 ++++++++++++++++---------- src/vm.c | 25 +++++++++++++++---------- 3 files changed, 33 insertions(+), 20 deletions(-) diff --git a/include/mruby/proc.h b/include/mruby/proc.h index 24f0f319f..5965a2b39 100644 --- a/include/mruby/proc.h +++ b/include/mruby/proc.h @@ -27,6 +27,8 @@ struct REnv { #define MRB_ENV_UNSHARE_STACK(e) ((e)->cioff = -1) #define MRB_ENV_STACK_SHARED_P(e) ((e)->cioff >= 0) +MRB_API void mrb_env_unshare(mrb_state*, struct REnv*); + struct RProc { MRB_OBJECT_HEADER; union { diff --git a/src/gc.c b/src/gc.c index 02e058f88..e31ec2f33 100644 --- a/src/gc.c +++ b/src/gc.c @@ -613,14 +613,11 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) case MRB_TT_ENV: { struct REnv *e = (struct REnv*)obj; + mrb_int i, len; - if (!MRB_ENV_STACK_SHARED_P(e)) { - mrb_int i, len; - - len = MRB_ENV_STACK_LEN(e); - for (i=0; istack[i]); - } + len = MRB_ENV_STACK_LEN(e); + for (i=0; istack[i]); } } break; @@ -725,9 +722,18 @@ obj_free(mrb_state *mrb, struct RBasic *obj) case MRB_TT_FIBER: { struct mrb_context *c = ((struct RFiber*)obj)->cxt; - - if (c != mrb->root_c) - mrb_free_context(mrb, c); + if (c && c != mrb->root_c) { + mrb_callinfo *ci = c->ci; + mrb_callinfo *ce = c->cibase; + + while (ce <= ci) { + struct REnv *e = ci->env; + if (e && !is_dead(&mrb->gc, e) && MRB_ENV_STACK_SHARED_P(e)) { + mrb_env_unshare(mrb, e); + } + ci--; + } + } } break; diff --git a/src/vm.c b/src/vm.c index b2149b250..58c73e4dd 100644 --- a/src/vm.c +++ b/src/vm.c @@ -237,22 +237,27 @@ cipush(mrb_state *mrb) return ci; } +MRB_API void +mrb_env_unshare(mrb_state *mrb, struct REnv *e) +{ + size_t len = (size_t)MRB_ENV_STACK_LEN(e); + mrb_value *p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len); + + MRB_ENV_UNSHARE_STACK(e); + if (len > 0) { + stack_copy(p, e->stack, len); + } + e->stack = p; + mrb_write_barrier(mrb, (struct RBasic *)e); +} + static void cipop(mrb_state *mrb) { struct mrb_context *c = mrb->c; if (c->ci->env) { - struct REnv *e = c->ci->env; - size_t len = (size_t)MRB_ENV_STACK_LEN(e); - mrb_value *p = (mrb_value *)mrb_malloc(mrb, sizeof(mrb_value)*len); - - MRB_ENV_UNSHARE_STACK(e); - if (len > 0) { - stack_copy(p, e->stack, len); - } - e->stack = p; - mrb_write_barrier(mrb, (struct RBasic *)e); + mrb_env_unshare(mrb, c->ci->env); } c->ci--; -- cgit v1.2.3