diff options
Diffstat (limited to 'mg.c')
-rw-r--r-- | mg.c | 95 |
1 files changed, 60 insertions, 35 deletions
@@ -26,34 +26,36 @@ # endif #endif +#ifdef PERL_OBJECT +# define VTBL this->*vtbl +#else +# define VTBL *vtbl +static void restore_magic _((void *p)); +#endif + /* * Use the "DESTRUCTOR" scope cleanup to reinstate magic. */ -#ifdef PERL_OBJECT - -#define VTBL this->*vtbl - -#else struct magic_state { SV* mgs_sv; U32 mgs_flags; + I32 mgs_ss_ix; }; -typedef struct magic_state MGS; - -static void restore_magic _((void *p)); -#define VTBL *vtbl - -#endif +/* MGS is typedef'ed to struct magic_state in perl.h */ STATIC void -save_magic(MGS *mgs, SV *sv) +save_magic(I32 mgs_ix, SV *sv) { + MGS* mgs; assert(SvMAGICAL(sv)); + SAVEDESTRUCTOR(restore_magic, (void*)mgs_ix); + + mgs = SSPTR(mgs_ix, MGS*); mgs->mgs_sv = sv; mgs->mgs_flags = SvMAGICAL(sv) | SvREADONLY(sv); - SAVEDESTRUCTOR(restore_magic, mgs); + mgs->mgs_ss_ix = PL_savestack_ix; /* points after the saved destructor */ SvMAGICAL_off(sv); SvREADONLY_off(sv); @@ -63,9 +65,12 @@ save_magic(MGS *mgs, SV *sv) STATIC void restore_magic(void *p) { - MGS* mgs = (MGS*)p; + MGS* mgs = SSPTR((I32)p, MGS*); SV* sv = mgs->mgs_sv; + if (!sv) + return; + if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) { if (mgs->mgs_flags) @@ -75,6 +80,24 @@ restore_magic(void *p) if (SvGMAGICAL(sv)) SvFLAGS(sv) &= ~(SVf_IOK|SVf_NOK|SVf_POK); } + + mgs->mgs_sv = NULL; /* mark the MGS structure as restored */ + + /* If we're still on top of the stack, pop us off. (That condition + * will be satisfied if restore_magic was called explicitly, but *not* + * if it's being called via leave_scope.) + * The reason for doing this is that otherwise, things like sv_2cv() + * may leave alloc gunk on the savestack, and some code + * (e.g. sighandler) doesn't expect that... + */ + if (PL_savestack_ix == mgs->mgs_ss_ix) + { + assert(SSPOPINT == SAVEt_DESTRUCTOR); + PL_savestack_ix -= 2; + assert(SSPOPINT == SAVEt_ALLOC); + PL_savestack_ix -= SSPOPINT; + } + } void @@ -97,13 +120,13 @@ mg_magical(SV *sv) int mg_get(SV *sv) { - MGS mgs; + I32 mgs_ix; MAGIC* mg; MAGIC** mgp; int mgp_valid = 0; - ENTER; - save_magic(&mgs, sv); + mgs_ix = SSNEW(sizeof(MGS)); + save_magic(mgs_ix, sv); mgp = &SvMAGIC(sv); while ((mg = *mgp) != 0) { @@ -113,7 +136,7 @@ mg_get(SV *sv) /* Ignore this magic if it's been deleted */ if ((mg == (mgp_valid ? *mgp : SvMAGIC(sv))) && (mg->mg_flags & MGf_GSKIP)) - mgs.mgs_flags = 0; + (SSPTR(mgs_ix, MGS*))->mgs_flags = 0; } /* Advance to next magic (complicated by possible deletion) */ if (mg == (mgp_valid ? *mgp : SvMAGIC(sv))) { @@ -124,32 +147,32 @@ mg_get(SV *sv) mgp = &SvMAGIC(sv); /* Re-establish pointer after sv_upgrade */ } - LEAVE; + restore_magic((void*)mgs_ix); return 0; } int mg_set(SV *sv) { - MGS mgs; + I32 mgs_ix; MAGIC* mg; MAGIC* nextmg; - ENTER; - save_magic(&mgs, sv); + mgs_ix = SSNEW(sizeof(MGS)); + save_magic(mgs_ix, sv); for (mg = SvMAGIC(sv); mg; mg = nextmg) { MGVTBL* vtbl = mg->mg_virtual; nextmg = mg->mg_moremagic; /* it may delete itself */ if (mg->mg_flags & MGf_GSKIP) { mg->mg_flags &= ~MGf_GSKIP; /* setting requires another read */ - mgs.mgs_flags = 0; + (SSPTR(mgs_ix, MGS*))->mgs_flags = 0; } if (vtbl && (vtbl->svt_set != NULL)) (VTBL->svt_set)(sv, mg); } - LEAVE; + restore_magic((void*)mgs_ix); return 0; } @@ -163,13 +186,13 @@ mg_length(SV *sv) for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) { MGVTBL* vtbl = mg->mg_virtual; if (vtbl && (vtbl->svt_len != NULL)) { - MGS mgs; + I32 mgs_ix; - ENTER; - save_magic(&mgs, sv); + mgs_ix = SSNEW(sizeof(MGS)); + save_magic(mgs_ix, sv); /* omit MGf_GSKIP -- not changed here */ len = (VTBL->svt_len)(sv, mg); - LEAVE; + restore_magic((void*)mgs_ix); return len; } } @@ -187,11 +210,13 @@ mg_size(SV *sv) for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) { MGVTBL* vtbl = mg->mg_virtual; if (vtbl && (vtbl->svt_len != NULL)) { - MGS mgs; - ENTER; + I32 mgs_ix; + + mgs_ix = SSNEW(sizeof(MGS)); + save_magic(mgs_ix, sv); /* omit MGf_GSKIP -- not changed here */ len = (VTBL->svt_len)(sv, mg); - LEAVE; + restore_magic((void*)mgs_ix); return len; } } @@ -212,11 +237,11 @@ mg_size(SV *sv) int mg_clear(SV *sv) { - MGS mgs; + I32 mgs_ix; MAGIC* mg; - ENTER; - save_magic(&mgs, sv); + mgs_ix = SSNEW(sizeof(MGS)); + save_magic(mgs_ix, sv); for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) { MGVTBL* vtbl = mg->mg_virtual; @@ -226,7 +251,7 @@ mg_clear(SV *sv) (VTBL->svt_clear)(sv, mg); } - LEAVE; + restore_magic((void*)mgs_ix); return 0; } |