Crash reports downloaded by Xcode contain impossible call hierarchy

I was just having a look at some crash reports downloaded by Xcode, and I noticed the same wrong pattern I already mentioned here: the crash reports indicate that method A calls method B, which is impossible.

In the first crash report below, method MainViewController.showSettings seems to be called by ConfirmMoveViewController.openSourceInFinder, which is impossible. ConfirmMoveViewController.openSourceInFinder is a context menu action in a modal window, and MainViewController.showSettings is in a completely different window and the two methods have no relation whatsoever.

In the second crash report below, MainViewController.setSortMode is triggered by the press of a button (and nothing else) but seems to be called by OtherViewController.copy that can be triggered by a context menu (or keyboard shortcut). The two methods have no relation whatsoever. The rest of the stack trace confirm that it's indeed the button that was pressed.

This seems to me like a quite serious bug in how macOS creates crash reports.

Process:               MyApp [797]
Path:                  /Applications/MyApp.app/Contents/MacOS/MyApp
Identifier:            com.example.myApp
Version:               5.0.4 (169)
App Item ID:           590386474
App External ID:       872883629
Code Type:             ARM-64
Parent Process:        launchd [1]
User ID:               501

Date/Time:             2025-03-08 13:52:07.7618 +0100
OS Version:            macOS 15.3.1 (24D70)
Report Version:        12
Anonymous UUID:        DA57E911-95FD-DA7E-7015-D6F1C3A94DB0


Time Awake Since Boot: 1600 seconds

System Integrity Protection: enabled

Crashed Thread:        0

Exception Type:        EXC_BREAKPOINT (SIGTRAP)
Exception Codes:       0x0000000000000001, 0x0000000100bfbe84

Termination Reason:    Namespace SIGNAL, Code 5 Trace/BPT trap: 5
Terminating Process:   exc handler [797]

Thread 0 Crashed:
0   MyApp                         	0x0000000100bfbe84 closure #1 in MainViewController.activeItem.getter + 192 (/:0)
1   MyApp                         	0x0000000100c03744 specialized Optional.map(_:) + 36 (MainViewController.swift:333)
2   MyApp                         	0x0000000100bf81d0 specialized Optional.map(_:) + 24 (MainViewController.swift:333)
3   MyApp                         	0x0000000100bf81d0 MainViewController.activeItem.getter + 24 (/:0)
4   MyApp                         	0x0000000100bf81d0 MainViewController.showSettings(_:) + 452
5   MyApp                         	0x0000000100ba2530 @objc ConfirmMoveViewController.openSourceInFinder(_:) + 80
6   AppKit                        	0x0000000199953454 -[NSApplication(NSResponder) sendAction:to:from:] + 460 (appEventRouting.m:2058)
7   AppKit                        	0x0000000199953258 -[NSControl sendAction:to:] + 72 (NSControl.m:1452)
8   AppKit                        	0x0000000199a5274c -[NSTableView _sendAction:to:row:column:] + 116 (NSTableView.m:8978)
9   AppKit                        	0x0000000199a50f80 -[NSTableView mouseDown:] + 4068 (NSTableView.m:11141)
10  AppKit                        	0x0000000199948564 forwardMethod + 252 (NSResponder.m:929)
11  AppKit                        	0x000000019994e0f0 -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] + 3672 (winEventRouting.m:983)
12  AppKit                        	0x00000001998d96f8 -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 384 (winEventRouting.m:379)
13  AppKit                        	0x00000001998d93a8 -[NSWindow(NSEventRouting) sendEvent:] + 284 (winEventRouting.m:251)
14  AppKit                        	0x000000019a117a08 -[NSApplication(NSEventRouting) sendEvent:] + 1656 (appEventRouting.m:0)
15  AppKit                        	0x0000000199d1eb04 -[NSApplication _handleEvent:] + 60 (NSApplication.m:3564)
16  AppKit                        	0x00000001997a589c -[NSApplication run] + 520 (NSApplication.m:3656)
17  AppKit                        	0x000000019977c068 NSApplicationMain + 888 (NSApplication.m:10523)
18  MyApp                         	0x0000000100b5f05c main + 128 (main.swift:12)
19  dyld                          	0x00000001957d4274 start + 2840 (dyldMain.cpp:1338)

Thread 1:
0   libsystem_kernel.dylib        	0x0000000195b12f54 mach_msg2_trap + 8 (:-1)
1   libsystem_kernel.dylib        	0x0000000195b25604 mach_msg2_internal + 80 (mach_msg.c:201)
2   libsystem_kernel.dylib        	0x0000000195b1baf8 mach_msg_overwrite + 480 (mach_msg.c:0)
3   libsystem_kernel.dylib        	0x0000000195b1329c mach_msg + 24 (mach_msg.c:323)
4   CoreFoundation                	0x0000000195c3ca4c __CFRunLoopServiceMachPort + 160 (CFRunLoop.c:2637)
5   CoreFoundation                	0x0000000195c3b2ac __CFRunLoopRun + 1212 (CFRunLoop.c:3021)
6   CoreFoundation                	0x0000000195c3a734 CFRunLoopRunSpecific + 588 (CFRunLoop.c:3434)
7   AppKit                        	0x00000001998d7278 _NSEventThread + 148 (NSEvent.m:5695)
8   libsystem_pthread.dylib       	0x0000000195b542e4 _pthread_start + 136 (pthread.c:931)
9   libsystem_pthread.dylib       	0x0000000195b4f0fc thread_start + 8 (:-1)

Thread 2:
0   libsystem_kernel.dylib        	0x0000000195b12ed0 semaphore_wait_trap + 8 (:-1)
1   caulk                         	0x00000001a0c7fff4 caulk::semaphore::timed_wait(double) + 220 (semaphore.cpp:98)
2   caulk                         	0x00000001a0c7fea0 caulk::concurrent::details::worker_thread::run() + 36 (messenger.cpp:236)
3   caulk                         	0x00000001a0c7fb74 void* caulk::thread_proxy>>(void*) + 96 (thread.h:197)
4   libsystem_pthread.dylib       	0x0000000195b542e4 _pthread_start + 136 (pthread.c:931)
5   libsystem_pthread.dylib       	0x0000000195b4f0fc thread_start + 8 (:-1)

Thread 3:
0   libsystem_kernel.dylib        	0x0000000195b12ed0 semaphore_wait_trap + 8 (:-1)
1   caulk                         	0x00000001a0c7fff4 caulk::semaphore::timed_wait(double) + 220 (semaphore.cpp:98)
2   caulk                         	0x00000001a0c7fea0 caulk::concurrent::details::worker_thread::run() + 36 (messenger.cpp:236)
3   caulk                         	0x00000001a0c7fb74 void* caulk::thread_proxy>>(void*) + 96 (thread.h:197)
4   libsystem_pthread.dylib       	0x0000000195b542e4 _pthread_start + 136 (pthread.c:931)
5   libsystem_pthread.dylib       	0x0000000195b4f0fc thread_start + 8 (:-1)

Thread 4:
0   libsystem_kernel.dylib        	0x0000000195b12ed0 semaphore_wait_trap + 8 (:-1)
1   caulk                         	0x00000001a0c7fff4 caulk::semaphore::timed_wait(double) + 220 (semaphore.cpp:98)
2   caulk                         	0x00000001a0c7fea0 caulk::concurrent::details::worker_thread::run() + 36 (messenger.cpp:236)
3   caulk                         	0x00000001a0c7fb74 void* caulk::thread_proxy>>(void*) + 96 (thread.h:197)
4   libsystem_pthread.dylib       	0x0000000195b542e4 _pthread_start + 136 (pthread.c:931)
5   libsystem_pthread.dylib       	0x0000000195b4f0fc thread_start + 8 (:-1)

Thread 5:
0   libsystem_pthread.dylib       	0x0000000195b4f0e8 start_wqthread + 0 (:-1)

Thread 6:
0   libsystem_pthread.dylib       	0x0000000195b4f0e8 start_wqthread + 0 (:-1)

Thread 7:
0   libsystem_pthread.dylib       	0x0000000195b4f0e8 start_wqthread + 0 (:-1)

Thread 8:
0   libsystem_pthread.dylib       	0x0000000195b4f0e8 start_wqthread + 0 (:-1)

Thread 9:
0   libsystem_pthread.dylib       	0x0000000195b4f0e8 start_wqthread + 0 (:-1)


Thread 0 crashed with ARM Thread State (64-bit):
    x0: 0x0000000000000000   x1: 0x000000016f2a2d78   x2: 0x0000000100bfbe0c   x3: 0x00006000019984c8
    x4: 0x0000000000000000   x5: 0x00000000b5a3b954   x6: 0x0000600002342a60   x7: 0x0000000000000001
    x8: 0x0000000000000005   x9: 0x0000000000000000  x10: 0x0600000100dac1bf  x11: 0x0700000100dac1bf
   x12: 0x0000000000000034  x13: 0x000000013c82c330  x14: 0x0600000100dac1bf  x15: 0x0000000100dac1b8
   x16: 0x00000001a6cc4ac0  x17: 0x5419000195787330  x18: 0x0000000000000000  x19: 0x0000000000000000
   x20: 0x000000016f2a2dc8  x21: 0x0000000000000000  x22: 0x0000000000000005  x23: 0x00006000009ac000
   x24: 0x000000016f2a2df0  x25: 0x0000600001998410  x26: 0x0000000201657f98  x27: 0x000000016f2a2e10
   x28: 0x0000000200879c48   fp: 0x000000016f2a2db0   lr: 0x8c45800100bfbe0c
    sp: 0x000000016f2a2d70   pc: 0x0000000100bfbe84 cpsr: 0x60000000
   esr: 0xf2000001 (Breakpoint) brk 1


Binary Images:
        0x100b5c000 -         0x100d8ffff MyApp (arm64)  <612FDB41-6CDC-3430-8996-DCBE072473F5> /Applications/MyApp.app/Contents/MacOS/MyApp
        0x1040d4000 -         0x1040f3fff csparser (arm64e)  <FB85321B-0FA8-3ACE-941C-ABEF6C37FF36> /System/Library/Frameworks/Security.framework/Versions/A/PlugIns/csparser.bundle/Contents/MacOS/csparser
        0x104a5c000 -         0x104a67fff libobjc-trampolines.dylib (arm64e)  <3D687E9B-E092-3632-BC1D-74B19D492DE0> /usr/lib/libobjc-trampolines.dylib
        0x1083a8000 -         0x108b0ffff AGXMetalG16G_B0 (arm64e)  <296C2F3D-1AB3-3EFC-84D7-4C428B9F4EBF> /System/Library/Extensions/AGXMetalG16G_B0.bundle/Contents/MacOS/AGXMetalG16G_B0
        0x11b018000 -         0x11b153fff CoreAudio (arm64e)  <CE006CED-EE1C-3174-BBA9-1E326231AB55> /System/Library/Components/CoreAudio.component/Contents/MacOS/CoreAudio
        0x143894000 -         0x1441ebfff AudioDSP (arm64e)  <C687F501-823B-3EB3-A35A-8F9F65C9AADA> /System/Library/Components/AudioDSP.component/Contents/MacOS/AudioDSP
        0x1957ce000 -         0x19584ff3f dyld (arm64e)  <398A133C-9BCB-317F-A064-A40D3CEA3C0F> /usr/lib/dyld
        0x195b12000 -         0x195b4cff7 libsystem_kernel.dylib (arm64e)  <EEE9D0D3-DFFC-37CB-9CED-B27CD0286D8C> /usr/lib/system/libsystem_kernel.dylib
        0x195b4d000 -         0x195b59fff libsystem_pthread.dylib (arm64e)  <642FAF7A-874E-37E6-8ABA-2B0CC09A3025> /usr/lib/system/libsystem_pthread.dylib
        0x195bbf000 -         0x1960b3fff CoreFoundation (arm64e)  <190E6A36-FCAA-3EA3-94BB-7009C44653DA> /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
        0x199777000 -         0x19abb3fff AppKit (arm64e)  <B88A44C1-D617-33DC-90ED-B6AB417C428E> /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit
        0x1a0c7e000 -         0x1a0ca5fff caulk (arm64e)  <A307BA82-97DE-37D1-99B7-BF68AC23C35C> /System/Library/PrivateFrameworks/caulk.framework/Versions/A/caulk
        0x1a68f5000 -         0x1a6e98fff libswiftCore.dylib (arm64e)  <A0EBE73E-3B7B-329E-985C-E884ABA916DF> /usr/lib/swift/libswiftCore.dylib


External Modification Summary:
  Calls made by other processes targeting this process:
    task_for_pid: 0
    thread_create: 0
    thread_set_state: 0
  Calls made by this process:
    task_for_pid: 0
    thread_create: 0
    thread_set_state: 0
  Calls made by all processes on this machine:
    task_for_pid: 0
    thread_create: 0
    thread_set_state: 0

EOF

As a getting started point, it would be helpful if you fed these reports to the xcrun crashlog /Path/To/Log.crash command, and see what it tells you. That command is a shortcut to a bunch of LLDB commands that pulls apart any optimizations that are present in a single frame of those call stacks. You may find that there are several layers of calls in-between the call stack frames due to optimizations, and things may make more sense once the complier's optimization passes are unwound.

If that doesn't explain things for you, please also include the output of that command in your follow-up.

— Ed Ford,  DTS Engineer

This seems to be in fact the same issue that was pointed out in https://developer.apple.com/forums/thread/760029

The output of xcrun crashlog /path/to/crash.crash contains

[ 4] 0x0000000100bf81b8 MyApp`MyApp.MainViewController.showSettings(Any) -> () + 428 at MainViewController.swift:132:30
[ 5] 0x0000000100ba252f MyApp`merged @objc MyApp.ConfirmMoveViewController.openSourceInFinder(Any) -> () + 79

merged @objc, if I understand correctly, indicates some compiler optimization. So it would seem that on the way to calling the showSettings method some reused part of the openSourceInFinder method is used, but the crash log makes it appear like openSourceInFinder was genuinely called.

Could this perhaps be something to be optimized in how macOS creates crash logs, or is there a way to consistently recognize this?

Are those frames from the LLDB output coherent to your understanding of how your app works? Based on your first post, I think they might not be, but want to make sure. If they still aren't, that will guide where we go from here.

— Ed Ford,  DTS Engineer

Well, the issue is that the crash report makes it look like a certain method is called which cannot be, and if I ignore that particular frame line, then everything is coherent. So if the explanation, as I assumed, is that merged @objc means that the method was not actually part of the call stack, then everything's ok. I just think that it shouldn't be listed there at all, because it's only confusing.

Would you mind opening an enhancement request for this, with both the crash log you have from the system and the one expanded by LLDB attached? (And please post the FB number here.) I'd like to treat this as a chance for improvement in the display of your crash log so that it was more intuitive to you what has happening.

Speaking broadly and not specifically to your examples, backtraces in optimized builds sometimes are surprising because of the optimizations. That's not to say that the crash report is wrong — it is correct to the actual instructions addresses that the system called in backtrace order to the crash — but that it may have either more or fewer frames than you expect from the source code because of what the optimizations added or removed. That's why I want to be specific that the above enhancement request regards displaying the optimization info that you needed to understand what happened, and not that what the crash report recorded the wrong instruction addresses.

— Ed Ford,  DTS Engineer

Thanks, I created FB16969117.

Crash reports downloaded by Xcode contain impossible call hierarchy
 
 
Q