SV**
Perl_stack_grow(pTHX_ SV **sp, SV **p, SSize_t n)
{
+ SSize_t extra;
+ SSize_t current = (p - PL_stack_base);
+
PERL_ARGS_ASSERT_STACK_GROW;
+ if (UNLIKELY(n < 0))
+ Perl_croak(aTHX_
+ "panic: stack_grow() negative count (%"IVdf")", (IV)n);
+
PL_stack_sp = sp;
-#ifndef STRESS_REALLOC
- av_extend(PL_curstack, (p - PL_stack_base) + (n) + 128);
+ extra =
+#ifdef STRESS_REALLOC
+ 1;
#else
- av_extend(PL_curstack, (p - PL_stack_base) + (n) + 1);
+ 128;
#endif
+ /* If the total might wrap, panic instead. This is really testing
+ * that (current + n + extra < SSize_t_MAX), but done in a way that
+ * can't wrap */
+ if (UNLIKELY( current > SSize_t_MAX - extra
+ || current + extra > SSize_t_MAX - n
+ ))
+ /* diag_listed_as: Out of memory during %s extend */
+ Perl_croak(aTHX_ "Out of memory during stack extend");
+
+ av_extend(PL_curstack, current + n + extra);
return PL_stack_sp;
}
Renew(PL_markstack, newmax, I32);
PL_markstack_max = PL_markstack + newmax;
PL_markstack_ptr = PL_markstack + oldmax;
+ DEBUG_s(DEBUG_v(PerlIO_printf(Perl_debug_log,
+ "MARK grow %p %"IVdf" by %"IVdf"\n",
+ PL_markstack_ptr, (IV)*PL_markstack_ptr, (IV)oldmax)));
return PL_markstack_ptr;
}
#undef GROW
-void
-Perl_tmps_grow(pTHX_ SSize_t n)
+/* The original function was called Perl_tmps_grow and was removed from public
+ API, Perl_tmps_grow_p is the replacement and it used in public macros but
+ isn't public itself.
+
+ Perl_tmps_grow_p takes a proposed ix. A proposed ix is PL_tmps_ix + extend_by,
+ where the result of (PL_tmps_ix + extend_by) is >= PL_tmps_max
+ Upon return, PL_tmps_stack[ix] will be a valid address. For machine code
+ optimization and register usage reasons, the proposed ix passed into
+ tmps_grow is returned to the caller which the caller can then use to write
+ an SV * to PL_tmps_stack[ix]. If the caller was using tmps_grow in
+ pre-extend mode (EXTEND_MORTAL macro), then it ignores the return value of
+ tmps_grow. Note, tmps_grow DOES NOT write ix to PL_tmps_ix, the caller
+ must assign ix or ret val of tmps_grow to PL_temps_ix themselves if that is
+ appropriate. The assignment to PL_temps_ix can happen before or after
+ tmps_grow call since tmps_grow doesn't look at PL_tmps_ix.
+ */
+
+SSize_t
+Perl_tmps_grow_p(pTHX_ SSize_t ix)
{
+ SSize_t extend_to = ix;
#ifndef STRESS_REALLOC
- if (n < 128)
- n = (PL_tmps_max < 512) ? 128 : 512;
+ if (ix - PL_tmps_max < 128)
+ extend_to += (PL_tmps_max < 512) ? 128 : 512;
#endif
- PL_tmps_max = PL_tmps_ix + n + 1;
+ PL_tmps_max = extend_to + 1;
Renew(PL_tmps_stack, PL_tmps_max, SV*);
+ return ix;
}
PERL_ARGS_ASSERT_SAVE_SCALAR_AT;
osv = *sptr;
- sv = (flags & SAVEf_KEEPOLDELEM) ? osv : (*sptr = newSV(0));
-
- if (SvTYPE(osv) >= SVt_PVMG && SvMAGIC(osv)) {
- if (SvGMAGICAL(osv)) {
- SvFLAGS(osv) |= (SvFLAGS(osv) &
- (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT;
- }
- if (!(flags & SAVEf_KEEPOLDELEM))
- mg_localize(osv, sv, cBOOL(flags & SAVEf_SETMAGIC));
+ if (flags & SAVEf_KEEPOLDELEM)
+ sv = osv;
+ else {
+ sv = (*sptr = newSV(0));
+ if (SvTYPE(osv) >= SVt_PVMG && SvMAGIC(osv))
+ mg_localize(osv, sv, cBOOL(flags & SAVEf_SETMAGIC));
}
return sv;
SS_ADD_END(4);
}
+/*
+=for apidoc save_gp
+
+Saves the current GP of gv on the save stack to be restored on scope exit.
+
+If empty is true, replace the GP with a new GP.
+
+If empty is false, mark gv with GVf_INTRO so the next reference
+assigned is localized, which is how C< local *foo = $someref; > works.
+
+=cut
+*/
+
void
Perl_save_gp(pTHX_ GV *gv, I32 empty)
{
/* Localise the effects of the TAINT_NOT inside the loop. */
bool was = TAINT_get;
+ I32 i;
+ SV *sv;
+
ANY arg0, arg1, arg2;
/* these initialisations are logically unnecessary, but they shut up
*svp = ARG0_SV;
SvREFCNT_dec(sv);
if (UNLIKELY(SvSMAGICAL(ARG0_SV))) {
+ /* mg_set could die, skipping the freeing of ARG0_SV and
+ * refsv; Ensure that they're always freed in that case */
+ dSS_ADD;
+ SS_ADD_PTR(ARG0_SV);
+ SS_ADD_UV(SAVEt_FREESV);
+ SS_ADD_PTR(refsv);
+ SS_ADD_UV(SAVEt_FREESV);
+ SS_ADD_END(4);
PL_localizing = 2;
mg_set(ARG0_SV);
PL_localizing = 0;
+ break;
}
SvREFCNT_dec_NN(ARG0_SV);
SvREFCNT_dec(refsv);
case SAVEt_AV: /* array reference */
SvREFCNT_dec(GvAV(ARG1_GV));
GvAV(ARG1_GV) = ARG0_AV;
+ avhv_common:
if (UNLIKELY(SvSMAGICAL(ARG0_SV))) {
+ /* mg_set might die, so make sure ARG1 isn't leaked */
+ dSS_ADD;
+ SS_ADD_PTR(ARG1_SV);
+ SS_ADD_UV(SAVEt_FREESV);
+ SS_ADD_END(2);
PL_localizing = 2;
mg_set(ARG0_SV);
PL_localizing = 0;
+ break;
}
SvREFCNT_dec_NN(ARG1_GV);
break;
case SAVEt_HV: /* hash reference */
SvREFCNT_dec(GvHV(ARG1_GV));
GvHV(ARG1_GV) = ARG0_HV;
- if (UNLIKELY(SvSMAGICAL(ARG0_SV))) {
- PL_localizing = 2;
- mg_set(ARG0_SV);
- PL_localizing = 0;
- }
- SvREFCNT_dec_NN(ARG1_GV);
- break;
+ goto avhv_common;
+
case SAVEt_INT_SMALL:
*(int*)ARG0_PTR = (int)(uv >> SAVE_TIGHT_SHIFT);
break;
case SAVEt_FREESV:
SvREFCNT_dec(ARG0_SV);
break;
+ case SAVEt_FREEPADNAME:
+ PadnameREFCNT_dec((PADNAME *)ARG0_PTR);
+ break;
case SAVEt_FREECOPHH:
cophh_free((COPHH *)ARG0_PTR);
break;
Safefree(ARG0_PTR);
break;
- {
- SV **svp;
- I32 i;
- SV *sv;
-
case SAVEt_CLEARPADRANGE:
i = (I32)((uv >> SAVE_TIGHT_SHIFT) & OPpPADRANGE_COUNTMASK);
svp = &PL_curpad[uv >>
(SvREFCNT(sv) <= 1 && !SvOBJECT(sv)) ? "clear" : "abandon"
));
- assert(SvPADMY(sv));
-
/* Can clear pad variable in place? */
if (SvREFCNT(sv) == 1 && !SvOBJECT(sv)) {
/* these flags are the union of all the relevant flags
* in the individual conditions within */
if (UNLIKELY(SvFLAGS(sv) & (
- SVf_READONLY /* for SvREADONLY_off() */
+ SVf_READONLY|SVf_PROTECT /*for SvREADONLY_off*/
| (SVs_GMG|SVs_SMG|SVs_RMG) /* SvMAGICAL() */
| SVf_OOK
| SVf_THINKFIRST)))
* readonlyness so that it can go out of scope
* quietly
*/
- if (SvREADONLY(sv) && !SvFAKE(sv))
+ if (SvREADONLY(sv))
SvREADONLY_off(sv);
if (SvOOK(sv)) { /* OOK or HvAUX */
? CvNAME_HEK((CV *)sv)
: GvNAME_HEK(CvGV(sv));
assert(hek);
- share_hek_hek(hek);
+ (void)share_hek_hek(hek);
cv_undef((CV *)sv);
CvNAME_HEK_set(sv, hek);
CvLEXICAL_on(sv);
SvFLAGS(sv) &=~ (SVf_OK|SVf_IVisUV|SVf_UTF8);
break;
}
+ SvPADTMP_off(sv);
SvPADSTALE_on(sv); /* mark as no longer live */
}
else { /* Someone has a claim on this, so abandon it. */
- assert( SvFLAGS(sv) & SVs_PADMY);
- assert(!(SvFLAGS(sv) & SVs_PADTMP));
switch (SvTYPE(sv)) { /* Console ourselves with a new value */
case SVt_PVAV: *svp = MUTABLE_SV(newAV()); break;
case SVt_PVHV: *svp = MUTABLE_SV(newHV()); break;
SvREFCNT_dec_NN(sv); /* Cast current value to the winds. */
/* preserve pad nature, but also mark as not live
* for any closure capturing */
- SvFLAGS(*svp) |= (SVs_PADMY|SVs_PADSTALE);
+ SvFLAGS(*svp) |= SVs_PADSTALE;
}
}
break;
- }
case SAVEt_DELETE:
(void)hv_delete(ARG0_HV, ARG2_PV, ARG1_I32, G_DISCARD);
SvREFCNT_dec(ARG0_HV);
}
/*
- * Local variables:
- * c-indentation-style: bsd
- * c-basic-offset: 4
- * indent-tabs-mode: nil
- * End:
- *
* ex: set ts=8 sts=4 sw=4 et:
*/