Skip to content

Commit 1c31919

Browse files
Peter Arganyfacebook-github-bot
authored andcommitted
Added locking around RN bridge cxx module registry to avoid crash
Summary: D12904277 was my sad, optimistic attempt to fix this crash. As @[100006577537606:Slobodan] mentioned on T35879909, the real issue is that moduleRegistry is being created (using _moduleDataByID dict) concurrently while we try to append to this dict. I added locks around these usage of _moduleDataByID. Reviewed By: fkgozali Differential Revision: D12911108 fbshipit-source-id: 2435b7a477c27585898f351c4a0d4c1bd4056756
1 parent 2486d12 commit 1c31919

File tree

1 file changed

+24
-12
lines changed

1 file changed

+24
-12
lines changed

React/CxxBridge/RCTCxxBridge.mm

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ @implementation RCTCxxBridge
155155
{
156156
BOOL _wasBatchActive;
157157
BOOL _didInvalidate;
158+
BOOL _moduleRegistryCreated;
158159

159160
NSMutableArray<RCTPendingCall> *_pendingCalls;
160161
std::atomic<NSInteger> _pendingCount;
@@ -169,6 +170,7 @@ @implementation RCTCxxBridge
169170
// JS thread management
170171
NSThread *_jsThread;
171172
std::shared_ptr<RCTMessageThread> _jsMessageThread;
173+
std::mutex _moduleRegistryLock;
172174

173175
// This is uniquely owned, but weak_ptr is used.
174176
std::shared_ptr<Instance> _reactInstance;
@@ -209,9 +211,9 @@ - (instancetype)initWithParentBridge:(RCTBridge *)bridge
209211
*/
210212
_valid = YES;
211213
_loading = YES;
214+
_moduleRegistryCreated = NO;
212215
_pendingCalls = [NSMutableArray new];
213216
_displayLink = [RCTDisplayLink new];
214-
215217
_moduleDataByName = [NSMutableDictionary new];
216218
_moduleClassesByID = [NSMutableArray new];
217219
_moduleDataByID = [NSMutableArray new];
@@ -442,7 +444,7 @@ - (BOOL)moduleIsInitialized:(Class)moduleClass
442444
return _moduleDataByName[RCTBridgeModuleNameForClass(moduleClass)].hasInstance;
443445
}
444446

445-
- (std::shared_ptr<ModuleRegistry>)_buildModuleRegistry
447+
- (std::shared_ptr<ModuleRegistry>)_buildModuleRegistryUnlocked
446448
{
447449
if (!self.valid) {
448450
return {};
@@ -489,12 +491,7 @@ - (void)_initializeBridge:(std::shared_ptr<JSExecutorFactory>)executorFactory
489491
executorFactory = std::make_shared<GetDescAdapter>(self, executorFactory);
490492
#endif
491493

492-
// This is async, but any calls into JS are blocked by the m_syncReady CV in Instance
493-
_reactInstance->initializeBridge(
494-
std::make_unique<RCTInstanceCallback>(self),
495-
executorFactory,
496-
_jsMessageThread,
497-
[self _buildModuleRegistry]);
494+
[self _initializeBridgeLocked:executorFactory];
498495

499496
#if RCT_PROFILE
500497
if (RCTProfileIsProfiling()) {
@@ -508,6 +505,19 @@ - (void)_initializeBridge:(std::shared_ptr<JSExecutorFactory>)executorFactory
508505
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
509506
}
510507

508+
- (void)_initializeBridgeLocked:(std::shared_ptr<JSExecutorFactory>)executorFactory
509+
{
510+
std::lock_guard<std::mutex> guard(_moduleRegistryLock);
511+
512+
// This is async, but any calls into JS are blocked by the m_syncReady CV in Instance
513+
_reactInstance->initializeBridge(
514+
std::make_unique<RCTInstanceCallback>(self),
515+
executorFactory,
516+
_jsMessageThread,
517+
[self _buildModuleRegistryUnlocked]);
518+
_moduleRegistryCreated = YES;
519+
}
520+
511521
- (NSArray<RCTModuleData *> *)registerModulesForClasses:(NSArray<Class> *)moduleClasses
512522
{
513523
RCT_PROFILE_BEGIN_EVENT(RCTProfileTagAlways,
@@ -706,11 +716,13 @@ - (void)registerExtraLazyModules
706716

707717
- (void)registerAdditionalModuleClasses:(NSArray<Class> *)modules
708718
{
709-
@synchronized (self) {
719+
std::lock_guard<std::mutex> guard(_moduleRegistryLock);
720+
if (_moduleRegistryCreated) {
710721
NSArray<RCTModuleData *> *newModules = [self _initializeModules:modules withDispatchGroup:NULL lazilyDiscovered:YES];
711-
if (_reactInstance) {
712-
_reactInstance->getModuleRegistry().registerModules(createNativeModules(newModules, self, _reactInstance));
713-
}
722+
assert(_reactInstance); // at this point you must have reactInstance as you already called reactInstance->initialzeBridge
723+
_reactInstance->getModuleRegistry().registerModules(createNativeModules(newModules, self, _reactInstance));
724+
} else {
725+
[self registerModulesForClasses:modules];
714726
}
715727
}
716728

0 commit comments

Comments
 (0)