I32 mgs_ss_ix;
U32 mgs_magical;
bool mgs_readonly;
+ bool mgs_bumped;
};
/* MGS is typedef'ed to struct magic_state in perl.h */
{
dVAR;
MGS* mgs;
+ bool bumped = FALSE;
PERL_ARGS_ASSERT_SAVE_MAGIC;
- /* guard against sv having being freed midway by holding a private
- reference. */
- SvREFCNT_inc_simple_void_NN(sv);
+ /* we shouldn't really be called here with RC==0, but it can sometimes
+ * happen via mg_clear() (which also shouldn't be called when RC==0,
+ * but it can happen). Handle this case gracefully(ish) by not RC++
+ * and thus avoiding the resultant double free */
+ if (SvREFCNT(sv) > 0) {
+ /* guard against sv getting freed midway through the mg clearing,
+ * by holding a private reference for the duration. */
+ SvREFCNT_inc_simple_void_NN(sv);
+ bumped = TRUE;
+ }
assert(SvMAGICAL(sv));
/* Turning READONLY off for a copy-on-write scalar (including shared
mgs->mgs_magical = SvMAGICAL(sv);
mgs->mgs_readonly = SvREADONLY(sv) != 0;
mgs->mgs_ss_ix = PL_savestack_ix; /* points after the saved destructor */
+ mgs->mgs_bumped = bumped;
SvMAGICAL_off(sv);
SvREADONLY_off(sv);
}
}
-
-/* is this container magic (%ENV, $1 etc), or value magic (pos, taint etc)? */
-
-STATIC bool
-S_is_container_magic(const MAGIC *mg)
-{
- assert(mg);
- switch (mg->mg_type) {
- case PERL_MAGIC_bm:
- case PERL_MAGIC_fm:
- case PERL_MAGIC_regex_global:
- case PERL_MAGIC_nkeys:
-#ifdef USE_LOCALE_COLLATE
- case PERL_MAGIC_collxfrm:
-#endif
- case PERL_MAGIC_qr:
- case PERL_MAGIC_taint:
- case PERL_MAGIC_vec:
- case PERL_MAGIC_vstring:
- case PERL_MAGIC_utf8:
- case PERL_MAGIC_substr:
- case PERL_MAGIC_defelem:
- case PERL_MAGIC_arylen:
- case PERL_MAGIC_pos:
- case PERL_MAGIC_backref:
- case PERL_MAGIC_arylen_p:
- case PERL_MAGIC_rhash:
- case PERL_MAGIC_symtab:
- case PERL_MAGIC_tied: /* treat as value, so 'local @tied' isn't tied */
- case PERL_MAGIC_checkcall:
- return 0;
- default:
- return 1;
- }
-}
-
/*
=for apidoc mg_get
mg->mg_flags &= ~MGf_GSKIP; /* setting requires another read */
(SSPTR(mgs_ix, MGS*))->mgs_magical = 0;
}
- if (PL_localizing == 2 && !S_is_container_magic(mg))
+ if (PL_localizing == 2
+ && (PERL_MAGIC_TYPE_IS_VALUE_MAGIC(mg->mg_type) || sv == DEFSV))
continue;
if (vtbl && vtbl->svt_set)
vtbl->svt_set(aTHX_ sv, mg);
return 0;
}
-MAGIC*
+static MAGIC*
S_mg_findext_flags(pTHX_ const SV *sv, int type, const MGVTBL *vtbl, U32 flags)
{
PERL_UNUSED_CONTEXT;
PERL_ARGS_ASSERT_MG_LOCALIZE;
+ if (nsv == DEFSV)
+ return;
+
for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
const MGVTBL* const vtbl = mg->mg_virtual;
- if (!S_is_container_magic(mg))
+ if (PERL_MAGIC_TYPE_IS_VALUE_MAGIC(mg->mg_type))
continue;
if ((mg->mg_flags & MGf_LOCAL) && vtbl->svt_local)
mg->mg_ptr, mg->mg_len);
/* container types should remain read-only across localization */
- SvFLAGS(nsv) |= SvREADONLY(sv);
+ if (!SvIsCOW(sv)) SvFLAGS(nsv) |= SvREADONLY(sv);
}
if (SvTYPE(nsv) >= SVt_PVMG && SvMAGIC(nsv)) {
if (PL_ors_sv)
sv_copypv(sv, PL_ors_sv);
break;
+ case '$': /* $$ */
+ {
+ IV const pid = (IV)PerlProc_getpid();
+ if (isGV(mg->mg_obj) || SvIV(mg->mg_obj) != pid)
+ /* never set manually, or at least not since last fork */
+ sv_setiv(sv, pid);
+ /* else a value has been assigned manually, so do nothing */
+ }
+ break;
+
case '!':
{
dSAVE_ERRNO;
Perl_magic_clearsig(pTHX_ SV *sv, MAGIC *mg)
{
PERL_ARGS_ASSERT_MAGIC_CLEARSIG;
- PERL_UNUSED_ARG(sv);
magic_setsig(NULL, mg);
return sv_unmagic(sv, mg->mg_type);
if (hv) {
(void) hv_iterinit(hv);
if (! SvTIED_mg((const SV *)hv, PERL_MAGIC_tied))
- i = HvKEYS(hv);
+ i = HvUSEDKEYS(hv);
else {
while (hv_iternext(hv))
i++;
{
PERL_ARGS_ASSERT_MAGIC_SETMGLOB;
PERL_UNUSED_CONTEXT;
+ PERL_UNUSED_ARG(sv);
mg->mg_len = -1;
- if (!isGV_with_GP(sv))
- SvSCREAM_off(sv);
return 0;
}
} else if (type == PERL_MAGIC_bm) {
SvTAIL_off(sv);
SvVALID_off(sv);
+ } else if (type == PERL_MAGIC_study) {
+ if (!isGV_with_GP(sv))
+ SvSCREAM_off(sv);
} else {
assert(type == PERL_MAGIC_fm);
- SvCOMPILED_off(sv);
}
return sv_unmagic(sv, type);
}
case ':':
PL_chopset = SvPV_force(sv,len);
break;
+ case '$': /* $$ */
+ /* Store the pid in mg->mg_obj so we can tell when a fork has
+ occurred. mg->mg_obj points to *$ by default, so clear it. */
+ if (isGV(mg->mg_obj)) {
+ if (mg->mg_flags & MGf_REFCOUNTED) /* probably never true */
+ SvREFCNT_dec(mg->mg_obj);
+ mg->mg_flags |= MGf_REFCOUNTED;
+ mg->mg_obj = newSViv((IV)PerlProc_getpid());
+ }
+ else sv_setiv(mg->mg_obj, (IV)PerlProc_getpid());
+ break;
case '0':
LOCK_DOLLARZERO_MUTEX;
#ifdef HAS_SETPROCTITLE
dVAR;
MGS* const mgs = SSPTR(PTR2IV(p), MGS*);
SV* const sv = mgs->mgs_sv;
+ bool bumped;
if (!sv)
return;
}
}
+ bumped = mgs->mgs_bumped;
mgs->mgs_sv = NULL; /* mark the MGS structure as restored */
/* If we're still on top of the stack, pop us off. (That condition
assert((popval & SAVE_MASK) == SAVEt_ALLOC);
PL_savestack_ix -= popval >> SAVE_TIGHT_SHIFT;
}
- if (SvREFCNT(sv) == 1) {
- /* We hold the last reference to this SV, which implies that the
- SV was deleted as a side effect of the routines we called.
- So artificially keep it alive a bit longer.
- We avoid turning on the TEMP flag, which can cause the SV's
- buffer to get stolen (and maybe other stuff). */
- int was_temp = SvTEMP(sv);
- sv_2mortal(sv);
- if (!was_temp) {
- SvTEMP_off(sv);
+ if (bumped) {
+ if (SvREFCNT(sv) == 1) {
+ /* We hold the last reference to this SV, which implies that the
+ SV was deleted as a side effect of the routines we called.
+ So artificially keep it alive a bit longer.
+ We avoid turning on the TEMP flag, which can cause the SV's
+ buffer to get stolen (and maybe other stuff). */
+ int was_temp = SvTEMP(sv);
+ sv_2mortal(sv);
+ if (!was_temp) {
+ SvTEMP_off(sv);
+ }
+ SvOK_off(sv);
}
- SvOK_off(sv);
+ else
+ SvREFCNT_dec(sv); /* undo the inc in S_save_magic() */
}
- else
- SvREFCNT_dec(sv); /* undo the inc in S_save_magic() */
}
/* clean up the mess created by Perl_sighandler().