[perl #123286] Lone C-style for in a block blead
authorFather Chrysostomos <sprout@cpan.org>
Wed, 26 Nov 2014 02:08:13 +0000 (18:08 -0800)
committerFather Chrysostomos <sprout@cpan.org>
Wed, 26 Nov 2014 04:11:05 +0000 (20:11 -0800)
commit0f602692adc580e73d2236976e9da7fec968ca93
tree9d6e87ddf1e27273dd168fce9b165a582f1626c8
parent205681b5d1e56b5ec94a53a7a80c51b866099763
[perl #123286] Lone C-style for in a block

A block in perl usually consists of an enter/leave pair plus the con-
tents of the block:

  leave
     enter
     nextstate
     whatever

But if the contents of the block are simple enough to forego the
full block structure, a simple scope op is used, which is not
even executed:

  scope
    ex-nextstate
    whatever

If there is a real nextstate op anywhere in the block, it resets the
stack to whatever it was at block entry, based on the value on the
context stack placed there by the enter op.  That’s why we can never
have scope+nextstate (we have ex-nextstate, or a former nextstate op
that is not executed).

A for-loop (for(init; cond; cont) { ... }) executes the init section
first, and then an unstack op, which is like nextstate in that it
resets the stack based on what the context stack says is the base off-
set for this block.

If we have an unstack op, we can’t use scope, just as we can’t use it
with nextstate.  But we *were* nonetheless using scope in this case.

Hence, map { for(...;...;...) {...} } ... caused the for-loop to reset
the stack to the beginning of map’s own arguments.  So the for-loop
would stomp on them.

We can see the same bug with ‘for’ clobbering an outer list:

$ perl5.20.1 -le 'print 1..3, do{for(0;0;){}}, 4..6;'
0456
perly.act
perly.h
perly.tab
perly.y
t/cmd/for.t