Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight

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

        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
        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,

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 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?

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
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (1)
As of 2022-07-03 05:21 GMT
Find Nodes?
    Voting Booth?

    No recent polls found