summaryrefslogtreecommitdiff
path: root/mg.c
diff options
context:
space:
mode:
Diffstat (limited to 'mg.c')
-rw-r--r--mg.c95
1 files changed, 60 insertions, 35 deletions
diff --git a/mg.c b/mg.c
index 185b4f54a9..e7472a6ec7 100644
--- a/mg.c
+++ b/mg.c
@@ -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;
}