Skip to content

feat(native): Provide crash metadata to on_crash - #2174

Merged
jpnurmi merged 1 commit into
v1from
jpnurmi/feat/native-crash-stack
Oct 15, 2026
Merged

jpnurmi merged 1 commit into
v1from
jpnurmi/feat/native-crash-stack

Conversation

@jpnurmi

@jpnurmi jpnurmi commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Reuse and extend the existing SDK unwinders already used by inproc to provide exception metadata, registers, and a basic crashing-thread stack for crash identification in native on_crash, matching inproc.

  • Capture up to 128 fault-context IPs and unwind source in shared memory. Retain the faulting IP when available.
  • Linux: SDK libunwind with signal-safe logging.
  • macOS: SDK frame-pointer walker, guarded Mach reads, PAC stripping, __DARWIN_OPAQUE_ARM_THREAD_STATE64 accessors, and instruction_addr_adjustment=none.
  • Android/Linux without libunwind: bounded frame-pointer capture via process_vm_readv; avoids libunwindstack's C++ allocation.
  • Windows: MSVC x64 RtlLookupFunctionEntry/RtlVirtualUnwind walking without DbgHelp; SP progress permits recursive frames. Frame-pointer capture on x86/ARM64 and other x64 builds.
  • ARM32 frame-pointer fallbacks retain only the faulting IP.

The daemon reuses partial captures and enriches existing frames. Preserve exception/register/frame edits and removals, and honor callback rejection.

Ref: #2102

@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Messages
📖 Do not forget to update Sentry-docs with your feature once the pull request gets approved.

Generated by 🚫 dangerJS against 69b83ca

Comment thread src/backends/native/sentry_crash_context.h
@codecov

codecov Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 37.03704% with 204 lines in your changes missing coverage. Please review.
✅ Project coverage is 75.00%. Comparing base (1f7b255) to head (69b83ca).

Additional details and impacted files
@@            Coverage Diff             @@
##               v1    #2174      +/-   ##
==========================================
- Coverage   75.65%   75.00%   -0.65%     
==========================================
  Files         103      103              
  Lines       28707    28902     +195     
  Branches     5294     5338      +44     
==========================================
- Hits        21718    21679      -39     
- Misses       5624     5854     +230     
- Partials     1365     1369       +4     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread src/backends/native/sentry_crash_context.h

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit bcf18cf. Configure here.

Comment thread CHANGELOG.md Outdated
Comment thread src/backends/native/sentry_crash_handler.c
@jpnurmi
jpnurmi force-pushed the jpnurmi/feat/native-crash-stack branch from bcf18cf to 59a96d8 Compare October 8, 2026 18:46
@jpnurmi
jpnurmi changed the base branch from master to jpnurmi/ref/native-crashing October 8, 2026 18:47
@jpnurmi
jpnurmi added this pull request to stack #2181 October 8, 2026 18:47
@jpnurmi
jpnurmi force-pushed the jpnurmi/feat/native-crash-stack branch from 59a96d8 to fda25c6 Compare October 9, 2026 07:49
Base automatically changed from jpnurmi/ref/native-crashing to master October 12, 2026 16:04
Provide exception metadata, registers, and a basic crashing-thread stack
for crash identification in native `on_crash`, matching `inproc`.
Use the same payload for `before_send` when `on_crash` is unset.

- Capture up to 128 fault-context IPs and unwind source in shared memory.
  Retain the faulting IP when available.
- Linux: SDK `libunwind` with signal-safe logging.
- macOS: SDK frame-pointer walker, guarded Mach reads, PAC stripping,
  `__DARWIN_OPAQUE_ARM_THREAD_STATE64` accessors, and
  `instruction_addr_adjustment=none`.
- Android/Linux without `libunwind`: bounded frame-pointer capture via
  `process_vm_readv`; avoids `libunwindstack`'s C++ allocation.
- Windows: MSVC x64 `RtlLookupFunctionEntry`/`RtlVirtualUnwind` walking
  without DbgHelp; SP progress permits recursive frames.
  Frame-pointer capture on x86/ARM64 and other x64 builds.
- ARM32 frame-pointer fallbacks retain only the faulting IP.

The daemon reuses partial captures and enriches existing frames.
Preserve exception/register/frame edits and removals, and honor callback
rejection.
@jpnurmi
jpnurmi force-pushed the jpnurmi/feat/native-crash-stack branch from 800ead5 to 69b83ca Compare October 15, 2026 14:00
@jpnurmi
jpnurmi removed this pull request from stack #2181 October 15, 2026 14:06
@jpnurmi
jpnurmi changed the base branch from master to v1 October 15, 2026 14:07
@jpnurmi
jpnurmi added this pull request to stack #2209 October 15, 2026 14:07
@jpnurmi
jpnurmi merged commit 5ae31e0 into v1 Oct 15, 2026
114 of 115 checks passed
@jpnurmi
jpnurmi deleted the jpnurmi/feat/native-crash-stack branch October 15, 2026 15:44
@jpnurmi jpnurmi linked an issue Oct 16, 2026 that may be closed by this pull request
jpnurmi added a commit that referenced this pull request Oct 16, 2026
The recently introduced crashed-thread stack unwinding in #2174
switched the native signal handler to the SDK unwinder. This brought
its 4 KiB `/proc/self/maps` read buffer onto the handler stack as an
unintended side effect.

Crash handlers can run on alternate signal stacks as small as 16 KiB,
as noted in #2029, which added stack monitoring for #997. The inproc
backend preserves existing alternate stacks, so the SDK's 64 KiB
default is not a universal budget. The signal frame, callbacks, and
handler work must fit; overflowing can prevent the original crash
from being reported.

Reduce the buffer to 512 bytes, preserving support for oversized lines
and address prefixes split across reads without adding allocations in
the signal handler.

With GCC 15 on Linux x86-64, both 512-byte and 256-byte buffers reduce
the native handler peak from 6,344 to 3,424 bytes and the inproc peak
from 7,592 to 4,672 bytes. The 2,920-byte reduction is about 18% of a
16 KiB stack budget.

Warm timings for two maps lookups (code and stack addresses), using
GCC 15 `-O3` on a Ryzen AI 9 HX 370, were:

                   4096 B    512 B    256 B
GNOME Shell        0.406 ms  0.490 ms  0.583 ms
Edge               0.776 ms  0.972 ms  1.288 ms

These are medians of nine rotating batches, excluding stack unwinding
and the rest of crash handling. Choose 512 bytes because it preserves
the measured handler stack reduction with less read overhead than 256.
jpnurmi added a commit that referenced this pull request Oct 16, 2026
#2174 brought the SDK unwinder's 4 KiB `/proc/self/maps` buffer onto
the native signal-handler stack. Use 512 bytes; preserve oversized
lines and address prefixes split across reads without new allocations.

Inproc preserves existing alternate stacks, which may have only 16 KiB
for the signal frame, callbacks, and handler, despite the 64 KiB
default. Overflow can lose the report (#997, #2029).

GCC 15 `-O3`, Linux x86-64, Ryzen AI 9 HX 370:

                         4096 B    512 B    256 B
Native handler peak (B)    6,344    3,424    3,424
Inproc handler peak (B)    7,592    4,672    4,672
GNOME maps lookups (ms)    0.406    0.490    0.583
Edge maps lookups (ms)     0.776    0.972    1.288

512 saves 2,920 bytes (~18% of 16 KiB), matching 256's handler peaks
with less read overhead. Lookup times are warm code/stack lookups:
medians of nine rotating batches, excluding unwinding and other
crash handling.
jpnurmi added a commit that referenced this pull request Oct 16, 2026
#2174 brought the SDK unwinder's 4 KiB `/proc/self/maps` buffer onto
the native signal-handler stack. Use 512 bytes; preserve oversized
lines and address prefixes split across reads without new allocations.

GCC 15 `-O3`, Linux x86-64, Ryzen AI 9 HX 370:

| Measurement | 4096 B | 512 B |
| --- | ---: | ---: |
| Native handler peak (B) | 6,344 | 3,424 |
| Maps lookups, 190 KiB / 1,900 mappings (ms) | 0.406 | 0.490 |
| Maps lookups, 308 KiB / 3,053 mappings (ms) | 0.776 | 0.972 |

This saves 2,920 bytes of handler stack at the cost of more reads.
Lookup timings are warm code/stack lookup pairs: medians of nine
rotating batches, excluding unwinding and other crash handling.
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.

on_crash receives an event without data

2 participants