I got a crash log on iPad mini2 with os_unfair_lock_lock

I have an app which is Live on Appstore and has several daily active users. Recently a user reported consistent crash at random sports on her device. After communicating with the user, I got that the crash from her iPad mini 2 with iOS 12.4.8 and the stack trace has following information:

After symbolicate the log:
Thread 0 name:  Dispatch queue: org.reactivecocoa.ReactiveObjC.RACScheduler.mainThreadScheduler
Thread 0 Crashed:
0   libsystem_platform.dylib      	0x0000000194547258 os_unfair_lock_lock$VARIANT$mp (in libsystem_platform.dylib) + 24
1   CoreFoundation                	0x0000000194903190 __CFGetConverter (in CoreFoundation) + 92
2   CoreFoundation                	0x0000000194902960 CFStringEncodingUnicodeToBytes (in CoreFoundation) + 180
3   CoreFoundation                	0x0000000194905d78 __CFStringEncodeByteStream (in CoreFoundation) + 1604
4   Foundation                    	0x00000001952953d4 -[NSString(NSStringOtherEncodings) getBytes:maxLength:usedLength:encoding:options:range:remainingRange:] (in Foundation) + 248
5   CoreFoundation                	0x000000019482de84 -[NSTaggedPointerString getBytes:maxLength:usedLength:encoding:options:range:remainingRange:] (in CoreFoundation) + 120
6   CoreFoundation                	0x00000001948eb958 CFStringGetBytes (in CoreFoundation) + 144
7   Foundation                    	0x00000001954415ac _convertJSONString (in Foundation) + 416
8   Foundation                    	0x000000019544074c _writeJSONString (in Foundation) + 92
9   Foundation                    	0x00000001954418e0 ___writeJSONObject_block_invoke (in Foundation) + 80
10  libswiftCore.dylib            	0x00000001c1f199f0 specialized _SwiftDeferredNSDictionary.enumerateKeysAndObjects(options:using:) (in libswiftCore.dylib) + 852
11  libswiftCore.dylib            	0x00000001c1d6776c @objc _SwiftDeferredNSDictionary.enumerateKeysAndObjects(options:using:) (in libswiftCore.dylib) + 44
12  Foundation                    	0x0000000195440f20 _writeJSONObject (in Foundation) + 384
13  Foundation                    	0x0000000195441b84 ___writeJSONArray_block_invoke (in Foundation) + 156
14  CoreFoundation                	0x0000000194919944 __NSArrayEnumerate (in CoreFoundation) + 412
15  Foundation                    	0x000000019544133c _writeJSONArray (in Foundation) + 288
16  Foundation                    	0x00000001952fd58c -[_NSJSONWriter dataWithRootObject:options:error:] (in Foundation) + 140
17  Foundation                    	0x00000001952fd2b4 +[NSJSONSerialization dataWithJSONObject:options:error:] (in Foundation) + 356
18  ???                           	0x00000001035737b8 static Mapper.toJSONData(_:options:) (in --) (Mapper.swift:388)
19  ???                           	0x00000001035736a4 static Mapper.toJSONString(_:prettyPrint:) (in --) (<compiler-generated>:0)
20  ???                           	0x0000000103570e38 Mapper.toJSONString(_:prettyPrint:) (in --) (Mapper.swift:370)
21  ???                           	0x000000010356eb94 Array<A>.toJSONString(prettyPrint:) (in --) (Mappable.swift:104)

The logic is to dump an array to a file. Can anyone suggest what could be the possible issue here?

Only brainstorming here: Lock can be hold by the serialization iterator and then on other thread some other code might have tried to change the array? Iterator might have panicked. Or vice versa. Only my speculative speculation. And this is on the main thread, iOS might have considered that is not a "resolvable" lock and killed you at once. If you do read-write access to this array, try to serialize it via, e.g. the queue?

Note this:

Termination Reason: Namespace SPRINGBOARD, Code 0x8badf00d

The watchdog has terminated your app because it’s non-responsive. This suggests that os_unfair_lock_lock hasn’t crashed, per se, but rather someone else is holding on to the lock and thus it’s deadlocked.

Looking at the other backtraces in your crash report there doesn’t seem to be any obvious candidates here. The only other threads that mentioned CFNetwork in the backtrace are blocked in reasonable places, like in the run loop. This suggests that it’s not a classic deadlock, but rather than someone has failed to unlock the lock.

Investigating that requires an understanding of the scope of the lock. For that, you can look at the open source code for CF in the Swift project. Specifically, look at the __CFGetConverter function in this file.

IMPORTANT There’s no guarantee that open source code like this directly matches up with the closed source running on Apple’s platforms. Moreover, this is modern code (aligned with macOS 12 beta and hence, roughly, iOS 15.0) and your user is crashing on iOS 12. However, I took a look at the iOS 12 aligned source for this function and it’s roughly similar.

As you can see, the lock is very tightly scoped. It’s a static variable within __CFGetConverter, so only that function can modify it. And the code within that function clearly balances the locks and unlocks.

I have two theories here:

  • Someone is randomly corrupting the lock.

  • Someone has exited a previous called __CFGetConverter incorrectly, which means it didn’t get a chance to unlock.

I’m not at all confident in my first theory. Sure, it’s possible, but it seems unlikely that such a problem would have any consistency.

With regards my second theory, the most common cause of such an event in a Objective-C / [Objective-]C++ language exception. Apple’s framework are not exception safe. You can’t throw an exception across framework boundaries. If one of the functions called by __CFGetConverter threw an exception, you’d see exactly this problem.

You should work with your user to get a sysdiagnose log from the device taken shortly after the problem occurs. This will include a copy of the system log, and you can look in that log to see if there’s any evidence of such an exception.

For more info on sysdiagnose logs, see Bug Reporting > Profiles and Logs.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Is there any others log can help to analy this problem?

Yes, a sysdiagnose log as per my previous post.

Is possible the user’s iPad hardware disk or memory is broken to cause this problem?

Anything is possible, but hardware is incredibly reliable these days and so it’s always the last item on my list of things to check.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I got a crash log on iPad mini2 with os_unfair_lock_lock
 
 
Q