diff --git a/CHANGELOG.md b/CHANGELOG.md index cf4a041f65..cb15c3c4f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - 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)) - Let downstream platform integrations supply the installation ID. ([#2150](https://github.com/getsentry/sentry-native/pull/2150)) +- Native/Crashpad/Linux: Add `max_stack_capture_size` option to limit non-crashing thread stack capture size. ([#2137](https://github.com/getsentry/sentry-native/pull/2137), [crashpad#172](https://github.com/getsentry/crashpad/pull/172)) - Add `sentry_value_from_json`, `sentry_value_from_msgpack`, and `sentry_value_from_msgpack_stream` alongside the existing JSON and MessagePack serialization APIs to provide public bidirectional APIs for serializing and deserializing sentry values as JSON and MessagePack. ([#2153](https://github.com/getsentry/sentry-native/pull/2153)) **Fixes**: diff --git a/external/crashpad b/external/crashpad index 7ce0f28e61..d0fb04940e 160000 --- a/external/crashpad +++ b/external/crashpad @@ -1 +1 @@ -Subproject commit 7ce0f28e61db64a3942b2b8207072bac72a0a986 +Subproject commit d0fb04940eeaf22dda8bfe0ae894d0fe96bdfcdf diff --git a/include/sentry.h b/include/sentry.h index ac83d7416d..1da8a937bd 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -2413,6 +2413,16 @@ 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` or `native` backend + * on Linux. + */ +SENTRY_API void sentry_options_set_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/native/minidump/sentry_minidump_linux.c b/src/backends/native/minidump/sentry_minidump_linux.c index 753a1939de..50a6115ac8 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); @@ -1277,13 +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 (stack_size > max_size) { + stack_size = max_size; } void *stack_buffer = sentry_malloc(stack_size); @@ -1387,8 +1396,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 +1486,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 7cd775ff62..83df53b2a0 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->max_stack_capture_size) { + crashpad_info->set_max_stack_capture_size( + options->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/backends/sentry_backend_native.c b/src/backends/sentry_backend_native.c index 24aacff8ca..0d69f7f7c5 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 3cac39b3e2..6504cf5d42 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->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_max_stack_capture_size( + sentry_options_t *opts, uint32_t max_stack_capture_size) +{ + opts->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..e3cb1b17bd 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 max_stack_capture_size; sentry_cache_keep_t cache_keep; time_t cache_max_age;