iosnewsstand-kit

NKLibrary crashing on init in iOS 11.3


We still have some old NewsstandKit code that hasn't been updated in a few years.

For some reason, the version of our app that has been in the store since 2017 is now getting a flurry of crashes with iOS 11.3, seemingly caused when we call [NKLibrary sharedLibrary] for the first time at app launch.

The stacktraces point to a network call deep in NewsstandKit.

Crashed: com.apple.main-thread
EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x0000000000000000

Crashed: com.apple.main-thread
0  CoreFoundation                 0x1810b63d4 CFBooleanGetValue + 80
1  CFNetwork                      0x181823944 URLRequest::initialize(long, void const**, long, __CFDictionary const*) + 328
2  CFNetwork                      0x1817d7298 _CFURLRequestCreateFromArchiveList + 136
3  CFNetwork                      0x18195bfd4 -[NSURLRequest initWithCoder:] + 1660
4  Foundation                     0x181ba01e8 _decodeObjectBinary + 1720
5  Foundation                     0x181b9fa88 _decodeObject + 308
6  Foundation                     0x181b2e8bc -[NSKeyedUnarchiver decodeObjectOfClasses:forKey:] + 432
7  NewsstandKit                   0x1a24031a4 -[NKAssetDownload initWithCoder:] + 216
8  Foundation                     0x181ba01e8 _decodeObjectBinary + 1720
9  Foundation                     0x181b4d010 -[NSKeyedUnarchiver _decodeArrayOfObjectsForKey:] + 1388
10 Foundation                     0x181b53c54 -[NSArray(NSArray) initWithCoder:] + 220
11 Foundation                     0x181ba01e8 _decodeObjectBinary + 1720
12 Foundation                     0x181b9fa88 _decodeObject + 308
13 Foundation                     0x181b2e8bc -[NSKeyedUnarchiver decodeObjectOfClasses:forKey:] + 432
14 NewsstandKit                   0x1a2401a08 -[NKIssue initWithCoder:] + 316
15 Foundation                     0x181ba01e8 _decodeObjectBinary + 1720
16 Foundation                     0x181b4d010 -[NSKeyedUnarchiver _decodeArrayOfObjectsForKey:] + 1388
17 Foundation                     0x181b53c54 -[NSArray(NSArray) initWithCoder:] + 220
18 Foundation                     0x181ba01e8 _decodeObjectBinary + 1720
19 Foundation                     0x181b4d010 -[NSKeyedUnarchiver _decodeArrayOfObjectsForKey:] + 1388
20 Foundation                     0x181b4d340 -[NSDictionary(NSDictionary) initWithCoder:] + 224
21 Foundation                     0x181ba01e8 _decodeObjectBinary + 1720
22 Foundation                     0x181b9fa88 _decodeObject + 308
23 Foundation                     0x181b2e8bc -[NSKeyedUnarchiver decodeObjectOfClasses:forKey:] + 432
24 Foundation                     0x181bcac84 -[NSCoder(Exceptions) __tryDecodeObjectForKey:error:decodeBlock:] + 80
25 Foundation                     0x181bca9e4 -[NSCoder decodeTopLevelObjectOfClasses:forKey:error:] + 92
26 Foundation                     0x181c088e4 +[NSKeyedUnarchiver(NSKeyedUnarchiverSecureCodingInitializers) unarchivedObjectOfClasses:fromData:error:] + 140
27 NewsstandKit                   0x1a240042c -[NKLibrary _load] + 272
28 NewsstandKit                   0x1a23fe8b8 -[NKLibrary init] + 568
29 NewsstandKit                   0x1a23fe628 __26+[NKLibrary sharedLibrary]_block_invoke + 92
30 libdispatch.dylib              0x180ae0ae4 _dispatch_client_callout + 16
31 libdispatch.dylib              0x180ae42ec dispatch_once_f$VARIANT$mp + 60
32 NewsstandKit                   0x1a23fe5c8 +[NKLibrary sharedLibrary] + 112
33 MY_APP                         0x1007d29e4 -[MYAPPCLASS MYAPPMETHOD] (MYFILE.m:90)

Line 33 is the point where we call [NKLibrary sharedLibrary].currentlyReadingIssue, and that's all the info we're getting right now. This appears to be happening just after app launch but there's no info if this is triggered in background or foreground.

Just curious if anyone else has seen this? My only thought is that we need to remove NewsstandKit.


Solution

  • I contacted Apple developer technical support about this. I received a very complete response.

    My understanding is:

    Apple's response, lightly edited for markup:

    I grabbed on of the crash reports from your bug (2018-04-12_08-08-18.4485_+0100-41f4ffc57b5f5e16c05c0baaa6a426ff9321cdb5.crash) and took an in-depth look. To start, here’s an edited version of the crash backtrace:

    Frame 37 is dispatch calling out to your code.
    Frames 36 through 34 is your code starting up Newsstand Kit.
    Frames 33 through 30 is +[NKLibrary sharedLibrary] doing the singleton thing.
    Frames 29 and 28 are the initialiser for NKLibrary. This clearly does the bulk of its work by unarchiving a keyed archive (frames 27 through 5).
    Finally, frame 4 indicates that one of the objects in the library is an NSURLRequest, and the frames leading up to the crash frame, frame 0, is the usual NSURLRequest decoding logic.

    Based on the above I started investigating how NKLibrary handles its archiving and unarchiving. While do that I stumbled across what I think is the underlying cause of this bug, namely that in 11.3 we updated Newsstand Kit to use secure coding for its library 34837823>. This is a good thing in general, but it seems to have exposed a latent problem in the secure coding support within NSURLRequest.

    Consider the attached test project (Test39132525). It has two buttons:

    • Save Insecure creates a simple keyed archive containing an NSURLRequest.

    • Load Secure tries to load that using a secure coder.

    If you run it in the obvious way (run, save, load) it crashes with a backtrace like this:

    Thread 6 Crashed:
    0  … CFBooleanGetValue + 80 (CFInternal.h:713)
    …
    4  … -[NSURLRequest initWithCoder:] + 1660 (NSURLRequest.mm:280)
    5  … _decodeObjectBinary + 1720 (NSKeyedArchiver.m:2391)
    …
    27 … +[NSKeyedUnarchiver(NSKeyedUnarchiverSecureCodingInitializers) unarch…
    28 … -[NKLibrary _load] + 272 (NKLibrary.m:470)
    29 … -[NKLibrary init] + 568 (NKLibrary.m:108)
    30 … __26+[NKLibrary sharedLibrary]_block_invoke + 92 (NKLibrary.m:75)
    31 … _dispatch_client_callout + 16 (object.m:507)
    32 … dispatch_once_f$VARIANT$mp + 60 (once.c:63)
    33 … +[NKLibrary sharedLibrary] + 112 (once.h:84)
    34 … static NewsstandUtilities.allIssues() + 36 (NewsstandUtilities.swift:…
    35 … closure #1 in static NewsstandIOUtility.deleteAllLegacyImagesFromExis…
    36 … thunk for @callee_owned () -> () + 36 (WelcomeViewController.swift:0)
    37 … _dispatch_call_block_and_release + 24 (init.c:994)
    …
    

    That looks very familiar, eh?

    I believe that this is what’s happening to your users:

    1. They were running your app on 11.2.6 and had an active asset with an active download. The result was that NKLibrary saved an insecure keyed archive containing an NSURLRequest.

    2. They updated to 11.3.

    3. NKLibrary tried to load its archive securely, which crashes.

    Most users don’t see this because they have no active downloads in 11.2.6, and thus the keyed archive doesn’t contain an NSURLRequest.

    I’ve asked CFNetwork engineering to see if they can get this fixed sooner rather than later. Depending on how that conversation pans out, I may or may not have a chat with the Newsstand Kit folks to see what they think about a potential workaround.