|
From: Michael E. G. <ga...@ma...> - 2005-07-29 18:24:40
|
On Jul 29, 2005, at 1:00 PM, Sam Hathaway wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Hi Mike,
>
> Here is my assessment of what's going on with $SIG{__WARN__} and
> $SIG{__DIE__} in Translator.pm.
>
> evaluate_modules() uses:
>
> local $SIG{__DIE__} = "DEFAULT";
>
> to set the default handler for the duration of the subroutine. It then
> goes onto use eval STRING to read in PG modules, and checks $@ for any
> error messages. This is not harmful, and it saves us a little time
> since the handler defined in Apache::WeBWorK would waste time
> generating a backtrace before calling the default handler. (But see
> below for why I think we should just let the Apache::WeBWorK handlers
> run.)
>
> At the beginning of translate(), we see a few things:
>
> # reset the error detection
> $SIG{__WARN__} = sub {CORE::warn(@_) } unless ref($SIG{__WARN__})
> =~/CODE/;
> my $save_SIG_warn_trap = $SIG{__WARN__};
> #FIXME -- this may not work with the xmlrpc access
> # this formats the error message within the existing warn message.
> $SIG{__WARN__} = sub
> {&$save_SIG_warn_trap(PG_errorMessage('message',@_))};
> #$SIG{__WARN__} = sub {CORE::warn(PG_errorMessage('message',@_))};
> my $save_SIG_die_trap = $SIG{__DIE__};
> $SIG{__DIE__} = sub {CORE::die(PG_errorMessage('traceback',@_))};
>
> This is a trouble spot, since it sets the handlers without using
> "local". From what I can tell, what we WANT to do here is provide a
> level of preprocessing to any warning or exception that comes out. We
> may also want to avoid calling the Apache::WeBWorK warn/die handlers,
> although I think we should leave them alone and assume our caller has
> some way they want to collect errors and warnings. (For example,
> WeBWorK::PG::Local has its own warn handler that accumulates warnings
> and returns them as part of the WeBWorK::PG object.) It seems to me
> that the simplest way to accomplish this is:
>
> # reset the error detection
> my $outer_sig_warn = $SIG{__WARN__};
> local $SIG{__WARN__} = sub {
> my $munged = PG_errorMessage('message', $_[0]);
> ref $outer_sig_warn eq "CODE" ? &$outer_sig_warn($munged) :
> warn $munged;
> };
> my $outer_sig_die = $SIG{__DIE__};
> local $SIG{__DIE__} = sub {
> my $munged = PG_errorMessage('traceback', $_[0]);
> ref $outer_sig_die eq "CODE" ? &$outer_sig_die($munged) : die
> $munged;
> };
>
> This doesn't deal with the case where the handlers are set to string
> names of subroutines, but that could be added. It also doesn't handle
> "IGNORE", but that could be added as well.
>
OK. I'd made this change also, omitting calling the outer DIE and WARN
handlers. I think your idea is better.
> in process_answers(), we have:
>
> local %errorTable;
> $SIG{__DIE__} = sub {
> #
> # Get full traceback, but save it in local variable so that
> # we can add it later. This is because some evaluators use
> # eval to trap errors and then report them in the message
> # column of the results table, and we don't want to include
> # the traceback there.
> #
> my $fullerror = PG_errorMessage('traceback',@_);
> my ($error,$traceback) = split /\n/, $fullerror, 2;
> $fullerror =~ s/\n /<BR> /g; $fullerror =~
> s/\n/<BR>/g;
> $error .= "\n";
> $errorTable{$error} = $fullerror;
> CORE::die($error);
> };
> # reset the error detection
> my $save_SIG_warn_trap = $SIG{__WARN__};
> $save_SIG_warn_trap = sub {CORE::warn @_} unless
> ref($save_SIG_warn_trap) =~/CODE/;
> $SIG{__WARN__} = sub
> {&$save_SIG_warn_trap(PG_errorMessage('message',@_))};
> my $save_SIG_die_trap = $SIG{__DIE__};
>
> and then later on, after the answers are evaluated:
>
> $SIG{__DIE__} = $save_SIG_die_trap;
> $SIG{__WARN__} = $save_SIG_warn_trap;
>
> First of all, restoring the die handler doesn't work at all, since
> $save_SIG_die_trap is set to the custom die handler we just installed
> a few lines before. In addition, I think we can do the same thing here
> that we did up above, inserting the code that accumulates exceptions.
> Also, I think %errorTable can be a lexical.
>
This is the error that was causing the immediate trouble in Hardcopy.pm
(the generation of the ARRAY string, but no ARRAY reference).
> # reset the error detection
> my $outer_sig_warn = $SIG{__WARN__};
> local $SIG{__WARN__} = sub {
> my $munged = PG_errorMessage('message', $_[0]);
> ref $outer_sig_warn eq "CODE" ? &$outer_sig_warn($munged) :
> warn $munged;
> };
> my %errorTable;
> my $outer_sig_die = $SIG{__DIE__};
> local $SIG{__DIE__} = sub {
> my $fullerror = PG_errorMessage('traceback', $_[0]);
> my ($error,$traceback) = split /\n/, $fullerror, 2;
> $fullerror =~ s/\n /<BR> /g; $fullerror =~
> s/\n/<BR>/g;
> $error .= "\n";
> $errorTable{$error} = $fullerror;
> ref $outer_sig_die eq "CODE" ? &$outer_sig_die($error) : die
> $error;
> };
>
The other thing I did in my fix was to move the definition of the WARN
and DIE handlers outside of the for loop. %errorTable can be
moved outside the loop to. I think this works ok. I'm still thinking
about the role of %errorTable and whether it has to be localize
for each answer. If necessary it could be emptied out at the top of
each loop.
> There are three more places where warn/die handlers get messed with -
> -- PG_restricted_eval(), PG_macro_file_eval(), and PG_answer_eval().
> In each case, subroutine begins with:
>
> my $save_SIG_warn_trap = $SIG{__WARN__};
> $SIG{__WARN__} = sub { CORE::die @_};
> my $save_SIG_die_trap = $SIG{__DIE__};
> $SIG{__DIE__}= sub {CORE::die @_};
>
> then some code gets passed to eval STRING, and then:
>
> $SIG{__DIE__} = $save_SIG_die_trap;
> $SIG{__WARN__} = $save_SIG_warn_trap;
>
> We can replace these with the same type of code that's used in
> evaluate_modules():
>
> local $SIG{__WARN__} = "DEFAULT";
> local $SIG{__DIE__} = "DEFAULT";
>
Is there an advantage to calling "DEFAULT" instead of
local $SIG{__WARN__} = sub { CORE::die @_};
One of us should make these changes and check in a new version of
Translator.pm
Then we can test and refine from there if needed.
Take care,
Mike
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.2.4 (Darwin)
>
> iD8DBQFC6mDE14CQX+2WvVgRAmifAKCf2Mjte5IUWjE/FVINpt+CMZkeVwCePwGh
> 8EQzltAV6e4ObIZN8iRpLvU=
> =LagG
> -----END PGP SIGNATURE-----
>
>
> -------------------------------------------------------
> SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
> from IBM. Find simple to follow Roadmaps, straightforward articles,
> informative Webcasts and more! Get everything you need to get up to
> speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
> _______________________________________________
> OpenWeBWorK-Devel mailing list
> Ope...@li...
> https://lists.sourceforge.net/lists/listinfo/openwebwork-devel
>
|