diff --git a/ReactCommon/cxxreact/NativeToJsBridge.cpp b/ReactCommon/cxxreact/NativeToJsBridge.cpp index 32cb06b9c..18aa788ca 100644 --- a/ReactCommon/cxxreact/NativeToJsBridge.cpp +++ b/ReactCommon/cxxreact/NativeToJsBridge.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "Instance.h" #include "JSBigString.h" @@ -99,7 +100,8 @@ void NativeToJsBridge::loadApplication( std::unique_ptr startupScript, std::string startupScriptSourceURL) { runOnExecutorQueue( - [bundleRegistryWrap=folly::makeMoveWrapper(std::move(bundleRegistry)), + [this, + bundleRegistryWrap=folly::makeMoveWrapper(std::move(bundleRegistry)), startupScript=folly::makeMoveWrapper(std::move(startupScript)), startupScriptSourceURL=std::move(startupScriptSourceURL)] (JSExecutor* executor) mutable { @@ -107,8 +109,13 @@ void NativeToJsBridge::loadApplication( if (bundleRegistry) { executor->setBundleRegistry(std::move(bundleRegistry)); } - executor->loadApplicationScript(std::move(*startupScript), - std::move(startupScriptSourceURL)); + try { + executor->loadApplicationScript(std::move(*startupScript), + std::move(startupScriptSourceURL)); + } catch (...) { + m_applicationScriptHasFailure = true; + throw; + } }); } @@ -119,8 +126,13 @@ void NativeToJsBridge::loadApplicationSync( if (bundleRegistry) { m_executor->setBundleRegistry(std::move(bundleRegistry)); } - m_executor->loadApplicationScript(std::move(startupScript), - std::move(startupScriptSourceURL)); + try { + m_executor->loadApplicationScript(std::move(startupScript), + std::move(startupScriptSourceURL)); + } catch (...) { + m_applicationScriptHasFailure = true; + throw; + } } void NativeToJsBridge::callFunction( @@ -136,8 +148,13 @@ void NativeToJsBridge::callFunction( systraceCookie); #endif - runOnExecutorQueue([module = std::move(module), method = std::move(method), arguments = std::move(arguments), systraceCookie] + runOnExecutorQueue([this, module = std::move(module), method = std::move(method), arguments = std::move(arguments), systraceCookie] (JSExecutor* executor) { + if (m_applicationScriptHasFailure) { + LOG(ERROR) << "Attempting to call JS function on a bad application bundle: " << module.c_str() << "." << method.c_str() << "()"; + throw std::runtime_error("Attempting to call JS function on a bad application bundle: " + module + "." + method + "()"); + } + #ifdef WITH_FBSYSTRACE FbSystraceAsyncFlow::end( TRACE_TAG_REACT_CXX_BRIDGE, @@ -162,8 +179,12 @@ void NativeToJsBridge::invokeCallback(double callbackId, folly::dynamic&& argume systraceCookie); #endif - runOnExecutorQueue([callbackId, arguments = std::move(arguments), systraceCookie] + runOnExecutorQueue([this, callbackId, arguments = std::move(arguments), systraceCookie] (JSExecutor* executor) { + if (m_applicationScriptHasFailure) { + LOG(ERROR) << "Attempting to call JS callback on a bad application bundle: " << callbackId; + throw std::runtime_error("Attempting to invoke JS callback on a bad application bundle."); + } #ifdef WITH_FBSYSTRACE FbSystraceAsyncFlow::end( TRACE_TAG_REACT_CXX_BRIDGE, diff --git a/ReactCommon/cxxreact/NativeToJsBridge.h b/ReactCommon/cxxreact/NativeToJsBridge.h index 0a6110f67..cde1b1668 100644 --- a/ReactCommon/cxxreact/NativeToJsBridge.h +++ b/ReactCommon/cxxreact/NativeToJsBridge.h @@ -94,6 +94,11 @@ private: std::unique_ptr m_executor; std::shared_ptr m_executorMessageQueueThread; + // Keep track of whether the JS bundle containing the application logic causes + // exception when evaluated initially. If so, more calls to JS will very + // likely fail as well, so this flag can help prevent them. + bool m_applicationScriptHasFailure = false; + #ifdef WITH_FBSYSTRACE std::atomic_uint_least32_t m_systraceCookie = ATOMIC_VAR_INIT(); #endif