djantzen has asked for the wisdom of the Perl Monks concerning the following question:

Hi All, I'm confused about a namespace issue when using Safe. According to the documentation, code executed within a Safe compartment believes that it resides in package main, when in fact it is in a special namespace of $Safe::Root0 (or another name of your choosing). Now, using B::Deparse::coderef2text will return a bare block where the first statement is a package statement reflecting the package in which the code was originally compiled. Something like:

{ package Foo; print "Hello World\n"; }

When running this B::Deparse'd code through Safe::reval, I'd expect the code then to execute within Safe::Root0::Foo. However, as the below example shows, the code thinks it is in package main, as the documentation of Safe says code ought to. Does this mean that package statements in Safe::reval'd strings are wholly ignored, thereby making it pointless to remove them, or is the code actually in Safe::Root0::Foo but believes it's in main?

Package Foo; sub new { my $class = shift; my $this = bless {}, $class; $this->_init(); return $this; } sub _init { my $cpt = new Safe(); my $s = sub {eval q/print "PACKAGE is ",__PACKAGE__,"\n"/; }; # explicitly permit use of 'eval' $cpt->permit('entereval'); my $deparse = B::Deparse->new(); # prepend 'sub' so we have an anonymous sub later my $code_str = 'sub '.$deparse->coderef2text($s); # Seems to have no effect on behavior to remove package statements # $code_str =~ s/package \w+\;//g; print "DEPARSED $code_str\n"; my $result = $cpt->reval($parsed); die $@ if $@; $result->(); }
Output: "PACKAGE is main"

Many thanks, fever

Replies are listed 'Best First'.
Re: Safe, namespaces, B::Deparse
by diotalevi (Canon) on Oct 31, 2002 at 10:13 UTC

    This is a problem if you completely discard Safe as well. Try your same snippet with a plain eval and see where that gets you - exactly nowhere. If you're going to start using eval that way then you'll want to alter your code generation accordingly to add the package in. You know the right package when you generate the code - just stick it in there as well.

    my $s = sub { eval qq/package @{[__PACKAGE]}; print "PACKAGE is ",__PACKAGE__,"\n";/; die $@ if $@; };

    __SIG__ use B; printf "You are here %08x\n", unpack "L!", unpack "P4", pack "L!", B::svref_2object(sub{})->OUTSIDE;

      Very interesting that a normal eval results in the same behavior; troubling too. The point though is that I want to know what happens when perl encounters package declarations that exist in the code executed within an instance of Safe. (Note that your version, because it is within a 'qq' not 'q' statement, takes the compile time version (of the enclosing program) of __PACKAGE__, which differs from the runtime version.) The reason I want to be assured of this behavior is that I'll be B::Deparse'ing arbitrary code and then checking it according to security measures via Safe::reval.

        Odd? I think so. Consider that the current package is still recognized somewhat if you query it via something like B::svref_2object(sub{})->STASH->NAME. I gather that what you are actually looking for is what changes can be propogated via the symbol table back out of a Safe module. When I try to touch a global $Foo::foo within the Safe module I get a memory fault. The ->reval operation actually calls Opcode::_safe_call_sv which internally creates a new symbol table for the about-to-be executed code. Obviously if the code being executed has internal package statements then those will be respected. Is there something else you are trying to get at here that I'm missing?

        BTW do a moment of 'use strict' on your code to fix your partially renamed $parsed / $code_str variable.

        __SIG__ use B; printf "You are here %08x\n", unpack "L!", unpack "P4", pack "L!", B::svref_2object(sub{})->OUTSIDE;