summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2015-10-21 19:10:34 +0100
committerDavid Mitchell <davem@iabyn.com>2016-02-03 09:18:32 +0000
commit86cc158350c1bc1d2159ec3dbf01e2800bca07dc (patch)
tree4fe7484be7b99f9c50aada3ef0aa972d036e233b
parentb28bb06c3ca3128edebf1b46812096d79b69de97 (diff)
downloadperl-86cc158350c1bc1d2159ec3dbf01e2800bca07dc.tar.gz
extend magic copy test to all scope exit types
Commit v5.15.6-387-g6f48390 forced leavesub to copy returned items if they were get-magical. Normally rvalue subs are supposed to return a copy of their return args, but that copy is sometimes skipped if leavesub thinks the side-effects will never be visible. Tied elements was an example where the implementation leaked. However, this applies equally well to other leave types, such as do { ....}, so test for get magic in those too.
-rw-r--r--pp_ctl.c6
-rw-r--r--t/op/gmagic.t7
2 files changed, 11 insertions, 2 deletions
diff --git a/pp_ctl.c b/pp_ctl.c
index d1229af760..c81df19895 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -2050,7 +2050,8 @@ S_leave_common(pTHX_ SV **newsp, SV **mark, I32 gimme,
if (MARK < SP) {
SV *sv = *SP;
- *++newsp = ((SvFLAGS(sv) & flags) && SvREFCNT(sv) == 1)
+ *++newsp = ((SvFLAGS(sv) & flags) && SvREFCNT(sv) == 1
+ && !SvMAGICAL(sv))
? sv
: lvalue
? sv_2mortal(SvREFCNT_inc_simple_NN(sv))
@@ -2065,7 +2066,8 @@ S_leave_common(pTHX_ SV **newsp, SV **mark, I32 gimme,
/* in case LEAVE wipes old return values */
while (++MARK <= SP) {
SV *sv = *MARK;
- if ((SvFLAGS(sv) & flags) && SvREFCNT(sv) == 1)
+ if ((SvFLAGS(sv) & flags) && SvREFCNT(sv) == 1
+ && !SvMAGICAL(sv))
*++newsp = sv;
else {
*++newsp = lvalue
diff --git a/t/op/gmagic.t b/t/op/gmagic.t
index 94e164e313..43f8fdbf59 100644
--- a/t/op/gmagic.t
+++ b/t/op/gmagic.t
@@ -181,6 +181,13 @@ ok($wgot == 0, 'a plain *foo causes no set-magic');
'mortal magic var is explicitly returned to refgen';
is tied $$x, undef,
'mortal magic var is copied when explicitly returned';
+
+ $tied_to = tie $_{elem}, "Tie::Monitor";
+ $x = \do { 1; delete $_{elem} };
+ expected_tie_calls $tied_to, 1, 0,
+ 'mortal magic var from do passed to refgen';
+ is tied $$x, undef,
+ 'mortal magic var from do is copied';
}
done_testing();