We use the GameSave framework to sync player save data to iCloud. Since iOS 27, our game crashes a few seconds after a cold launch, the first time it calls GameSaveSyncedDirectory.openDirectory(). We call the API only from the main actor, but the crash is on a cooperative thread inside GameSave:
EXC_BAD_ACCESS (SIGSEGV) KERN_INVALID_ADDRESS at 0x400000000000bad0
libobjc.A.dylib objc_release
CloudDocs initUIApplicationWillResignActiveNotification
CloudDocs -[BRQuery _setQueryState:]
CloudDocs -[BRQuery _runQuery]
CloudDocs -[BRQuery executeWithOptions:]
Foundation -[NSMetadataQuery startQuery]
GameSave BundleUpdatesWaiter.initMetadataQuery()
GameSave BundleUpdatesWaiter.init(bundleURL:)
GameSave closure #1 in GameSyncedDirectoryHolder.allowReaders(for:)
Other threads are inside the same BRQuery path at the same moment. The crash reproduces without GameSave: starting twoNSMetadataQuery objects at once on background threads in a fresh process crashes 94 times in 100 in the iOS 27.0 Simulator, and never on iOS 26.5, so this seems like a regression. Starting one query on a single thread never crashes.
I've submitted a support request (FB25352978) so hopefully this will be looked at fairly soon - if anyone else runs into this it would be good to know!
Hey hey, you’ve done well so far!
so I'm not sure what the fix proccess/timeline looks like for something like this?
Unfortunately it’s hard to offer predictions here. Sometimes bugs like this get fixed in the next software update, sometimes they lurk for (literally, and sadly) decades.
Yeah, I think that’ll work, for reasons that should be obvious once I fill in some details about what’s crashing.
Thanks for the crash report.
In that report we see that the crashing thread’s backtrace looks like this:
Thread 5 Crashed:
0 libobjc.A.dylib … objc_release + 8
1 CloudDocs … initUIApplicationWillResignActiveNotification + 52
2 CloudDocs … -[BRQuery _setQueryState:] + 356
This is doing what’s called a soft link [1]. It’s a technique used by Apple frameworks to resolve layering loops. In this case, CloudDocs [2] depends on Foundation but NSMetadataQuery, which exists within Foundation, depends on CloudDocs. This soft link resolves the issue by having Foundation load CloudDocs at runtime, using dlopen and dlsym.
With that in mind, check out the backtrace of thread 12:
Thread 12:
0 dyld_sim … mach_o::GenericTrie::find(CString, bool) const + 388
1 dyld_sim … mach_o::ExportsTrie::hasExportedSymbol(CString, mach_o::Symbol&, bool) const + 44
2 dyld_sim … dyld4::Loader::hasExportedSymbol(…) const + 624
3 dyld_sim … dyld4::Loader::hasExportedSymbol(…) const + 1024
4 dyld_sim … dyld4::Loader::hasExportedSymbol(…) const + 1024
5 dyld_sim … dyld4::Loader::hasExportedSymbol(…) const + 1024
6 dyld_sim … dyld4::Loader::hasExportedSymbol(…) const + 1024
7 dyld_sim … dyld4::Loader::hasExportedSymbol(…) const + 1024
8 dyld_sim … dyld4::Loader::hasExportedSymbol(…) const + 1024
9 dyld_sim … dyld4::Loader::hasExportedSymbol(…) const + 1024
10 dyld_sim … dyld4::APIs::dlsym(void*, char const*) + 1116
11 CloudDocs … initUIApplicationDidBecomeActiveNotification + 28
12 CloudDocs … -[BRQuery _setQueryState:] + 408
It’s actively working within the dynamic linker to resolve this soft link. So it seems that you have two threads, 5 and 12, doing the same work without any serialisation, and hence this crash.
As I said, this is our bug to fix.
And it also speaks to your workaround. By running a single NSMetadataQuery request in a serialised fashion, there’s only one thread attempting to resolve the soft link at a time. That resolution is then cached, and so subsequent requests use the cached value and don’t collide with each other.
The only mystery here is how this worked prior to iOS 27. I looked at the code and I didn’t see any obvious changes, so I just don’t have an answer to that. Fortunately, I don’t think I need one, because we have a clear bug report and a workaround, and that means my work here is done (-:
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
[1] This isn’t a term I’ve seen used a lot of outside of Apple. Do not confuse it with a weak link. That’s a different concept entirely. Well, actually, it’s two different concepts. See An Apple Library Primer for more on that topic.
[2] This is a private framework but it’s not hard to guess what it does (-: