Swift library causes random crashes in Objective-C app on iPhone

Viewed 285

I have a Swift library that crashes when used in Objective-C iOS app. The app crashes for about 3 % of users on the App store. The user base is big though, so it is a lot in absolute numbers. When the library is removed, the crashes do not happen. All of the crashes happen on iOS 14, with 95 % of devices being an iPhone.

I don’t have access to source code of the app and I can not debug it. Also I can not reproduce this problem on my phone on demand. I have got the app to randomly crash here and there.

Crashlytics is pointing at a UrlBuilder class within our library. I am posting it below.

struct ExternalConfigConstants {
    static let configJsonURL = "https://cdn.mycompany.com/sdk/live/%@/config.json"
}


protocol ConfigurationUrlBuilder {
    func getExternalConfigUrl() throws -> String
}

class UrlBuilder: ConfigurationUrlBuilder {
    func getExternalConfigUrl() throws -> String {
        if let appName = ExternalConfigurationManagerBuilder.appName {
            return String(format: ExternalConfigConstants.configJsonURL, appName)
        } else {
            throw ConfigurationParsingError.undefinedAppName
        }
    }
}

It might be useful to understand where the UrlBuilder takes appName property from. This is a stored type property. Its’ value is passed by the app developer.

public class ExternalConfigurationManagerBuilder {
    public static var appName: String?
}
@objc public class MyAPI: NSObject {

    @objc public static let instance = MyAPI()

    @objc public func setAppName(appName: String) {
        ExternalConfigurationManagerBuilder.appName = appName
    }
}

This is how app developer passes the appName:

[MyAPI.instance setAppNameWithAppName:@"clientApp"];

Then at some later point UrlBuilder.getExternalConfigUrl() is called by the library.

MyAPI and ExternalConfigurationManagerBuilder/UrlBuilder classes are packaged in two different Pods. We use CocoaPods to distribute the library.

The error messages mention "type metadata accessor for UrlBuilder". I have read about type metadata accessors and they seem to be compiler-generated functions that are used by runtime for type checking.

When looking into this, we have found the following problems with our code, however we can not link any of these to the crashes:

  1. We do not give stored type property appName a default value as Swift book advises. We rely on the fact that the app developer assigns it a value before UrlBuilder is called

  2. ExternalConfigurationManagerBuilder class is used as singleton, but does not follow the recommended pattern of assigning an instance to a static property

  3. The string interpolation method we use can crash when passed an int instead of a string. I have checked with the app developer and they confirmed they are passing a string.

We have also tried switching a phone to different languages and locales and these do not seem to cause a crash.

What could be the cause of those crashes? What could help me isolate the problem and reproduce it on demand?

Here are the logs:

Crashed: NSOperationQueue 0x104d61d10 (QOS: UNSPECIFIED)
0  libobjc.A.dylib                0x1a4bba128 lookUpImpOrForward + 76
1  libobjc.A.dylib                0x1a4ba4524 _objc_msgSend_uncached + 68
2  CoreFoundation                 0x18fad45d8 _CFErrorCopyUserInfoKeyFromUserInfo + 24
3  CoreFoundation                 0x18fad469c _CFErrorCopyUserInfoKey + 28
4  CoreFoundation                 0x18fad4310 _CFErrorCreateLocalizedDescription + 164
5  Foundation                     0x190e08948 -[NSError localizedDescription] + 88
6  clientApp-ios                  0x103072b60 type metadata accessor for UrlBuilder + 4342754144 (<compiler-generated>:4342754144)
7  clientApp-ios                  0x103072260 type metadata accessor for UrlBuilder + 4342751840 (<compiler-generated>:4342751840)
8  clientApp-ios                  0x103076624 type metadata accessor for UrlBuilder + 4342769188 (<compiler-generated>:4342769188)
9  clientApp-ios                  0x103076408 type metadata accessor for UrlBuilder + 4342768648 (<compiler-generated>:4342768648)
10 Foundation                     0x190edc850 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 24
11 Foundation                     0x190dc9740 -[NSBlockOperation main] + 104
12 Foundation                     0x190edeca4 __NSOPERATION_IS_INVOKING_MAIN__ + 24
13 Foundation                     0x190dc93c8 -[NSOperation start] + 808
14 Foundation                     0x190edf74c __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 24
15 Foundation                     0x190edf1d4 __NSOQSchedule_f + 184
16 libdispatch.dylib              0x18f78ffb8 _dispatch_block_async_invoke2 + 148
17 libdispatch.dylib              0x18f781db0 _dispatch_client_callout + 20
18 libdispatch.dylib              0x18f78512c _dispatch_continuation_pop + 416
19 libdispatch.dylib              0x18f784854 _dispatch_async_redirect_invoke + 592
20 libdispatch.dylib              0x18f79293c _dispatch_root_queue_drain + 356
21 libdispatch.dylib              0x18f793120 _dispatch_worker_thread2 + 116
22 libsystem_pthread.dylib        0x1db63d7d8 _pthread_wqthread + 216
23 libsystem_pthread.dylib        0x1db64476c start_wqthread + 8

Another log:

Fatal Exception: NSInvalidArgumentException
0  CoreFoundation                 0x184d8986c __exceptionPreprocess
1  libobjc.A.dylib                0x199da4c50 objc_exception_throw
2  CoreFoundation                 0x184c9095c -[NSOrderedSet initWithSet:copyItems:]
3  CoreFoundation                 0x184d8c438 ___forwarding___
4  CoreFoundation                 0x184d8e740 _CF_forwarding_prep_0
5  clientApp-ios                  0x1031ceb60 type metadata accessor for UrlBuilder (<compiler-generated>)
6  clientApp-ios                  0x1031ce260 type metadata accessor for UrlBuilder (<compiler-generated>)
7  clientApp-ios                  0x1031d2624 type metadata accessor for UrlBuilder (<compiler-generated>)
8  clientApp-ios                  0x1031d2408 type metadata accessor for UrlBuilder (<compiler-generated>)
9  Foundation                     0x1860d8850 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__
10 Foundation                     0x185fc5740 -[NSBlockOperation main]
11 Foundation                     0x1860daca4 __NSOPERATION_IS_INVOKING_MAIN__
12 Foundation                     0x185fc53c8 -[NSOperation start]
13 Foundation                     0x1860db74c __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__
14 Foundation                     0x1860db1d4 __NSOQSchedule_f
15 libdispatch.dylib              0x18498bfb8 _dispatch_block_async_invoke2
16 libdispatch.dylib              0x18497ddb0 _dispatch_client_callout
17 libdispatch.dylib              0x18498112c _dispatch_continuation_pop
18 libdispatch.dylib              0x184980854 _dispatch_async_redirect_invoke
19 libdispatch.dylib              0x18498e93c _dispatch_root_queue_drain
20 libdispatch.dylib              0x18498f120 _dispatch_worker_thread2
21 libsystem_pthread.dylib        0x1d08397d8 _pthread_wqthread
22 libsystem_pthread.dylib        0x1d084076c start_wqthread
0 Answers
Related