X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=Magic.xs;h=d3d17bf24b48edb3ba273309f7c2c2c19aed28bc;hb=4b913bc8188ef7f2fc57062123c8b537db8c0796;hp=59eaa75de25d6ff88dfe32f96486a1bad4a815c5;hpb=d67d5aa3c48466b4302b1e9be9fe31e032ca48f2;p=perl%2Fmodules%2FVariable-Magic.git diff --git a/Magic.xs b/Magic.xs index 59eaa75..d3d17bf 100644 --- a/Magic.xs +++ b/Magic.xs @@ -224,7 +224,7 @@ STATIC void vmg_mg_magical(SV *sv) { #define VMG_SAVE_LAST_CX (!VMG_HAS_PERL(5, 8, 4) || VMG_HAS_PERL(5, 9, 5)) -STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, I32 destructor) { +STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, SV *dsv) { #define vmg_call_sv(S, F, D) vmg_call_sv(aTHX_ (S), (F), (D)) I32 ret, cxix = 0, in_eval = 0; #if VMG_SAVE_LAST_CX @@ -239,7 +239,7 @@ STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, I32 destructor) { if (cxstack_ix < cxstack_max) { cxix = cxstack_ix + 1; - if (destructor && CxTYPE(cxstack + cxix) == CXt_EVAL) + if (dsv && CxTYPE(cxstack + cxix) == CXt_EVAL) in_eval = 1; } @@ -277,8 +277,23 @@ STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, I32 destructor) { #else ++PL_Ierror_count; #endif - } else if (!in_eval) + } else if (!in_eval) { + if (dsv) { + /* We are about to croak() while dsv is being destroyed. Try to clean up + * things a bit. */ + MAGIC *mg = SvMAGIC(dsv); + SvREFCNT_dec((SV *) mg->mg_ptr); + /* mg->mg_obj may not be refcounted if the data constructor returned the + * variable itself. */ + if (mg->mg_flags & MGf_REFCOUNTED) + SvREFCNT_dec(mg->mg_obj); + SvMAGIC_set(dsv, mg->mg_moremagic); + Safefree(mg); + mg_magical(dsv); + SvREFCNT_dec(dsv); + } croak(NULL); + } } else { if (old_err) { SvREFCNT_dec(ERRSV); @@ -734,7 +749,7 @@ STATIC SV *vmg_data_new(pTHX_ SV *ctor, SV *sv, SV **args, I32 items) { PUSHs(args[i]); PUTBACK; - vmg_call_sv(ctor, G_SCALAR, 0); + vmg_call_sv(ctor, G_SCALAR, NULL); SPAGAIN; nsv = POPs; @@ -763,6 +778,11 @@ STATIC SV *vmg_data_get(pTHX_ SV *sv, const vmg_wizard *w) { #if VMG_UVAR STATIC I32 vmg_svt_val(pTHX_ IV, SV *); +typedef struct { + struct ufuncs new_uf; + struct ufuncs old_uf; +} vmg_uvar_ud; + STATIC void vmg_uvar_del(SV *sv, MAGIC *prevmagic, MAGIC *mg, MAGIC *moremagic) { if (prevmagic) { prevmagic->mg_moremagic = moremagic; @@ -822,14 +842,14 @@ STATIC UV vmg_cast(pTHX_ SV *sv, const vmg_wizard *w, const SV *wiz, SV **args, #if VMG_UVAR if (w->uvar) { MAGIC *prevmagic, *moremagic = NULL; - struct ufuncs uf[2]; + vmg_uvar_ud ud; - uf[0].uf_val = vmg_svt_val; - uf[0].uf_set = NULL; - uf[0].uf_index = 0; - uf[1].uf_val = NULL; - uf[1].uf_set = NULL; - uf[1].uf_index = 0; + ud.new_uf.uf_val = vmg_svt_val; + ud.new_uf.uf_set = NULL; + ud.new_uf.uf_index = 0; + ud.old_uf.uf_val = NULL; + ud.old_uf.uf_set = NULL; + ud.old_uf.uf_index = 0; /* One uvar magic in the chain is enough. */ for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic) { @@ -839,18 +859,18 @@ STATIC UV vmg_cast(pTHX_ SV *sv, const vmg_wizard *w, const SV *wiz, SV **args, } if (mg) { /* Found another uvar magic. */ - struct ufuncs *olduf = (struct ufuncs *) mg->mg_ptr; - if (olduf->uf_val == vmg_svt_val) { + struct ufuncs *uf = (struct ufuncs *) mg->mg_ptr; + if (uf->uf_val == vmg_svt_val) { /* It's our uvar magic, nothing to do. oldgmg was true. */ goto done; } else { /* It's another uvar magic, backup it and replace it by ours. */ - uf[1] = *olduf; + ud.old_uf = *uf; vmg_uvar_del(sv, prevmagic, mg, moremagic); } } - sv_magic(sv, NULL, PERL_MAGIC_uvar, (const char *) &uf, sizeof(uf)); + sv_magic(sv, NULL, PERL_MAGIC_uvar, (const char *) &ud, sizeof(ud)); vmg_mg_magical(sv); /* Our hash now carries uvar magic. The uvar/clear shortcoming has to be * handled by our uvar callback. */ @@ -927,21 +947,23 @@ STATIC UV vmg_dispell(pTHX_ SV *sv, const vmg_wizard *w) { } if (uvars == 1) { - struct ufuncs *uf; + vmg_uvar_ud *ud; + for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic){ moremagic = mg->mg_moremagic; if (mg->mg_type == PERL_MAGIC_uvar) break; } - /* assert(mg); */ - uf = (struct ufuncs *) mg->mg_ptr; - /* assert(uf->uf_val == vmg_svt_val); */ - if (uf[1].uf_val || uf[1].uf_set) { + + ud = (vmg_uvar_ud *) mg->mg_ptr; + if (ud->old_uf.uf_val || ud->old_uf.uf_set) { /* Revert the original uvar magic. */ - uf[0] = uf[1]; - Renew(uf, 1, struct ufuncs); + struct ufuncs *uf; + Newx(uf, 1, struct ufuncs); + *uf = ud->old_uf; + Safefree(ud); mg->mg_ptr = (char *) uf; - mg->mg_len = sizeof(struct ufuncs); + mg->mg_len = sizeof(*uf); } else { /* Remove the uvar magic. */ vmg_uvar_del(sv, prevmagic, mg, moremagic); @@ -1051,7 +1073,7 @@ STATIC int vmg_cb_call(pTHX_ SV *cb, unsigned int flags, SV *sv, ...) { XPUSHs(vmg_op_info(opinfo)); PUTBACK; - vmg_call_sv(cb, G_SCALAR, 0); + vmg_call_sv(cb, G_SCALAR, NULL); SPAGAIN; svr = POPs; @@ -1143,7 +1165,7 @@ STATIC U32 vmg_svt_len(pTHX_ SV *sv, MAGIC *mg) { XPUSHs(vmg_op_info(opinfo)); PUTBACK; - vmg_call_sv(w->cb_len, G_SCALAR, 0); + vmg_call_sv(w->cb_len, G_SCALAR, NULL); SPAGAIN; svr = POPs; @@ -1218,7 +1240,7 @@ STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { XPUSHs(vmg_op_info(w->opinfo)); PUTBACK; - vmg_call_sv(w->cb_free, G_SCALAR, 1); + vmg_call_sv(w->cb_free, G_SCALAR, sv); SPAGAIN; svr = POPs; @@ -1304,7 +1326,7 @@ STATIC OP *vmg_pp_resetuvar(pTHX) { } STATIC I32 vmg_svt_val(pTHX_ IV action, SV *sv) { - struct ufuncs *uf; + vmg_uvar_ud *ud; MAGIC *mg, *umg; SV *key = NULL, *newkey = NULL; int tied = 0; @@ -1312,12 +1334,12 @@ STATIC I32 vmg_svt_val(pTHX_ IV action, SV *sv) { umg = mg_find(sv, PERL_MAGIC_uvar); /* umg can't be NULL or we wouldn't be there. */ key = umg->mg_obj; - uf = (struct ufuncs *) umg->mg_ptr; + ud = (vmg_uvar_ud *) umg->mg_ptr; - if (uf[1].uf_val) - uf[1].uf_val(aTHX_ action, sv); - if (uf[1].uf_set) - uf[1].uf_set(aTHX_ action, sv); + if (ud->old_uf.uf_val) + ud->old_uf.uf_val(aTHX_ action, sv); + if (ud->old_uf.uf_set) + ud->old_uf.uf_set(aTHX_ action, sv); for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) { const vmg_wizard *w;