Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

eval '__PACKAGE__' in debug mode do not return right package #16512

Open
p5pRT opened this issue Apr 19, 2018 · 10 comments
Open

eval '__PACKAGE__' in debug mode do not return right package #16512

p5pRT opened this issue Apr 19, 2018 · 10 comments

Comments

@p5pRT
Copy link

p5pRT commented Apr 19, 2018

Migrated from rt.perl.org#133123 (status was 'open')

Searchable as RT133123$

@p5pRT
Copy link
Author

p5pRT commented Apr 19, 2018

From @KES777

Created by @KES777

[DOC](https://perldoc.perl.org/functions/eval.html)

An eval '' executed within a subroutine defined in the DB package doesn't
see the usual surrounding lexical scope, but rather the scope of the first
non-DB piece of code that called it

How to reproduce​:

$ cat Devel/DB.pm
package DB;

sub DB {
  print eval '__PACKAGE__';
}

1;

$ cat t.pl
print __PACKAGE__;

$ perl -d​:DB t.pl
DBmain

Expected​:
mainmain

Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl 5.24.0:

Configured by kes at Wed Oct 19 14:07:47 EEST 2016.

Summary of my perl5 (revision 5 version 24 subversion 0) configuration:
   
  Platform:
    osname=linux, osvers=4.4.0-43-generic, archname=x86_64-linux
    uname='linux work 4.4.0-43-generic #63-ubuntu smp wed oct 12 13:48:03 utc 2016 x86_64 x86_64 x86_64 gnulinux '
    config_args='-de -Dprefix=/home/kes/perl5/perlbrew/perls/perl-5.24.0 -Aeval:scriptdir=/home/kes/perl5/perlbrew/perls/perl-5.24.0/bin'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=undef, usemultiplicity=undef
    use64bitint=define, use64bitall=define, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2',
    cppflags='-fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include'
    ccversion='', gccversion='5.4.0 20160609', gccosandvers=''
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678, doublekind=3
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16, longdblkind=3
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='cc', ldflags =' -fstack-protector-strong -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib/gcc/x86_64-linux-gnu/5/include-fixed /usr/include/x86_64-linux-gnu /usr/lib /lib/x86_64-linux-gnu /lib/../lib /usr/lib/x86_64-linux-gnu /usr/lib/../lib /lib /lib64 /usr/lib64
    libs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
    perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
    libc=libc-2.23.so, so=so, useshrplib=false, libperl=libperl.a
    gnulibc_version='2.23'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector-strong'

Locally applied patches:
    Devel::PatchPerl 1.38


@INC for perl 5.24.0:
    /home/kes/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0/x86_64-linux
    /home/kes/perl5/perlbrew/perls/perl-5.24.0/lib/site_perl/5.24.0
    /home/kes/perl5/perlbrew/perls/perl-5.24.0/lib/5.24.0/x86_64-linux
    /home/kes/perl5/perlbrew/perls/perl-5.24.0/lib/5.24.0
    .


Environment for perl 5.24.0:
    HOME=/home/kes
    LANG=en_US.UTF-8
    LANGUAGE=en
    LC_ADDRESS=uk_UA.UTF-8
    LC_IDENTIFICATION=uk_UA.UTF-8
    LC_MEASUREMENT=uk_UA.UTF-8
    LC_MESSAGES=en_US.UTF-8
    LC_MONETARY=uk_UA.UTF-8
    LC_NAME=uk_UA.UTF-8
    LC_NUMERIC=uk_UA.UTF-8
    LC_PAPER=uk_UA.UTF-8
    LC_TELEPHONE=uk_UA.UTF-8
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/home/kes/perl5/perlbrew/bin:/home/kes/perl5/perlbrew/perls/perl-5.24.0/bin:/home/kes/bin:/home/kes/bin:/home/kes/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
    PERLBREW=command perlbrew
    PERLBREW_BASHRC_VERSION=0.78
    PERLBREW_HOME=/home/kes/.perlbrew
    PERLBREW_MANPATH=/home/kes/perl5/perlbrew/perls/perl-5.24.0/man
    PERLBREW_PATH=/home/kes/perl5/perlbrew/bin:/home/kes/perl5/perlbrew/perls/perl-5.24.0/bin
    PERLBREW_PERL=perl-5.24.0
    PERLBREW_ROOT=/home/kes/perl5/perlbrew
    PERLBREW_VERSION=0.78
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Apr 19, 2018

From @iabyn

On Thu, Apr 19, 2018 at 07​:06​:06AM -0700, KES wrote​:

[DOC](https://perldoc.perl.org/functions/eval.html)

An eval '' executed within a subroutine defined in the DB package doesn't
see the usual surrounding lexical scope, but rather the scope of the first
non-DB piece of code that called it

That paragraph says nothing about about the package an eval is executed;
it refers purely to what *lexical* scope is seen in. This code​:

  my $x = 'outer';
  package notDB { sub f { my $x = 'notDB'; eval '$x' } }
  package DB { sub f { my $x = 'DB'; eval '$x' } }
  print notDB​::f(), "-", DB​::f(), "\n";

outputs​:

  notDB-outer

(which is what I expect).

How to reproduce​:

$ cat Devel/DB.pm
package DB;

sub DB {
print eval '__PACKAGE__';
}

1;

$ cat t.pl
print __PACKAGE__;

$ perl -d​:DB t.pl
DBmain

Expected​:
mainmain

I would expect DBmain.

@p5pRT
Copy link
Author

p5pRT commented Apr 19, 2018

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Apr 20, 2018

From @KES777

outputs​:

notDB\-outer

(which is what I expect).

Yes, this is right.
Thus the EXPR which is evaled in 'DB' package sees 'main' package
Does __PACKAGE__ will see also 'main' package or it will see 'DB' pacakge still??

I suppose it does. Because this is 'string eval' which​:

is executed as a block within the lexical context of the current Perl program, any outer lexical variables are visible to it, and any package variable settings

The 'eval' in DB package

doesn't see the usual surrounding lexical scope, but rather the scope of the first non-DB piece

The first non-DB piece is 'main' package, thus __PACKAGE__ should return 'main'

@p5pRT
Copy link
Author

p5pRT commented Apr 21, 2018

From @iabyn

On Fri, Apr 20, 2018 at 01​:17​:53AM -0700, KES via RT wrote​:

Thus the EXPR which is evaled in 'DB' package sees 'main' package
Does __PACKAGE__ will see also 'main' package or it will see 'DB' pacakge still??

You are conflating two completely different issues.

perl has a hack that affects how it looks up lexical (my) variables
in outer scopes when doing an eval, if the eval is run from within the DB
package.

This has nothing to do with __PACKAGE__, which is static and completely
unaffected by DB.

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2018

From @KES777

Yes, It is implemented in this way. But to my mind it would be more consistent
if __PACKAGE__, __LINE__ would be bound to COP

Thus if we look at N frames up the `p __LINE__` will show user's script line and not debugger's eval.

This is minor, but looks more expected

Also when evaluating at users context, it is eval at first non-DB frame.

Just like​: 'eval EXPR, 0'. It would be cool if eval in debugger mode (-d) will accept second argument which means stack frame number from TOP. And evaluates given EXPR at given frame.

This will be not so criminal to support it, because it already support 0 frame. Also this will simplify hacks like this​: https://github.com/KES777/Devel-DebugHooks/blob/master/lib/Devel/DebugHooks/Commands.pm#L716

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2018

From @iabyn

On Mon, Apr 23, 2018 at 01​:24​:11AM -0700, KES via RT wrote​:

Yes, It is implemented in this way. But to my mind it would be more consistent
if __PACKAGE__, __LINE__ would be bound to COP

Thus if we look at N frames up the `p __LINE__` will show user's script line and not debugger's eval.

This is minor, but looks more expected

If I understand you correctly, you're wanting __LINE__etc to be changed
from compile-time constants to run-time functions?

Even so, I don't see how that will help make 'p __LINE__' in the
debugger display an arbitrary caller's frame location - the current COP is
still at a line in perl5db.pl.

Also when evaluating at users context, it is eval at first non-DB frame.

Just like​: 'eval EXPR, 0'. It would be cool if eval in debugger mode
(-d) will accept second argument which means stack frame number from
TOP. And evaluates given EXPR at given frame.

By 'eval in debugger mode', are you referring to the 'x' debugger command,
or perl's built-in 'eval' function, or something else?

I'm afraid I don't understand what you're proposing.

--
Little fly, thy summer's play my thoughtless hand
has terminated with extreme prejudice.
  (with apologies to William Blake)

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2018

From @KES777

If I understand you correctly, you're wanting __LINE__etc to be changed from compile-time constants to run-time functions?

No. Maybe change the value it is compiled into when this is 'eval' in DB package

By 'eval in debugger mode', are you referring to the 'x' debugger
command,
or perl's built-in 'eval' function, or something else?
Sorry, This is too often I may explain poor

I mean next​:
eval EXPR, FRAMENUMBER

An eval '' executed within a subroutine defined in the DB package doesn't see the usual surrounding lexical scope, but rather the scope of **the first** non-DB piece (FRAMENUMBER=0) of code that called it. You can provide FRAMENUMBER to force eval see the second (FRAMENUMBER=1), the third (FREAMENUMBER=2) scope

@p5pRT
Copy link
Author

p5pRT commented Apr 25, 2018

From @iabyn

On Mon, Apr 23, 2018 at 07​:14​:08AM -0700, KES via RT wrote​:

If I understand you correctly, you're wanting __LINE__etc to be changed from compile-time constants to run-time functions?

No. Maybe change the value it is compiled into when this is 'eval' in DB
package

So, this​:

  package DB {
  sub do_foo { print __PACKAGE__, "\n" }
  sub do_eval { print eval '__PACKAGE__', "\n" }
  }
  do_foo();
  do_eval();

would output
  main
  DB

what about errors and warnings within the eval? Would they appear to come
from within the eval, or from the first non-DB caller.

I mean next​:
eval EXPR, FRAMENUMBER

It's not possible to give eval an optional second argument. Eval used as
part of list is expected to consume 1 argument. So for example this is
valid perl which passes two arguments to f()​:

  f(eval $x, 1);

--
You live and learn (although usually you just live).

@p5pRT
Copy link
Author

p5pRT commented Apr 25, 2018

From @KES777

package DB {
sub do_foo { print __PACKAGE__, "\n" }
sub do_eval { print eval '__PACKAGE__', "\n" }
}
do_foo();
do_eval();

would output
main
DB

No. It would output​:
  DB
  main

because inside do_foo the __PACKAGE__ is used without 'eval'
and inside do_eval '__PACKAGE__' is evaled in first non-DB

what about errors and warnings within the eval? Would they appear to
come
from within the eval, or from the first non-DB caller.
I did not think about that, if expression is eval'ed at first non-DB caller thus
errors and warning should appear as from the first non-DB caller
probably using Current​::Package​::__ANON__[local/lib/perl5/Path/To/Module.pm​:15] form

f(eval $x, 1);

would it be reasonable eval_at/DB​::eval_at?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants