Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Executing code block in memory

by morissette (Novice)
on Aug 08, 2012 at 19:51 UTC ( #986352=perlquestion: print w/ replies, xml ) Need Help??
morissette has asked for the wisdom of the Perl Monks concerning the following question:

Hey guys, this is my first post I hope that I dont make any mistakes.... I am working on a Perl REPL and have a problem that I am trying to find a solution for. Before we go please do not reply w/ possible security issues, im working that out now.

So pretty much, I have a shell built with css and jquery that sends an ajax request to a perl script then i want to execute that code in memory.

I've experimented with eval but that doesn't exactly function the way I want because I want to capture fatal and warnings and output them to STDOUT.

That works with writing the code to a file then executing with backticks but I want to avoid doing that.

Any help would be greatly appreciated, thanks!

Comment on Executing code block in memory
Re: Executing code block in memory
by kennethk (Monsignor) on Aug 08, 2012 at 20:07 UTC

    From my perspective, it would be easier to just redirect STDERR to STDOUT (or perhaps to an in-memory scalar), since warnings bypass the normal $@ error capture in eval. There are instructions for redirecting STDERR in open. You could also modify the $SIG{__WARN__} handler (see %SIG in perlvar). Or, as long as you've tossed security to the wind, maybe you could achieve your goal with CGI::Carp  qw(fatalsToBrowser);?


    #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

      I tried this but I dont think its everything you were talking about:
      #!/usr/bin/perl -w use URI::Escape; use HTML::Entities; use CGI qw/:standard/; print "Content-type: text/html\n\n"; my $file; if(param('test')){ my $code = param('test'); $code = uri_unescape($code); $code = encode_entities($code); open STDERR, '>&STDOUT'; open my $fh, '>', \$file; print $fh $code; close $fh; open my $pipe, '-|', "perl -w $file"; close $pipe; close STDERR; }
      The output I get with this is:
      sh: -c: line 0: syntax error near unexpected token `;;' sh: -c: line 0: `perl -w print "hi";'
      This is what is passed to the script:
      print "hi"; print "hello world\n";
        A modified version of your sample that does what I mean:
        #!/usr/bin/perl -w use strict; use URI::Escape; use HTML::Entities; use CGI qw/:standard/; use CGI::Carp 'fatalsToBrowser'; print header; my $file; if(param('test')){ my $code = param('test'); $code = uri_unescape($code); $code = encode_entities($code); open STDERR, '>&STDOUT'; eval $code; print $@ if $@; }

        No need to create external, temporary files. There are some potential messy issues in there, but this is good enough for rough cut.


        #11929 First ask yourself `How would I do this without a computer?' Then have the computer do it the same way.

Re: Executing code block in memory
by davido (Archbishop) on Aug 08, 2012 at 20:13 UTC

      Here's the output:

      Stdout: Stderr: Result: print "hi";

      Here's my test code

      #!/usr/bin/perl use URI::Escape; use HTML::Entities; use Capture::Tiny qw/capture/; use CGI qw/:standard/; print "Content-type: text/html\n\n"; if(param('test')){ my $code = param('test'); $code = uri_unescape($code); $code = encode_entities($code); my($stdout, $stderr, @result) = capture { $code }; print "Stdout: $stdout\n"; print "Stderr: $stderr\n"; print "Result: @result\n"; }

      Obviously what I really want to be returned here is the word: 'hi'. Maybe that clears up what I am trying to do.

        Capture::Tiny doesn't actually evaluate a string as code. You still need to use eval (or Safe) for that. Here's a minimal example:
        use strict; use warnings; use Capture::Tiny qw/capture/; my $code = 'print "hi"'; my($stdout, $stderr, @result) = capture { eval $code }; print "Stdout: $stdout\n"; print "Stderr: $stderr\n"; print "Result: @result\n";

        The output will be:

        Stdout: hi Stderr: Result: 1

        You might be wondering where "1" comes from. print returns true on success, and that propagates through the eval back to capture, which rolls it into the result set.

        Now once you introduce Safe (which I suspect you probably will end up doing), things get a lot more complicated really fast, and you'll still be exposed to DOS attacks.


        Dave

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (10)
As of 2014-11-24 18:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My preferred Perl binaries come from:














    Results (144 votes), past polls