From bd596153f1de4e6469383463c7b5750176816a1b Mon Sep 17 00:00:00 2001 From: dearblue Date: Thu, 6 Jun 2024 21:35:24 +0900 Subject: [PATCH] Detach `env` of ci explicitly on atexit Supplement to commit 177debacc589d85614e7b5d12f012193702dfd48 (#6276). If the ci is incomplete, the previous method may cause the application to crash because `env->stack` points to an invalid address when expanding the data stack. Since the ci is in an abnormal state, control it by putting `NULL` in `env->stack`. If the ci is fine and top-level, detach `env` as usual with `mrb_env_unshare()`. --- src/error.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/error.c b/src/error.c index 4cf6acc75..c622df789 100644 --- a/src/error.c +++ b/src/error.c @@ -592,10 +592,33 @@ mrb_protect_atexit(mrb_state *mrb) // Clean-up also makes it easier to collect unnecessary objects. mrb_callinfo zero = { 0 }; struct mrb_context *c = mrb->c = mrb->root_c; - c->ci = c->cibase; - *c->ci = zero; - c->ci->stack = c->stbase; mrb_gc_arena_restore(mrb, 0); + + if (c->ci == c->cibase) { + // Since there is no problem with the ci, the env object is detached normally. + struct REnv *e = mrb_vm_ci_env(c->ci); + *c->ci = zero; + c->ci->stack = c->stbase; + if (e) { + c->ci->u.env = NULL; + mrb_env_unshare(mrb, e, TRUE); + } + } + else { + // Any env objects on the ci that are in the process of being executed are destroyed. + do { + struct REnv *e = mrb_vm_ci_env(c->ci); + if (e) { + e->stack = NULL; + MRB_ENV_SET_LEN(e, 0); + MRB_ENV_SET_BIDX(e, 0); + MRB_ENV_CLOSE(e); + } + } while (c->ci-- > c->cibase); + c->ci = c->cibase; + *c->ci = zero; + c->ci->stack = c->stbase; + } } struct mrb_jmpbuf *prev_jmp = mrb->jmp;