From c02e3b1c601bbd54bf02090efe1f957407dc143e Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Thu, 21 Nov 2024 14:09:08 -0800 Subject: [PATCH] Only handle the first javascript fatal error (#47783) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/47783 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 fbshipit-source-id: 61a731850f7ac4f00bfac24e3260673bf94ba8ed --- .../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 a0b22359ea0..ecb2171961e 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 6742322af13..fda5c18920e 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 f24a006e697..2a695fc28b2 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); } }