Tom Hale
Tom Hale

Reputation: 46795

Prevent compiler execution of BEGIN / UNITCHECK / CHECK / INIT blocks

I want to detect grammar errors in my perl code. I've found that perlcritic misses many of them, (eg a random else inserted before any if, so trying to compile with perl -cw looks like the only viable option.

However, I don't want to open myself up for executing code when checking for errors.

This perlmonks post shows that in BEGIN, INIT, UNITCHECK, and CHECK blocks can / do get executed when compiling.

Can I grammar check perl code without running any of it?

What about removing or renaming the block which could cause execution?

Upvotes: 1

Views: 364

Answers (1)

ikegami
ikegami

Reputation: 385839

Neither perlcritic nor perltidy execute any of the code they analyse/manipulate.


To properly parse Perl code, part of it needs to be executed.

For example,

BEGIN {
   if (rand() < 0.5) {
      *f = sub { 5 };
   } else {
      *f = sub() { 5 };
   }
}

print f + 2;

randomly outputs 5 or 7 because the last statement is randomly compiled as one of the following:

print( f( +2 ) );   # rand() >= 0.5
print( f() + 2 );   # rand() < 0.5

Ok, so that's pretty far-fetched. Or is it? How is that different than

use Module qw( f );   # No different than a BEGIN block.

print f + 2;

Ok, so prototypes are discouraged. But what about

say "foo";   # This is a sub call.

use feature qw( say );

say "foo";   # This isn't a sub call; this is the say operator.

This means that correctly parsing code that uses the say operator (not counting CORE::say) requires executing code. A lot code uses the say operator.

But, if you account for a few common special cases, and if you accept a certain amount of imprecision (like whether say is a sub call or the say operator), one could parse Perl code fairly accurately without executing any of it. This is the idea behind PPI.

  • perlcritic uses PPI. It doesn't execute any of the code it analyses.
  • perltidy uses its own parser. It doesn't execute any of the code it analyses.
  • perl -c will execute BEGIN blocks (including use statements) and the like.

Upvotes: 2

Related Questions