Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Safe / @ISA Problem

by rdw (Curate)
on Mar 15, 2002 at 23:34 UTC ( #152108=perlquestion: print w/ replies, xml ) Need Help??
rdw has asked for the wisdom of the Perl Monks concerning the following question:

I've been playing around with Safe, but I've hit a problem with @ISA / inheritance, and I can't seem to work round it. I managed to strip everything right back to a very small example which shows the problem.

#! /usr/bin/perl -w use strict; use Safe; my $CODE = << 'END'; package A; sub new { my($class) = @_; bless { }, $class; } package B; our @ISA = qw(A); END # If I uncomment this line, everything works. # eval $CODE; my $safe = Safe->new(); $safe->reval($CODE); warn "code - $@" if $@; $safe->reval("B->new();"); warn "new - $@" if $@;

When I run this, I get "Can't locate package A for @B::ISA" (twice). If I uncomment the eval, then the problem goes away - but of course in the real app, I don't want to eval the untrusted code outside of Safe (so just suggesting that I uncomment it, isn't going to help me much :-)

Can someone explain to me what's going on? Any idea how I might get round this problem?

Have fun,

rdw

Comment on Safe / @ISA Problem
Download Code
Re: Safe / @ISA Problem
by simon.proctor (Vicar) on Mar 16, 2002 at 00:22 UTC
    I'm no expert on Safe but I believe this to be a namespace problem. I played with your code and produced:
    use strict; use Safe; my $CODE = << 'END'; package A; sub new { my($class) = @_; print "hi there"; bless { }, $class; } package B; @ISA = qw(ROOT::A); END # If I uncomment this line, everything works. # eval $CODE; my $safe = Safe->new('ROOT'); $safe->reval($CODE); warn "code - $@" if $@; ROOT::B->new(); warn "new - $@" if $@;


    Which prints the 'hi there' message. I don't think this is what you want, however. If you are wanting to load code and run it (from packages) then I would keep the package code in separate files and do the loading, run-time evaluation in the Safe compartment.

    Now a disclaimer, this is how I do it but I don't know if there are any issues with it. I'd appreciate feedback :). If there is something wrong with this method then I've got some work to do on some of my projects :).

    My way is slightly more complex cos I use a factory object to load the modules. Here is a stripped down version with that factory code removed.
    use strict; use warnings; use Safe; my $despatch = {}; my $code = sub { my $module = "A"; my $mainmodule = $module . ".pm"; require $mainmodule; import $mainmodule; my $obj = $module->new(); $despatch->{"A"} = $obj; $module = "B"; $obj = $module->new(); $despatch->{"$obj"} = $obj; }; my $compartment = Safe->new('testing'); $compartment->reval(&{$code}()); $compartment->reval( $despatch->{'A'}->test() );
    I put your module code in a file, called A.pm. I also added a method:
    package A; sub new { my($class) = @_; print "hi there\n"; bless { }, $class; } sub test { print "In test"; } package B; @ISA = qw(A); 1;
    I know theres some useless variables (mainmodule etc) but they were all getting set via object methods and config file values so I left them in place.

    All the best and I hope this helps.

      Thanks for the reply, but I'm not sure how much of that I'm going to be able to use. You called ROOT::B->new() outside the compartment, which isn't what I want. If you move it back inside reval it doesn't work again.

      Also, in the real app, the untrusted code isn't going to be written by me (that's why it's untrusted :-) and I don't really want it to have to be changed at all. I did have a quick go at modifying the code as it went in, and after it had been evaled (patching up @ISA to include the compartment root) but it still didn't fly. Putting the packages in files isn't really an option either, since I don't want to allow require/use inside, or any access to the filesystem.

      I'm beginning to think that I'm not going to be able to use Safe as-is because of the namespace thing, but I'll have to do something similar myself.

      Have fun,

      rdw

Re: Safe / @ISA Problem
by dragonchild (Archbishop) on Mar 18, 2002 at 14:07 UTC
    I cut'n'pasted your code, added a print within A::new(), and ran it. It ran just fine for me. *shrugs* Maybe it's your system/setup?

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

      Ok, that works for me as well if I add a print just after the bless inside A::new - but that's no use - because now A::new doesn't work any more (it returns '1', not a blessed reference).

      Have fun,

      rdw

        Try having a return $self; as the last line in the function instead of depending on an explicit return. *wink*

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

Re: Safe / @ISA Problem - worked it out
by rdw (Curate) on Mar 19, 2002 at 20:49 UTC

    I've worked out what's going on (at least I think I have, and I know how to fix the problem now, so that's all I really care about). The warnings are because when the reference which is returned by B->new() is returned, it's then cleaned up - it's the cleanup which is issuing the warnings - it can't work out what 'B' is, because the @ISA isn't visible anymore - it's inside the Safe compartment.

    If you add a sub DESTROY to package B (inside or outside) then the problem goes away.

    Have fun,

    rdw

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://152108]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (19)
As of 2014-08-27 15:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The best computer themed movie is:











    Results (242 votes), past polls