/* scope.c
*
- * Copyright (c) 1991-2001, Larry Wall
+ * Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ * 2000, 2001, 2002, 2003, by Larry Wall and others
*
* You may distribute under the terms of either the GNU General Public
* License or the Artistic License, as specified in the README file.
SV**
Perl_stack_grow(pTHX_ SV **sp, SV **p, int n)
{
-#if defined(DEBUGGING) && !defined(USE_THREADS)
- static int growing = 0;
- if (growing++)
- abort();
-#endif
PL_stack_sp = sp;
#ifndef STRESS_REALLOC
av_extend(PL_curstack, (p - PL_stack_base) + (n) + 128);
#else
av_extend(PL_curstack, (p - PL_stack_base) + (n) + 1);
#endif
-#if defined(DEBUGGING) && !defined(USE_THREADS)
- growing--;
-#endif
return PL_stack_sp;
}
si->si_cxix = -1;
si->si_type = PERLSI_UNDEF;
New(56, si->si_cxstack, cxitems, PERL_CONTEXT);
+ /* Without any kind of initialising PUSHSUBST()
+ * in pp_subst() will read uninitialised heap. */
+ Poison(si->si_cxstack, cxitems, PERL_CONTEXT);
return si;
}
I32
Perl_cxinc(pTHX)
{
+ IV old_max = cxstack_max;
cxstack_max = GROW(cxstack_max);
Renew(cxstack, cxstack_max + 1, PERL_CONTEXT); /* XXX should fix CXINC macro */
+ /* Without any kind of initialising deep enough recursion
+ * will end up reading uninitialised PERL_CONTEXTs. */
+ Poison(cxstack + old_max + 1, cxstack_max - old_max, PERL_CONTEXT);
return cxstack_ix + 1;
}
void
Perl_savestack_grow(pTHX)
{
- PL_savestack_max = GROW(PL_savestack_max) + 4;
+ PL_savestack_max = GROW(PL_savestack_max) + 4;
+ Renew(PL_savestack, PL_savestack_max, ANY);
+}
+
+void
+Perl_savestack_grow_cnt(pTHX_ I32 need)
+{
+ PL_savestack_max = PL_savestack_ix + need;
Renew(PL_savestack, PL_savestack_max, ANY);
}
while (PL_tmps_ix > myfloor) { /* clean up after last statement */
SV* sv = PL_tmps_stack[PL_tmps_ix];
PL_tmps_stack[PL_tmps_ix--] = Nullsv;
- if (sv) {
+ if (sv && sv != &PL_sv_undef) {
SvTEMP_off(sv);
SvREFCNT_dec(sv); /* note, can modify tmps_ix!!! */
}
sv = *sptr = NEWSV(0,0);
if (SvTYPE(osv) >= SVt_PVMG && SvMAGIC(osv) && SvTYPE(osv) != SVt_PVGV) {
+ MAGIC *mg;
sv_upgrade(sv, SvTYPE(osv));
if (SvGMAGICAL(osv)) {
- MAGIC* mg;
bool oldtainted = PL_tainted;
mg_get(osv); /* note, can croak! */
- if (PL_tainting && PL_tainted && (mg = mg_find(osv, 't'))) {
+ if (PL_tainting && PL_tainted &&
+ (mg = mg_find(osv, PERL_MAGIC_taint))) {
SAVESPTR(mg->mg_obj);
mg->mg_obj = osv;
}
SvFLAGS(osv) |= (SvFLAGS(osv) &
- (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT;
+ (SVp_NOK|SVp_POK)) >> PRIVSHIFT;
PL_tainted = oldtainted;
}
SvMAGIC(sv) = SvMAGIC(osv);
+ /* if it's a special scalar or if it has no 'set' magic,
+ * propagate the SvREADONLY flag. --rgs 20030922 */
+ for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
+ if (SvMAGIC(sv)->mg_type == '\0'
+ || !SvMAGIC(sv)->mg_virtual->svt_set)
+ {
+ SvFLAGS(sv) |= SvREADONLY(osv);
+ break;
+ }
+ }
SvFLAGS(sv) |= SvMAGICAL(osv);
+ /* XXX SvMAGIC() is *shared* between osv and sv. This can
+ * lead to coredumps when both SVs are destroyed without one
+ * of their SvMAGIC() slots being NULLed. */
PL_localizing = 1;
SvSETMAGIC(sv);
PL_localizing = 0;
SSPUSHINT(SAVEt_GENERIC_PVREF);
}
+/* Like save_generic_pvref(), but uses PerlMemShared_free() rather than Safefree().
+ * Can be used to restore a shared global char* to its prior
+ * contents, freeing new value. */
+void
+Perl_save_shared_pvref(pTHX_ char **str)
+{
+ SSCHECK(3);
+ SSPUSHPTR(str);
+ SSPUSHPTR(*str);
+ SSPUSHINT(SAVEt_SHARED_PVREF);
+}
+
+/* set the SvFLAGS specified by mask to the values in val */
+
+void
+Perl_save_set_svflags(pTHX_ SV* sv, U32 mask, U32 val)
+{
+ SSCHECK(4);
+ SSPUSHPTR(sv);
+ SSPUSHINT(mask);
+ SSPUSHINT(val);
+ SSPUSHINT(SAVEt_SET_SVFLAGS);
+}
+
void
Perl_save_gp(pTHX_ GV *gv, I32 empty)
{
- SSCHECK(6);
+ SSGROW(6);
SSPUSHIV((IV)SvLEN(gv));
SvLEN(gv) = 0; /* forget that anything was allocated here */
SSPUSHIV((IV)SvCUR(gv));
}
void
+Perl_save_bool(pTHX_ bool *boolp)
+{
+ SSCHECK(3);
+ SSPUSHBOOL(*boolp);
+ SSPUSHPTR(boolp);
+ SSPUSHINT(SAVEt_BOOL);
+}
+
+void
Perl_save_I32(pTHX_ I32 *intp)
{
SSCHECK(3);
Perl_save_padsv(pTHX_ PADOFFSET off)
{
SSCHECK(4);
+ ASSERT_CURPAD_ACTIVE("save_padsv");
SSPUSHPTR(PL_curpad[off]);
- SSPUSHPTR(PL_curpad);
+ SSPUSHPTR(PL_comppad);
SSPUSHLONG((long)off);
SSPUSHINT(SAVEt_PADSV);
}
SV **
Perl_save_threadsv(pTHX_ PADOFFSET i)
{
-#ifdef USE_THREADS
- SV **svp = &THREADSV(i); /* XXX Change to save by offset */
- DEBUG_S(PerlIO_printf(Perl_debug_log, "save_threadsv %"UVuf": %p %p:%s\n",
- (UV)i, svp, *svp, SvPEEK(*svp)));
- save_svref(svp);
- return svp;
-#else
Perl_croak(aTHX_ "panic: save_threadsv called in non-threaded perl");
return 0;
-#endif /* USE_THREADS */
}
void
}
void
+Perl_save_mortalizesv(pTHX_ SV *sv)
+{
+ SSCHECK(2);
+ SSPUSHPTR(sv);
+ SSPUSHINT(SAVEt_MORTALIZESV);
+}
+
+void
Perl_save_freeop(pTHX_ OP *o)
{
SSCHECK(2);
void
Perl_save_clearsv(pTHX_ SV **svp)
{
+ ASSERT_CURPAD_ACTIVE("save_clearsv");
SSCHECK(2);
SSPUSHLONG((long)(svp-PL_curpad));
SSPUSHINT(SAVEt_CLEARSV);
+ SvPADSTALE_off(*svp); /* mark lexical as active */
}
void
void
Perl_save_aelem(pTHX_ AV *av, I32 idx, SV **sptr)
{
+ SV *sv;
SSCHECK(4);
SSPUSHPTR(SvREFCNT_inc(av));
SSPUSHINT(idx);
SSPUSHPTR(SvREFCNT_inc(*sptr));
SSPUSHINT(SAVEt_AELEM);
+ /* if it gets reified later, the restore will have the wrong refcnt */
+ if (!AvREAL(av) && AvREIFY(av))
+ SvREFCNT_inc(*sptr);
save_scalar_at(sptr);
+ sv = *sptr;
+ /* If we're localizing a tied array element, this new sv
+ * won't actually be stored in the array - so it won't get
+ * reaped when the localize ends. Ensure it gets reaped by
+ * mortifying it instead. DAPM */
+ if (SvTIED_mg(sv, PERL_MAGIC_tiedelem))
+ sv_2mortal(sv);
}
void
Perl_save_helem(pTHX_ HV *hv, SV *key, SV **sptr)
{
+ SV *sv;
SSCHECK(4);
SSPUSHPTR(SvREFCNT_inc(hv));
SSPUSHPTR(SvREFCNT_inc(key));
SSPUSHPTR(SvREFCNT_inc(*sptr));
SSPUSHINT(SAVEt_HELEM);
save_scalar_at(sptr);
+ sv = *sptr;
+ /* If we're localizing a tied hash element, this new sv
+ * won't actually be stored in the hash - so it won't get
+ * reaped when the localize ends. Ensure it gets reaped by
+ * mortifying it instead. DAPM */
+ if (SvTIED_mg(sv, PERL_MAGIC_tiedelem))
+ sv_2mortal(sv);
}
void
Perl_save_alloc(pTHX_ I32 size, I32 pad)
{
register I32 start = pad + ((char*)&PL_savestack[PL_savestack_ix]
- - (char*)PL_savestack);
+ - (char*)PL_savestack);
register I32 elems = 1 + ((size + pad - 1) / sizeof(*PL_savestack));
/* SSCHECK may not be good enough */
while (PL_savestack_ix + elems + 2 > PL_savestack_max)
- savestack_grow();
+ savestack_grow();
PL_savestack_ix += elems;
SSPUSHINT(elems);
SvSETMAGIC(sv);
PL_localizing = 0;
break;
- case SAVEt_SV: /* scalar reference */
+ case SAVEt_SV: /* scalar reference */
value = (SV*)SSPOPPTR;
gv = (GV*)SSPOPPTR;
ptr = &GvSV(gv);
- SvREFCNT_dec(gv);
+ av = (AV*)gv; /* what to refcnt_dec */
goto restore_sv;
- case SAVEt_GENERIC_PVREF: /* generic pv */
+ case SAVEt_GENERIC_PVREF: /* generic pv */
str = (char*)SSPOPPTR;
ptr = SSPOPPTR;
if (*(char**)ptr != str) {
*(char**)ptr = str;
}
break;
- case SAVEt_GENERIC_SVREF: /* generic sv */
+ case SAVEt_SHARED_PVREF: /* shared pv */
+ str = (char*)SSPOPPTR;
+ ptr = SSPOPPTR;
+ if (*(char**)ptr != str) {
+#ifdef NETWARE
+ PerlMem_free(*(char**)ptr);
+#else
+ PerlMemShared_free(*(char**)ptr);
+#endif
+ *(char**)ptr = str;
+ }
+ break;
+ case SAVEt_GENERIC_SVREF: /* generic sv */
value = (SV*)SSPOPPTR;
ptr = SSPOPPTR;
sv = *(SV**)ptr;
SvREFCNT_dec(sv);
SvREFCNT_dec(value);
break;
- case SAVEt_SVREF: /* scalar reference */
+ case SAVEt_SVREF: /* scalar reference */
value = (SV*)SSPOPPTR;
ptr = SSPOPPTR;
+ av = Nullav; /* what to refcnt_dec */
restore_sv:
sv = *(SV**)ptr;
DEBUG_S(PerlIO_printf(Perl_debug_log,
"restore svref: %p %p:%s -> %p:%s\n",
- ptr, sv, SvPEEK(sv), value, SvPEEK(value)));
+ ptr, sv, SvPEEK(sv), value, SvPEEK(value)));
if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv) &&
SvTYPE(sv) != SVt_PVGV)
{
SvMAGICAL_off(sv);
SvMAGIC(sv) = 0;
}
- /* XXX this branch is pretty bogus--note that we seem to
- * only get here if the mg_get() in save_scalar_at() ends
- * up croaking. This code irretrievably clears(!) the magic
- * on the SV to avoid further croaking that might ensue
- * when the SvSETMAGIC() below is called. This needs a
- * total rethink. --GSAR */
+ /* XXX This branch is pretty bogus. This code irretrievably
+ * clears(!) the magic on the SV (either to avoid further
+ * croaking that might ensue when the SvSETMAGIC() below is
+ * called, or to avoid two different SVs pointing at the same
+ * SvMAGIC()). This needs a total rethink. --GSAR */
else if (SvTYPE(value) >= SVt_PVMG && SvMAGIC(value) &&
SvTYPE(value) != SVt_PVGV)
{
SvFLAGS(value) |= (SvFLAGS(value) &
- (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT;
+ (SVp_NOK|SVp_POK)) >> PRIVSHIFT;
SvMAGICAL_off(value);
- mg_free(value);
+ /* XXX this is a leak when we get here because the
+ * mg_get() in save_scalar_at() croaked */
+ SvMAGIC(value) = 0;
}
- SvREFCNT_dec(sv);
+ SvREFCNT_dec(sv);
*(SV**)ptr = value;
PL_localizing = 2;
SvSETMAGIC(value);
PL_localizing = 0;
SvREFCNT_dec(value);
- break;
- case SAVEt_AV: /* array reference */
+ if (av) /* actually an av, hv or gv */
+ SvREFCNT_dec(av);
+ break;
+ case SAVEt_AV: /* array reference */
av = (AV*)SSPOPPTR;
gv = (GV*)SSPOPPTR;
if (GvAV(gv)) {
SvMAGIC(goner) = 0;
SvREFCNT_dec(goner);
}
- GvAV(gv) = av;
+ GvAV(gv) = av;
if (SvMAGICAL(av)) {
PL_localizing = 2;
SvSETMAGIC((SV*)av);
PL_localizing = 0;
}
- break;
- case SAVEt_HV: /* hash reference */
+ break;
+ case SAVEt_HV: /* hash reference */
hv = (HV*)SSPOPPTR;
gv = (GV*)SSPOPPTR;
if (GvHV(gv)) {
SvMAGIC(goner) = 0;
SvREFCNT_dec(goner);
}
- GvHV(gv) = hv;
+ GvHV(gv) = hv;
if (SvMAGICAL(hv)) {
PL_localizing = 2;
SvSETMAGIC((SV*)hv);
PL_localizing = 0;
}
- break;
+ break;
case SAVEt_INT: /* int reference */
ptr = SSPOPPTR;
*(int*)ptr = (int)SSPOPINT;
ptr = SSPOPPTR;
*(long*)ptr = (long)SSPOPLONG;
break;
+ case SAVEt_BOOL: /* bool reference */
+ ptr = SSPOPPTR;
+ *(bool*)ptr = (bool)SSPOPBOOL;
+ break;
case SAVEt_I32: /* I32 reference */
ptr = SSPOPPTR;
*(I32*)ptr = (I32)SSPOPINT;
case SAVEt_GP: /* scalar reference */
ptr = SSPOPPTR;
gv = (GV*)SSPOPPTR;
- if (SvPVX(gv) && SvLEN(gv) > 0) {
- Safefree(SvPVX(gv));
- }
- SvPVX(gv) = (char *)SSPOPPTR;
- SvCUR(gv) = (STRLEN)SSPOPIV;
- SvLEN(gv) = (STRLEN)SSPOPIV;
- gp_free(gv);
- GvGP(gv) = (GP*)ptr;
+ if (SvPVX(gv) && SvLEN(gv) > 0) {
+ Safefree(SvPVX(gv));
+ }
+ SvPVX(gv) = (char *)SSPOPPTR;
+ SvCUR(gv) = (STRLEN)SSPOPIV;
+ SvLEN(gv) = (STRLEN)SSPOPIV;
+ gp_free(gv);
+ GvGP(gv) = (GP*)ptr;
if (GvCVu(gv))
PL_sub_generation++; /* putting a method back into circulation */
SvREFCNT_dec(gv);
- break;
+ break;
case SAVEt_FREESV:
ptr = SSPOPPTR;
SvREFCNT_dec((SV*)ptr);
break;
+ case SAVEt_MORTALIZESV:
+ ptr = SSPOPPTR;
+ sv_2mortal((SV*)ptr);
+ break;
case SAVEt_FREEOP:
ptr = SSPOPPTR;
- if (PL_comppad)
- PL_curpad = AvARRAY(PL_comppad);
+ ASSERT_CURPAD_LEGAL("SAVEt_FREEOP"); /* XXX DAPM tmp */
op_free((OP*)ptr);
break;
case SAVEt_FREEPV:
case SAVEt_CLEARSV:
ptr = (void*)&PL_curpad[SSPOPLONG];
sv = *(SV**)ptr;
+
+ DEBUG_Xv(PerlIO_printf(Perl_debug_log,
+ "Pad 0x%"UVxf"[0x%"UVxf"] clearsv: %ld sv=0x%"UVxf"<%"IVdf"> %s\n",
+ PTR2UV(PL_comppad), PTR2UV(PL_curpad),
+ (long)((SV **)ptr-PL_curpad), PTR2UV(sv), (IV)SvREFCNT(sv),
+ (SvREFCNT(sv) <= 1 && !SvOBJECT(sv)) ? "clear" : "abandon"
+ ));
+
/* Can clear pad variable in place? */
if (SvREFCNT(sv) <= 1 && !SvOBJECT(sv)) {
+ /*
+ * if a my variable that was made readonly is going out of
+ * scope, we want to remove the readonlyness so that it can
+ * go out of scope quietly
+ */
+ if (SvPADMY(sv) && !SvFAKE(sv))
+ SvREADONLY_off(sv);
+
if (SvTHINKFIRST(sv))
sv_force_normal_flags(sv, SV_IMMEDIATE_UNREF);
if (SvMAGICAL(sv))
(void)SvOOK_off(sv);
break;
}
+ SvPADSTALE_on(sv); /* mark as no longer live */
}
else { /* Someone has a claim on this, so abandon it. */
- U32 padflags = SvFLAGS(sv) & (SVs_PADBUSY|SVs_PADMY|SVs_PADTMP);
+ U32 padflags = SvFLAGS(sv) & (SVs_PADMY|SVs_PADTMP);
switch (SvTYPE(sv)) { /* Console ourselves with a new value */
case SVt_PVAV: *(SV**)ptr = (SV*)newAV(); break;
case SVt_PVHV: *(SV**)ptr = (SV*)newHV(); break;
default: *(SV**)ptr = NEWSV(0,0); break;
}
SvREFCNT_dec(sv); /* Cast current value to the winds. */
- SvFLAGS(*(SV**)ptr) |= padflags; /* preserve pad nature */
+ /* preserve pad nature, but also mark as not live
+ * for any closure capturing */
+ SvFLAGS(*(SV**)ptr) |= padflags | SVs_PADSTALE;
}
break;
case SAVEt_DELETE:
ptr = SSPOPPTR;
(void)hv_delete(hv, (char*)ptr, (U32)SSPOPINT, G_DISCARD);
SvREFCNT_dec(hv);
- Safefree(ptr);
+ Safefree(ptr);
break;
case SAVEt_DESTRUCTOR:
ptr = SSPOPPTR;
break;
case SAVEt_DESTRUCTOR_X:
ptr = SSPOPPTR;
- (*SSPOPDXPTR)(aTHXo_ ptr);
+ (*SSPOPDXPTR)(aTHX_ ptr);
break;
case SAVEt_REGCONTEXT:
case SAVEt_ALLOC:
value = (SV*)SSPOPPTR;
i = SSPOPINT;
av = (AV*)SSPOPPTR;
+ if (!AvREAL(av) && AvREIFY(av)) /* undo reify guard */
+ SvREFCNT_dec(value);
ptr = av_fetch(av,i,1);
if (ptr) {
sv = *(SV**)ptr;
if (sv && sv != &PL_sv_undef) {
- if (SvTIED_mg((SV*)av, 'P'))
+ if (SvTIED_mg((SV*)av, PERL_MAGIC_tied))
(void)SvREFCNT_inc(sv);
- SvREFCNT_dec(av);
goto restore_sv;
}
}
SV *oval = HeVAL((HE*)ptr);
if (oval && oval != &PL_sv_undef) {
ptr = &HeVAL((HE*)ptr);
- if (SvTIED_mg((SV*)hv, 'P'))
+ if (SvTIED_mg((SV*)hv, PERL_MAGIC_tied))
(void)SvREFCNT_inc(*(SV**)ptr);
- SvREFCNT_dec(hv);
SvREFCNT_dec(sv);
+ av = (AV*)hv; /* what to refcnt_dec */
goto restore_sv;
}
}
PL_op = (OP*)SSPOPPTR;
break;
case SAVEt_HINTS:
+ if ((PL_hints & HINT_LOCALIZE_HH) && GvHV(PL_hintgv)) {
+ SvREFCNT_dec((SV*)GvHV(PL_hintgv));
+ GvHV(PL_hintgv) = NULL;
+ }
*(I32*)&PL_hints = (I32)SSPOPINT;
break;
case SAVEt_COMPPAD:
- PL_comppad = (AV*)SSPOPPTR;
+ PL_comppad = (PAD*)SSPOPPTR;
if (PL_comppad)
PL_curpad = AvARRAY(PL_comppad);
else
PADOFFSET off = (PADOFFSET)SSPOPLONG;
ptr = SSPOPPTR;
if (ptr)
- ((SV**)ptr)[off] = (SV*)SSPOPPTR;
+ AvARRAY((PAD*)ptr)[off] = (SV*)SSPOPPTR;
+ }
+ break;
+ case SAVEt_SET_SVFLAGS:
+ {
+ U32 val = (U32)SSPOPINT;
+ U32 mask = (U32)SSPOPINT;
+ sv = (SV*)SSPOPPTR;
+ SvFLAGS(sv) &= ~mask;
+ SvFLAGS(sv) |= val;
}
break;
default: