[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index][Thread Index][Top&Search][Original]
[perl #38809][PATCH] loss of stack elements with a do block insidea return
This is the bug that makes
sub foo { do { return do { 1; 2 } }; 3 }
returns undef. The 1 is here to prevent the return do block to be
optimized away, and the 3 to ensure that the first statement receives
void context. Concise says :
1 <;> nextstate(main 3 -e:1) v
2 <0> enter v
3 <;> nextstate(main 2 -e:1) v
4 <0> pushmark s
5 <0> enter
6 <;> nextstate(main 1 -e:1) v
7 <;> nextstate(main 1 -e:1) v
8 <$> const[IV 2] s
9 <@> leave KP
a <@> return K
b <@> leave vKP
c <;> nextstate(main 3 -e:1) v
d <$> const[IV 3] s
e <1> leavesub[1 ref] K/REFC,1
The problem is that the enter after the pushmark has no context and
hence its associated leave won't drop its return value on the stack.
The patch attached is a way better solution compared to the previous one
I sent some months ago. In ck_return, it looks at the kids and force
list context on NULLs that have the OPf_SPECIAL flag set (which
corresponds to do { } blocks, op.h says). Maybe other kids could receive
the same treatment.
Vincent.
--- op.c 2008-06-17 13:25:08.000000000 +0200
+++ op.c 2008-08-30 17:21:16.000000000 +0200
@@ -7561,13 +7561,19 @@
Perl_ck_return(pTHX_ OP *o)
{
dVAR;
+ OP *kid;
PERL_ARGS_ASSERT_CK_RETURN;
+ kid = cLISTOPo->op_first->op_sibling;
if (CvLVALUE(PL_compcv)) {
- OP *kid;
- for (kid = cLISTOPo->op_first->op_sibling; kid; kid = kid->op_sibling)
+ for (; kid; kid = kid->op_sibling)
mod(kid, OP_LEAVESUBLV);
+ } else {
+ for (; kid; kid = kid->op_sibling) {
+ if (kid->op_type == OP_NULL && kid->op_flags & OPf_SPECIAL) /* do */
+ list(kid);
+ }
}
return o;
}
--- t/op/do.t 2007-01-08 22:22:52.000000000 +0100
+++ t/op/do.t 2008-08-30 16:32:00.000000000 +0200
@@ -29,7 +29,7 @@
return $ok;
}
-print "1..22\n";
+print "1..23\n";
# Test do &sub and proper @_ handling.
$_[0] = 0;
@@ -92,6 +92,10 @@
push @t, ($u = (do {} . "This should be pushed."));
ok( $#t == 0, "empty do result value" );
+# [perl #38809]
+@a = sub { do { return 38, do { 1; 80, 9 } }; 2 }->();
+ok( join('', @a) eq '38809', "do blocks in return should have list context" );
+
END {
1 while unlink("$$.16", "$$.17", "$$.18");
}
- Follow-Ups from:
-
Vincent Pit <perl@profvince.com>
[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index][Thread Index][Top&Search][Original]