The perlfunc manpage says, with regard to the built-in eval forms,

If there is a syntax error or runtime error, or a "die" statement is executed, "eval" returns an undefined value in scalar context or an empty list in list context, and $@ is set to the error message. If there was no error, $@ is guaranteed to be the empty string. Beware that using "eval" neither silences Perl from printing warnings to STDERR, nor does it stuff the text of warning messages into $@.
...
It is also Perl's exception trapping mechanism, where the die operator is used to raise exceptions.

Note that EXP30-PL. Do not use deprecated or obsolete functions or modules recommends using croak() rather than die().

Programmers may often suppress exceptions, which is easily accomplished by not examining the $@ variable (also known as $EVAL_ERROR). Because eval makes ignoring exceptions the default, it is critically important that programmers inspect $@ after using eval.

Exceptions are intended to disrupt the expected control flow of the application. Many exceptions are suppressed out of not knowing how to handle the exception or not even knowing that one may have been thrown. Consequently, exceptions must never be suppressed. If a call to eval fails, the calling code must at least inspect $@. If the developer does not know how to handle the exception, he can always propagate it up the stack by issuing his own fatal error.

Noncompliant Code Example

This noncompliant code example uses the eval built-in form to divide two numbers. Without using eval, the code would abort if $b happened to be 0, but thanks to eval, code processing can resume normally, with $answer being uninitialized. It produces a warning when the uninitialized value is embedded in the string passed to print(). So eval can be used to completely ignore an important error that may occur.

my ($a, $b) = # initialize
my $answer;
eval { $answer = $a / $b };
print "The quotient is $answer\n";

Compliant Solution

This compliant solution checks to see if eval failed and, if so, emits a warning message and initializes $answer.

my ($a, $b) = # initialize
my $answer;
if (! eval { $answer = $a / $b }) {
  carp($@) if $@;
  $answer = 0;
}
print "The quotient is $answer\n";

Exceptions

EXP31-PL-EX0: Exceptions that occur during the freeing of a resource may be suppressed in those cases where failure to free the resource cannot affect future program behavior. Examples of freeing resources include closing files or network sockets. When closed, normally or abnormally, the exception cannot influence future program behavior through any avenue other than resource exhaustion. When resource exhaustion is adequately handled, it is sufficient to sanitize and log the exception for future improvement; additional error handling is unnecessary in this case.

Risk Assessment

Suppressing exceptions can result in inconsistent program state and erroneous behavior.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

EXP31-PL

Low

Probable

Medium

P4

L3

Related Guidelines

Bibliography

 


 


8 Comments

  1. The examples here use string eval, which contravenes another recommendation (IDS35-PL).  Suggest changing the code to use block-form eval, which will make the code simpler anyway.

      1. Also, in the descriptive text, say just 'eval' instead of 'eval()'.  That way it covers both forms of eval.

         

        1. Both forms of eval are functions (they just differ in what type their argument is). The CERT standards employ the style of using parens after functions to disambiguate them from other code items like variables. (this was partially becase the first CERT standard was for C.) While Perl allows functions to take arguments without parentheses, we actually recommend using parens to avoid ambiguous syntax. This may become an official recommendation someday, for now it is just part of our internal style guide.

          1. My point is that there are two forms of 'eval' in Perl.  They share the same keyword but are grammatically different; one takes an expression and the other takes a block of code.

             

            If you write eval() it looks like you are talking about eval the function.  As you say the guidelines suggest using parens for function calls.  Because there is also the other form of eval - which is not a function, and cannot take parens - by writing it with parens you have implicitly excluded the other type of eval.

             

            If you wish to keep the parens, then replace each mention of 'eval()' with 'eval() or eval { ... }'.  Then you are explicitly covering both forms.  I think it is simpler to just write 'eval' as a bare keyword, though.

             

             

             

            1. This is a style issue, so the best source is perldoc and the perlfunc manpage. Which lists both forms of eval, but never explicitly refers to it as a function (it always says "eval form" for both forms.). I suppose 'eval()' and 'eval{}' are both useful for distniguishing between the two forms, but there is no 'official' guidance here. So I'll use the eval form like you suggest.

  2. Anonymous

    There is not always a need to refer to $@.

    For example:

    require Some::Module;

    if( ! eval{ Some::Module->VERSION(1.0); 1 } ){

      ... # some code which needs to run on older versions of Some::Module

    }

    Which really only uses eval as a control flow statement. It is also a lot clearer in intent than:

    require Some::Module;

    eval{ Some::Module->VERSION(1.0) };

    if( length $@ ){

      ...

    }

    1. $@ isn't necessary, but it is helpful in reporting an error.
      Nonetheless, I shortened the compliant solution as you suggest.