From eb5238d186de50191a7aa0eae8ec6ef1ada368ad Mon Sep 17 00:00:00 2001 From: Khalef Hosany Date: Fri, 14 Aug 2026 23:42:35 -0700 Subject: [PATCH] Prevent partially initialized TurboModules during shutdown Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: e5dad4bf-4f71-43ee-aa7f-d2f11d43121e --- ...-c5366f79-8343-45d0-9916-3f13b872c4d8.json | 7 +++ .../TurboModulesProvider.cpp | 43 +++++++++++++------ 2 files changed, 37 insertions(+), 13 deletions(-) create mode 100644 change/react-native-windows-c5366f79-8343-45d0-9916-3f13b872c4d8.json diff --git a/change/react-native-windows-c5366f79-8343-45d0-9916-3f13b872c4d8.json b/change/react-native-windows-c5366f79-8343-45d0-9916-3f13b872c4d8.json new file mode 100644 index 00000000000..1d057e06b29 --- /dev/null +++ b/change/react-native-windows-c5366f79-8343-45d0-9916-3f13b872c4d8.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Prevent lazy TurboModules from being created without a runtime during shutdown", + "packageName": "react-native-windows", + "email": "khosany@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/vnext/Microsoft.ReactNative/TurboModulesProvider.cpp b/vnext/Microsoft.ReactNative/TurboModulesProvider.cpp index 28991974022..2e05bd9a3b5 100644 --- a/vnext/Microsoft.ReactNative/TurboModulesProvider.cpp +++ b/vnext/Microsoft.ReactNative/TurboModulesProvider.cpp @@ -36,7 +36,8 @@ struct TurboModuleMethodInfo { }; struct TurboModuleBuilder : winrt::implements { - TurboModuleBuilder(const IReactContext &reactContext) noexcept : m_reactContext(reactContext) {} + TurboModuleBuilder(const IReactContext &reactContext, IInspectable runtimeHandle) noexcept + : m_reactContext(reactContext), m_runtimeHandle(std::move(runtimeHandle)) {} public: // IReactModuleBuilder void AddInitializer(InitializerDelegate const &initializer) noexcept { @@ -44,11 +45,7 @@ struct TurboModuleBuilder : winrt::implements(m_reactContext) - ->GetInner() - .JsiRuntime()); + initializer(m_reactContext, m_runtimeHandle); } void AddConstantProvider(ConstantProviderDelegate const &constantProvider) noexcept { @@ -91,6 +88,10 @@ struct TurboModuleBuilder : winrt::implements m_eventEmitters; std::unordered_map m_methods; std::unordered_map m_syncMethods; @@ -121,17 +123,16 @@ class TurboModuleImpl : public facebook::react::TurboModule { const std::string &name, const std::shared_ptr &jsInvoker, std::weak_ptr longLivedObjectCollection, + IInspectable runtimeHandle, const ReactModuleProvider &reactModuleProvider) : facebook::react::TurboModule(name, jsInvoker), m_reactContext(reactContext), m_longLivedObjectCollection(std::move(longLivedObjectCollection)), - m_moduleBuilder(winrt::make_self(reactContext)), - m_providedModule(reactModuleProvider(m_moduleBuilder.as())) { + m_moduleBuilder(winrt::make_self(reactContext, std::move(runtimeHandle))) { + m_providedModule = reactModuleProvider(m_moduleBuilder.as()); + m_moduleBuilder->CompleteRegistration(); + if (auto hostObject = m_providedModule.try_as()) { - // Force ABI runtime creation if it hasn't already been created - winrt::get_self(m_reactContext) - ->GetInner() - .JsiRuntime(); m_hostObjectWrapper = std::make_shared(hostObject); } } @@ -488,8 +489,24 @@ std::shared_ptr TurboModulesProvider::getModule( return nullptr; } + if (!m_reactContext) { + return nullptr; + } + + auto runtimeHandle = winrt::get_self(m_reactContext) + ->GetInner() + .JsiRuntime(); + if (!runtimeHandle) { + return nullptr; + } + auto tm = std::make_shared( - m_reactContext, moduleName, callInvoker, m_longLivedObjectCollection, /*reactModuleProvider*/ it->second); + m_reactContext, + moduleName, + callInvoker, + m_longLivedObjectCollection, + std::move(runtimeHandle), + /*reactModuleProvider*/ it->second); return tm; }