perl5
perl5 copied to clipboard
eval '$foo' in package DB called from lexical sub can not see closure values or globals
Perl v5.30.0
eval "string" in package DB is supposed to be evaluated in the nearest non-DB context, useful for debug tools. However when code in package DB is called from a nested lexical ("my") sub, only the lexicals in the innermost sub are visible; globals and lexicals in enclosing scopes can no longer be accessed.
(This may seem obscure, but it is important to me because I use some debugging tools which depend on eval in package DB being able to see user-defined lexicals).
The output from the following script is:
$w_from_outer = 41;
$x_from_outer = 42;
$y_from_outer = 43;
$w_from_inner = undef;
$x_from_inner = undef;
$y_from_inner = undef;
$z_from_inner = 44;
and here is the script:
!/usr/bin/perl
use strict; use warnings; use v5.18; use Data::Dumper;
our $w = 41;
my $x = 42;
my ($w_from_outer, $x_from_outer, $y_from_outer,
$w_from_inner, $x_from_inner, $y_from_inner, $z_from_inner);
sub outer {
my $y = 43;
$w_from_outer = &DB::doeval('$w');
$x_from_outer = &DB::doeval('$x');
$y_from_outer = &DB::doeval('$y');
my sub inner {
my $z = 44;
$w_from_inner = &DB::doeval('$w'); # gets undef
$x_from_inner = &DB::doeval('$x'); # gets undef
$y_from_inner = &DB::doeval('$y'); # gets undef
$z_from_inner = &DB::doeval('$z');
}
inner();
}
outer();
say Data::Dumper->Dump(
[
$w_from_outer, $x_from_outer, $y_from_outer,
$w_from_inner, $x_from_inner, $y_from_inner, $z_from_inner
],
[qw(
w_from_outer x_from_outer y_from_outer
w_from_inner x_from_inner y_from_inner z_from_inner
)] );
package DB;
sub doeval($) {
return eval $_[0];
}
This looks like a consequence of a0d2bbd5c47035a4f7369e4fddd46b502764d86e.
This broke the CvOUTSIDE() links from the inner sub to the outer sub, so the outer names weren't visible from the inner sub, unless the inner sub has an eval or the debugger is enabled.
The documentation for eval doesn't require that the debugger be enabled, so this is definitely a bug.
I haven't worked out a fix yet, given this works if the inner sub is anonymous, I suspect some CvANON(cv) needs to be CvANON(cv) || CvLEXICAL(cv).
Actually it happens for anonymous subs too, if that sub is a closure:
$ ./perl -Ilib ../19370c.pl
12
Global symbol "$x" requires explicit package name (did you forget to declare "my $x"?) at (eval 1) line 1.
$ cat ../19370c.pl
use v5.36.0;
sub x {
my $x = 10;
my $y = 12;
my $j = sub {
my $z = 11;
say $y;
DB::do_eval('say $x, $z; 1;');
};
$j->();
}
x();
package DB;
sub do_eval {
eval $_[0] or die $@;
}
$
Comments out the say $y; and the eval compiles.
So my speculation that including CvLEXICAL() subs was incorrect.
If I make setting CvOUTSIDE() for the clone unconditional, as it was before a0d2bbd5c47035a4f7369e4fddd46b502764d86e, both the lexical inner sub and the anonymous closure work.
At this point I think the change from a0d2bbd5c4703 is just broken, this was a fix for #11286, we need the CvOUTSIDE() links to implement this documented (in 2002) behaviour.
@leont and @iabyn both commented on the original ticket.
@iabyn wrote the original change d819b83ae9e that implemented this visibility.
The fix for this is being reverted.