Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

How to use Safe to compile anonymous subs

by lstein (Novice)
on Jul 30, 2008 at 18:49 UTC ( #701225=perlquestion: print w/replies, xml ) Need Help??

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

I want to compile an anonymous subroutine within a Safe compartment, and then execute it from outside. This does not seem to work correctly. If I create a compartment that forbids file operations, and compile an anonymous subroutine that uses IO::File to open a file, it executes properly without complaint:
my $code =<<'END'; sub { my $a = ''; my $f = IO::File->new('/etc/passwd'); while (my $l = $f->getline) { $a .= $l } return $a; } END my $compartment = Safe->new(':default'); $safe = $compartment->reval($code); print $safe->();
If I replace IO::File->new with a direct call to open(), then the call is trapped, as desired. Is there a way to prevent anonymous subs defined within Safe compartments from invoking Class methods?

Replies are listed 'Best First'.
Re: How to use Safe to compile anonymous subs
by moritz (Cardinal) on Jul 30, 2008 at 19:01 UTC
    I don't know if that works for you, but you could try to move the evaluation into the subroutine:
    #!/usr/bin/perl use Safe; use IO::File; my $code =<<'END'; my $a = ''; my $f = IO::File->new('/etc/passwd'); while (my $l = $f->getline) { $a .= $l } return $a; END my $compartment = Safe->new; $safe = sub { $compartment->reval($code) || die $@}; print $safe->();

    This way the reval complains with Can't locate object method "new" via package "IO::File", which seems to me what you want (and a use is caught).

      Thanks, but using the suggested pattern, I don't understand how to pass arguments to the inner code:
      my $code = 'my $a = shift; warn $a'; my $compartment = Safe->new(':default'); $safe = sub { $compartment->reval($code) || die $@ }; $safe->(42);
      Is there any way to do this?
        This seems to work. The localised copy is shared into the compartments namespace.
        #!/usr/bin/perl use Safe; use IO::File; my $compartment = Safe->new; my $safe = sub { local @SHAREDARGS = @_; $compartment->share('@SHAREDARGS'); my $code = 'print "Got: ", join (", ", @SHAREDARGS),"\n" +'; $compartment->reval($code) || die "die $@" }; print $safe->(42, 47, 11 , "xyz"); __END__ Got: 42, 47, 11, xyz
        You can by sharing variables. Somehow I didn't manage to do with simply sharing a variable and localizing it, but I'm quite sure it can be done.

        This is my workaround for now:

        #!/usr/bin/perl use Safe; use IO::File; our @args; my $code =<<'END'; my @args = pass_options(); return "Arguments: @args\n"; END my $compartment = Safe->new; sub pass_options { @args }; $compartment->share('&pass_options'); $safe = sub { local @args = @_; $compartment->reval($code) || die $@}; print $safe->(1, 2, 3); __END__ Arguments: 123

        This takes the sideway of sharing a sub that returns the arguments. Not ideal, but at least it works.

        What you want is probably:

        my $code = 'sub { my $arg = shift; warn $arg; }';

        Update: Since the above looks alot like your original post, here is more.

        I've never used Safe but my doc's indicate that you need a namespace as the first arg to Safe->new.

        use Safe; my $code = 'sub { my $arg = shift; warn $arg; }'; my $safe = Safe->new(); my $ssub = $safe->reval( $code) || die ; $ssub->( "hello$/" ); &$ssub( "hello$/" );

        Be well,
        rir

Re: How to use Safe to compile anonymous subs
by zshzn (Hermit) on Jul 30, 2008 at 23:00 UTC
    I'm curious just what version of Safe you're using, given the usage problems.

    Can't use ":default" as root name at Safe.pl line 10

    Anyways, it doesn't work like that. When you reval($code), it analyzes the code path it has to build. Look at the optree for the sub you generate. Using a subroutine is part of :base_core, so no problem there.

    If you remove the sub{} wrapper in $code you can get closer to understanding your problems.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://701225]
Approved by moritz
Front-paged by almut
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (6)
As of 2022-06-28 05:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    My most frequent journeys are powered by:









    Results (90 votes). Check out past polls.

    Notices?