Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Testing if Perl Code is Valid - but don't execute!

by skazat (Chaplain)
on Aug 10, 2010 at 21:08 UTC ( [id://854137]=perlquestion: print w/replies, xml ) Need Help??

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

Is there a way to test if Perl code is valid, without having the Perl code you want to validate, affect the rest of the script? eval() just seems like a natural choice:

my $n = 0; my $result = undef; eval { $result = 10 / $n; }; if ($@) { print "can't do that!\n"; } else { print "here's your answer: $result\n"; }

But that won't work, if say, I want to test if another Perl script validates - and I also don't want the code to affect anything in my own program:

open my $perl, '<', 'perlscript.pl'; my $code = do { local $/; <$perl> }; close ($perl); eval {$perl}; # what am I eval'ing?

Since you know, who knows what that perl code actually does! That could lead to all sorts of bad things. do() also look enticing, but it still will run the code it... um, does, if there's no problems. Is there a,

eval_but_dont_execute($some_shaky_perl_code);

in existence? The more I think of it, the more I'm probably asking for a whole lot.

I'm trying to figure something out for a program who's config file format is just Perl code, instead of something intelligent like, INI or $Your_Favorite_Config_Format. Upgrades to the program could potentially hose an installation, if, for example, config variables in the config file don't exist anymore. Casual users who try to edit Perl code can also, easily host the installation.

-skazat

Replies are listed 'Best First'.
Re: Testing if Perl Code is Valid - but don't execute!
by JavaFan (Canon) on Aug 10, 2010 at 21:16 UTC
    Is there a way to test if Perl code is valid, without having the Perl code you want to validate, affect the rest of the script?
    No. Consider:
    BEGIN { my $p = rand() < .5 ? '$' : ''; eval "sub foo($p) {1;}"; } foo / 1;
    Valid or not? Without executing the begin block, impossible to answer. (It's valid if the prototype is empty, it's a syntax error otherwise.)
      Even with executing the BEGIN block, you still only have a 50% success rate. :)

      For more examples like this, check my seminal classic On Parsing Perl.

      -- Randal L. Schwartz, Perl hacker

      The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

        Even with executing the BEGIN block, you still only have a 50% success rate.
        No. After executing the BEGIN block, you can determine in 100% of the cases whether the rest of the code is valid or not. (50% of the time it will be valid, and 50% of the time it will not. But at that stage, you can tell whether it's valid or not. And that's the question to be answered.)
Re: Testing if Perl Code is Valid - but don't execute!
by kennethk (Abbot) on Aug 10, 2010 at 21:58 UTC
    One possibility for your case is the switch -c. This sort-of does what you want in that it

    causes Perl to check the syntax of the program and then exit without executing it

    assuming you don't use modules with side-effects or have side-effects in BEGIN, UNITCHECK, or CHECK blocks. By shelling it out, you guarantee not to muck up local variables. Perhaps something like:

    my $script = 'perlscript.pl'; if (`perl -c $script 2>&1` =~ /syntax OK/) { print "$script compiles\n"; } else { print "Parsing $script failed\n"; }

    Of course, this certainly fails on sorts of pathological cases. It might work as a stop gap for you, however, until you can bring your colleague over to your point of view.

      Update: I incorrectly remembered the question. The OP did not say the code is unstrusted. While perl -c can execute code, it won't affect the currently running script. Disregard the rest of the post if execute code without disrupting the current script it ok.


      One possibility for your case is the switch -c. This sort-of does what you want in that it

      No, it's possible to execute code when the script is still being compiled.

      $ perl -c -E'BEGIN { say "owned" }' owned -e syntax OK

      assuming you don't use modules with side-effects or have side-effects in BEGIN, UNITCHECK, or CHECK blocks. By shelling it out, you guarantee not to muck up local variables. Perhaps something like:

      That should be "assuming you don't use use".

      $ cat Module.pm package Module; use 5.010; say "owned"; 1; $ perl -c -e'use Module;' owned -e syntax OK
Re: Testing if Perl Code is Valid - but don't execute!
by GrandFather (Saint) on Aug 10, 2010 at 21:19 UTC

    Well, you could fire up a VM and run the code on that to see if it behaves well or not, but that may involve a few more cpu cycles than you would like.

    If you supply a Markov chain saw where a screwdriver would suffice then don't be surprised if someone ends up cutting the legs out from under your system. If at all possible I'd suggest switching to YAML or some similar format. You may even be able to take the existing Perlish configuration files and convert them.

    True laziness is hard work
Re: Testing if Perl Code is Valid - but don't execute!
by ikegami (Patriarch) on Aug 10, 2010 at 21:25 UTC
    PPI does a rather good job.
Re: Testing if Perl Code is Valid - but don't execute!
by aquarium (Curate) on Aug 11, 2010 at 04:02 UTC
    The people that cotton on that your config file is really perl code will give you headaches...so instead best to have some kind of simple config where var=value, which you can load into hashes or arrays of config parameters under your full control. Otherwise it becomes config_and_do instead of just config.
    the hardest line to type correctly is: stty erase ^H
      Oh, I totally agree! Just hard to change horses in mid-stream, sadly.
      -skazat
Re: Testing if Perl Code is Valid - but don't execute!
by LanX (Saint) on Aug 11, 2010 at 01:05 UTC
    If you

  • only accept Perl-code in your configs with lower case letters and
  • can restrict the load paths for useable moduls and
  • are sure that there won't be any untrusted code in the file system accessible with do ¹ AND
  • I haven't forgotten any other back-doors ...

    ... you should have a good chance that a syntax check with perl-c will not execute code.

    No guaranty given!!!

    (Looks like I invented a new kind of perl game ... :)

    Cheers Rolf

    ¹) IMHO shouldn't be a problem anyway beacuse do is run-time only.

      Sorry, unfortunately not that simple!

      There's a way to have compile-time execution just with lower cased code! :(

      Never mind!

      Cheers Rolf

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (5)
As of 2024-03-29 10:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found