Question

[IOS 17][Xcode 15.1][Debug] FSReactSwizzleBootstrap - Crash on react native app

  • 28 December 2023
  • 7 replies
  • 184 views

  • New Contributor
  • 1 reply

Hello!
 

I'm currently experiencing a crash in my company's app after updating to Xcode 15 && running IOS 17.
 

Error:

 

Thread 4: EXC_BAD_ACCESS (code=2, address=0x16b178000)

 

Caused by the call to
 

dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{

in the file FSReactSwizzleBootstrap.

Everything works correctly on iOS 16.1 and earlier.

 

Technical details:

 

"@fullstory/babel-plugin-annotate-react": "^2.3.0",
"@fullstory/react-native": "^1.4.0",
"react-native": "0.65.3"

Xcode 15.1
Emulator: iOS 17 (or higher)
 

As a workaround, I made a patch by commenting out the line that calls dispatch async (only in debug). Do you know if there are any repercussions of this workaround, and why does this code fail in iOS 17?

Workaround

 

diff --git a/node_modules/@fullstory/react-native/ios/FullStory.mm b/node_modules/@fullstory/react-native/ios/FullStory.mm
index 6faff0f..93eaacc 100644
--- a/node_modules/@fullstory/react-native/ios/FullStory.mm
+++ b/node_modules/@fullstory/react-native/ios/FullStory.mm
@@ -372,59 +372,59 @@ static bool array_contains_string(const char **array, const char *string) {
SWIZZLE_HANDLE_COMMAND(RCTPullToRefreshViewComponentView);
SWIZZLE_HANDLE_COMMAND(RCTLegacyViewManagerInteropComponentView);
#pragma clang pop
-#ifdef DEBUG
- dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
- // RCTViewComponentView subclasses don't tend to call their superclass implementations of handleCommand, so in debug mode, we want to make sure that we don't have any "straggler" classes (especially React core classes!) that don't have their implementations of handleCommand interposed. We enumerate all the classes on the system, determine if any has a superclass of RCTViewComponentView, and if so, make sure that we have it covered.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wundeclared-selector"
- SEL sel = @selector(handleCommand:args:);
-#pragma clang pop
- const char* swizzled_classes[] = {
- "RCTViewComponentView",
- "RCTTextInputComponentView",
- "RCTSwitchComponentView",
- "RCTScrollViewComponentView",
- "RCTPullToRefreshViewComponentView",
- "RCTLegacyViewManagerInteropComponentView",
- 0};
- // Grab the impl of RCTViewComponentView
- Class viewComponentView = NSClassFromString(@"RCTViewComponentView");
- Method _Nullable swizzledViewComponentViewCommand = class_getInstanceMethod(viewComponentView, sel);
- IMP swizzledViewComponentViewCommandImplementation = method_getImplementation(swizzledViewComponentViewCommand);
-
- int classCount = objc_getClassList(NULL, 0);
- // The classes stored in this array may not be NSObject classes,
- // so may not respond to retain messages. See:
- // https://gist.github.com/mikeash/1267596
- __unsafe_unretained Class classes[classCount];
- // Verify swizzle in all subclasses of RCTViewComponentView
- objc_getClassList(classes, classCount);
- for (int i = 0; i < classCount; i++) {
- Class _Nullable __unsafe_unretained cls = classes[i];
- while (cls && cls != viewComponentView) {
- cls = class_getSuperclass(cls);
- }
- if (cls == viewComponentView && cls && !array_contains_string(swizzled_classes, class_getName(classes[i]))) {
- cls = classes[i];
- const char *className = class_getName(cls);
- // Note that this will find the superclass's implementation,
- // which informs us whether this class gets its implementation
- // from the swizzle above.
- // Since we skip the explicitly swizzled classes, each with
- // its own implementation, the remaining classes should either
- // have the superclass implementation, or their own, which is
- // incapable of receiving FS properties.
- Method _Nullable existingMethod = class_getInstanceMethod(cls, sel);
- if (existingMethod) {
- IMP existingImplementation = method_getImplementation(existingMethod);
- if (existingImplementation != swizzledViewComponentViewCommandImplementation) {
- NSAssert(strncmp(className, "RCT", 3) != 0, @"React Native framework class %s needs handleCommand support! Please contact FullStory support with this message.", className);
- NSLog(@"RCTViewComponentView subclass %s cannot receive FullStory commands; FullStory attributes on such views may not function correctly.", className);
- }
- }
- }
- }
- });
-#endif
+//#ifdef DEBUG
+// dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
+// // RCTViewComponentView subclasses don't tend to call their superclass implementations of handleCommand, so in debug mode, we want to make sure that we don't have any "straggler" classes (especially React core classes!) that don't have their implementations of handleCommand interposed. We enumerate all the classes on the system, determine if any has a superclass of RCTViewComponentView, and if so, make sure that we have it covered.
+//#pragma clang diagnostic push
+//#pragma clang diagnostic ignored "-Wundeclared-selector"
+// SEL sel = @selector(handleCommand:args:);
+//#pragma clang pop
+// const char* swizzled_classes[] = {
+// "RCTViewComponentView",
+// "RCTTextInputComponentView",
+// "RCTSwitchComponentView",
+// "RCTScrollViewComponentView",
+// "RCTPullToRefreshViewComponentView",
+// "RCTLegacyViewManagerInteropComponentView",
+// 0};
+// // Grab the impl of RCTViewComponentView
+// Class viewComponentView = NSClassFromString(@"RCTViewComponentView");
+// Method _Nullable swizzledViewComponentViewCommand = class_getInstanceMethod(viewComponentView, sel);
+// IMP swizzledViewComponentViewCommandImplementation = method_getImplementation(swizzledViewComponentViewCommand);
+//
+// int classCount = objc_getClassList(NULL, 0);
+// // The classes stored in this array may not be NSObject classes,
+// // so may not respond to retain messages. See:
+// // https://gist.github.com/mikeash/1267596
+// __unsafe_unretained Class classes[classCount];
+// // Verify swizzle in all subclasses of RCTViewComponentView
+// objc_getClassList(classes, classCount);
+// for (int i = 0; i < classCount; i++) {
+// Class _Nullable __unsafe_unretained cls = classes[i];
+// while (cls && cls != viewComponentView) {
+// cls = class_getSuperclass(cls);
+// }
+// if (cls == viewComponentView && cls && !array_contains_string(swizzled_classes, class_getName(classes[i]))) {
+// cls = classes[i];
+// const char *className = class_getName(cls);
+// // Note that this will find the superclass's implementation,
+// // which informs us whether this class gets its implementation
+// // from the swizzle above.
+// // Since we skip the explicitly swizzled classes, each with
+// // its own implementation, the remaining classes should either
+// // have the superclass implementation, or their own, which is
+// // incapable of receiving FS properties.
+// Method _Nullable existingMethod = class_getInstanceMethod(cls, sel);
+// if (existingMethod) {
+// IMP existingImplementation = method_getImplementation(existingMethod);
+// if (existingImplementation != swizzledViewComponentViewCommandImplementation) {
+// NSAssert(strncmp(className, "RCT", 3) != 0, @"React Native framework class %s needs handleCommand support! Please contact FullStory support with this message.", className);
+// NSLog(@"RCTViewComponentView subclass %s cannot receive FullStory commands; FullStory attributes on such views may not function correctly.", className);
+// }
+// }
+// }
+// }
+// });
+//#endif
}
@end

Thanks!


7 replies

Improved workaround, i’m unable to replicate it on a bare new project using same react native version, probably a specific mix of packages causing this crash.
 

diff --git a/node_modules/@fullstory/react-native/ios/FullStory.mm b/node_modules/@fullstory/react-native/ios/FullStory.mm
index 6faff0f..9c834a8 100644
--- a/node_modules/@fullstory/react-native/ios/FullStory.mm
+++ b/node_modules/@fullstory/react-native/ios/FullStory.mm
@@ -372,7 +372,8 @@ static bool array_contains_string(const char **array, const char *string) {
SWIZZLE_HANDLE_COMMAND(RCTPullToRefreshViewComponentView);
SWIZZLE_HANDLE_COMMAND(RCTLegacyViewManagerInteropComponentView);
#pragma clang pop
-#ifdef DEBUG
+#if defined(DEBUG) && TARGET_OS_IOS && (__IPHONE_OS_VERSION_MAX_ALLOWED < 170000)
+
dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
// RCTViewComponentView subclasses don't tend to call their superclass implementations of handleCommand, so in debug mode, we want to make sure that we don't have any "straggler" classes (especially React core classes!) that don't have their implementations of handleCommand interposed. We enumerate all the classes on the system, determine if any has a superclass of RCTViewComponentView, and if so, make sure that we have it covered.
#pragma clang diagnostic push

 

Userlevel 5
Badge

Hey @Dan. Thanks for reaching out, and sorry to hear about the trouble! I’m going to create a case for our Mobile Support team so they can take a closer look. They’ll be in touch via email soon - likely early next week as we finish out the holidays. 

@megan We’re having the same issue. Was there an update on this?

Userlevel 1
Badge

Hey @ServerCimen ! Our engineers are still working on this one but I’ve asked them to share an update here once they’ve found a resolution to this issue.

@megan  @Tym We are experiencing the same issue. Any update from the team?

Userlevel 1
Badge

Hi @Norbert 

Thanks for reaching out and sorry to hear you’re experiencing a similar issue. Our engineering team is actively investigating at the moment.
As this requires more technical troubleshooting, would it be possible to reach out to mobile-support@fullstory.com with the following information:

  1. Podfile
  2. package.json
  3. Are you able to reproduce the issue? If so, are you able to share any steps to reproduce or share a sample project etc.

We will keep an eye out for this information so we take a closer look.
Gemma

(Also tagging @ServerCimen as it may be useful for you to pass along the above details so we can get to the bottom of this issue as quickly as possible!)

Badge

Hi @Norbert @ServerCimen @Dan ,

Exciting news! We've rolled out an update addressing the crash issue and the fix is in version 1.4.2 of our React Native plugin (https://www.npmjs.com/package/@fullstory/react-native/v/1.4.2?activeTab=versions).
 
Kindly upgrade to this version at your earliest convenience and share your feedback on whether it successfully rectifies the problem.
 
Thanks!

Reply