fix(ios): fix Hermes startup race in ExpoBridgeModule (patch) (#10672)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,3 +13,39 @@ index 47c4d15f6b10bbd77858cfff425cda9a618735b9..afe138d22d566244482498a7be0e14b8
|
|||||||
// Check for Content-Type
|
// Check for Content-Type
|
||||||
val skipContentTypes = listOf(
|
val skipContentTypes = listOf(
|
||||||
"text/event-stream", // Server Sent Events
|
"text/event-stream", // Server Sent Events
|
||||||
|
diff --git a/ios/Core/ExpoBridgeModule.mm b/ios/Core/ExpoBridgeModule.mm
|
||||||
|
index 2ed1c00f47406e109750cc27ace7e0d88e42c00e..99d0d140eddf95a8db7beb57c61dfcb12c1424b4 100644
|
||||||
|
--- a/ios/Core/ExpoBridgeModule.mm
|
||||||
|
+++ b/ios/Core/ExpoBridgeModule.mm
|
||||||
|
@@ -7,6 +7,9 @@
|
||||||
|
// The runtime executor is included as of React Native 0.74 in bridgeless mode.
|
||||||
|
#if __has_include(<ReactCommon/RCTRuntimeExecutor.h>)
|
||||||
|
#import <ReactCommon/RCTRuntimeExecutor.h>
|
||||||
|
+#else // React Native <0.74
|
||||||
|
+// dispatchBlock:queue: is declared in RCTBridge+Private.h, not the public header.
|
||||||
|
+#import <React/RCTBridge+Private.h>
|
||||||
|
#endif // React Native >=0.74
|
||||||
|
|
||||||
|
@implementation ExpoBridgeModule
|
||||||
|
@@ -46,7 +49,20 @@ - (void)setBridge:(RCTBridge *)bridge
|
||||||
|
_appContext.reactBridge = bridge;
|
||||||
|
|
||||||
|
#if !__has_include(<ReactCommon/RCTRuntimeExecutor.h>)
|
||||||
|
- _appContext._runtime = [EXJavaScriptRuntimeManager runtimeFromBridge:bridge];
|
||||||
|
+ // Hop the runtime install (and the prepareRuntime() chain it triggers via
|
||||||
|
+ // _runtime.didSet) onto RCTJSThread. The original line ran synchronously
|
||||||
|
+ // on whatever thread called setBridge: - typically the main thread - and
|
||||||
|
+ // raced JSIExecutor::initializeRuntime() on the JS thread, corrupting
|
||||||
|
+ // Hermes' Hades GC (HadesGC::writeBarrierSlow EXC_BAD_ACCESS).
|
||||||
|
+ __weak EXAppContext *weakAppContext = _appContext;
|
||||||
|
+ __weak RCTBridge *weakBridge = bridge;
|
||||||
|
+ [bridge dispatchBlock:^{
|
||||||
|
+ EXAppContext *strongAppContext = weakAppContext;
|
||||||
|
+ RCTBridge *strongBridge = weakBridge;
|
||||||
|
+ if (strongAppContext != nil && strongBridge != nil && strongAppContext._runtime == nil) {
|
||||||
|
+ strongAppContext._runtime = [EXJavaScriptRuntimeManager runtimeFromBridge:strongBridge];
|
||||||
|
+ }
|
||||||
|
+ } queue:RCTJSThread];
|
||||||
|
#endif // React Native <0.74
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,26 @@
|
|||||||
## expo-modules-core Patch
|
## expo-modules-core Patch
|
||||||
|
|
||||||
This patch fixes an issue where bitdrift's API stream gets blocked by the Expo interceptor used to power the devtools
|
This patch contains two unrelated fixes:
|
||||||
|
|
||||||
|
### Android: bitdrift interceptor
|
||||||
|
|
||||||
|
Fixes an issue where bitdrift's API stream gets blocked by the Expo interceptor used to power the devtools.
|
||||||
|
|
||||||
|
### iOS: Hermes startup race in `ExpoBridgeModule.setBridge:`
|
||||||
|
|
||||||
|
On the legacy bridge (old architecture, where `RCTRuntimeExecutor.h` is
|
||||||
|
absent), `setBridge:` installed the Expo runtime synchronously on whatever
|
||||||
|
thread called it - typically the main thread, since RN's lazy module-load
|
||||||
|
path ignores `+requiresMainQueueSetup`. The `_runtime.didSet` then ran
|
||||||
|
`prepareRuntime()` (JSI mutations) on the main thread while the JS thread was
|
||||||
|
concurrently inside `JSIExecutor::initializeRuntime()`. Two threads mutating
|
||||||
|
the same Hermes runtime corrupted Hades GC, producing intermittent
|
||||||
|
`EXC_BAD_ACCESS` launch crashes (e.g. `HadesGC::writeBarrierSlow`,
|
||||||
|
`prepareRuntime` / `bindNativePerformanceNow`).
|
||||||
|
|
||||||
|
The fix hops the runtime install onto `RCTJSThread` so all JSI mutation is
|
||||||
|
serialized on the JS thread. This backports the upstream fix discussed in
|
||||||
|
expo/expo#45374; the racy `ExpoBridgeModule` is removed entirely in SDK 55+
|
||||||
|
(expo/expo#44351), so this patch can be dropped on that upgrade.
|
||||||
|
|
||||||
|
Refs: expo/expo#43003, expo/expo#45374, expo/expo#44351
|
||||||
|
|||||||
Generated
+3
-3
@@ -222,7 +222,7 @@ patchedDependencies:
|
|||||||
expo-image-picker@17.0.11: 47b28f6ddb8bcaa6483f8714c82daaa0001122f2b0dac6c05d19e98a61a6ceab
|
expo-image-picker@17.0.11: 47b28f6ddb8bcaa6483f8714c82daaa0001122f2b0dac6c05d19e98a61a6ceab
|
||||||
expo-image@3.0.11: 6d46ffac33426c5285777da5bf5f88c68c8ce27290595dfa65f38c478930c2c4
|
expo-image@3.0.11: 6d46ffac33426c5285777da5bf5f88c68c8ce27290595dfa65f38c478930c2c4
|
||||||
expo-media-library@18.2.1: 2b84c17999bb0c977eaef7fa8ac297f7074d91c94fb63726b42d2a277b26b39a
|
expo-media-library@18.2.1: 2b84c17999bb0c977eaef7fa8ac297f7074d91c94fb63726b42d2a277b26b39a
|
||||||
expo-modules-core@3.0.30: 86e57bb33bc6c3f7021e948e099c2b5378772147b92a82a16e2e90ddcb857ace
|
expo-modules-core@3.0.30: 952fb1c8cb6dc8a0d8ef4e1114942a341d89b025e011f1acfff788929997346e
|
||||||
expo-notifications@0.32.17: a45a8dcf3d8c4b5df4ee0e62bc79b755fcf9d28ca51a6f685b85830bf4afc2e5
|
expo-notifications@0.32.17: a45a8dcf3d8c4b5df4ee0e62bc79b755fcf9d28ca51a6f685b85830bf4afc2e5
|
||||||
expo-updates@29.0.17: 04f28cb005b770e9ae8f0065eab96e43cbb1e58107f5f6ad1bdd18f6deb66487
|
expo-updates@29.0.17: 04f28cb005b770e9ae8f0065eab96e43cbb1e58107f5f6ad1bdd18f6deb66487
|
||||||
react-native-compressor@1.13.0: 58379dfaace6ced8590cb341c77f2ca8099dfa8f7df6297032ec51de767a9925
|
react-native-compressor@1.13.0: 58379dfaace6ced8590cb341c77f2ca8099dfa8f7df6297032ec51de767a9925
|
||||||
@@ -15033,7 +15033,7 @@ snapshots:
|
|||||||
require-from-string: 2.0.2
|
require-from-string: 2.0.2
|
||||||
resolve-from: 5.0.0
|
resolve-from: 5.0.0
|
||||||
|
|
||||||
expo-modules-core@3.0.30(patch_hash=86e57bb33bc6c3f7021e948e099c2b5378772147b92a82a16e2e90ddcb857ace)(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
|
expo-modules-core@3.0.30(patch_hash=952fb1c8cb6dc8a0d8ef4e1114942a341d89b025e011f1acfff788929997346e)(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
invariant: 2.2.4
|
invariant: 2.2.4
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
@@ -15169,7 +15169,7 @@ snapshots:
|
|||||||
expo-font: 14.0.11(expo@54.0.34(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
expo-font: 14.0.11(expo@54.0.34(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||||
expo-keep-awake: 15.0.8(expo@54.0.34(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react@19.1.0)
|
expo-keep-awake: 15.0.8(expo@54.0.34(@babel/core@7.29.0)(react-native-webview@13.15.0(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react@19.1.0)
|
||||||
expo-modules-autolinking: 3.0.25
|
expo-modules-autolinking: 3.0.25
|
||||||
expo-modules-core: 3.0.30(patch_hash=86e57bb33bc6c3f7021e948e099c2b5378772147b92a82a16e2e90ddcb857ace)(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
expo-modules-core: 3.0.30(patch_hash=952fb1c8cb6dc8a0d8ef4e1114942a341d89b025e011f1acfff788929997346e)(react-native@0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
|
||||||
pretty-format: 29.7.0
|
pretty-format: 29.7.0
|
||||||
react: 19.1.0
|
react: 19.1.0
|
||||||
react-native: 0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0)
|
react-native: 0.81.5(patch_hash=2656ac6deb71b92a4df4af4593d13ace6a5740936432e5e7e8ef32bc3cd05194)(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0)
|
||||||
|
|||||||
Reference in New Issue
Block a user