test(benchmark): crash handler stack usage - #2029
Open
jpnurmi wants to merge 1 commit into
Open
Conversation
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit b0d7092. Configure here.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## jpnurmi/test/benchmark-libsize #2029 +/- ##
==================================================================
+ Coverage 74.27% 74.28% +0.01%
==================================================================
Files 104 104
Lines 26627 26670 +43
Branches 4844 4850 +6
==================================================================
+ Hits 19777 19813 +36
- Misses 5502 5506 +4
- Partials 1348 1351 +3 🚀 New features to boost your workflow:
|
Crash handlers often run with little stack headroom, including alternate signal stacks as small as 16 KiB. Measure the real crash path so stack growth can be caught before it becomes an overflow. Add async-signal-safe integration callbacks around crash-handler work in each backend. A dedicated fixture uses those boundaries to paint 12 KiB of stack with a recognizable pattern and then returns, making the painted space available to the handler. At handler exit it finds the deepest overwritten byte and reports that interval's high-water mark. The benchmark publishes the largest interval for each backend because separate intervals are independent peaks rather than values that should be added together. The 12 KiB window leaves 4 KiB of a 16 KiB alternate signal stack for the signal frame and measurement callback while the pattern is installed. Once the painting function returns, the full painted window is available to the real handler. Use a dummy HTTP client so the measured path includes the HTTP transport's crash-time queue drain without depending on network I/O. Skip Crashpad on macOS because it has no first-chance handler there. The stack usage measurements are published in benchmark charts and monitored over time: <img width="2070" height="1010" alt="Screenshot From 2026-08-27 17-23-15" src="https://github.com/user-attachments/assets/150e0d0c-a23c-4368-aaed-5903c925070f" /> To run the benchmark fixture locally: $ cmake -S . -B build \ -DSENTRY_BUILD_TESTS=ON \ -DSENTRY_BUILD_BENCHMARKS=ON \ -DSENTRY_BACKEND=inproc $ cmake --build build --target sentry_stack_usage $ ./build/tests/fixtures/stack_usage/sentry_stack_usage [...] [STACK] 0 bytes [...] [STACK] 7560 bytes [STACK] 336 bytes Segmentation fault (core dumped) The final crash is intentional. The number of handler intervals and their values depend on the backend and platform. Separately, add `make stack-frames` for manual inspection of the functions compiled into `libsentry`. It builds the selected backend with `-fstack-usage` and prints the 20 largest compiler-reported function frames. This does not measure a call chain or runtime high-water mark and is not published as a benchmark result. $ make stack-frames SENTRY_BACKEND=inproc 4192 src/unwinder/sentry_unwinder_libunwind.c:66:5:find_mem_range_from_fd static [...] Use `N` to change the default limit: $ make stack-frames SENTRY_BACKEND=native N=50 Fixes: #997
jpnurmi
force-pushed
the
jpnurmi/test/benchmark-stack-usage
branch
from
August 28, 2026 14:29
fe71085 to
8a1133b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Measure how much stack each crash backend uses while processing a fatal error.
Boring details for the curious
When a thread first enters crash handling, the fixture fills a 12 KiB local array with a recognizable byte pattern. The helper then returns, leaving the pattern in stack space available for reuse. As the real crash handler runs, its call frames overwrite that pattern.
Before the thread leaves crash handling, the fixture scans the remaining pattern. The deepest overwritten position is reported as
[STACK] N bytes. Nested entries on the same thread form one measurement, while separate handler intervals or threads may produce multiple values. The benchmark records the largest value because these are independent stack peaks, not additive memory usage.Crash callbacks may run on alternate signal stacks as small as 16 KiB. Painting 12 KiB leaves the remaining 4 KiB for the signal frame and callback machinery while
paint_stackis active. Painting the full 16 KiB would risk overflowing the stack before measurement begins.Add integration callbacks around each backend's crash-handling work so the fixture can apply the same measurement consistently. These callbacks must remain async-signal-safe because some backends invoke them from a signal handler.
Use a dummy custom HTTP client so the measured path includes the HTTP transport's crash-time queue drain without depending on network I/O.
Share the SDK target-property helper used by source-compiling test targets instead of duplicating it in each CMake file.
The stack usage measurements are published in benchmark charts and monitored over time:
To inspect stack usage locally:
$ cmake -S . -B build -DSENTRY_BACKEND=inproc -DSENTRY_BUILD_TESTS=ON -DSENTRY_BUILD_BENCHMARKS=ON $ cmake --build build --target sentry_stack_usage $ ./build/tests/fixtures/stack_usage/sentry_stack_usage [...] [STACK] 0 bytes [...] [STACK] 7512 bytes [STACK] 336 bytes Segmentation fault (core dumped)The number and values of the measurements depend on the backend and platform. The final crash is intentional.
Separately, add
make stack-framesfor manual inspection of the functions compiled intolibsentry. It builds the selected backend with-fstack-usageand prints the 20 largest compiler-reported function frames. This does not measure a call chain or runtime high-water mark and is not published as a benchmark result.Close: #997