Help interpreting crash report, is KVO involved?

I'm getting occasional crashes, which have not happened while running under a debugger and I haven't figured out how to reproduce. I wonder if anyone can help me glean more information from a crash report. Here's the main part. This particular report if from macOS 14.2 beta, but I've also seen it from 14.1.1.

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000000000018
Exception Codes:       0x0000000000000001, 0x0000000000000018

VM Region Info: 0x18 is not in any region.  Bytes before following region: 140723250839528
      REGION TYPE                    START - END         [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      UNUSED SPACE AT START
--->  
      mapped file              7ffcaf60c000-7ffcd7f48000 [649.2M] r-x/r-x SM=COW  ...t_id=b7394f27

Error Formulating Crash Report:
PC register does not match crashing frame (0x0 vs 0x1022A3630)

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   <translation info unavailable>	       0x1022a3630 ???
1   libsystem_platform.dylib      	    0x7ff819d0b393 _sigtramp + 51
2   AppKit                        	    0x7ff81d3549a6 -[NSControl _setWindow:] + 59
3   AppKit                        	    0x7ff81d413c19 -[NSSegmentedControl _setWindow:] + 42
4   AppKit                        	    0x7ff81defd3be __21-[NSView _setWindow:]_block_invoke.391 + 324
5   AppKit                        	    0x7ff81d33a62c -[NSView _setWindow:] + 1886
6   AppKit                        	    0x7ff81defd3be __21-[NSView _setWindow:]_block_invoke.391 + 324
7   AppKit                        	    0x7ff81d33a62c -[NSView _setWindow:] + 1886
8   AppKit                        	    0x7ff81d572d08 -[NSWindow dealloc] + 922
9   MyApp	                            0x1011b6b81 -[JWWindow dealloc] (in MyApp) (JWWindow.m:37)
10  Foundation                    	    0x7ff81b3d179c _NSKVOPerformWithDeallocatingObservable + 151
11  Foundation                    	    0x7ff81acc6d54 NSKVODeallocate + 150
12  libobjc.A.dylib               	    0x7ff8199189d7 AutoreleasePoolPage::releaseUntil(objc_object**) + 169
13  libobjc.A.dylib               	    0x7ff819915cf0 objc_autoreleasePoolPop + 235
14  CoreFoundation                	    0x7ff819d794a1 _CFAutoreleasePoolPop + 22
15  Foundation                    	    0x7ff81ac869ea -[NSAutoreleasePool drain] + 133
16  AppKit                        	    0x7ff81d315694 -[NSApplication run] + 653
17  AppKit                        	    0x7ff81d2e9662 NSApplicationMain + 816
18  MyApp                               0x100ef5034 start (in MyApp) + 52

I can see that it involves deallocating a window as part of draining an autorelease pool, but does the presence of _NSKVOPerformWithDeallocatingObservable mean that KVO is involved somehow? And does the note "PC register does not match crashing frame" tell me anything?

Replies

The full crash report would be helpful here. At first glance, it doesn't look like KVO is directly involved in this crash - I'd expect the top of the stack trace to be closer to _NSKVOPerformWithDeallocatingObservable if it were. I suspect bad memory management of the NSControl in frame 2 or an object associated with that NSControl.

Next step would be to run your app under the Zombies Instrument or Address Sanitizer. Sometimes those environments can tease out a memory management crash that is otherwise difficult to reproduce.

And does the note "PC register does not match crashing frame" tell me anything?

Does your application include a 3rd party crash reporter?

I tried to add the full crash report, but the forum software won't let me, I guess it's too long. I've added as much as I could.

I usually debug using Address Sanitizer, and that hasn't helped me in this case. I tried launching in Terminal with NSZombieEnabled=1, is that pretty much the same as using the Zombies instrument?

Does your application include a 3rd party crash reporter?

Depends on what you mean. I have a helper that watches to see if my app crashes, and if so offers to send me the report. But it doesn't do any funny business to create its own crash report, it just looks for the one written by Apple.

Process:               MyApp 4.2 [903]
Path:                  /Users/USER/*/MyApp 4.2.app/Contents/MacOS/MyApp 4.2
Identifier:            com.myapp.myapp
Version:               4.2.0.2 (4.2.0.2)
Code Type:             X86-64 (Translated)
Parent Process:        launchd [1]
User ID:               501

Date/Time:             2023-11-19 15:02:56.8986 -0800
OS Version:            macOS 14.2 (23C5047e)
Report Version:        12
Anonymous UUID:        E2250852-79B5-CFB8-A8CE-C60A82A41C40

Time Awake Since Boot: 180 seconds

System Integrity Protection: enabled

Notes:
PC register does not match crashing frame (0x0 vs 0x1022A3630)

Crashed Thread:        0  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000000000018
Exception Codes:       0x0000000000000001, 0x0000000000000018

VM Region Info: 0x18 is not in any region.  Bytes before following region: 140723250839528
      REGION TYPE                    START - END         [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      UNUSED SPACE AT START
--->  
      mapped file              7ffcaf60c000-7ffcd7f48000 [649.2M] r-x/r-x SM=COW  ...t_id=b7394f27

Error Formulating Crash Report:
PC register does not match crashing frame (0x0 vs 0x1022A3630)

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   <translation info unavailable>	       0x1022a3630 ???
1   libsystem_platform.dylib      	    0x7ff819d0b393 _sigtramp + 51
2   AppKit                        	    0x7ff81d3549a6 -[NSControl _setWindow:] + 59
3   AppKit                        	    0x7ff81d413c19 -[NSSegmentedControl _setWindow:] + 42
4   AppKit                        	    0x7ff81defd3be __21-[NSView _setWindow:]_block_invoke.391 + 324
5   AppKit                        	    0x7ff81d33a62c -[NSView _setWindow:] + 1886
6   AppKit                        	    0x7ff81defd3be __21-[NSView _setWindow:]_block_invoke.391 + 324
7   AppKit                        	    0x7ff81d33a62c -[NSView _setWindow:] + 1886
8   AppKit                        	    0x7ff81d572d08 -[NSWindow dealloc] + 922
9   MyApp 4.2	       0x1011b6b81 0x100ef3000 + 2898817
10  Foundation                    	    0x7ff81b3d179c _NSKVOPerformWithDeallocatingObservable + 151
11  Foundation                    	    0x7ff81acc6d54 NSKVODeallocate + 150
12  libobjc.A.dylib               	    0x7ff8199189d7 AutoreleasePoolPage::releaseUntil(objc_object**) + 169
13  libobjc.A.dylib               	    0x7ff819915cf0 objc_autoreleasePoolPop + 235
14  CoreFoundation                	    0x7ff819d794a1 _CFAutoreleasePoolPop + 22
15  Foundation                    	    0x7ff81ac869ea -[NSAutoreleasePool drain] + 133
16  AppKit                        	    0x7ff81d315694 -[NSApplication run] + 653
17  AppKit                        	    0x7ff81d2e9662 NSApplicationMain + 816
18  MyApp 4.2	       0x100ef5034 0x100ef3000 + 8244

Thread 1:: com.apple.rosetta.exceptionserver
0   runtime                       	    0x7ff7fff10294 0x7ff7fff0c000 + 17044

Thread 2:
0   runtime                       	    0x7ff7fff2e94c 0x7ff7fff0c000 + 141644

Thread 3:: com.apple.NSURLConnectionLoader
0   ???                           	    0x7ff8aa25ea78 ???
1   libsystem_kernel.dylib        	    0x7ff819c9da0e mach_msg2_trap + 10
2   libsystem_kernel.dylib        	    0x7ff819cabe1a mach_msg2_internal + 84
3   libsystem_kernel.dylib        	    0x7ff819ca4b42 mach_msg_overwrite + 653
4   libsystem_kernel.dylib        	    0x7ff819c9dcff mach_msg + 19
5   CoreFoundation                	    0x7ff819db8b19 __CFRunLoopServiceMachPort + 143
6   CoreFoundation                	    0x7ff819db758c __CFRunLoopRun + 1371
7   CoreFoundation                	    0x7ff819db6a69 CFRunLoopRunSpecific + 557
8   CFNetwork                     	    0x7ff81f05add9 0x7ff81ee13000 + 2391513
9   Foundation                    	    0x7ff81acab78c __NSThread__start__ + 1013
10  libsystem_pthread.dylib       	    0x7ff819cdd202 _pthread_start + 99
11  libsystem_pthread.dylib       	    0x7ff819cd8bab thread_start + 15

Thread 4:: com.apple.CFSocket.private
0   ???                           	    0x7ff8aa25ea78 ???
1   libsystem_kernel.dylib        	    0x7ff819ca68fe __select + 10
2   CoreFoundation                	    0x7ff819de067f __CFSocketManager + 637
3   libsystem_pthread.dylib       	    0x7ff819cdd202 _pthread_start + 99
4   libsystem_pthread.dylib       	    0x7ff819cd8bab thread_start + 15

Thread 5:: com.apple.NSEventThread
0   ???                           	    0x7ff8aa25ea78 ???
1   libsystem_kernel.dylib        	    0x7ff819c9da0e mach_msg2_trap + 10
2   libsystem_kernel.dylib        	    0x7ff819cabe1a mach_msg2_internal + 84
3   libsystem_kernel.dylib        	    0x7ff819ca4b42 mach_msg_overwrite + 653
4   libsystem_kernel.dylib        	    0x7ff819c9dcff mach_msg + 19
5   CoreFoundation                	    0x7ff819db8b19 __CFRunLoopServiceMachPort + 143
6   CoreFoundation                	    0x7ff819db758c __CFRunLoopRun + 1371
7   CoreFoundation                	    0x7ff819db6a69 CFRunLoopRunSpecific + 557
8   AppKit                        	    0x7ff81d48176c _NSEventThread + 122
9   libsystem_pthread.dylib       	    0x7ff819cdd202 _pthread_start + 99
10  libsystem_pthread.dylib       	    0x7ff819cd8bab thread_start + 15

Thread 6:: engine.unload-texture
0   ???                           	    0x7ff8aa25ea78 ???
1   libsystem_kernel.dylib        	    0x7ff819ca05ae __psynch_cvwait + 10
2   libsystem_pthread.dylib       	    0x7ff819cdd76b _pthread_cond_wait + 1211
3   libc++.1.dylib                	    0x7ff819c153c2 std::__1::condition_variable::wait(std::__1::unique_lock<std::__1::mutex>&) + 18
4   SBEngineLib4                  	       0x10b8315f0 WorkerThreadLoop() + 81
5   SBEngineLib4                  	       0x10b83208d void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (*)()>>(void*) + 36
6   libsystem_pthread.dylib       	    0x7ff819cdd202 _pthread_start + 99
7   libsystem_pthread.dylib       	    0x7ff819cd8bab thread_start + 15

Thread 0 crashed with X86 Thread State (64-bit):
  rax: 0x00007fb73664b360  rbx: 0x00007fb7860aa5f0  rcx: 0x00007fb7860aa5f0  rdx: 0x0000000000000000

I tried to add the full crash report, but the forum software won't let me

Did you try adding it as a text attachment? See Posting a Crash Report for the specifics.

This crash report is coming from Rosetta. Is that expected?

Share and Enjoy

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

Did you try adding it as a text attachment? See Posting a Crash Report for the specifics.

No, didn't think of that...

This crash report is coming from Rosetta. Is that expected?

Yes, the app is x86_64 only. Performance on Apple Silicon seems fine, so updating that hasn't seemed like a priority.

The crash report points to -[NSControl _setWindow:] as the location of the crash. Specifically, the implementation of -[NSControl _setWindow:] calls self.window to get the current window, and then calls self.currentEditor to get the current field editor. The crash is occurring on the call to self.currentEditor. Because the immediately prior call to self.window did not crash, this suggests:

  1. A race condition. The NSControl was deallocated on a background thread between the calls to self.window and self.currentEditor.

  2. The crash actually occurred further down (up) the stack from -[NSControl _setWindow:], but part of the backtrace was truncated. Typically we would expect to see objc_msgSend at the top of the stack trace when a crash occurs due to messaging a deallocated object. The _sigtramp in the stack trace suggests that some code in your app process was trying to handle the SIGSEGV signal - either code you wrote, or a third party crash reporter package.

The _sigtramp in the stack trace suggests that some code in your app process was trying to handle the SIGSEGV signal - either code you wrote, or a third party crash reporter package.

You're right, I do have a sigaction handler, which writes to a file and then attempts to re-send the signal as follows:

signal( inSignal, SIG_DFL ); // restore default signal handling
pthread_kill( pthread_self(), inSignal ); // re-send the signal
usleep( 10000 ); /* give time for signal to happen */

Is this kind of signal handler doomed to mess up the stack trace, or is there a more careful way I could do it?

Yes, the app is x86_64 only. Performance on Apple silicon seems fine, so updating that hasn't seemed like a priority.

I recommend that you make it a priority, for two reasons:

  • Historical experience suggests that Rosetta won’t be around forever.

  • Rosetta, while just amazing, is not perfect, especially when you stray into areas that don’t affect customers, like LLDB and Apple’s crash reporter.

You're right, I do have a sigaction handler, which writes to a file

Using async signal safe functions, right? See Implementing Your Own Crash Reporter for more on that topic.

Is this kind of signal handler doomed to mess up the stack trace, or is there a more careful way I could do it?

The only winning move is not to play. However, if you insist, remove your signal handler and just return.

static void signalHandler(int sigNum) {
    write(STDERR_FILENO, "Hello Cruel World!\n", 19);
    signal(sigNum, SIG_DFL);
}

Consider this code:

- (IBAction)testAction:(id)sender {
    #pragma unused(sender)
    NSLog(@"-[AppDelegate testAction:]");
    * (int *) 0x1234 += 1;
}

When I run it with the above signal handler installed, I see this in the crash report:

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   Test741854     0x10447722f -[AppDelegate testAction:] + 63 (AppDelegate.m:24)
1   AppKit      0x7ff8100a742c -[NSApplication(NSResponder) sendAction:to:from:] + 323
2   AppKit      0x7ff8100a72b0 -[NSControl sendAction:to:] + 86

…

Thread 0 crashed with X86 Thread State (64-bit):
  rax: 0x0000000000001234  rbx: 0x0000600002ddf9d0  rcx: 0x00007feee9009338  rdx: 0x0000000000000000
  rdi: 0x00007feee9009338  rsi: 0x00007feee9009338  rbp: 0x00007ff7bba8a930  rsp: 0x00007ff7bba8a910
   r8: 0x0000000000000155   r9: 0x0000000000000154  r10: 0x00000000000003f0  r11: 0x0000600000cea500
  r12: 0x00007ff850463f68  r13: 0x0000600000cf8460  r14: 0x00007feee7707f80  r15: 0x0000000104477b05
  rip: 0x000000010447722f  rfl: 0x0000000000010206  cr2: 0x0000000000001234

Compare with the disassembly:

(lldb) disas -n '-[AppDelegate testAction:]'
Test741854`-[AppDelegate testAction:]:
Test741854[0x1000031f0] <+0>:  pushq  %rbp
Test741854[0x1000031f1] <+1>:  movq   %rsp, %rbp
Test741854[0x1000031f4] <+4>:  subq   $0x20, %rsp
Test741854[0x1000031f8] <+8>:  movq   %rdx, -0x20(%rbp)
Test741854[0x1000031fc] <+12>: movq   %rsi, %rax
Test741854[0x1000031ff] <+15>: movq   -0x20(%rbp), %rsi
Test741854[0x100003203] <+19>: movq   %rdi, -0x8(%rbp)
Test741854[0x100003207] <+23>: movq   %rax, -0x10(%rbp)
Test741854[0x10000320b] <+27>: movq   $0x0, -0x18(%rbp)
Test741854[0x100003213] <+35>: leaq   -0x18(%rbp), %rdi
Test741854[0x100003217] <+39>: callq  0x10000329a               ; symbol stub for: objc_storeStrong
Test741854[0x10000321c] <+44>: leaq   0xe2d(%rip), %rdi         ; @"-[AppDelegate testAction:]"
Test741854[0x100003223] <+51>: movb   $0x0, %al
Test741854[0x100003225] <+53>: callq  0x10000328e               ; symbol stub for: NSLog
Test741854[0x10000322a] <+58>: movl   $0x1234, %eax             ; imm = 0x1234 
Test741854[0x10000322f] <+63>: movl   (%rax), %ecx

Note how +63 is the crashing instruction and rax still contains 0x1234.

Share and Enjoy

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

Thanks for the hints on simplifying my signal handler, but it looks like the unpleasantness at the top of the stack trace is just an artifact of Rosetta. The trace is cleaner on Intel.

@Justin said:

Typically we would expect to see objc_msgSend at the top of the stack trace when a crash occurs due to messaging a deallocated object.

Since I originally wrote this post, I updated my app to be universal, and I'm still getting these crash reports. Here's the start of the backtrace, now showing objc_msgSend:

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   libobjc.A.dylib               	       0x19f716290 lookUpImpOrForward + 72
1   libobjc.A.dylib               	       0x19f715f64 _objc_msgSend_uncached + 68
2   AppKit                        	       0x1a3453e54 -[NSControl currentEditor] + 56
3   AppKit                        	       0x1a344ba14 -[NSControl _setWindow:] + 48
4   AppKit                        	       0x1a34ee160 -[NSSegmentedControl _setWindow:] + 52
5   AppKit                        	       0x1a3ebbeb4 __21-[NSView _setWindow:]_block_invoke.146 + 268
6   AppKit                        	       0x1a34344a4 -[NSView _setWindow:] + 1780
7   AppKit                        	       0x1a3ebbeb4 __21-[NSView _setWindow:]_block_invoke.146 + 268
8   AppKit                        	       0x1a34344a4 -[NSView _setWindow:] + 1780
9   AppKit                        	       0x1a3618a70 -[NSWindow dealloc] + 684

A full crash report: