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
.
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 forNKLibrary
. 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 anNSURLRequest
, and the frames leading up to the crash frame, frame 0, is the usualNSURLRequest
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 withinNSURLRequest
.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:
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 anNSURLRequest
.They updated to 11.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.