Skip to content

Commit 708f84e

Browse files
Peter Arganyaleclarson
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 f96f08b commit 708f84e

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
@@ -158,6 +158,7 @@ @implementation RCTCxxBridge
158158
{
159159
BOOL _wasBatchActive;
160160
BOOL _didInvalidate;
161+
BOOL _moduleRegistryCreated;
161162

162163
NSMutableArray<RCTPendingCall> *_pendingCalls;
163164
std::atomic<NSInteger> _pendingCount;
@@ -172,6 +173,7 @@ @implementation RCTCxxBridge
172173
// JS thread management
173174
NSThread *_jsThread;
174175
std::shared_ptr<RCTMessageThread> _jsMessageThread;
176+
std::mutex _moduleRegistryLock;
175177

176178
// This is uniquely owned, but weak_ptr is used.
177179
std::shared_ptr<Instance> _reactInstance;
@@ -219,9 +221,9 @@ - (instancetype)initWithParentBridge:(RCTBridge *)bridge
219221
*/
220222
_valid = YES;
221223
_loading = YES;
224+
_moduleRegistryCreated = NO;
222225
_pendingCalls = [NSMutableArray new];
223226
_displayLink = [RCTDisplayLink new];
224-
225227
_moduleDataByName = [NSMutableDictionary new];
226228
_moduleClassesByID = [NSMutableArray new];
227229
_moduleDataByID = [NSMutableArray new];
@@ -456,7 +458,7 @@ - (BOOL)moduleIsInitialized:(Class)moduleClass
456458
return _moduleDataByName[RCTBridgeModuleNameForClass(moduleClass)].hasInstance;
457459
}
458460

459-
- (std::shared_ptr<ModuleRegistry>)_buildModuleRegistry
461+
- (std::shared_ptr<ModuleRegistry>)_buildModuleRegistryUnlocked
460462
{
461463
if (!self.valid) {
462464
return {};
@@ -503,12 +505,7 @@ - (void)_initializeBridge:(std::shared_ptr<JSExecutorFactory>)executorFactory
503505
executorFactory = std::make_shared<GetDescAdapter>(self, executorFactory);
504506
#endif
505507

506-
// This is async, but any calls into JS are blocked by the m_syncReady CV in Instance
507-
_reactInstance->initializeBridge(
508-
std::make_unique<RCTInstanceCallback>(self),
509-
executorFactory,
510-
_jsMessageThread,
511-
[self _buildModuleRegistry]);
508+
[self _initializeBridgeLocked:executorFactory];
512509

513510
#if RCT_PROFILE
514511
if (RCTProfileIsProfiling()) {
@@ -522,6 +519,19 @@ - (void)_initializeBridge:(std::shared_ptr<JSExecutorFactory>)executorFactory
522519
RCT_PROFILE_END_EVENT(RCTProfileTagAlways, @"");
523520
}
524521

522+
- (void)_initializeBridgeLocked:(std::shared_ptr<JSExecutorFactory>)executorFactory
523+
{
524+
std::lock_guard<std::mutex> guard(_moduleRegistryLock);
525+
526+
// This is async, but any calls into JS are blocked by the m_syncReady CV in Instance
527+
_reactInstance->initializeBridge(
528+
std::make_unique<RCTInstanceCallback>(self),
529+
executorFactory,
530+
_jsMessageThread,
531+
[self _buildModuleRegistryUnlocked]);
532+
_moduleRegistryCreated = YES;
533+
}
534+
525535
- (NSArray *)configForModuleName:(NSString *)moduleName
526536
{
527537
return _moduleDataByName[moduleName].config;
@@ -682,11 +692,13 @@ - (void)registerExtraModules
682692

683693
- (void)registerAdditionalModuleClasses:(NSArray<Class> *)modules
684694
{
685-
@synchronized (self) {
695+
std::lock_guard<std::mutex> guard(_moduleRegistryLock);
696+
if (_moduleRegistryCreated) {
686697
NSArray<RCTModuleData *> *newModules = [self _initializeModules:modules withDispatchGroup:NULL lazilyDiscovered:YES];
687-
if (_reactInstance) {
688-
_reactInstance->getModuleRegistry().registerModules(createNativeModules(newModules, self, _reactInstance));
689-
}
698+
assert(_reactInstance); // at this point you must have reactInstance as you already called reactInstance->initialzeBridge
699+
_reactInstance->getModuleRegistry().registerModules(createNativeModules(newModules, self, _reactInstance));
700+
} else {
701+
[self registerModulesForClasses:modules];
690702
}
691703
}
692704

0 commit comments

Comments
 (0)