MWExceptionHandler: Remove HHVM-specific behavior
With the removal of HHVM support, we can remove HHVM-specific error handling from MWExceptionHandler. * Remove references to HHVM from comments. * Remove references to PHP 7/PHP 7+ from comments, as we now require PHP 7+. * Remove support for the HHVM-exclusive $trace parameter from MWExceptionHandler::handleFatalError(). * Remove HHVM-specific regex when checking if the current error is a class not found error. * Remove delegation to MWExceptionHandler::handleFatalError() from MWExceptionHandler::handleError(), as it was only used for HHVM fatals when running in PHP 5 mode. * Remove MWExceptionHandler::$handledFatalCallback that was protecting against running MWExceptionHandler::handleFatalError() twice, since this could only happen if MWExceptionHandler::handleError() called MWExceptionHandler::handleFatalError(). * Remove HHVM's FATAL_ERROR constant from MWExceptionHandler::$fatalErrorTypes. Change-Id: I110f7195c3094e761264d382f3a26e9a425bb8ad
This commit is contained in:
parent
b847e327b8
commit
d1679955b4
1 changed files with 25 additions and 77 deletions
|
|
@ -38,13 +38,7 @@ class MWExceptionHandler {
|
|||
|
||||
/**
|
||||
* Error types that, if unhandled, are fatal to the request.
|
||||
*
|
||||
* On PHP 7, these error types may be thrown as Error objects, which
|
||||
* implement Throwable (but not Exception).
|
||||
*
|
||||
* On HHVM, these invoke the set_error_handler callback, similar to how
|
||||
* (non-fatal) warnings and notices are reported, except that after this
|
||||
* handler runs for fatal error tpyes, script execution stops!
|
||||
* These error types may be thrown as Error objects, which implement Throwable (but not Exception).
|
||||
*
|
||||
* The user will be shown an HTTP 500 Internal Server Error.
|
||||
* As such, these should be sent to MediaWiki's "fatal" or "exception"
|
||||
|
|
@ -61,14 +55,7 @@ class MWExceptionHandler {
|
|||
|
||||
// E.g. "Catchable fatal error: Argument X must be Y, null given"
|
||||
E_RECOVERABLE_ERROR,
|
||||
|
||||
// HHVM's FATAL_ERROR constant
|
||||
16777217,
|
||||
];
|
||||
/**
|
||||
* @var bool $handledFatalCallback
|
||||
*/
|
||||
protected static $handledFatalCallback = false;
|
||||
|
||||
/**
|
||||
* Install handlers with PHP.
|
||||
|
|
@ -82,25 +69,20 @@ class MWExceptionHandler {
|
|||
// catch clauses would then call MWExceptionHandler::logException
|
||||
// or MWExceptionHandler::handleException.
|
||||
// If they are not caught, then they are handled here.
|
||||
// * Error objects (on PHP 7+), for issues that would historically
|
||||
// * Error objects for issues that would historically
|
||||
// cause fatal errors but may now be caught as Throwable (not Exception).
|
||||
// Same as previous case, but more common to bubble to here instead of
|
||||
// caught locally because they tend to not be safe to recover from.
|
||||
// (e.g. argument TypeErorr, devision by zero, etc.)
|
||||
// (e.g. argument TypeError, division by zero, etc.)
|
||||
set_exception_handler( 'MWExceptionHandler::handleUncaughtException' );
|
||||
|
||||
// This catches:
|
||||
// * Non-fatal errors (e.g. PHP Notice, PHP Warning, PHP Error) that do not
|
||||
// interrupt execution in any way. We log these in the background and then
|
||||
// continue execution.
|
||||
// * Fatal errors (on HHVM in PHP5 mode) where PHP 7 would throw Throwable.
|
||||
// This catches non-fatal errors (e.g. PHP Notice, PHP Warning, PHP Error) that do not
|
||||
// interrupt execution in any way. We log these in the background and then continue execution.
|
||||
set_error_handler( 'MWExceptionHandler::handleError' );
|
||||
|
||||
// This catches:
|
||||
// * Fatal error for which no Throwable is thrown (PHP 7), and no Error emitted (HHVM).
|
||||
// This includes Out-Of-Memory and Timeout fatals.
|
||||
//
|
||||
// Reserve 16k of memory so we can report OOM fatals
|
||||
// This catches fatal errors for which no Throwable is thrown,
|
||||
// including Out-Of-Memory and Timeout fatals.
|
||||
// Reserve 16k of memory so we can report OOM fatals.
|
||||
self::$reservedMemory = str_repeat( ' ', 16384 );
|
||||
register_shutdown_function( 'MWExceptionHandler::handleFatalError' );
|
||||
}
|
||||
|
|
@ -200,8 +182,7 @@ class MWExceptionHandler {
|
|||
*
|
||||
* Receive a callback from the interpreter for a raised error, create an
|
||||
* ErrorException, and log the exception to the 'error' logging
|
||||
* channel(s). If the raised error is a fatal error type (only under HHVM)
|
||||
* delegate to handleFatalError() instead.
|
||||
* channel(s).
|
||||
*
|
||||
* @since 1.25
|
||||
*
|
||||
|
|
@ -218,10 +199,6 @@ class MWExceptionHandler {
|
|||
) {
|
||||
global $wgPropagateErrors;
|
||||
|
||||
if ( in_array( $level, self::$fatalErrorTypes ) ) {
|
||||
return self::handleFatalError( ...func_get_args() );
|
||||
}
|
||||
|
||||
// Map PHP error constant to a PSR-3 severity level.
|
||||
// Avoid use of "DEBUG" or "INFO" levels, unless the
|
||||
// error should evade error monitoring and alerts.
|
||||
|
|
@ -283,10 +260,8 @@ class MWExceptionHandler {
|
|||
}
|
||||
|
||||
/**
|
||||
* Dual purpose callback used as both a set_error_handler() callback and
|
||||
* a registered shutdown function. Receive a callback from the interpreter
|
||||
* for a raised error or system shutdown, check for a fatal error, and log
|
||||
* to the 'fatal' logging channel.
|
||||
* Callback used as a registered shutdown function. Receive a callback from the interpreter
|
||||
* for a system shutdown, check for a fatal error, and log to the 'fatal' logging channel.
|
||||
*
|
||||
* Special handling is included for missing class errors as they may
|
||||
* indicate that the user needs to install 3rd-party libraries via
|
||||
|
|
@ -294,41 +269,22 @@ class MWExceptionHandler {
|
|||
*
|
||||
* @since 1.25
|
||||
*
|
||||
* @param int|null $level Error level raised
|
||||
* @param string|null $message Error message
|
||||
* @param string|null $file File that error was raised in
|
||||
* @param int|null $line Line number error was raised at
|
||||
* @param array|null $context Active symbol table point of error
|
||||
* @param array|null $trace Backtrace at point of error (undocumented HHVM
|
||||
* feature)
|
||||
* @return bool Always returns false
|
||||
*/
|
||||
public static function handleFatalError(
|
||||
$level = null, $message = null, $file = null, $line = null,
|
||||
$context = null, $trace = null
|
||||
) {
|
||||
public static function handleFatalError() {
|
||||
// Free reserved memory so that we have space to process OOM
|
||||
// errors
|
||||
self::$reservedMemory = null;
|
||||
|
||||
if ( $level === null ) {
|
||||
// Called as a shutdown handler, get data from error_get_last()
|
||||
if ( static::$handledFatalCallback ) {
|
||||
// Already called once (probably as an error handler callback
|
||||
// under HHVM) so don't log again.
|
||||
return false;
|
||||
}
|
||||
|
||||
$lastError = error_get_last();
|
||||
if ( $lastError !== null ) {
|
||||
$level = $lastError['type'];
|
||||
$message = $lastError['message'];
|
||||
$file = $lastError['file'];
|
||||
$line = $lastError['line'];
|
||||
} else {
|
||||
$level = 0;
|
||||
$message = '';
|
||||
}
|
||||
$lastError = error_get_last();
|
||||
if ( $lastError !== null ) {
|
||||
$level = $lastError['type'];
|
||||
$message = $lastError['message'];
|
||||
$file = $lastError['file'];
|
||||
$line = $lastError['line'];
|
||||
} else {
|
||||
$level = 0;
|
||||
$message = '';
|
||||
}
|
||||
|
||||
if ( !in_array( $level, self::$fatalErrorTypes ) ) {
|
||||
|
|
@ -348,10 +304,8 @@ class MWExceptionHandler {
|
|||
];
|
||||
$msg = implode( '', $msgParts );
|
||||
|
||||
// Look at message to see if this is a class not found failure
|
||||
// HHVM: Class undefined: foo
|
||||
// PHP7: Class 'foo' not found
|
||||
if ( preg_match( "/Class (undefined: \w+|'\w+' not found)/", $message ) ) {
|
||||
// Look at message to see if this is a class not found failure (Class 'foo' not found)
|
||||
if ( preg_match( "/Class '\w+' not found/", $message ) ) {
|
||||
// phpcs:disable Generic.Files.LineLength
|
||||
$msg = <<<TXT
|
||||
{$msg}
|
||||
|
|
@ -365,11 +319,8 @@ TXT;
|
|||
|
||||
// We can't just create an exception and log it as it is likely that
|
||||
// the interpreter has unwound the stack already. If that is true the
|
||||
// stacktrace we would get would be functionally empty. If however we
|
||||
// have been called as an error handler callback *and* HHVM is in use
|
||||
// we will have been provided with a useful stacktrace that we can
|
||||
// log.
|
||||
$trace = $trace ?: debug_backtrace();
|
||||
// stacktrace we would get would be functionally empty.
|
||||
$trace = debug_backtrace();
|
||||
$logger = LoggerFactory::getInstance( 'fatal' );
|
||||
$logger->error( $msg, [
|
||||
'fatal_exception' => [
|
||||
|
|
@ -385,9 +336,6 @@ TXT;
|
|||
'caught_by' => self::CAUGHT_BY_HANDLER
|
||||
] );
|
||||
|
||||
// Remember call so we don't double process via HHVM's fatal
|
||||
// notifications and the shutdown hook behavior
|
||||
static::$handledFatalCallback = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue