Features & Development

Problem with eval and $@

Problem with eval and $@

by Peter Selinger -
Number of replies: 2

I am having a vexing problem with eval. Normally in Perl, when you call eval { ... } and the bracketed process dies or fails, the variable $@ is set to the error message. For example, the following command line outputs "XYZ at -e line 1":

perl -e 'eval { die "XYZ" }; $a = $@ // "undefined"; die $a'

I believe that this is standard Perl behavior. The webwork library also uses this feature of eval, for example in pg/lib/Value/AnswerChecker.pm.

On the other hand, when I try this in a WebWork problem or macro, it does not work, and it is vexing me. I cannot figure out why this is not working. For example, the following test problem outputs "Debug: undefined", rather than "Debug: XYZ" as it should.

DOCUMENT();

loadMacros(
  "PGbasicmacros.pl",
);

TEXT(beginproblem());

eval { die "XYZ" };
$a = $@ // "undefined";

BEGIN_TEXT
  Debug: $a
END_TEXT

ENDDOCUMENT(); 

Does someone know why? I am trying to program a new kind of answer checker, and I am trying to replicate what I found in pg/lib/Value/AnswerChecker.pm. Everything works more or less fine, except I cannot get $@ to hold the error message. I thought maybe it has something to do with the PG preprocessor, but I don't think this is the case. Help?

Thanks! -- Peter

In reply to Peter Selinger

Re: Problem with eval and $@

by Michael Gage -
I'm a little surprised that problem even runs in WeBWorK. The run time version
of eval, eval("....command....") is replaced by PG_restricted_eval(); -- mainly
so we can protect against exploits using the eval command. (This was a design decision of 15 years ago, just in case ... for the most part we've never had a need to take advantage of it.) (Defined in PG::Translator::PG_restricited_eval and referenced in PGcore, PG.pl, PGbasicmacros.pl, etc. ).

I would have to do some tests to see what happens with the
eval { } (which is the closest thing we have to a try statement in perl
(and PG).

If the problem you have isn't tripped up by the Safe compartment detecting an illegal command "eval" I would expect it to work.

Overrides for the die and warn commands have been written by different people
(mainly Davide Cervone and me) at different times over many years and they may at times conflict with each other. They activate in different parts of the code (e.g inside MathObects or not inside MathObjects). You might try using warn instead of die and see what happens.

There is a need for a complete overhaul and uniformization of the Exception handling mechanism in PG that takes advantage of the exception handling capabilities added to perl over the last 15 years. It would not be an easy project however.


-- Mike
In reply to Peter Selinger

Re: Problem with eval and $@

by Davide Cervone -
I did some testing on this, and it turns out that although
eval("...");
is trapped by the Safe compartment
eval {...};
is not. So this does work in the sense that it will trap errors. But it also turns out that $@ is not set by this, as you point out. I suspect that it may be that $@ is being set outside the Safe compartment, or something like that, but in any event, it is not being set within the PG problem. It might be the error trapping that Mike mentioned is interfering with it, but I haven't tried to look into that.

I'm surprised that eval {...}; is allowed, as Im pretty sure that wasn't the case in earlier versions of Perl or Safe.pm. I know that I had all kinds of heartache over this when writing the MathObjects library (so much so that I had to add Parser::Eval(sub {...}) to do essentially what eval {...} does. So I think something has changed along the way.

I don't know if anything can be done to fix that, but Parser::Eval() could probably be modified to set $@ to the error, if there is one.