Saturday, March 18, 2006

Perl BEGIN Blocks Considered Harmful

Adam Kennedy pointed this out to me:
  1. Create a new Perl file containing the following:

    BEGIN {
    print "hello world\n";
    }

  2. Check the syntax with

    perl -c filename

This will print hello world, even though "all" you did was compile the file.

What's going on here?

Well, BEGIN blocks get executed when Perl compiles the file.

So what?

If you run perl -c on a file that contains nasty code in a BEGIN block, you're screwed.

Consider this:
  1. You associate the filename extension .pm with a fancy Perl editor, like Komodo, or Affrus.
  2. You click on a link in your web browser.
  3. The web server redirects you to a URL for nasty_file.pm
  4. Your browser opens the associated editor and performs a"syntax check" by compiling the file
  5. The file's BEGIN block has naughty code in it...

You're screwed.

So, keep in mind that "just compiling" Perl code may actually execute the code, so, be careful!

Here's a bug report on this subject that I filed for the Eclipse/EPIC Perl IDE.

Tags: ,

2 comments:

Damian Green said...

Good point! But when would there ever be a situation in which you would want to compile a perl program and not execute it? Or in other words, in what situation would you ever feel it is safe to compile something but not safe to execute it?

I'm not going to say that I agree with the usage of the BEGIN block in perl, but you probably shouldn't ever be in that situation where you would expect to be able to compile something "naughty" safely anyway...

That being said, looking at perl from a higher level, I think it would be best to do away with the Begin block too... The problem right now though is that sometimes you need to run a little code to analyze your machine before you can call other pre-compiler functions. For example:
BEGIN{
$perl_location = "/depends/on/machine/";
}
"use lib $perl_location;"

In cases such as this, I think the ideal solution would be to eliminate the pre-compiler process all together, and just have one compilation process execute all functions in exactly the order that they are encountered. There should be no functions that should execute out of order from which the program is written. For example, the $perl_location variable in "use lib $perl_location" should not be evaluated first if it is put at the end of the program, but under current perl compiler rules, it does.

We'll see if things change in perl6...

Matisse Enzer said...

The primary case where I want to compile but not execute code is where I want to check the syntax and other compile-time rules. In these cases I might discover that there is a compile-time dependency on a module I have not installed, or that there is an undeclared variable while strict is enabled.