summaryrefslogtreecommitdiff
path: root/pp_hot.c
diff options
context:
space:
mode:
authorFather Chrysostomos <sprout@cpan.org>2011-06-16 06:27:50 -0700
committerFather Chrysostomos <sprout@cpan.org>2011-06-16 20:17:52 -0700
commit3ed94dc04bd73c956fbfa66348a55f94c8a2268b (patch)
tree0b97f0066f7f723345414b177a96044984551633 /pp_hot.c
parentad37a74e7dc5e204efc84791373a791f142ac7b4 (diff)
downloadperl-3ed94dc04bd73c956fbfa66348a55f94c8a2268b.tar.gz
[perl #81944] Non-lvalue subs do not copy return values
return and leavesub see if they can cheat by not copying anything marked TEMP, since presumably nothing else is using it. That means the return values of delete() and shift() are not copied. Since @_ aliases to the caller’s variables, sometimes what is returned *is* used elsewhere and still marked TEMP. So cases like sub { return delete $_[0] } ->($x) end up returning $x unchanged, instead of copying it. As mentioned in the ticket, the solution is to copy only if the refer- ence count is 1. This also allows me to simplify the lvalue-returning code without spreading this bug further. (pp_leavesublv currently avoids calling sv_2mortal, in order not to set the TEMP flag.)
Diffstat (limited to 'pp_hot.c')
-rw-r--r--pp_hot.c6
1 files changed, 3 insertions, 3 deletions
diff --git a/pp_hot.c b/pp_hot.c
index f1c4977cd2..b2970d88c6 100644
--- a/pp_hot.c
+++ b/pp_hot.c
@@ -2611,7 +2611,7 @@ PP(pp_leavesub)
MARK = newsp + 1;
if (MARK <= SP) {
if (cx->blk_sub.cv && CvDEPTH(cx->blk_sub.cv) > 1) {
- if (SvTEMP(TOPs)) {
+ if (SvTEMP(TOPs) && SvREFCNT(TOPs) == 1) {
*MARK = SvREFCNT_inc(TOPs);
FREETMPS;
sv_2mortal(*MARK);
@@ -2624,7 +2624,7 @@ PP(pp_leavesub)
SvREFCNT_dec(sv);
}
}
- else if (SvTEMP(TOPs)) {
+ else if (SvTEMP(TOPs) && SvREFCNT(TOPs) == 1) {
*MARK = TOPs;
if (gmagic) SvGETMAGIC(TOPs);
}
@@ -2639,7 +2639,7 @@ PP(pp_leavesub)
}
else if (gimme == G_ARRAY) {
for (MARK = newsp + 1; MARK <= SP; MARK++) {
- if (!SvTEMP(*MARK)) {
+ if (!SvTEMP(*MARK) || SvREFCNT(*MARK) != 1) {
*MARK = sv_mortalcopy(*MARK);
TAINT_NOT; /* Each item is independent */
}