From 2a9456d46e5b79597f464992ede05df289f196f4 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Wed, 20 Nov 2024 14:35:34 -0800 Subject: [PATCH] Only handle the first javascript fatal error Summary: After the first javascript fatal, the runtime starts tearing down. And it becomes invalid. So, subsequent js fatals will most likely be just noise. Let's filter them out. This impacts bridgeless mode: both the javascript and c++ pipeline. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D66193194 --- .../Libraries/Core/ExceptionsManager.js | 6 ++++ .../jserrorhandler/JsErrorHandler.cpp | 6 +--- .../react/runtime/ReactInstance.cpp | 35 ++++++++++++++++--- 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/packages/react-native/Libraries/Core/ExceptionsManager.js b/packages/react-native/Libraries/Core/ExceptionsManager.js index a0b22359ea0778..ecb2171961e9c5 100644 --- a/packages/react-native/Libraries/Core/ExceptionsManager.js +++ b/packages/react-native/Libraries/Core/ExceptionsManager.js @@ -121,6 +121,12 @@ function reportException( const NativeExceptionsManager = require('./NativeExceptionsManager').default; if (NativeExceptionsManager) { + if (isFatal) { + if (global.RN$hasHandledFatalException?.()) { + return; + } + global.RN$notifyOfFatalException?.(); + } NativeExceptionsManager.reportException(data); } } diff --git a/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.cpp b/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.cpp index 6742322af13cbd..fda5c18920e944 100644 --- a/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.cpp +++ b/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.cpp @@ -232,10 +232,6 @@ void JsErrorHandler::handleError( if (!ReactNativeFeatureFlags::useAlwaysAvailableJSErrorHandling() && _isRuntimeReady) { - if (isFatal) { - _hasHandledFatalError = true; - } - try { handleJSError(runtime, error, isFatal); return; @@ -382,7 +378,7 @@ void JsErrorHandler::handleErrorWithCppPipeline( } } - if (*shouldPreventDefault) { + if (*shouldPreventDefault || _hasHandledFatalError) { return; } diff --git a/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp b/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp index f24a006e697013..2a695fc28b2ff4 100644 --- a/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp +++ b/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp @@ -436,6 +436,37 @@ void ReactInstance::initializeRuntime( return jsErrorHandler->isRuntimeReady(); })); + defineReadOnlyGlobal( + runtime, + "RN$hasHandledFatalException", + jsi::Function::createFromHostFunction( + runtime, + jsi::PropNameID::forAscii(runtime, "hasHandledFatalException"), + 0, + [jsErrorHandler = jsErrorHandler_]( + jsi::Runtime& /*runtime*/, + const jsi::Value& /*unused*/, + const jsi::Value* /*args*/, + size_t /*count*/) { + return jsErrorHandler->hasHandledFatalError(); + })); + + defineReadOnlyGlobal( + runtime, + "RN$notifyOfFatalException", + jsi::Function::createFromHostFunction( + runtime, + jsi::PropNameID::forAscii(runtime, "notifyOfFatalException"), + 0, + [jsErrorHandler = jsErrorHandler_]( + jsi::Runtime& /*runtime*/, + const jsi::Value& /*unused*/, + const jsi::Value* /*args*/, + size_t /*count*/) { + jsErrorHandler->notifyOfFatalError(); + return jsi::Value::undefined(); + })); + defineReadOnlyGlobal( runtime, "RN$inExceptionHandler", @@ -475,10 +506,6 @@ void ReactInstance::initializeRuntime( if (!ReactNativeFeatureFlags:: useAlwaysAvailableJSErrorHandling()) { if (jsErrorHandler->isRuntimeReady()) { - if (isFatal) { - jsErrorHandler->notifyOfFatalError(); - } - return jsi::Value(false); } }