#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
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;
}
#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);
PUSHs(args[i]);
PUTBACK;
- vmg_call_sv(ctor, G_SCALAR, 0);
+ vmg_call_sv(ctor, G_SCALAR, NULL);
SPAGAIN;
nsv = POPs;
#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;
#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) {
}
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. */
}
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);
XPUSHs(vmg_op_info(opinfo));
PUTBACK;
- vmg_call_sv(cb, G_SCALAR, 0);
+ vmg_call_sv(cb, G_SCALAR, NULL);
SPAGAIN;
svr = POPs;
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;
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;
}
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;
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;