From b8b57b2c41fd39d4c4791699759d2b68a3a2215a Mon Sep 17 00:00:00 2001 From: Byron Jones Date: Tue, 10 Apr 2012 21:09:28 +0800 Subject: Bug 739153: fix infinite recursion in error handler --- Bugzilla/Arecibo.pm | 91 +++++++++++++++++++++++++++++++++++++---------------- Bugzilla/Error.pm | 5 +++ 2 files changed, 69 insertions(+), 27 deletions(-) (limited to 'Bugzilla') diff --git a/Bugzilla/Arecibo.pm b/Bugzilla/Arecibo.pm index 54458cca2..92c99c399 100644 --- a/Bugzilla/Arecibo.pm +++ b/Bugzilla/Arecibo.pm @@ -228,39 +228,76 @@ sub _in_eval { return $in_eval; } -BEGIN { - require CGI::Carp; - CGI::Carp::set_die_handler(sub { - return if _in_eval(); - my $message = shift; - my $is_compilation_failure = $message =~ /\bcompilation (aborted|failed)\b/i; - if (!$is_compilation_failure) { - eval { Bugzilla::Error::ThrowTemplateError($message) }; - } - if ($is_compilation_failure || $@) { - print "Content-type: text/html\n\n"; - my $uid = arecibo_generate_id(); - my $notified = arecibo_handle_error('error', $message, $uid); - my $maintainer = html_quote(Bugzilla->params->{'maintainer'}); - $message = html_quote($message); - $uid = html_quote($uid); +sub _arecibo_die_handler { + my $message = shift; + $message =~ s/^undef error - //; + + # avoid recursion, and check for CGI::Carp::die failures + my $in_cgi_carp_die = 0; + for (my $stack = 1; my $sub = (caller($stack))[3]; $stack++) { + return if $sub =~ /:_arecibo_die_handler$/; + $in_cgi_carp_die = 1 if $sub =~ /CGI::Carp::die$/; + } + + return if _in_eval(); + + # mod_perl overrides exit to call die with this string + exit if $message =~ /\bModPerl::Util::exit\b/; + + my $nested_error = ''; + my $is_compilation_failure = $message =~ /\bcompilation (aborted|failed)\b/i; + + # if we are called via CGI::Carp::die chances are something is seriously + # wrong, so skip trying to use ThrowTemplateError + if (!$in_cgi_carp_die && !$is_compilation_failure) { + eval { Bugzilla::Error::ThrowTemplateError($message) }; + $nested_error = $@ if $@; + } + + # right now it's hard to determine if we've already returned a content-type + # header, it's better to return two than none + print "Content-type: text/html\n\n"; + + if ($is_compilation_failure || + $in_cgi_carp_die || + ($nested_error && $nested_error !~ /\bModPerl::Util::exit\b/) + ) { + $nested_error = html_quote($nested_error); + my $uid = arecibo_generate_id(); + my $notified = arecibo_handle_error('error', $message, $uid); + my $maintainer = html_quote(Bugzilla->params->{'maintainer'}); + $message =~ s/ at \S+ line \d+\.\s*$//; + $message = html_quote($message); + $uid = html_quote($uid); + print qq( +

Bugzilla has suffered an internal error

+
$message
+
+
$nested_error
+ ); + if ($notified) { print qq( -

Bugzilla has suffered an internal error

-
$message
+ The Bugzilla maintainers have + been notified of this error [#$uid]. ); - if ($notified) { - print qq( - The Bugzilla maintainers have - been notified of this error [#$uid]. - ); - }; - exit; - } - }); + }; + } + exit; +} + +sub install_arecibo_handler { + require CGI::Carp; + CGI::Carp::set_die_handler(\&_arecibo_die_handler); $main::SIG{__WARN__} = sub { return if _in_eval(); arecibo_handle_error('warning', shift); }; } +BEGIN { + if ($ENV{SCRIPT_NAME} || $ENV{MOD_PERL}) { + install_arecibo_handler(); + } +} + 1; diff --git a/Bugzilla/Error.pm b/Bugzilla/Error.pm index c2fcfdd55..df03dfd6d 100644 --- a/Bugzilla/Error.pm +++ b/Bugzilla/Error.pm @@ -192,11 +192,16 @@ sub ThrowTemplateError { die("error: template error: $template_err"); } + # mod_perl overrides exit to call die with this string + # we never want to display this to the user + exit if $template_err =~ /\bModPerl::Util::exit\b/; + $vars->{'template_error_msg'} = $template_err; $vars->{'error'} = "template_error"; $vars->{'uid'} = arecibo_generate_id(); arecibo_handle_error('error', $template_err, $vars->{'uid'}); + $vars->{'template_error_msg'} =~ s/ at \S+ line \d+\.\s*$//; my $template = Bugzilla->template; -- cgit v1.2.3-24-g4f1b