Skip to content

Commit

Permalink
[perl #121827] Fix repeat stack bugs
Browse files Browse the repository at this point in the history
(...)x... is marked as a list at compile time and given a pushmark,
before the context is known.  If it turns out to be called in scalar
or void context after all, then pp_repeat has to handle the mark that
has been pushed on to the markstack.

It was not handling the mark for overloading.  Nor was it handling
void context correctly at all.  (The stack may have an empty list, in
which case we call FETCH on a potentially tied stack item that has
nothing to do with us.)

I tested it in void context, because I plan to undo the listification
when scalar context is applied, for speed.
  • Loading branch information
Father Chrysostomos committed Nov 6, 2014
1 parent d71b73c commit 3a100da
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 11 deletions.
8 changes: 7 additions & 1 deletion lib/overload.t
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ package main;

$| = 1;
BEGIN { require './test.pl' }
plan tests => 5198;
plan tests => 5199;

use Scalar::Util qw(tainted);

Expand Down Expand Up @@ -2748,6 +2748,12 @@ package refsgalore {
is ioref->(), 46, '(overloaded constant that is not a sub ref)->()';
}

package xstack { use overload 'x' => sub { shift . " x " . shift },
'""'=> sub { "xstack" } }
is join(",", 1..3, scalar((bless([], 'xstack')) x 3, 1), 4..6),
"1,2,3,1,4,5,6",
'(...)x... in void cx with x overloaded [perl #121827]';

{ # undefining the overload stash -- KEEP THIS TEST LAST
package ant;
use overload '+' => 'onion';
Expand Down
28 changes: 19 additions & 9 deletions pp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1650,6 +1650,25 @@ PP(pp_repeat)
SvGETMAGIC(sv);
}
else {
if (UNLIKELY(PL_op->op_private & OPpREPEAT_DOLIST)) {
/* The parser saw this as a list repeat, and there
are probably several items on the stack. But we're
in scalar/void context, and there's no pp_list to save us
now. So drop the rest of the items -- robin@kitsite.com
*/
dMARK;
if (MARK + 1 < SP) {
MARK[1] = TOPm1s;
MARK[2] = TOPs;
}
else {
dTOPss;
ASSUME(MARK + 1 == SP);
XPUSHs(sv);
MARK[1] = &PL_sv_undef;
}
SP = MARK + 2;
}
tryAMAGICbin_MG(repeat_amg, AMGf_assign);
sv = POPs;
}
Expand Down Expand Up @@ -1741,15 +1760,6 @@ PP(pp_repeat)
else
(void)SvPOK_only(TARG);

if (PL_op->op_private & OPpREPEAT_DOLIST) {
/* The parser saw this as a list repeat, and there
are probably several items on the stack. But we're
in scalar context, and there's no pp_list to save us
now. So drop the rest of the items -- robin@kitsite.com
*/
dMARK;
SP = MARK;
}
PUSHTARG;
}
RETURN;
Expand Down
12 changes: 11 additions & 1 deletion t/op/repeat.t
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ BEGIN {
}

require './test.pl';
plan(tests => 46);
plan(tests => 47);

# compile time

Expand Down Expand Up @@ -141,6 +141,16 @@ is($y, undef, ' no extra values on stack');
# operand of the eq binop needs to remain!
is(77, scalar ((1,7)x2), 'stack truncation');

# ( )x in void context should not read preceding stack items
package Tiecount {
sub TIESCALAR { bless[]} sub FETCH { our $Tiecount++; study; 3 }
}
sub nil {}
tie my $t, "Tiecount";
{ push my @temp, $t, scalar((nil) x 3, 1) }
is($Tiecount::Tiecount, 1,
'(...)x... in void context in list (via scalar comma)');


# perlbug 20011113.110 works in 5.6.1, broken in 5.7.2
{
Expand Down

0 comments on commit 3a100da

Please sign in to comment.