X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=Magic.xs;h=1dada023c031867f619d812dc50bdc76facc7a78;hb=refs%2Ftags%2Fv0.37;hp=1c25a9bc7dca6e47ff61a090fff406ee0de13367;hpb=381ddc3601a29d14e23535dc97fc2c64cb9c495d;p=perl%2Fmodules%2FVariable-Magic.git diff --git a/Magic.xs b/Magic.xs index 1c25a9b..1dada02 100644 --- a/Magic.xs +++ b/Magic.xs @@ -36,6 +36,11 @@ # define dNOOP #endif +/* Safe unless stated otherwise in Makefile.PL */ +#ifndef VMG_FORKSAFE +# define VMG_FORKSAFE 1 +#endif + #ifndef VMG_MULTIPLICITY # if defined(MULTIPLICITY) || defined(PERL_IMPLICIT_CONTEXT) # define VMG_MULTIPLICITY 1 @@ -135,8 +140,9 @@ STATIC SV *vmg_clone(pTHX_ SV *sv, tTHX owner) { # endif #endif -/* uvar magic and Hash::Util::FieldHash were commited with 28419 */ -#if VMG_HAS_PERL_MAINT(5, 9, 4, 28419) || VMG_HAS_PERL(5, 10, 0) +/* uvar magic and Hash::Util::FieldHash were commited with 28419, but only + * enable it on 5.10 */ +#if VMG_HAS_PERL(5, 10, 0) # define VMG_UVAR 1 #else # define VMG_UVAR 0 @@ -337,8 +343,7 @@ STATIC U16 vmg_gensig(pTHX) { char buf[8]; dMY_CXT; - if (HvKEYS(MY_CXT.wizards) >= SIG_NBR) - croak(vmg_toomanysigs); + if (HvKEYS(MY_CXT.wizards) >= SIG_NBR) croak(vmg_toomanysigs); do { sig = SIG_NBR * Drand01() + SIG_MIN; @@ -515,7 +520,8 @@ STATIC UV vmg_cast(pTHX_ SV *sv, SV *wiz, AV *args) { /* One uvar magic in the chain is enough. */ for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic) { moremagic = mg->mg_moremagic; - if (mg->mg_type == PERL_MAGIC_uvar) { break; } + if (mg->mg_type == PERL_MAGIC_uvar) + break; } if (mg) { /* Found another uvar magic. */ @@ -547,7 +553,8 @@ STATIC UV vmg_dispell(pTHX_ SV *sv, U16 sig) { #endif /* VMG_UVAR */ MAGIC *mg, *prevmagic, *moremagic = NULL; - if (SvTYPE(sv) < SVt_PVMG) { return 0; } + if (SvTYPE(sv) < SVt_PVMG) + return 0; for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic) { moremagic = mg->mg_moremagic; @@ -567,7 +574,8 @@ STATIC UV vmg_dispell(pTHX_ SV *sv, U16 sig) { } } } - if (!mg) { return 0; } + if (!mg) + return 0; if (prevmagic) { prevmagic->mg_moremagic = moremagic; @@ -576,8 +584,11 @@ STATIC UV vmg_dispell(pTHX_ SV *sv, U16 sig) { } mg->mg_moremagic = NULL; - if (mg->mg_obj != sv) { SvREFCNT_dec(mg->mg_obj); } /* Destroy private data */ - SvREFCNT_dec((SV *) mg->mg_ptr); /* Unreference the wizard */ + /* Destroy private data */ + if (mg->mg_obj != sv) + SvREFCNT_dec(mg->mg_obj); + /* Unreference the wizard */ + SvREFCNT_dec((SV *) mg->mg_ptr); Safefree(mg); #if VMG_UVAR @@ -598,7 +609,8 @@ STATIC UV vmg_dispell(pTHX_ SV *sv, U16 sig) { struct ufuncs *uf; for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic){ moremagic = mg->mg_moremagic; - if (mg->mg_type == PERL_MAGIC_uvar) { break; } + if (mg->mg_type == PERL_MAGIC_uvar) + break; } /* assert(mg); */ uf = (struct ufuncs *) mg->mg_ptr; @@ -806,6 +818,10 @@ STATIC int vmg_svt_clear(pTHX_ SV *sv, MAGIC *mg) { STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { const MGWIZ *w; +#if VMG_HAS_PERL(5, 9, 5) + PERL_CONTEXT saved_cx; + I32 cxix; +#endif unsigned int had_err, has_err, flags = G_SCALAR | G_EVAL; int ret = 0; @@ -843,8 +859,23 @@ STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { if (had_err) flags |= G_KEEPERR; +#if VMG_HAS_PERL(5, 9, 5) + /* This context should not be used anymore, but since we croak in places the + * core doesn't even dare to, some pointers to it may remain in the upper call + * stack. Make sure call_sv() doesn't clobber it. */ + if (cxstack_ix < cxstack_max) + cxix = cxstack_ix + 1; + else + cxix = Perl_cxinc(aTHX); + saved_cx = cxstack[cxix]; +#endif + call_sv(w->cb_free, flags); +#if VMG_HAS_PERL(5, 9, 5) + cxstack[cxix] = saved_cx; +#endif + has_err = SvTRUE(ERRSV); if (IN_PERL_COMPILETIME && !had_err && has_err) ++PL_error_count; @@ -854,15 +885,6 @@ STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { FREETMPS; LEAVE; - if (has_err) { - /* Get the eval context that was pushed by call_sv, and fake an entry for the - * namesv, as die_where will need it to be non NULL later */ - PERL_CONTEXT *cx = cxstack + cxstack_ix + 1; - if (!cx->blk_eval.old_namesv) - cx->blk_eval.old_namesv - = sv_2mortal(newSVpvn_share("Variable/Magic/DUMMY.pm", 23, 0)); - } - /* Calling SvREFCNT_dec() will trigger destructors in an infinite loop, so * we have to rely on SvREFCNT() being a lvalue. Heck, even the core does it */ --SvREFCNT(sv); @@ -930,8 +952,10 @@ STATIC I32 vmg_svt_val(pTHX_ IV action, SV *sv) { key = umg->mg_obj; uf = (struct ufuncs *) umg->mg_ptr; - if (uf[1].uf_val != NULL) { uf[1].uf_val(aTHX_ action, sv); } - if (uf[1].uf_set != NULL) { uf[1].uf_set(aTHX_ action, sv); } + if (uf[1].uf_val) + uf[1].uf_val(aTHX_ action, sv); + if (uf[1].uf_set) + uf[1].uf_set(aTHX_ action, sv); action &= HV_FETCH_ISSTORE | HV_FETCH_ISEXISTS | HV_FETCH_LVALUE | HV_DELETE; for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) { @@ -1020,29 +1044,37 @@ STATIC int vmg_wizard_free(pTHX_ SV *wiz, MAGIC *mg) { if (hv_delete(MY_CXT.wizards, buf, sprintf(buf, "%u", w->sig), 0) != wiz) return 0; } - SvFLAGS(wiz) |= SVf_BREAK; - FREETMPS; - if (w->cb_data != NULL) { SvREFCNT_dec(SvRV(w->cb_data)); } - if (w->cb_get != NULL) { SvREFCNT_dec(SvRV(w->cb_get)); } - if (w->cb_set != NULL) { SvREFCNT_dec(SvRV(w->cb_set)); } - if (w->cb_len != NULL) { SvREFCNT_dec(SvRV(w->cb_len)); } - if (w->cb_clear != NULL) { SvREFCNT_dec(SvRV(w->cb_clear)); } - if (w->cb_free != NULL) { SvREFCNT_dec(SvRV(w->cb_free)); } + /* Unmortalize the wizard to avoid it being freed in weird places. */ + if (SvTEMP(wiz) && !SvREFCNT(wiz)) { + const I32 myfloor = PL_tmps_floor; + I32 i; + for (i = PL_tmps_ix; i > myfloor; --i) { + if (PL_tmps_stack[i] == wiz) + PL_tmps_stack[i] = NULL; + } + } + + if (w->cb_data) SvREFCNT_dec(SvRV(w->cb_data)); + if (w->cb_get) SvREFCNT_dec(SvRV(w->cb_get)); + if (w->cb_set) SvREFCNT_dec(SvRV(w->cb_set)); + if (w->cb_len) SvREFCNT_dec(SvRV(w->cb_len)); + if (w->cb_clear) SvREFCNT_dec(SvRV(w->cb_clear)); + if (w->cb_free) SvREFCNT_dec(SvRV(w->cb_free)); #if MGf_COPY - if (w->cb_copy != NULL) { SvREFCNT_dec(SvRV(w->cb_copy)); } + if (w->cb_copy) SvREFCNT_dec(SvRV(w->cb_copy)); #endif /* MGf_COPY */ #if 0 /* MGf_DUP */ - if (w->cb_dup != NULL) { SvREFCNT_dec(SvRV(w->cb_dup)); } + if (w->cb_dup) SvREFCNT_dec(SvRV(w->cb_dup)); #endif /* MGf_DUP */ #if MGf_LOCAL - if (w->cb_local != NULL) { SvREFCNT_dec(SvRV(w->cb_local)); } + if (w->cb_local) SvREFCNT_dec(SvRV(w->cb_local)); #endif /* MGf_LOCAL */ #if VMG_UVAR - if (w->cb_fetch != NULL) { SvREFCNT_dec(SvRV(w->cb_fetch)); } - if (w->cb_store != NULL) { SvREFCNT_dec(SvRV(w->cb_store)); } - if (w->cb_exists != NULL) { SvREFCNT_dec(SvRV(w->cb_exists)); } - if (w->cb_delete != NULL) { SvREFCNT_dec(SvRV(w->cb_delete)); } + if (w->cb_fetch) SvREFCNT_dec(SvRV(w->cb_fetch)); + if (w->cb_store) SvREFCNT_dec(SvRV(w->cb_store)); + if (w->cb_exists) SvREFCNT_dec(SvRV(w->cb_exists)); + if (w->cb_delete) SvREFCNT_dec(SvRV(w->cb_delete)); #endif /* VMG_UVAR */ Safefree(w->vtbl); @@ -1236,6 +1268,7 @@ BOOT: newSVuv(VMG_COMPAT_SCALAR_LENGTH_NOLEN)); newCONSTSUB(stash, "VMG_PERL_PATCHLEVEL", newSVuv(VMG_PERL_PATCHLEVEL)); newCONSTSUB(stash, "VMG_THREADSAFE", newSVuv(VMG_THREADSAFE)); + newCONSTSUB(stash, "VMG_FORKSAFE", newSVuv(VMG_FORKSAFE)); newCONSTSUB(stash, "VMG_OP_INFO_NAME", newSVuv(VMG_OP_INFO_NAME)); newCONSTSUB(stash, "VMG_OP_INFO_OBJECT", newSVuv(VMG_OP_INFO_OBJECT)); } @@ -1400,9 +1433,11 @@ OUTPUT: SV *getsig(SV *wiz) PROTOTYPE: $ +PREINIT: + U16 sig; CODE: - if (!SvROK(wiz)) { croak(vmg_invalid_wiz); } - RETVAL = newSVuv(SV2MGWIZ(SvRV(wiz))->sig); + sig = vmg_wizard_sig(wiz); + RETVAL = newSVuv(sig); OUTPUT: RETVAL @@ -1420,7 +1455,7 @@ CODE: for (i = 2; i < items; ++i) { SV *arg = ST(i); SvREFCNT_inc(arg); - if (av_store(args, i - 2, arg) == NULL) { croak(vmg_argstorefailed); } + if (av_store(args, i - 2, arg) == NULL) croak(vmg_argstorefailed); } } ret = newSVuv(vmg_cast(SvRV(sv), wiz, args)); @@ -1438,7 +1473,8 @@ PREINIT: PPCODE: sig = vmg_wizard_sig(wiz); data = vmg_data_get(SvRV(sv), sig); - if (!data) { XSRETURN_UNDEF; } + if (!data) + XSRETURN_EMPTY; ST(0) = data; XSRETURN(1);