Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash in [SentrySubClassFinder actOnSubclassesOfViewControllerInImage] (SentrySubClassFinder.m:61) #3798

Closed
dimacorp opened this issue Mar 27, 2024 · 7 comments · Fixed by #3813

Comments

@dimacorp
Copy link

dimacorp commented Mar 27, 2024

Platform

iOS

Environment

Production, Develop

Installed

CocoaPods

Version

8.22.4

Did it work on previous versions?

No response

Steps to Reproduce

  1. Add Swift conditional class for example
    import RoomPlan
    @available(iOS 17.0, *)
    class RoomCaptureTools {
    private var finalResults: CapturedStructure?
    }
    This class is a helper class to a feature available on latest iOS while the app itself supports iOS 13
  2. Integrate Sentry
  3. Start the app on older iOS (for example 15.5)

Expected Result

no crash

Actual Result

The app crashes in SentrySDK startWithConfigureOptions

Thread 3 Queue : sentry-ui-view-controller-swizzling (serial)
#0	0x0000000000000000 in 0x00000000 ()
#1	0x00000001043eb498 in type metadata accessor for CapturedStructure? ()
#2	0x00000001043eb3ac in type metadata completion function for RoomCaptureTools ()
#3	0x000000018f9c7930 in swift::MetadataCacheEntryBase<(anonymous namespace)::SingletonMetadataCacheEntry, int>::doInitialization(swift::MetadataWaitQueue::Worker&, swift::MetadataRequest) ()
#4	0x000000018f9b8cf8 in swift_getSingletonMetadata ()
#5	0x00000001043eb360 in type metadata accessor for RoomCaptureTools ()
#6	0x00000001043eb314 in ObjC metadata update function for RoomCaptureTools ()
#7	0x000000018017d938 in realizeClassMaybeSwiftMaybeRelock(objc_class*, mutex_tt<false>&, bool) ()
#8	0x0000000180183548 in look_up_class ()
#9	0x00000001807e7cb8 in NSClassFromString ()
#10	0x000000010514b4c0 in __69-[SentrySubClassFinder actOnSubclassesOfViewControllerInImage:block:]_block_invoke at /Pods/Sentry/Sources/Sentry/SentrySubClassFinder.m:61
#11	0x00000001050e0f04 in __53-[SentryDispatchQueueWrapper dispatchAsyncWithBlock:]_block_invoke at /Pods/Sentry/Sources/Sentry/SentryDispatchQueueWrapper.m:31
#12	0x0000000104db433c in _dispatch_call_block_and_release ()
#13	0x0000000104db5b94 in _dispatch_client_callout ()
#14	0x0000000104dbccc4 in _dispatch_lane_serial_drain ()
#15	0x0000000104dbd978 in _dispatch_lane_invoke ()
#16	0x0000000104dc9a00 in _dispatch_workloop_worker_thread ()
#17	0x00000001cc0af878 in _pthread_wqthread ()
Enqueued from com.apple.main-thread (Thread 1) Queue : com.apple.main-thread (serial)
#0	0x0000000104db9ef4 in dispatch_async ()
#1	0x00000001050e0ea8 in -[SentryDispatchQueueWrapper dispatchAsyncWithBlock:] at 
/Pods/Sentry/Sources/Sentry/SentryDispatchQueueWrapper.m:29
#2	0x000000010514b25c in -[SentrySubClassFinder actOnSubclassesOfViewControllerInImage:block:] at /Pods/Sentry/Sources/Sentry/SentrySubClassFinder.m:35
#3	0x000000010516b7f0 in -[SentryUIViewControllerSwizzling swizzleUIViewControllersOfImage:] at /Pods/Sentry/Sources/Sentry/SentryUIViewControllerSwizzling.m:199
#4	0x000000010516a7d0 in -[SentryUIViewControllerSwizzling start] at /Pods/Sentry/Sources/Sentry/SentryUIViewControllerSwizzling.m:80
#5	0x000000010511c31c in -[SentryPerformanceTrackingIntegration installWithOptions:] at /Pods/Sentry/Sources/Sentry/SentryPerformanceTrackingIntegration.m:48
#6	0x000000010513e1fc in +[SentrySDK installIntegrations] at /Pods/Sentry/Sources/Sentry/SentrySDK.m:440
#7	0x000000010513c678 in __30+[SentrySDK startWithOptions:]_block_invoke at /Pods/Sentry/Sources/Sentry/SentrySDK.m:211
#8	0x000000010515589c in +[SentryThreadWrapper onMainThread:] at /Pods/Sentry/Sources/Sentry/SentryThreadWrapper.m:27
#9	0x000000010513c47c in +[SentrySDK startWithOptions:] at /Pods/Sentry/Sources/Sentry/SentrySDK.m:205
#10	0x000000010513c864 in +[SentrySDK startWithConfigureOptions:] at /Pods/Sentry/Sources/Sentry/SentrySDK.m:229
#11	0x000000010439e3a0 in -[AppDelegate application:didFinishLaunchingWithOptions:] at /AppDelegate.m:44
Screenshot 2024-03-27 at 13 11 15

Are you willing to submit a PR?

No response

@philipphofmann
Copy link
Member

@dimacorp, I tried to reproduce your problem in our iOS-Swift sample application by adding the following class

@available(iOS 17.0, *)
class RoomCaptureTools {

    func doSomething() {
        
    }
}

but I couldn't reproduce the issue. The SentrySubClassFinder can load the RoomCaptureTools without crashing. Furthermore, I added sentry via CocoaPods to an empty sample project and also added the RoomCaptureTools, but again I couldn't reproduce the issue.

Please share more details on your project setup and how you include Sentry, so we can reproduce the problem.

@dimacorp
Copy link
Author

The app is quite big and actually mostly in ObjC but please try to add this line to RoomCaptureTools, it looks it's essential as CapturedStructure is from the new API:

private var finalResults: CapturedStructure?

and please make sure to run with older iOS (we do with 15.5).

@philipphofmann
Copy link
Member

philipphofmann commented Mar 27, 2024

Ah, importing RoomPlan and using it like this does the trick. I can reproduce the problem now:

import RoomPlan

@available(iOS 17.0, *)
class RoomCaptureTools {
    
    private var finalResults: CapturedStructure?

    func doSomething() {
        
    }
}

Using canImport doesn't solve the problem.

#if canImport(RoomPlan)
import RoomPlan
#endif

@philipphofmann
Copy link
Member

The same problem exists also for ActivityKit:

import ActivityKit

@available(iOS 17.0, *)
class SomeClass {
    
    private var activity : PushType?

    func doSomething() {
        
    }
}

When looking at your stacktrace, the culprit seems to be in the Swift runtime somewhere around swift_getSingletonMetadata:

#1	0x00000001043eb498 in type metadata accessor for CapturedStructure? ()
#2	0x00000001043eb3ac in type metadata completion function for RoomCaptureTools ()
#3	0x000000018f9c7930 in swift::MetadataCacheEntryBase<(anonymous namespace)::SingletonMetadataCacheEntry, int>::doInitialization(swift::MetadataWaitQueue::Worker&, swift::MetadataRequest) ()
#4	0x000000018f9b8cf8 in swift_getSingletonMetadata ()
#5	0x00000001043eb360 in type metadata accessor for RoomCaptureTools ()
#6	0x00000001043eb314 in ObjC metadata update function for RoomCaptureTools ()
#7	0x000000018017d938 in realizeClassMaybeSwiftMaybeRelock(objc_class*, mutex_tt<false>&, bool) ()
#8	0x0000000180183548 in look_up_class ()
#9	0x00000001807e7cb8 in NSClassFromString ()

My first guess was that this could be a bug in the latest Swift version, but I can also reproduce the problem with Xcode 15.1 / Swift 5.9 and Swift 4.2.

Anyways, NSClassFromString shouldn't crash in that scenario; instead, it should return nil, IMO. This could be a bug in the Swift runtime, so I created an issue swiftlang/swift#72657.

For now, you can disable the swizzling logic via options.enableSwizzling = false, but this turns off a couple of features:

/**
* Wether the SDK should use swizzling or not.
* @discussion When turned off the following features are disabled: breadcrumbs for touch events and
* navigation with @c UIViewControllers, automatic instrumentation for @c UIViewControllers,
* automatic instrumentation for HTTP requests, automatic instrumentation for file IO with
* @c NSData, and automatically added sentry-trace header to HTTP requests for distributed tracing.
* @note Default is @c YES.
*/
@property (nonatomic, assign) BOOL enableSwizzling;

@philipphofmann
Copy link
Member

One idea for another workaround is to provide an ignore list for classes to swizzle, so you would have to do something like

options.swizzleIgnoreList = ["RoomCaptureTools"]

for every class that imports RoomPlan. Would that work for you, @dimacorp?

@dimacorp
Copy link
Author

Thanks for taking a look, at this point we disabled Sentry for iOS < 17, turning off swizzling might work but disables a number of features, swizzleIgnoreList sounds like a better idea.

@philipphofmann philipphofmann self-assigned this Apr 2, 2024
philipphofmann added a commit that referenced this issue Apr 2, 2024
Add an option to exclude certain classes from swizzling.

Fixes GH-3798
@philipphofmann
Copy link
Member

philipphofmann commented Apr 2, 2024

@dimacorp, we will add swizzleClassNameExcludes with #3813. Once released, you can disable swizzling only for RoomCaptureTools by doing the following:

options.swizzleClassNameExcludes = ["RoomPlanWrapper"]

We are also going to add the workaround to our troubleshooting section in the docs with getsentry/sentry-docs#9596.

philipphofmann added a commit that referenced this issue Apr 3, 2024
Add an option to exclude certain classes from swizzling.

Fixes GH-3798
dKasabwala pushed a commit to dKasabwala/sentry-cocoa that referenced this issue May 6, 2024
Add an option to exclude certain classes from swizzling.

Fixes getsentryGH-3798
threema-matteo pushed a commit to threema-ch/sentry-cocoa that referenced this issue May 21, 2024
Add an option to exclude certain classes from swizzling.

Fixes getsentryGH-3798
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Archived in project
Archived in project
Development

Successfully merging a pull request may close this issue.

2 participants