From d93cb688961b069cb06147106fa6d781105ab6fc Mon Sep 17 00:00:00 2001 From: Corentin Kerisit Date: Fri, 25 Sep 2026 15:43:45 +0200 Subject: [PATCH 1/7] feat(crashpad): Support optional stack capture size limit --- external/crashpad | 2 +- include/sentry.h | 9 +++++++++ src/backends/sentry_backend_crashpad.cpp | 5 +++++ src/sentry_options.c | 8 ++++++++ src/sentry_options.h | 1 + 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/external/crashpad b/external/crashpad index 000e3ad7a5..0e89f5db49 160000 --- a/external/crashpad +++ b/external/crashpad @@ -1 +1 @@ -Subproject commit 000e3ad7a51c89e49bc00eca9846aa0485cccc96 +Subproject commit 0e89f5db4934d17e36627106a7ef3f166a15eb0f diff --git a/include/sentry.h b/include/sentry.h index f12916d6a9..af3d16e81f 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -2377,6 +2377,15 @@ SENTRY_API void sentry_options_set_crashpad_wait_for_upload( SENTRY_API void sentry_options_set_crashpad_limit_stack_capture_to_sp( sentry_options_t *opts, int enabled); +/** + * Sets the maximum stack capture size for non-crashing threads. + * A value of `0` disables the limit. This is disabled by default. + * + * This setting only has an effect when using the `crashpad` backend on Linux. + */ +SENTRY_API void sentry_options_set_crashpad_max_stack_capture_size( + sentry_options_t *opts, uint32_t max_stack_capture_size); + /** * Sets the maximum time (in milliseconds) to wait for the asynchronous * tasks to end on shutdown before attempting a forced termination. diff --git a/src/backends/sentry_backend_crashpad.cpp b/src/backends/sentry_backend_crashpad.cpp index f99b487916..06e83e6f72 100644 --- a/src/backends/sentry_backend_crashpad.cpp +++ b/src/backends/sentry_backend_crashpad.cpp @@ -1192,6 +1192,11 @@ crashpad_backend_startup( crashpad::TriState::kEnabled); } + if (options->crashpad_max_stack_capture_size) { + crashpad_info->set_max_stack_capture_size( + options->crashpad_max_stack_capture_size); + } + #if defined(SENTRY_PLATFORM_WINDOWS) || defined(SENTRY_PLATFORM_LINUX) \ || defined(SENTRY_PLATFORM_MACOS) sentry_scope_observer_t *observer = sentry__scope_observer_new(); diff --git a/src/sentry_options.c b/src/sentry_options.c index 3cac39b3e2..acb717ef6b 100644 --- a/src/sentry_options.c +++ b/src/sentry_options.c @@ -90,6 +90,7 @@ sentry_options_new(void) opts->propagate_traceparent = false; opts->strict_trace_continuation = false; opts->crashpad_limit_stack_capture_to_sp = false; + opts->crashpad_max_stack_capture_size = 0; opts->cache_keep = SENTRY_CACHE_KEEP_NONE; opts->cache_max_age = 0; opts->cache_max_size = 0; @@ -755,6 +756,13 @@ sentry_options_set_crashpad_limit_stack_capture_to_sp( opts->crashpad_limit_stack_capture_to_sp = !!enabled; } +void +sentry_options_set_crashpad_max_stack_capture_size( + sentry_options_t *opts, uint32_t max_stack_capture_size) +{ + opts->crashpad_max_stack_capture_size = max_stack_capture_size; +} + void sentry_options_set_shutdown_timeout( sentry_options_t *opts, uint64_t shutdown_timeout) diff --git a/src/sentry_options.h b/src/sentry_options.h index 43e58b60a2..11e99e412b 100644 --- a/src/sentry_options.h +++ b/src/sentry_options.h @@ -54,6 +54,7 @@ struct sentry_options_s { bool propagate_traceparent; bool strict_trace_continuation; bool crashpad_limit_stack_capture_to_sp; + uint32_t crashpad_max_stack_capture_size; sentry_cache_keep_t cache_keep; time_t cache_max_age; From 0c771fe242ea57f99d9d6339d35b3b00d587ba3d Mon Sep 17 00:00:00 2001 From: Corentin Kerisit Date: Fri, 25 Sep 2026 15:44:21 +0200 Subject: [PATCH 2/7] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c19b1d5f8..c9fe132824 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ **Features**: - Add `SENTRY_SDK_VERSION_MAJOR`, `SENTRY_SDK_VERSION_MINOR`, `SENTRY_SDK_VERSION_PATCH`, and `SENTRY_SDK_VERSION_AT_LEAST` for compile-time version checks. ([#2136](https://github.com/getsentry/sentry-native/pull/2136)) +- Add an option to limit non-crashing thread stack capture size in `crashpad` on Linux. ([#2137](https://github.com/getsentry/sentry-native/pull/2137), [crashpad#172](https://github.com/getsentry/crashpad/pull/172)) ## 0.17.1 From 7a88c4c3d587af7151d6380dd2ac4f9d158e7f04 Mon Sep 17 00:00:00 2001 From: Corentin Kerisit Date: Fri, 25 Sep 2026 15:54:38 +0200 Subject: [PATCH 3/7] Update crashpad submodule --- external/crashpad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/crashpad b/external/crashpad index 0e89f5db49..5f8742208b 160000 --- a/external/crashpad +++ b/external/crashpad @@ -1 +1 @@ -Subproject commit 0e89f5db4934d17e36627106a7ef3f166a15eb0f +Subproject commit 5f8742208bd825a8d416ea6b400e6daf226fa685 From 90c8a43ebac06b57edeb2343192788fad62a9e03 Mon Sep 17 00:00:00 2001 From: Corentin Kerisit Date: Fri, 25 Sep 2026 16:04:01 +0200 Subject: [PATCH 4/7] Update crashpad submodule --- external/crashpad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/crashpad b/external/crashpad index 5f8742208b..89893f4955 160000 --- a/external/crashpad +++ b/external/crashpad @@ -1 +1 @@ -Subproject commit 5f8742208bd825a8d416ea6b400e6daf226fa685 +Subproject commit 89893f49556b35be7479db412101445a5d221221 From 62e342e0d66b53148728c2944d5aa8960b7287b5 Mon Sep 17 00:00:00 2001 From: Corentin Kerisit Date: Wed, 30 Sep 2026 09:09:46 +0200 Subject: [PATCH 5/7] Update crashpad submodule --- external/crashpad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/crashpad b/external/crashpad index 89893f4955..33eef31884 160000 --- a/external/crashpad +++ b/external/crashpad @@ -1 +1 @@ -Subproject commit 89893f49556b35be7479db412101445a5d221221 +Subproject commit 33eef31884ef4ffee7830d7bc57aba63405bff57 From c88558cfa2e36bb4115aed1d68fedff410b3edd9 Mon Sep 17 00:00:00 2001 From: Corentin Kerisit Date: Wed, 30 Sep 2026 13:35:31 +0200 Subject: [PATCH 6/7] Support stack capture size limit in native backend --- CHANGELOG.md | 2 +- include/sentry.h | 5 +++-- .../native/minidump/sentry_minidump_linux.c | 15 ++++++++++----- src/backends/native/sentry_crash_context.h | 1 + src/backends/sentry_backend_crashpad.cpp | 4 ++-- src/backends/sentry_backend_native.c | 1 + src/sentry_options.c | 6 +++--- src/sentry_options.h | 2 +- 8 files changed, 22 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9fe132824..1af7865755 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ **Features**: - Add `SENTRY_SDK_VERSION_MAJOR`, `SENTRY_SDK_VERSION_MINOR`, `SENTRY_SDK_VERSION_PATCH`, and `SENTRY_SDK_VERSION_AT_LEAST` for compile-time version checks. ([#2136](https://github.com/getsentry/sentry-native/pull/2136)) -- Add an option to limit non-crashing thread stack capture size in `crashpad` on Linux. ([#2137](https://github.com/getsentry/sentry-native/pull/2137), [crashpad#172](https://github.com/getsentry/crashpad/pull/172)) +- Add an option to limit non-crashing thread stack capture size in `crashpad` and `native` on Linux. ([#2137](https://github.com/getsentry/sentry-native/pull/2137), [crashpad#172](https://github.com/getsentry/crashpad/pull/172)) ## 0.17.1 diff --git a/include/sentry.h b/include/sentry.h index af3d16e81f..dc7a7cfa13 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -2381,9 +2381,10 @@ SENTRY_API void sentry_options_set_crashpad_limit_stack_capture_to_sp( * Sets the maximum stack capture size for non-crashing threads. * A value of `0` disables the limit. This is disabled by default. * - * This setting only has an effect when using the `crashpad` backend on Linux. + * This setting only has an effect when using the `crashpad` or `native` backend + * on Linux. */ -SENTRY_API void sentry_options_set_crashpad_max_stack_capture_size( +SENTRY_API void sentry_options_set_max_stack_capture_size( sentry_options_t *opts, uint32_t max_stack_capture_size); /** diff --git a/src/backends/native/minidump/sentry_minidump_linux.c b/src/backends/native/minidump/sentry_minidump_linux.c index 753a1939de..7b5c08c44b 100644 --- a/src/backends/native/minidump/sentry_minidump_linux.c +++ b/src/backends/native/minidump/sentry_minidump_linux.c @@ -1216,7 +1216,7 @@ write_cv_record(minidump_writer_t *writer, const char *module_path, */ static minidump_rva_t write_thread_stack(minidump_writer_t *writer, uint64_t stack_pointer, - size_t *stack_size_out, uint64_t *stack_start_out) + pid_t thread_id, size_t *stack_size_out, uint64_t *stack_start_out) { SENTRY_DEBUGF( "write_thread_stack: SP=0x%llx", (unsigned long long)stack_pointer); @@ -1285,6 +1285,11 @@ write_thread_stack(minidump_writer_t *writer, uint64_t stack_pointer, if (stack_size > SENTRY_CRASH_MAX_STACK_SIZE) { stack_size = SENTRY_CRASH_MAX_STACK_SIZE; } + if (thread_id != writer->crash_ctx->crashed_tid + && writer->crash_ctx->max_stack_capture_size + && stack_size > writer->crash_ctx->max_stack_capture_size) { + stack_size = writer->crash_ctx->max_stack_capture_size; + } void *stack_buffer = sentry_malloc(stack_size); if (!stack_buffer) { @@ -1387,8 +1392,8 @@ ptrace_capture_thread( if (ptrace_sp != 0) { size_t stack_size = 0; uint64_t stack_start = 0; - thread->stack.memory.rva - = write_thread_stack(writer, ptrace_sp, &stack_size, &stack_start); + thread->stack.memory.rva = write_thread_stack( + writer, ptrace_sp, thread->thread_id, &stack_size, &stack_start); thread->stack.memory.size = stack_size; thread->stack.start_address = stack_start; record_thread_stack(writer, thread); @@ -1477,8 +1482,8 @@ write_thread_list_stream(minidump_writer_t *writer, minidump_directory_t *dir) if (sp != 0) { size_t stack_size = 0; uint64_t stack_start = 0; - thread->stack.memory.rva - = write_thread_stack(writer, sp, &stack_size, &stack_start); + thread->stack.memory.rva = write_thread_stack( + writer, sp, thread->thread_id, &stack_size, &stack_start); thread->stack.memory.size = stack_size; thread->stack.start_address = stack_start; record_thread_stack(writer, thread); diff --git a/src/backends/native/sentry_crash_context.h b/src/backends/native/sentry_crash_context.h index b57264a721..5409b1c7e1 100644 --- a/src/backends/native/sentry_crash_context.h +++ b/src/backends/native/sentry_crash_context.h @@ -292,6 +292,7 @@ typedef struct { int crash_reporting_mode; // sentry_crash_reporting_mode_t int crash_upload_mode; // sentry_crash_upload_mode_t int thread_stackwalk_mode; // sentry_thread_stackwalk_mode_t + uint32_t max_stack_capture_size; bool debug_enabled; // Debug logging enabled in parent process bool attach_screenshot; // Screenshot attachment enabled in parent process bool attach_session_replay; // Session replay attachment enabled in parent diff --git a/src/backends/sentry_backend_crashpad.cpp b/src/backends/sentry_backend_crashpad.cpp index 06e83e6f72..bd1ae143db 100644 --- a/src/backends/sentry_backend_crashpad.cpp +++ b/src/backends/sentry_backend_crashpad.cpp @@ -1192,9 +1192,9 @@ crashpad_backend_startup( crashpad::TriState::kEnabled); } - if (options->crashpad_max_stack_capture_size) { + if (options->max_stack_capture_size) { crashpad_info->set_max_stack_capture_size( - options->crashpad_max_stack_capture_size); + options->max_stack_capture_size); } #if defined(SENTRY_PLATFORM_WINDOWS) || defined(SENTRY_PLATFORM_LINUX) \ diff --git a/src/backends/sentry_backend_native.c b/src/backends/sentry_backend_native.c index 21c0ae706b..84df419b5f 100644 --- a/src/backends/sentry_backend_native.c +++ b/src/backends/sentry_backend_native.c @@ -727,6 +727,7 @@ native_backend_startup( ctx->system_crash_reporter_enabled = options->system_crash_reporter_enabled; ctx->crash_upload_mode = options->crash_upload_mode; ctx->thread_stackwalk_mode = options->thread_stackwalk_mode; + ctx->max_stack_capture_size = options->max_stack_capture_size; // Pass debug logging setting to daemon ctx->debug_enabled = options->debug; diff --git a/src/sentry_options.c b/src/sentry_options.c index acb717ef6b..6504cf5d42 100644 --- a/src/sentry_options.c +++ b/src/sentry_options.c @@ -90,7 +90,7 @@ sentry_options_new(void) opts->propagate_traceparent = false; opts->strict_trace_continuation = false; opts->crashpad_limit_stack_capture_to_sp = false; - opts->crashpad_max_stack_capture_size = 0; + opts->max_stack_capture_size = 0; opts->cache_keep = SENTRY_CACHE_KEEP_NONE; opts->cache_max_age = 0; opts->cache_max_size = 0; @@ -757,10 +757,10 @@ sentry_options_set_crashpad_limit_stack_capture_to_sp( } void -sentry_options_set_crashpad_max_stack_capture_size( +sentry_options_set_max_stack_capture_size( sentry_options_t *opts, uint32_t max_stack_capture_size) { - opts->crashpad_max_stack_capture_size = max_stack_capture_size; + opts->max_stack_capture_size = max_stack_capture_size; } void diff --git a/src/sentry_options.h b/src/sentry_options.h index 11e99e412b..e3cb1b17bd 100644 --- a/src/sentry_options.h +++ b/src/sentry_options.h @@ -54,7 +54,7 @@ struct sentry_options_s { bool propagate_traceparent; bool strict_trace_continuation; bool crashpad_limit_stack_capture_to_sp; - uint32_t crashpad_max_stack_capture_size; + uint32_t max_stack_capture_size; sentry_cache_keep_t cache_keep; time_t cache_max_age; From fce82eb9f6f5c10ffd20dc946fface752cf8171a Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 5 Oct 2026 09:01:38 +0200 Subject: [PATCH 7/7] fix(native): Honor stack capture limits and preserve SP coverage The x86_64 red zone puts the capture start 128 bytes below SP. When the capture limit fits entirely below SP, omit the red zone so the captured range includes SP. Use an explicit nonzero limit for non-crashing threads in place of the internal 1 MiB default. Keep the default when the option is zero and for the crashing thread. --- .../native/minidump/sentry_minidump_linux.c | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/backends/native/minidump/sentry_minidump_linux.c b/src/backends/native/minidump/sentry_minidump_linux.c index 7b5c08c44b..50a6115ac8 100644 --- a/src/backends/native/minidump/sentry_minidump_linux.c +++ b/src/backends/native/minidump/sentry_minidump_linux.c @@ -1277,18 +1277,22 @@ write_thread_stack(minidump_writer_t *writer, uint64_t stack_pointer, if (capture_start < stack_start) { capture_start = stack_start; } + // Limit to 1MB by default + size_t max_size = SENTRY_CRASH_MAX_STACK_SIZE; + if (thread_id != writer->crash_ctx->crashed_tid + && writer->crash_ctx->max_stack_capture_size) { + max_size = writer->crash_ctx->max_stack_capture_size; + } + // Omit the red zone to include SP + if (max_size <= stack_pointer - capture_start) { + capture_start = stack_pointer; + } // Capture from adjusted SP to end of stack (upwards) size_t stack_size = stack_end - capture_start; - // Limit to 1MB - if (stack_size > SENTRY_CRASH_MAX_STACK_SIZE) { - stack_size = SENTRY_CRASH_MAX_STACK_SIZE; - } - if (thread_id != writer->crash_ctx->crashed_tid - && writer->crash_ctx->max_stack_capture_size - && stack_size > writer->crash_ctx->max_stack_capture_size) { - stack_size = writer->crash_ctx->max_stack_capture_size; + if (stack_size > max_size) { + stack_size = max_size; } void *stack_buffer = sentry_malloc(stack_size);