summaryrefslogtreecommitdiff
path: root/mg.c
diff options
context:
space:
mode:
authorChip Salzenberg <chip@ci005.sv2.upperbeyond.com>2009-10-28 16:41:02 -0700
committerChip Salzenberg <chip@pobox.com>2009-12-05 20:36:36 -0800
commitf9c6fee519b868a2e8ef8c5b701c0d3f95565423 (patch)
tree7c5bcf7bf963200c9494e98ad8f24303634bdd02 /mg.c
parent077f834239e40e0523e428946baaf95eaec43724 (diff)
downloadperl-f9c6fee519b868a2e8ef8c5b701c0d3f95565423.tar.gz
preserve readonly flag when saving and restoring magic flags
Diffstat (limited to 'mg.c')
-rw-r--r--mg.c31
1 files changed, 20 insertions, 11 deletions
diff --git a/mg.c b/mg.c
index f7d3634c57..fb913259fd 100644
--- a/mg.c
+++ b/mg.c
@@ -77,8 +77,9 @@ void setegid(uid_t id);
struct magic_state {
SV* mgs_sv;
- U32 mgs_flags;
I32 mgs_ss_ix;
+ U32 mgs_magical;
+ bool mgs_readonly;
};
/* MGS is typedef'ed to struct magic_state in perl.h */
@@ -100,7 +101,8 @@ S_save_magic(pTHX_ I32 mgs_ix, SV *sv)
mgs = SSPTR(mgs_ix, MGS*);
mgs->mgs_sv = sv;
- mgs->mgs_flags = SvMAGICAL(sv) | SvREADONLY(sv);
+ mgs->mgs_magical = SvMAGICAL(sv);
+ mgs->mgs_readonly = SvREADONLY(sv) != 0;
mgs->mgs_ss_ix = PL_savestack_ix; /* points after the saved destructor */
SvMAGICAL_off(sv);
@@ -125,8 +127,9 @@ Perl_mg_magical(pTHX_ SV *sv)
const MAGIC* mg;
PERL_ARGS_ASSERT_MG_MAGICAL;
PERL_UNUSED_CONTEXT;
+
+ SvMAGICAL_off(sv);
if ((mg = SvMAGIC(sv))) {
- SvRMAGICAL_off(sv);
do {
const MGVTBL* const vtbl = mg->mg_virtual;
if (vtbl) {
@@ -191,7 +194,7 @@ Perl_mg_get(pTHX_ SV *sv)
dVAR;
const I32 mgs_ix = SSNEW(sizeof(MGS));
const bool was_temp = (bool)SvTEMP(sv);
- int have_new = 0;
+ bool have_new = 0;
MAGIC *newmg, *head, *cur, *mg;
/* guard against sv having being freed midway by holding a private
reference. */
@@ -216,21 +219,24 @@ Perl_mg_get(pTHX_ SV *sv)
newmg = cur = head = mg = SvMAGIC(sv);
while (mg) {
const MGVTBL * const vtbl = mg->mg_virtual;
+ MAGIC * const nextmg = mg->mg_moremagic; /* it may delete itself */
if (!(mg->mg_flags & MGf_GSKIP) && vtbl && vtbl->svt_get) {
CALL_FPTR(vtbl->svt_get)(aTHX_ sv, mg);
/* guard against magic having been deleted - eg FETCH calling
* untie */
- if (!SvMAGIC(sv))
+ if (!SvMAGIC(sv)) {
+ (SSPTR(mgs_ix, MGS *))->mgs_magical = 0; /* recalculate flags */
break;
+ }
- /* Don't restore the flags for this entry if it was deleted. */
+ /* recalculate flags if this entry was deleted. */
if (mg->mg_flags & MGf_GSKIP)
- (SSPTR(mgs_ix, MGS *))->mgs_flags = 0;
+ (SSPTR(mgs_ix, MGS *))->mgs_magical = 0;
}
- mg = mg->mg_moremagic;
+ mg = nextmg;
if (have_new) {
/* Have we finished with the new entries we saw? Start again
@@ -247,6 +253,7 @@ Perl_mg_get(pTHX_ SV *sv)
have_new = 1;
cur = mg;
mg = newmg;
+ (SSPTR(mgs_ix, MGS *))->mgs_magical = 0; /* recalculate flags */
}
}
@@ -285,7 +292,7 @@ Perl_mg_set(pTHX_ SV *sv)
nextmg = mg->mg_moremagic; /* it may delete itself */
if (mg->mg_flags & MGf_GSKIP) {
mg->mg_flags &= ~MGf_GSKIP; /* setting requires another read */
- (SSPTR(mgs_ix, MGS*))->mgs_flags = 0;
+ (SSPTR(mgs_ix, MGS*))->mgs_magical = 0;
}
if (PL_localizing == 2 && !S_is_container_magic(mg))
continue;
@@ -2977,8 +2984,10 @@ S_restore_magic(pTHX_ const void *p)
sv_force_normal_flags(sv, 0);
#endif
- if (mgs->mgs_flags)
- SvFLAGS(sv) |= mgs->mgs_flags;
+ if (mgs->mgs_readonly)
+ SvREADONLY_on(sv);
+ if (mgs->mgs_magical)
+ SvFLAGS(sv) |= mgs->mgs_magical;
else
mg_magical(sv);
if (SvGMAGICAL(sv)) {