Crash in IndexSet.map during menu item validation in client report downloaded by Xcode

For many years I've had the following code to access the active objects of a table view in my App Store app:

class MyViewController: NSViewController: NSMenuItemValidation {
private var tableView: NSTableView!
private var objects = [MyObject]()
func numberOfRows(in tableView: NSTableView) -> Int {
return objects.count
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
// make view for row
}
private var activeObjects: [MyObject] {
return tableView?.activeRowIndexes.map({ objects[$0] }) ?? []
}
func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
let activeObjects = self.activeObjects
...
}
}
extension NSTableView {
var activeRowIndexes: IndexSet {
return clickedRow == -1 || selectedRowIndexes.contains(clickedRow) ? selectedRowIndexes : IndexSet(integer: clickedRow)
}
}

In one of the recent updates, I wanted to add some kind of header to the table view, so I decided to add a row at the beginning and offset the indexes by 1.

func numberOfRows(in tableView: NSTableView) -> Int {
return objects.count + 1
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
if row == 0 {
// make header view
} else {
// make view for row - 1
}
}
private var activeObjects: [MyObject] {
return tableView?.activeRowIndexes.subtracting(IndexSet(integer: 0)).map({ objects[$0 - 1] }) ?? []
}

But since I added this change, Xcode regularly downloads crash reports from clients crashing during menu item validation in IndexSet.map with reason Code 5 Trace/BPT trap: 5. I assumed that I was accessing an invalid array index, so I added some debug code: the crash report would then show the invalid index beside the crashed thread's name.

private var activeObjects: [MyObject] {
return tableView?.activeRowIndexes.subtracting(IndexSet(integer: 0)).map({ i in
if !objects.indices.contains(i - 1) {
Thread.current.name = (Thread.current.name ?? "") + ". Invalid index \(i - 1) for count \(objects.count)"
preconditionFailure()
}
return objects[i - 1]
}) ?? []
}

But the crash reports for this new app version look just like the old ones and the thread name is not changed. Indeed, when recreating an invalid index access on my Mac, the crash report mentions Array._checkSubscript(_:wasNativeTypeChecked:), which does not appear in the crash reports downloaded by Xcode.

Manually symbolicating the crash report also doesn't give any more information: all lines referring to my app code are resolved to either /<compiler-generated>:0 or MyViewController.swift:0.

Apparently the problem is not an invalid array index, but something else. Does anybody have a clue what the problem could be?

(Note: the crash report mentions Sequence.compactMap because now I'm effectively calling tableView?.activeRowIndexes.compactMap, but the same crash happened before when calling IndexSet.map, which would appear in the crash report as Collection.map.)

Process:               MyApp [3925]
Path:                  /Applications/MyApp.app/Contents/MacOS/MyApp
Identifier:            com.example.MyApp
Version:               5.1 (170)
App Item ID:           590386474
App External ID:       874430434
Code Type:             ARM-64
Parent Process:        launchd [1]
User ID:               501

Date/Time:             2025-05-10 16:37:45.6889 -0400
OS Version:            macOS 15.4.1 (24E263)
Report Version:        12
Anonymous UUID:        89753C58-4E7F-BE3E-0A0A-03D3F47DBB7A


Time Awake Since Boot: 36000 seconds

System Integrity Protection: enabled

Crashed Thread:        0

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

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

Thread 0 Crashed:
0   MyApp                         	0x0000000102ff59c0 closure #1 in MyViewController.activeObjects.getter + 616 (/:0)
1   MyApp                         	0x0000000102fff838 specialized Sequence.compactMap<a>(_:) + 476 (/:0)
2   MyApp                         	0x0000000102ff5b70 MyViewController.activeObjects.getter + 416
3   MyApp                         	0x0000000102fee614 MyViewController.validateMenuItem(_:) + 724
4   MyApp                         	0x0000000102ff0b78 @objc MyViewController.validateMenuItem(_:) + 52 (/:0)
5   AppKit                        	0x000000018f645474 -[NSMenu _enableItem:] + 692
6   AppKit                        	0x000000018f64502c -[NSMenu _enableItems] + 156
7   AppKit                        	0x000000018fd04a44 __32-[NSMenu _enableItemsWithFlags:]_block_invoke + 60
8   AppKit                        	0x000000018fd075c0 -[NSMenu _withUpdateFlags:do:] + 72
9   AppKit                        	0x000000018fd049fc -[NSMenu _enableItemsWithFlags:] + 96
10  AppKit                        	0x000000018fea55cc -[NSCocoaMenuImpl _sendMenuEnableItems] + 268
11  AppKit                        	0x000000018fea4854 -[NSCocoaMenuImpl viewWillAppear] + 64
12  AppKit                        	0x000000018fc5a11c -[NSContextMenuImpl viewWillAppear] + 60
13  AppKit                        	0x000000018fd81f28 -[NSPopupMenuWindow _orderFrontWithParentWindow:screenFrame:] + 320
14  AppKit                        	0x000000018fd81cb4 -[NSPopupMenuWindow _commonPresentFromView:animated:] + 572
15  AppKit                        	0x000000018fd81a40 -[NSPopupMenuWindow presentAsPopUpRelativeToView:animated:] + 88
16  AppKit                        	0x000000018fc59804 +[NSContextMenuImpl presentPopup:fromView:withContext:animated:] + 960
17  AppKit                        	0x000000018feb1934 _NSPopUpMenu + 2124
18  AppKit                        	0x000000018feb5ce4 -[NSCocoaMenuImpl _popUpContextMenu:withEvent:forView:withFont:] + 304
19  AppKit                        	0x000000018f80101c -[NSMenu _popUpContextMenu:withEvent:forView:withFont:] + 192
20  AppKit                        	0x000000019000a0b8 -[NSView _showMenuForEvent:] + 72
21  AppKit                        	0x000000018f7fd4e4 -[NSView rightMouseDown:] + 76
22  AppKit                        	0x000000018fb74bc8 -[NSControl _rightMouseUpOrDown:] + 352
23  AppKit                        	0x000000018f67a110 forwardMethod + 252
24  AppKit                        	0x000000018f7fd528 -[NSView rightMouseDown:] + 144
25  AppKit                        	0x000000018f67a110 forwardMethod + 252
26  AppKit                        	0x000000018f7fd528 -[NSView rightMouseDown:] + 144
27  AppKit                        	0x000000018f67a110 forwardMethod + 252
28  AppKit                        	0x000000018f7fd528 -[NSView rightMouseDown:] + 144
29  AppKit                        	0x000000018f67a110 forwardMethod + 252
30  AppKit                        	0x000000018f7fd528 -[NSView rightMouseDown:] + 144
31  AppKit                        	0x000000018f67a110 forwardMethod + 252
32  AppKit                        	0x000000018f7fd528 -[NSView rightMouseDown:] + 144
33  AppKit                        	0x000000018f67a110 forwardMethod + 252
34  AppKit                        	0x000000018f7fd528 -[NSView rightMouseDown:] + 144
35  AppKit                        	0x00000001900a9e8c _routeRightMouseDownEvent + 256
36  AppKit                        	0x000000018f60bcf0 -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 508
37  AppKit                        	0x000000018f60b92c -[NSWindow(NSEventRouting) sendEvent:] + 288
38  AppKit                        	0x000000018fe83094 -[NSApplication(NSEventRouting) sendEvent:] + 1504
39  AppKit                        	0x000000018fa824a4 -[NSApplication _handleEvent:] + 60
40  AppKit                        	0x000000018f4d8c8c -[NSApplication run] + 520
41  AppKit                        	0x000000018f4af35c NSApplicationMain + 880
42  MyApp                         	0x0000000102f55c70 main + 128 (main.swift:12)
43  dyld                          	0x000000018b40ab4c start + 6000

Thread 1:
0   libsystem_pthread.dylib       	0x000000018b7a4b6c start_wqthread + 0

Thread 2:
0   libsystem_pthread.dylib       	0x000000018b7a4b6c start_wqthread + 0

Thread 3:
0   libsystem_pthread.dylib       	0x000000018b7a4b6c start_wqthread + 0

Thread 4:
0   libsystem_kernel.dylib        	0x000000018b767c34 mach_msg2_trap + 8
1   libsystem_kernel.dylib        	0x000000018b77a308 mach_msg2_internal + 76
2   libsystem_kernel.dylib        	0x000000018b770764 mach_msg_overwrite + 484
3   libsystem_kernel.dylib        	0x000000018b767fa8 mach_msg + 24
4   CoreFoundation                	0x000000018b894f8c __CFRunLoopServiceMachPort + 160
5   CoreFoundation                	0x000000018b8938a8 __CFRunLoopRun + 1208
6   CoreFoundation                	0x000000018b892d68 CFRunLoopRunSpecific + 572
7   AppKit                        	0x000000018f609818 _NSEventThread + 140
8   libsystem_pthread.dylib       	0x000000018b7a9c0c _pthread_start + 136
9   libsystem_pthread.dylib       	0x000000018b7a4b80 thread_start + 8

Thread 5:
0   libsystem_pthread.dylib       	0x000000018b7a4b6c start_wqthread + 0

Thread 6:
0   libsystem_pthread.dylib       	0x000000018b7a4b6c start_wqthread + 0

Thread 7:
0   libsystem_pthread.dylib       	0x000000018b7a4b6c start_wqthread + 0


Thread 0 crashed with ARM Thread State (64-bit):
    x0: 0x0000600002eaba08   x1: 0x0000000200000003   x2: 0x00000001fa71cfd8   x3: 0x00000001fa67ccee
    x4: 0x0000600002eaba20   x5: 0x000000000000001d   x6: 0x0000000000000000   x7: 0x0000000000000001
    x8: 0xfffffffe00000000   x9: 0x0000000200000003  x10: 0x0000000000000003  x11: 0x000000000000000f
   x12: 0x000000000000000b  x13: 0x00006000007bb7a0  x14: 0x01000001fab49585  x15: 0x00000001fab49580
   x16: 0x000000019cf88c18  x17: 0x23eb0001fa67a6f0  x18: 0x0000000000000000  x19: 0x0000600002e8ca40
   x20: 0x0000600002eaba00  x21: 0xf00000000000001d  x22: 0x0000600002eaba00  x23: 0x0000000000000000
   x24: 0x0000600002eaba00  x25: 0x00000001fd070100  x26: 0xe100000000000000  x27: 0x00000001fac18d10
   x28: 0x0000000153891560   fp: 0x000000016ceaa010   lr: 0x0000000102ff59c0
    sp: 0x000000016cea9f90   pc: 0x0000000102ff59c0 cpsr: 0x60000000
   esr: 0xf2000001 (Breakpoint) brk 1


Binary Images:
        0x102f54000 -         0x10318ffff MyApp (arm64)  <8D656E3F-C683-3B48-96AA-147E5CFFDDED> /Applications/MyApp.app/Contents/MacOS/MyApp
        0x10fd80000 -         0x10fd8bfff libobjc-trampolines.dylib (arm64e)  <FB6F2685-3C65-37EC-8EE3-8ADBA6E1995F> /usr/lib/libobjc-trampolines.dylib
        0x111d64000 -         0x112497fff AGXMetalG16X (arm64e)  <FD527CD4-1B88-39FC-B3C6-366343B947B0> /System/Library/Extensions/AGXMetalG16X.bundle/Contents/MacOS/AGXMetalG16X
        0x116d84000 -         0x116da3fff csparser (arm64e)  <4F8AEDE3-4DA2-3140-B588-C759EEC4EEDE> /System/Library/Frameworks/Security.framework/Versions/A/PlugIns/csparser.bundle/Contents/MacOS/csparser
        0x18b404000 -         0x18b49ea83 dyld (arm64e)  <ACA43A8D-6369-3A2C-AF92-3D4C458523D6> /usr/lib/dyld
        0x18b767000 -         0x18b7a230b libsystem_kernel.dylib (arm64e)  <225CB279-20A9-381D-A163-D2BE263F5327> /usr/lib/system/libsystem_kernel.dylib
        0x18b7a3000 -         0x18b7afa47 libsystem_pthread.dylib (arm64e)  <8D27EC9A-D919-31A4-8DF8-31A2FD2E593C> /usr/lib/system/libsystem_pthread.dylib
        0x18b818000 -         0x18bd56fff CoreFoundation (arm64e)  <39E0F63A-3AB8-39E9-97F8-333CDE9A7BA4> /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation
        0x18f4ab000 -         0x19093bdff AppKit (arm64e)  <1D6DF541-4A74-3A0E-8A8F-15AEE6F93DA9> /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit
        0x19cbee000 -         0x19d15cbbf libswiftCore.dylib (arm64e)  <C5CCFFBF-EFE8-36B9-9386-E0E840770A09> /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

VM Region Summary:
ReadOnly portion of Libraries: Total=1.6G resident=0K(0%) swapped_out_or_unallocated=1.6G(100%)
Writable regions: Total=2.2G written=753K(0%) resident=753K(0%) swapped_out=0K(0%) unallocated=2.2G(100%)

                                VIRTUAL   REGION 
REGION TYPE                        SIZE    COUNT (non-coalesced) 
===========                     =======  ======= 
Accelerate framework               256K        2 
Activity Tracing                   256K        1 
CG image                          1200K       46 
CG raster data                     224K        7 
ColorSync                          560K       29 
CoreAnimation                     2896K      126 
CoreGraphics                        96K        6 
CoreUI image data                 3280K       29 
Foundation                          48K        2 
Kernel Alloc Once                   32K        1 
MALLOC                             2.1G       78 
MALLOC guard page                  288K       18 
STACK GUARD                       56.1M        8 
Stack                             11.7M        8 
VM_ALLOCATE                        416K       17 
__AUTH                            5421K      689 
__AUTH_CONST                      76.0M      930 
__CTF                               824        1 
__DATA                            25.5M      913 
__DATA_CONST                      26.8M      940 
__DATA_DIRTY                      2763K      339 
__FONT_DATA                        2352        1 
__INFO_FILTER                         8        1 
__LINKEDIT                       622.4M        5 
__OBJC_RO                         61.3M        1 
__OBJC_RW                         2391K        1 
__TEXT                             1.0G      960 
__TEXT (graphics)                  128K        1 
__TPRO_CONST                       128K        2 
mapped file                      333.5M       48 
page table in kernel               753K        1 
shared memory                     1392K       14 
===========                     =======  ======= 
TOTAL                              4.4G     5225 


EOF
</a>

From the stack trace, the crash most likely cause is this: objects[$0 - 1]. If $0 is out of bounds, the array access will trap.

That's what I thought too, but like I mentioned at the end, wouldn't Array._checkSubscript(_:wasNativeTypeChecked:) appear in the stack trace?

Do you agree, and have another suggestion for what the issue could be?

Crash in IndexSet.map during menu item validation in client report downloaded by Xcode
 
 
Q