Closed p5pRT closed 21 years ago
Dear maintainers\,
the following program behaves unexpected:
#-------------------------------------------------- #!/usr/bin/perl
for ($i=1; $i\<=1; $i++) { my $var='val'; print "before \$var='$var'\n"; goto Jump; Jump: print "after \$var='$var'\n"; } #--------------------------------------------------
The output is:
#-------------------------------------------------- before $var='val' after $var='' #--------------------------------------------------
It seems\, all ingredients (C-style for\, my-variable\, goto) are crucial; e.g. a for(1)-loop behaves as expected.
I think it would be a good idea to correct this glitch in an otherwise excellent language.
Sincerely\, Thomas Schmitt
Wow! This is a venerable bug\, dating at least back to 5.00404.
When a for(;;) is compiled\, there's no nextstate immediately before the enterloop\, and so when pp_goto does this:
case CXt_LOOP: gotoprobe = cx->blk_oldcop->op_sibling; break;
gotoprobe ends up pointing into a dead end.
That means that the label doesn't get found until the next context up is searched; and so the loop context is left and re-entered when the goto is executed.
I'm not sure whether it is the best fix\, but the patch below seems to solve the problem (and still passes all tests).
[The alternative approach\, I suppose\, would be to say that pp_goto is making unreasonable assumptions]
You'll have to make run_byacc of course: perly_c.diff will still apply but with fuzz of one line in the final hunk.
.robin.
On 10 Mar 2001\, at 2:14\, Robin Houston wrote:
I'm not sure whether it is the best fix\, but the patch below seems to solve the problem (and still passes all tests).
Are you going to provide a test case as well that will show in the future whether this bug does not exist?
Otherwise\, the snippet in the original bug report could probably be used\, but I don't know which test script it should wander into:
for ($i=1; $i\<=1; $i++) { my $var='val'; print "before \$var='$var'\n"; goto Jump; Jump: print "after \$var='$var'\n"; }
and check that $var is correctly set after the goto.
Cheers\, Philip
On Mon\, Mar 12\, 2001 at 05:08:00PM +0100\, Philip Newton wrote:
Are you going to provide a test case as well that will show in the future whether this bug does not exist?
Sure! See below. (Patch against 5.7.0)
I was really waiting for someone to tell me whether or not the patch was okay before doing any more work on it. But since a) nobody has complained yet\, and b) the test is trivial\, here it is :-)
.robin.
In article \20010312165814\.A12249@​puffinry\.freeserve\.co\.uk\, Robin Houston \robin@​kitsite\.com writes:
This sounds extremely simular to http://bugs.perl.org/perlbug.cgi?req=bid&bid=20000313.004&range=10985&format=H&trim=25
Does it happen to fix that too ?
On Sat\, Mar 10\, 2001 at 02:14:31AM +0000\, Robin Houston wrote:
Wow! This is a venerable bug\, dating at least back to 5.00404.
When a for(;;) is compiled\, there's no nextstate immediately before the enterloop\, and so when pp_goto does this:
case CXt\_LOOP​: gotoprobe = cx\->blk\_oldcop\->op\_sibling; break;
gotoprobe ends up pointing into a dead end.
That means that the label doesn't get found until the next context up is searched; and so the loop context is left and re-entered when the goto is executed.
I'm not sure whether it is the best fix\, but the patch below seems to solve the problem (and still passes all tests).
In 5.7.0+ the lib/tie-substrhash fails:
ok 15 Exiting subroutine via next at ../lib/Tie/SubstrHash.pm line 201. Label not found for "next NUM" at ../lib/Tie/SubstrHash.pm line 201.
Here's the code:
# using POSIX::ceil() would be too heavy\, and not all platforms have it. sub ceil { my $num = shift; $num = int($num + 1) unless $num == int $num; return $num; }
sub findgteprime { # find the smallest prime integer greater than or equal to use integer;
# It may be sufficient (and more efficient\, IF IT IS CORRECT) to use # $max = 1 + int sqrt $num and calculate it once only\, but is it correct?
my $num = ceil(shift); return 2 if $num \<= 2;
$num++ unless $num % 2;
NUM: for (;; $num += 2) { my $max = int sqrt $num; for ($i = 3; $i \<= $max; $i += 2) { next NUM unless $num % $i; } return $num; } }
On Mon\, 12 Mar 2001 at 18:24:53\, Jarkko laid this on us:
sub findgteprime { # find the smallest prime integer greater than or equal to use integer;
# It may be sufficient (and more efficient\, IF IT IS CORRECT) to use # $max = 1 + int sqrt $num and calculate it once only\, but is it correct?
my $num = ceil\(shift\); return 2 if $num \<= 2; $num\+\+ unless $num % 2;
NUM: for (;; $num += 2) { my $max = int sqrt $num; for ($i = 3; $i \<= $max; $i += 2) { next NUM unless $num % $i; } return $num; } }
A bit off the real topic\, for which I apologize\, but\, according to
http://www-groups.dcs.st-andrews.ac.uk/~history/HistTopics/Prime_numbers.html
the following is an unsolved problem:
4. Is there always a prime between n ** 2 and (n + 1) ** 2 ? (The fact that there is always a prime between n and 2n was called Bertrand's conjecture and was proved by Chebyshev.)
If n in the unsolved problem is int sqrt $num\, then the algorithm works iff there *is* a prime between n ** 2 and (n + 1) ** 2\, solving the problem. My gambling side would favor the existence of such a prime\, but I don't like to gamble with code.
findgteprime3 benchmarks as well as the uncertain algorithm (findgteprime1) (at least on my Intel PC and an SGI box)\, and doesn't rely on the status of unsolved problems. But there isn't a *lot* of difference in the runtime of any of the algorithms. -- jpl
=======
use Benchmark;
# using POSIX::ceil() would be too heavy\, and not all platforms have it. sub ceil { my $num = shift; $num = int($num + 1) unless $num == int $num; return $num; }
sub findgteprime1 { # find the smallest prime integer greater than or equal to use integer;
# It may be sufficient (and more efficient\, IF IT IS CORRECT) to use # $max = 1 + int sqrt $num and calculate it once only\, but is it correct?
my $num = ceil(shift); return 2 if $num \<= 2;
$num++ unless $num % 2; my $max = 1 + int sqrt $num; my $i;
NUM: for (;; $num += 2) { for ($i = 3; $i \<= $max; $i += 2) { next NUM unless $num % $i; } return $num; } }
sub findgteprime2 { # find the smallest prime integer greater than or equal to use integer;
# It may be sufficient (and more efficient\, IF IT IS CORRECT) to use # $max = 1 + int sqrt $num and calculate it once only\, but is it correct?
my $num = ceil(shift); return 2 if $num \<= 2;
$num++ unless $num % 2; my $i;
NUM: for (;; $num += 2) { my $max = int sqrt $num; for ($i = 3; $i \<= $max; $i += 2) { next NUM unless $num % $i; } return $num; } }
sub findgteprime3 { # find the smallest prime integer greater than or equal to use integer;
my $num = ceil(shift); return 2 if $num \<= 2;
$num++ unless $num % 2; my $i; my $sqrtnum = int sqrt $num; my $sqrtnumsquared = $sqrtnum * $sqrtnum;
NUM: for (;; $num += 2) { if ($sqrtnumsquared \< $num) { $sqrtnum++; $sqrtnumsquared = $sqrtnum * $sqrtnum; } for ($i = 3; $i \<= $sqrtnum; $i += 2) { next NUM unless $num % $i; } return $num; } }
$n = 500000; $t = $i = 0; timethis($n\, '$t += findgteprime1($i); $i++'); print("\$t = $t\n"); $t = $i = 0; timethis($n\, '$t += findgteprime2($i); $i++'); print("\$t = $t\n"); $t = $i = 0; timethis($n\, '$t += findgteprime3($i); $i++'); print("\$t = $t\n");
==============
Intel results:
timethis 500000: 565 wallclock secs (258.29 usr + 1.15 sys = 259.44 CPU) @ 1927.23/s (n=500000) $t = 125004425341 timethis 500000: 608 wallclock secs (277.77 usr + 1.38 sys = 279.15 CPU) @ 1791.15/s (n=500000) $t = 125004425341 timethis 500000: 534 wallclock secs (256.53 usr + 0.70 sys = 257.23 CPU) @ 1943.79/s (n=500000) $t = 125004425341
SGI results:
timethis 500000: 630 wallclock secs (626.84 usr + 0.40 sys = 627.24 CPU) @ 797.14/s (n=500000) $t = 125004425341 timethis 500000: 629 wallclock secs (627.30 usr + 0.40 sys = 627.70 CPU) @ 796.56/s (n=500000) $t = 125004425341 timethis 500000: 627 wallclock secs (624.89 usr + 0.41 sys = 625.30 CPU) @ 799.62/s (n=500000) $t = 125004425341
A bit off the real topic\, for which I apologize\, but\, according to
http://www-groups.dcs.st-andrews.ac.uk/~history/HistTopics/Prime_numbers.html
the following is an unsolved problem:
4. Is there always a prime between n ** 2 and (n + 1) ** 2 ? (The fact that there is always a prime between n and 2n was called Bertrand's conjecture and was proved by Chebyshev.)
If n in the unsolved problem is int sqrt $num\, then the algorithm works iff there *is* a prime between n ** 2 and (n + 1) ** 2\, solving the problem. My gambling side would favor the existence of such a prime\, but I don't like to gamble with code.
Thanks. Good that we have number theoreticians among us :-)
As Jarkko pointed out\, my last patch simply switched one kind of brokenness for a different (probably worse) one. Sorry.
Below is round two.
I've added a new test file\, op/loopctl.t which gives the loop control operators (last\, next\, redo) a thorough workout. The bug addressed here and some plausible variants are tested by three new tests in op/goto.t
What I've done is to compile this:
LABEL: for(A; B; C) {D}
as though it were:
LABEL: A; LABEL: while(B) {D} continue {C}
duplicating the label may look like madness\, but it makes the construct behave as expected: because of the way that goto searches for labels it will always find the first occurence; whereas last/next/redo will always find the second occurence.
Incidentally\, perl will currently give the "Use of implicit split to @_" warning TWICE for things like perl -wce 'for(;;split) {}' I fixed that too.
perl-mvs is CCed because perly.y is patched. I got rid of the fuzz from perly_c.diff - so there's a patch of a patch there.
Patch is against perl-current (as of yesterday).
.robin.
Ton Hospel wrote:
This sounds extremely simular to http://bugs.perl.org/perlbug.cgi?req=bid&bid=20000313.004&range=10985&format=H&trim=25
Does it happen to fix that too ?
No\, that's a different bug! :-) Thanks for pointing it out.
Try the patch below\, which applies over the one I just posted.
.robin.
On Wed\, Mar 14\, 2001 at 12:43:45AM +0000\, Robin Houston wrote:
As Jarkko pointed out\, my last patch simply switched one kind of brokenness for a different (probably worse) one. Sorry.
Below is round two.
Thanks\, applied.
On Wed\, Mar 14\, 2001 at 01:52:51AM +0000\, Robin Houston wrote:
Ton Hospel wrote:
This sounds extremely simular to http://bugs.perl.org/perlbug.cgi?req=bid&bid=20000313.004&range=10985&format=H&trim=25
Does it happen to fix that too ?
No\, that's a different bug! :-) Thanks for pointing it out.
Try the patch below\, which applies over the one I just posted.
Thanks\, applied.
On Sat\, 10 Mar 2001\, Robin Houston wrote:
Wow! This is a venerable bug\, dating at least back to 5.00404.
When a for(;;) is compiled\, there's no nextstate immediately before the enterloop\, and so when pp_goto does this:
case CXt\_LOOP​: gotoprobe = cx\->blk\_oldcop\->op\_sibling; break;
gotoprobe ends up pointing into a dead end.
--- perly.y.orig Fri Mar 9 23:24:30 2001 +++ perly.y Sat Mar 10 00:19:03 2001 @@ -249\,9 +249\,10 @@ /* basically fake up an initialize-while lineseq */
I think this is what made it in as change 9139(?). I am happy to report that perl@9172 builds and passes about as many tests as the previous devel kit ("Failed 23 test scripts out of 309\, 92.56% okay.").
Thank you for cross-posting the perly.y diff to perl-mvs.
Peter Prymmer
Migrated from rt.perl.org#5998 (status was 'resolved')
Searchable as RT5998$