From 101190f7f8b08e1b1f537fbb901524da0edca20a Mon Sep 17 00:00:00 2001 From: Kasper Hirvikoski Date: Mon, 29 Aug 2016 12:07:28 -0700 Subject: [PATCH] Verify exported modules only once to support dynamic context in DEBUG-mode Summary: **Motivation:** We have a project that dynamically changes classes in runtime. This component is initialised within the React Native context. Therefor `RCTBatchedBridge` copies the classes before changes are made to them. While React Native is running, changes are made to the classes dynamically. When the project reloads the `RCTBatchedBridge`, it now has an invalid list of classes containing trash pointers. This causes the project to crash on https://github.com/facebook/react-native/blob/master/React/Base/RCTBatchedBridge.m#L288 with EXC_BAD_ACCESS in the DEBUG-mode. **Solution:** Copy the class list on each reload to get the current state. Since this is only a DEBUG-feature the overhead of this should not be a major issue. Closes https://github.com/facebook/react-native/pull/9541 Differential Revision: D3775012 Pulled By: javache fbshipit-source-id: d55fa0742ca100d8018c73080230cf718aa5a7e9 --- React/Base/RCTBatchedBridge.m | 46 +++++++++++++++++------------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/React/Base/RCTBatchedBridge.m b/React/Base/RCTBatchedBridge.m index 66cad87b1..152e48793 100644 --- a/React/Base/RCTBatchedBridge.m +++ b/React/Base/RCTBatchedBridge.m @@ -266,38 +266,38 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithDelegate:(id)dele extraModules = self.moduleProvider(); } - if (RCT_DEBUG && !RCTRunningInTestEnvironment()) { - // Check for unexported modules - static Class *classes; - static unsigned int classCount; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (RCT_DEBUG && !RCTRunningInTestEnvironment()) { + // Check for unexported modules + Class *classes; + unsigned int classCount; classes = objc_copyClassList(&classCount); - }); - NSMutableSet *moduleClasses = [NSMutableSet new]; - [moduleClasses addObjectsFromArray:RCTGetModuleClasses()]; - [moduleClasses addObjectsFromArray:[extraModules valueForKeyPath:@"class"]]; + NSMutableSet *moduleClasses = [NSMutableSet new]; + [moduleClasses addObjectsFromArray:RCTGetModuleClasses()]; + [moduleClasses addObjectsFromArray:[extraModules valueForKeyPath:@"class"]]; - for (unsigned int i = 0; i < classCount; i++) - { - Class cls = classes[i]; - Class superclass = cls; - while (superclass) + for (unsigned int i = 0; i < classCount; i++) { - if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule))) + Class cls = classes[i]; + Class superclass = cls; + while (superclass) { - if (![moduleClasses containsObject:cls] && - ![cls respondsToSelector:@selector(moduleName)]) { - RCTLogWarn(@"Class %@ was not exported. Did you forget to use " - "RCT_EXPORT_MODULE()?", cls); + if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule))) + { + if (![moduleClasses containsObject:cls] && + ![cls respondsToSelector:@selector(moduleName)]) { + RCTLogWarn(@"Class %@ was not exported. Did you forget to use " + "RCT_EXPORT_MODULE()?", cls); + } + break; } - break; + superclass = class_getSuperclass(superclass); } - superclass = class_getSuperclass(superclass); } } - } + }); NSMutableArray *moduleClassesByID = [NSMutableArray new]; NSMutableArray *moduleDataByID = [NSMutableArray new];