weird bug

weird bug

am 18.04.2008 19:27:10 von kj

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.

Re: weird bug

am 18.04.2008 19:51:32 von xhoster

kj 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.

Re: weird bug

am 18.04.2008 19:59:42 von Ben Morrow

Quoth kj :
>
> 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 : '';
}

foo;

1;

which gives

~% perl -MFoo -eFoo::foo
from Foo: 1
from main:

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

Re: weird bug

am 18.04.2008 20:27:28 von xhoster

Ben Morrow 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 : '';
> }
> foo;
> 1;
>
> which gives
>
> ~% perl -MFoo -eFoo::foo
> from Foo: 1
> from main:
>
> 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.

Re: weird bug

am 18.04.2008 21:08:05 von Ben Morrow

Quoth xhoster@gmail.com:
> Ben Morrow 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