summaryrefslogtreecommitdiff
path: root/pp_ctl.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2011-06-07 17:05:06 -0700
committerFather Chrysostomos <sprout@cpan.org>2011-06-07 20:44:46 -0700
commite08be60b99b393465a58e174337c5e8237231b1f (patch)
treef2277272b40601e910d5599b8d5e9c99fdbe55e6 /pp_ctl.c
parentd507ecb9ce86ef53117ff81c35d0686965c6b715 (diff)
downloadperl-e08be60b99b393465a58e174337c5e8237231b1f.tar.gz
[perl #92290, #92406] Returning a pad var from lv sub
This fixes a recent (post-5.14.0) regression. Commit bf8fb5e (the fix for #62498) introduced it for lvalue subs with no return statement [perl #92406]. Commit fa1e92c (the fix for #72724) introduced it for lvalue subs that do have an explicit return [perl #92290]. Simply returning a scalar itself from an lvalue sub does not work if it is a pad variable with a reference count of 1. In that circum- stance, the sub-popping code sees that the SV can be re-used the next time the sub is called, so it undefines it and hangs on to it. So the scalar returned gets emptied before the calling code can see it. The reference count has to be increased temporarily, which sv_2mortal and SvREFCNT_inc combined accomplish.
Diffstat (limited to 'pp_ctl.c')
-rw-r--r--pp_ctl.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/pp_ctl.c b/pp_ctl.c
index eed88f8e0a..868ef011f0 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -2227,7 +2227,11 @@ S_return_lvalues(pTHX_ SV **mark, SV **sp, SV **newsp, I32 gimme,
sv_2mortal(*newsp);
}
else
- *++newsp = *SP;
+ *++newsp =
+ (!CxLVAL(cx) || CxLVAL(cx) & OPpENTERSUB_INARGS) &&
+ !SvTEMP(*SP)
+ ? sv_2mortal(SvREFCNT_inc_simple_NN(*SP))
+ : *SP;
}
else
*++newsp = &PL_sv_undef;
@@ -2249,7 +2253,13 @@ S_return_lvalues(pTHX_ SV **mark, SV **sp, SV **newsp, I32 gimme,
}
else if (gimme == G_ARRAY) {
assert (!(CxLVAL(cx) & OPpENTERSUB_DEREF));
- while (++MARK <= SP) {
+ if (!CxLVAL(cx) || CxLVAL(cx) & OPpENTERSUB_INARGS)
+ while (++MARK <= SP)
+ *++newsp =
+ SvTEMP(*MARK)
+ ? *MARK
+ : sv_2mortal(SvREFCNT_inc_simple_NN(*MARK));
+ else while (++MARK <= SP) {
*++newsp = *MARK;
TAINT_NOT; /* Each item is independent */
}