Skip to content

fix: image size computation on Apple#1740

Merged
bitsandfoxes merged 11 commits into
masterfrom
fix/apple-imagesize
May 22, 2026
Merged

fix: image size computation on Apple#1740
bitsandfoxes merged 11 commits into
masterfrom
fix/apple-imagesize

Conversation

@bitsandfoxes
Copy link
Copy Markdown
Contributor

On macOS arm64 the native crash handler computed each module's image_size as max(seg->vmaddr + seg->vmsize) across all LC_SEGMENT_64 commands. For dyld-shared-cache libraries seg->vmaddr is a shared-cache-absolute address, not relative to the image base, so the result lands in the multi-GB range. Every system image's half-open range [image_addr, image_addr + image_size) then overlaps every other. This caused the symbolicator to attribute every frame to whichever image has the lowest image_addr. Turns out that typically is dyld or the first libsystem module.

See misattribution:

EXC_SOFTWARE / 0x00000000 / 0x1206cceac: Fatal Error: EXC_SOFTWARE / 0x00000000 / 0x1206cceac
  GameAssembly        0x1206cceac  crash_in_c (CppPlugin.cpp:9)
  GameAssembly        0x1220a72a0  UnityAction_Invoke_m5CB9EE17CCDF64D00DE5D96DF3553CDB20D66F70_inline (UnityEngine.CoreModule__2.cpp:41033)
  GameAssembly        0x1220a72a0  InvokableCall_Invoke_m6F4828FD2B3E3BBB7AA6EECC2C37FB08538363F4 (UnityEngine.CoreModule__2.cpp:23612)
  GameAssembly        0x1220a72a0  UnityEvent_Invoke_mFBF80D59B03C30C5FE6A06F897D954ACADE061D2 (UnityEngine.CoreModule__2.cpp)
  GameAssembly        0x120b43ef0  EventFunction_1_Invoke_m98A8A653E7180305E41F7CFFDDD9D32C63B96FE7_gshared_inline (EnumerableIList.cs:15)
  GameAssembly        0x120b43ef0  EventFunction_1_Invoke_m98A8A653E7180305E41F7CFFDDD9D32C63B96FE7_inline (GenericMethods__17.cpp:8877)
  GameAssembly        0x120b43ef0  ExecuteEvents_Execute_TisRuntimeObject_mDC4455B743BE4A6BA46DD741D0E0AB150FF1209A_gshared (ExecuteEvents.cs:272)
  GameAssembly        0x1224248cc  ExecuteEvents_Execute_TisIPointerClickHandler_t77341AA19DE37C26F5F619DE8BD28B70D5A2B5D8_m024FB23AA1DBB1B7A5E1935FA35A1E4FF57AC5F6 (UnityEngine.UI__3.cpp:5160)
  GameAssembly        0x1224248cc  StandaloneInputModule_ReleaseMouse_mC5C3083C356ACD5CD420A58662D99A6CACC5FAF5 (StandaloneInputModule.cs:216)
  GameAssembly        0x12242643c  StandaloneInputModule_ProcessMouseEvent_m8A8214EB9286BA31C18F515BCC3349DF740B2BBA (StandaloneInputModule.cs:578)
  GameAssembly        0x122424fcc  StandaloneInputModule_ProcessMouseEvent_mCE1BA96E47D9A4448614CB9DAF5A406754F655DD (StandaloneInputModule.cs:558)
  GameAssembly        0x122424fcc  StandaloneInputModule_Process_mBD949CC45BBCAB5A0FAF5E24F3BB4C3B22FF3E81 (StandaloneInputModule.cs:306)
  GameAssembly        0x1209c928c  il2cpp::vm::Runtime::InvokeWithThrow (Runtime.cpp:624)
  GameAssembly        0x1209c91c8  il2cpp::vm::Runtime::Invoke (Runtime.cpp:610)
  UnityPlayer         0x1060be25c  UNITY_TT_RunIns
  UnityPlayer         0x1060c6078  UNITY_TT_RunIns
  UnityPlayer         0x1060dcc50  UNITY_TT_RunIns
  UnityPlayer         0x105d9d9fc  UNITY_TT_RunIns
  UnityPlayer         0x105f4a3e4  UNITY_TT_RunIns
  UnityPlayer         0x105f4a424  UNITY_TT_RunIns
  UnityPlayer         0x105f4a6f4  UNITY_TT_RunIns
  UnityPlayer         0x1062eb59c  unity_operator_delete_dealloc
  UnityPlayer         0x1062eb354  unity_operator_delete_dealloc
  libobjc.A           0x18ee07da0  startWeakTableScan
  libobjc.A           0x18d59dd4c  startWeakTableScan
  libobjc.A           0x18d59da44  startWeakTableScan
  libobjc.A           0x18d59d5bc  startWeakTableScan
  libobjc.A           0x18d5838c4  startWeakTableScan
  libobjc.A           0x18d655bdc  startWeakTableScan
  libobjc.A           0x19a35855c  startWeakTableScan
  libobjc.A           0x19a35b8b8  startWeakTableScan
  libobjc.A           0x19a4e5138  startWeakTableScan
  libobjc.A           0x19205b1a0  startWeakTableScan
  libobjc.A           0x1919af080  startWeakTableScan
  libobjc.A           0x192544698  startWeakTableScan
  libobjc.A           0x1925443a4  startWeakTableScan
  libobjc.A           0x1919a2138  startWeakTableScan
  libobjc.A           0x19197a7ac  startWeakTableScan
  UnityPlayer         0x1062eaf10  PlayerMain
  libobjc.A           0x18d10bda0  startWeakTableScan
  libobjc.A           0x18d0ebffc  startWeakTableScan
  unity-of-bugs       0x100f8ff6c  _mh_execute_header
  libobjc.A           0x18d10bffc  startWeakTableScan

We already use __TEXT in sentry_modulefinder_apple.c

if (sentry__string_eq(seg->segname, "__TEXT")) {
sentry_value_set_by_key(module, "image_size",
sentry_value_new_int32((uint32_t)seg->vmsize));

to get to the correct per-image extent.

So now it looks like

EXC_SOFTWARE / 0x00000000 / 0x11f4bceac: Fatal Error: EXC_SOFTWARE / 0x00000000 / 0x11f4bceac
  GameAssembly        0x11f4bceac  crash_in_c (CppPlugin.cpp:9)
  GameAssembly        0x11f933ef0  EventFunction_1_Invoke_m98A8A653E7180305E41F7CFFDDD9D32C63B96FE7_gshared_inline (EnumerableIList.cs:15)
  GameAssembly        0x11f933ef0  EventFunction_1_Invoke_m98A8A653E7180305E41F7CFFDDD9D32C63B96FE7_inline (GenericMethods__17.cpp:8877)
  GameAssembly        0x11f933ef0  ExecuteEvents_Execute_TisRuntimeObject_mDC4455B743BE4A6BA46DD741D0E0AB150FF1209A_gshared (ExecuteEvents.cs:272)
  GameAssembly        0x1212148cc  ExecuteEvents_Execute_TisIPointerClickHandler_t77341AA19DE37C26F5F619DE8BD28B70D5A2B5D8_m024FB23AA1DBB1B7A5E1935FA35A1E4FF57AC5F6 (UnityEngine.UI__3.cpp:5160)
  GameAssembly        0x1212148cc  StandaloneInputModule_ReleaseMouse_mC5C3083C356ACD5CD420A58662D99A6CACC5FAF5 (StandaloneInputModule.cs:216)
  GameAssembly        0x12121643c  StandaloneInputModule_ProcessMouseEvent_m8A8214EB9286BA31C18F515BCC3349DF740B2BBA (StandaloneInputModule.cs:578)
  GameAssembly        0x121214fcc  StandaloneInputModule_ProcessMouseEvent_mCE1BA96E47D9A4448614CB9DAF5A406754F655DD (StandaloneInputModule.cs:558)
  GameAssembly        0x121214fcc  StandaloneInputModule_Process_mBD949CC45BBCAB5A0FAF5E24F3BB4C3B22FF3E81 (StandaloneInputModule.cs:306)
  GameAssembly        0x11f7b928c  il2cpp::vm::Runtime::InvokeWithThrow (Runtime.cpp:624)
  GameAssembly        0x11f7b91c8  il2cpp::vm::Runtime::Invoke (Runtime.cpp:610)
  UnityPlayer         0x10565a25c  UNITY_TT_RunIns
  UnityPlayer         0x105662078  UNITY_TT_RunIns
  UnityPlayer         0x105678c50  UNITY_TT_RunIns
  UnityPlayer         0x1053399fc  UNITY_TT_RunIns
  UnityPlayer         0x1054e63e4  UNITY_TT_RunIns
  UnityPlayer         0x1054e6424  UNITY_TT_RunIns
  UnityPlayer         0x1054e66f4  UNITY_TT_RunIns
  UnityPlayer         0x10588759c  unity_operator_delete_dealloc
  UnityPlayer         0x105887354  unity_operator_delete_dealloc
  Foundation          0x18ee07da0  __NSFireTimer
  CoreFoundation      0x18d59dd4c  __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__
  CoreFoundation      0x18d59da44  __CFRunLoopDoTimer
  CoreFoundation      0x18d59d5bc  __CFRunLoopDoTimers
  CoreFoundation      0x18d5838c4  __CFRunLoopRun
  CoreFoundation      0x18d655bdc  _CFRunLoopRunSpecificWithOptions
  HIToolbox           0x19a35855c  RunCurrentEventLoopInMode
  HIToolbox           0x19a35b8b8  ReceiveNextEventCommon
  HIToolbox           0x19a4e5138  _BlockUntilNextEventMatchingListInMode
  AppKit              0x19205b1a0  _DPSBlockUntilNextEventMatchingListInMode
  AppKit              0x1919af080  _DPSNextEvent
  AppKit              0x192544698  -[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:]
  AppKit              0x1925443a4  -[NSApplication(NSEventRouting) nextEventMatchingMask:untilDate:inMode:dequeue:]
  AppKit              0x1919a2138  -[NSApplication run]
  AppKit              0x19197a7ac  NSApplicationMain
  UnityPlayer         0x105886f10  PlayerMain
  0x18d10bda4  null
  unity-of-bugs       0x10039ff6c  _mh_execute_header

Comment on lines +565 to +569
bool has_size = false;
bool has_uuid = false;

for (uint32_t j = 0; j < header64->ncmds && j < 256; j++) {
for (uint32_t j = 0;
j < header64->ncmds && j < 256 && (!has_size || !has_uuid);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The loop walks Mach-O load commands looking for two things:

  1. the __TEXT segment's vmsize
  2. the LC_UUID

The new has_size/has_uuid flags let the loop short-circuit once both are found. So we don't have to iterate through every remaining load command.

Comment thread tests/assertions.py
)


def assert_debug_meta_images_do_not_overlap(event):
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I read that correctly then on darwin platforms we get a list of modules loaded, which basically guarantees that images and image addresses do not overlap. Adding this as regression proofing.

@bitsandfoxes bitsandfoxes requested review from jpnurmi and mujacica May 22, 2026 09:33
Comment thread CHANGELOG.md Outdated
bitsandfoxes and others added 2 commits May 22, 2026 13:55
@bitsandfoxes bitsandfoxes merged commit e040cca into master May 22, 2026
51 of 54 checks passed
@bitsandfoxes bitsandfoxes deleted the fix/apple-imagesize branch May 22, 2026 11:56
@github-actions
Copy link
Copy Markdown

Fails
🚫 Please consider adding a changelog entry for the next release.

Instructions and example for changelog

Please add an entry to CHANGELOG.md to the "Unreleased" section. Make sure the entry includes this PR's number.

Example:

## Unreleased

### Fixes

- image size computation on Apple ([#1740](https://github.com/getsentry/sentry-native/pull/1740))

If none of the above apply, you can opt out of this check by adding #skip-changelog to the PR description or adding a skip-changelog label.

Generated by 🚫 dangerJS against 692b628

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants