|
From: kj on 18 Apr 2008 13:27 The following short module illustrates a puzzling bug: use strict; package Foo; my $x = +{ 1 => 'one' }; sub foo { keys %$x if 0; # should do nothing my $y = eval '$x'; die if $@; printf "%d\n", scalar keys %$y; } 1; __END__ OK, now: the following one-liner produces the expected output: % perl -MFoo -e 'Foo::foo()' 1 ....but if one comments-out the first line of Foo::foo, the output changes: % perl -MFoo -e 'Foo::foo()' 0 Note that the line that was commented out should do nothing, because it ends with the conditional qualifier "if 0". Therefore, this line is essentially a no-op and should have absolutely no effect on the execution of this code. I'm seeing this behavior with v. 5.8.8. Does anyone see it also with more recent versions? I have no doubt that this is a bug, but I can't begin to figure out why it's happening. Any light that may be thrown on this puzzle would be much appreciated. Also, is there a better solution to this problem than including silly "voodoo code" like the first line in Foo::foo? TIA! Kynn -- NOTE: In my address everything before the first period is backwards; and the last period, and everything after it, should be discarded.
From: xhoster on 18 Apr 2008 13:51 kj <socyl(a)987jk.com.invalid> wrote: > The following short module illustrates a puzzling bug: > > use strict; > package Foo; > my $x = +{ 1 => 'one' }; > > sub foo { > keys %$x if 0; # should do nothing > my $y = eval '$x'; die if $@; > printf "%d\n", scalar keys %$y; > } > > 1; > __END__ The appearance of $x in %$x causes the subroutine to take out and hold a "reference" to $x. The appearance of $x in the string eval doesn't cause that happen. I assume that when the __END__ is encountered, the "my $x" goes out of scope, decrementing the refcount. In the one case, the refcount is decremented to zero, and $x is freed. Later, when the string eval is invoked, it operates on this freed $x. > Also, is there a better solution to this problem than including > silly "voodoo code" like the first line in Foo::foo? Change my $y = eval '$x'; to my $y = eval {$x}; That way, the use of $x is not hidden from the subroutine so it knows to keep a reference to $x. Unless there is a good reason you were using '$x' instead of {$x} in the first place. I can't think of such a reason off the top of my head. Xho -- -------------------- http://NewsReader.Com/ -------------------- The costs of publication of this article were defrayed in part by the payment of page charges. This article must therefore be hereby marked advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate this fact.
From: Ben Morrow on 18 Apr 2008 13:59 Quoth kj <socyl(a)987jk.com.invalid>: > > The following short module illustrates a puzzling bug: > > use strict; > package Foo; > my $x = +{ 1 => 'one' }; > > sub foo { > keys %$x if 0; # should do nothing > my $y = eval '$x'; die if $@; > printf "%d\n", scalar keys %$y; > } > > 1; > __END__ > > > OK, now: the following one-liner produces the expected output: > > % perl -MFoo -e 'Foo::foo()' > 1 > > ...but if one comments-out the first line of Foo::foo, the output changes: > > % perl -MFoo -e 'Foo::foo()' > 0 This can be reduced to package Foo; my $x = 1; sub foo { #$x; my $y = eval '$x'; printf "from %s: %s\n", scalar caller, defined $y ? $y : '<undef>'; } foo; 1; which gives ~% perl -MFoo -eFoo::foo from Foo: 1 from main: <undef> with all perls I have to hand (5.6, 5.8, 5.10, blead). This is a longstanding bug in eval STRING: it won't capture variables from an outer lexical scope unless they are explicitly mentioned in the immediately surrounding scope. Any mention, such as the line commented out, is sufficient. What I don't understand is 1. why it works when called from the same file and 2. I though this had been fixed in 5.10. I guess not... > Also, is there a better solution to this problem than including > silly "voodoo code" like the first line in Foo::foo? Fix perl's eval-handling to work properly? :) Ben
From: xhoster on 18 Apr 2008 14:27 Ben Morrow <ben(a)morrow.me.uk> wrote: > > This can be reduced to > > package Foo; > my $x = 1; > sub foo { > #$x; > my $y = eval '$x'; > printf "from %s: %s\n", > scalar caller, defined $y ? $y : '<undef>'; > } > foo; > 1; > > which gives > > ~% perl -MFoo -eFoo::foo > from Foo: 1 > from main: <undef> > > with all perls I have to hand (5.6, 5.8, 5.10, blead). This is a > longstanding bug in eval STRING: it won't capture variables from an > outer lexical scope unless they are explicitly mentioned in the > immediately surrounding scope. Any mention, such as the line commented > out, is sufficient. > > What I don't understand is 1. why it works when called from the same > file When it is called in the same file, the variable is still "in scope" in its own right because the file scope has not yet ended. Once the file scope has ended, the variable contents are destroyed unless something else (like a subroutine stuffed into the symbol table) keeps it alive. By replacing file-scope with extra curlies, you can get the same thing without using packages. perl -le ' {my $x=1; sub foo { print eval q{$x}}; foo; } foo;' I don't see how this could be fixed. Either you parse the eval string at compile time (which is not usually possible--if the string can't change between compile time and run time, why use string eval rather than block eval in the first place?), or you don't do garbage collection on any lexical variable which happens to be in scope when a string eval is encountered during the compilation pass. Or maybe when using a variable whose contents have already been freed should throw an error rather than treating it as undefined. Xho -- -------------------- http://NewsReader.Com/ -------------------- The costs of publication of this article were defrayed in part by the payment of page charges. This article must therefore be hereby marked advertisement in accordance with 18 U.S.C. Section 1734 solely to indicate this fact.
From: Ben Morrow on 18 Apr 2008 15:08 Quoth xhoster(a)gmail.com: > Ben Morrow <ben(a)morrow.me.uk> wrote: > > > > What I don't understand is 1. why it works when called from the same > > file > > When it is called in the same file, the variable is still "in scope" in its > own right because the file scope has not yet ended. Once the file > scope has ended, the variable contents are destroyed unless something else > (like a subroutine stuffed into the symbol table) keeps it alive. Yup. Thank you: I was confusing locating an entry in the lexical pad with refcounting of the contents of that entry. Ben
|
Pages: 1 Prev: HTTP::Recorder and WWW::Mechanize for testing web sites Next: Selecting Default Gateway |