From 977e58e82e9de439a8565ad09dce7fe4cca125c5 Mon Sep 17 00:00:00 2001 From: Timo Tijhof Date: Tue, 7 May 2019 18:53:03 +0100 Subject: [PATCH] exception: Document the three ways we listen for errors/fatals/exceptions It is now clear to me why most fatals are logged to 'exception' on PHP 7, instead of 'fatal' (as on HHVM). It is because these are, as of PHP 7, technically recoverable if caught locally with 'catch (Throwable)', and as such should no longer be classified as 'fatal'. I suppose that's fine and something we'll get used to. The most important distinction to keep is between 'error' and 'fatal/exception' given the latter is more heavily monitored and alerted on, but otherwise they are not usually distingished in query, we treat them equal for the most part. Bug: T187147 Change-Id: I64bf0b32dd2648cf72297bdc294e315375329a4d --- includes/exception/MWExceptionHandler.php | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/includes/exception/MWExceptionHandler.php b/includes/exception/MWExceptionHandler.php index 6e3fa794ce..b4e483bf53 100644 --- a/includes/exception/MWExceptionHandler.php +++ b/includes/exception/MWExceptionHandler.php @@ -74,9 +74,32 @@ class MWExceptionHandler { * Install handlers with PHP. */ public static function installHandler() { + // This catches: + // * Exception objects that were explicitly thrown but not + // caught anywhere in the application. This is rare given those + // would normally be caught at a high-level like MediaWiki::run (index.php), + // api.php, or ResourceLoader::respond (load.php). These high-level + // 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 + // 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.) 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. 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 self::$reservedMemory = str_repeat( ' ', 16384 ); register_shutdown_function( 'MWExceptionHandler::handleFatalError' ); -- 2.20.1