int main() { array(int) positions=({4,3}); int pos=1; array unrolled=({}); foreach (positions, int nextpos) { write("Extending to %d\n",nextpos); for (;pos<=nextpos;++pos) unrolled+=({"Spam"}); } }
The basic concept is that it should unroll an array of counts into individual entries. (Think run-length decoding or something.) There's a bug in it, that the second position is lower than the first. A naive implementation would simply note that pos isn't less than or equal to nextpos, ergo it should skip the loop altogether; and in Pike 7.8.352, this is what happens. In Pike 8.1 current, this results in an infinite loop that allocates gobs of memory.
I tried to bisect to find the problem, but it's been there for a very long time, and a lot of the old builds won't compile on my system for some reason.
ChrisA
With inlined byte code disassembly (and some braces and newlines):
int main() {
=== 3 1c entry === 3 30 function start === 3 30 mark_at(0) === 3 54 pop to mark === 3 90 fill_stack(4,0) === 3 b6 init_frame(0,4)
array(int) positions=({4,3});
=== 4 be constant(0) === 4 e5 copy_value === 4 ed assign local and pop(0)
int pos=1;
=== 5 123 assign local number and pop(1,1)
array unrolled=({});
=== 6 160 mark, call builtin(1) === 6 176 assign local and pop(2)
=== 7 1b3 local(0) === 7 1e0 & local(3) === 7 203 clear local(3) === 7 236 push 0 === 7 24d branch(3)
foreach (positions, int nextpos) {
=== 7 252 label(5)
write("Extending to %d\n",nextpos);
=== 9 261 string(1) === 9 28b local(3) === 9 2b1 apply N(2,2) === 9 2c5 pop
=== 10 2f1 --local(1) === 10 34b ~ === 10 362 local(3) === 10 388 add integer(1) === 10 3d1 int+int === 10 403 branch(6)
for (;pos<=nextpos;++pos) {
=== 10 408 label(7)
unrolled += ({"Spam"});
=== 10 417 mark === 10 42b & local(2) === 10 44e push 0 === 10 465 string(2) === 10 481 append array === 10 489 pop
=== 10 4b1 label(6) === 10 4c0 loop(7)
}
=== 10 521 local(3) === 10 547 add integer(1) === 10 590 assign local and pop(1)
=== 7 5ca label(3) === 7 5d9 foreach(5)
}
=== 7 67f pop_n_elems(4) === 12 68d clear n local(0,4)
=== 12 6d4 return 0
}
Looks like the problem is either in the loop opcode, or in the setup.
F_LOOP is rather simple.
is type int? yes: is it 0? yes: end loop no: decrement call body no: call f_loop
Note the absence of "or less than" in the check for 0. I guess there should be such a check. It's there in the interret_functions.h version.
I will fix it this evening if nobody get's there first. Around line 2854 in amd64.c, for those interreseted. :)
pike-devel@lists.lysator.liu.se