summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pp_ctl.c3
-rw-r--r--pp_hot.c29
2 files changed, 30 insertions, 2 deletions
diff --git a/pp_ctl.c b/pp_ctl.c
index c81df19895..b49f86dd3c 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -2337,8 +2337,7 @@ PP(pp_leavesublv)
if (gimme == G_SCALAR) {
if (CxLVAL(cx) && !ref) { /* Leave it as it is if we can. */
if (MARK <= SP) {
- if ((SvPADTMP(TOPs) || SvREADONLY(TOPs)) &&
- !SvSMAGICAL(TOPs)) {
+ if ((SvPADTMP(TOPs) || SvREADONLY(TOPs))) {
what =
SvREADONLY(TOPs) ? (TOPs == &PL_sv_undef) ? "undef"
: "a readonly value" : "a temporary";
diff --git a/pp_hot.c b/pp_hot.c
index 4c6beb4401..3ed672d4bb 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -3381,6 +3381,35 @@ S_leavesub_adjust_stacks(pTHX_ SV **base_sp, I32 gimme)
SV *sv = *from_sp++;
assert(PL_tmps_ix + nargs < PL_tmps_max);
+#ifdef DEBUGGING
+ /* PADTMPs with container set magic shouldn't appear in the
+ * wild. This assert is more important for pp_leavesublv(),
+ * but by testing for it here, we're more likely to catch
+ * bad cases (what with :lvalue subs not being widely
+ * deployed). The two issues are that for something like
+ * sub :lvalue { $tied{foo} }
+ * or
+ * sub :lvalue { substr($foo,1,2) }
+ * pp_leavesublv() will croak if the sub returns a PADTMP,
+ * and currently functions like pp_substr() return a mortal
+ * rather than using their PADTMP when returning a PVLV.
+ * This is because the PVLV will hold a ref to $foo,
+ * so $foo would get delayed in being freed while
+ * the PADTMP SV remained in the PAD.
+ * So if this assert fails it means either:
+ * 1) there is pp code similar to pp_substr that is
+ * returning a PADTMP instead of a mortal, and probably
+ * needs fixing, or
+ * 2) pp_leavesub is making unwarranted assumptions
+ * about always croaking on a PADTMP
+ */
+ if (SvPADTMP(sv) && SvSMAGICAL(sv)) {
+ MAGIC *mg;
+ for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
+ assert(PERL_MAGIC_TYPE_IS_VALUE_MAGIC(mg->mg_type));
+ }
+ }
+#endif
if (SvTEMP(sv) && !SvMAGICAL(sv) && SvREFCNT(sv) == 1) {
/* can optimise away the copy */