diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d6f56c5e..9abd2c685 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ **Features** - Android: Expose app-hang detection through the NDK bindings via `NdkOptions.setEnableAppHangTracking()` and `NdkOptions.setAppHangTimeoutMillis()`. ([#1823](https://github.com/getsentry/sentry-native/pull/1823)) +- Native/Windows: Allow configuring whether SEH and fast-fail crashes propagate to WER via `sentry_options_set_wer_mode`. ([#1833](https://github.com/getsentry/sentry-native/pull/1833)) ## 0.15.2 diff --git a/include/sentry.h b/include/sentry.h index 28c3cde0c..ba63bd10c 100644 --- a/include/sentry.h +++ b/include/sentry.h @@ -1116,6 +1116,36 @@ typedef enum { SENTRY_CACHE_KEEP_ALWAYS = 2, } sentry_cache_keep_t; +/** + * Windows Error Reporting (WER) mode. + */ +typedef enum { + /** + * SEH crashes: the SDK's unhandled exception filter returns + * `EXCEPTION_EXECUTE_HANDLER`, the process is terminated, and the crash is + * not propagated to WER. + * Fast-fail crashes: no WER module is registered, so fast-fail crashes are + * not captured by Sentry, and are handled by WER instead. + */ + SENTRY_WER_MODE_NONE = 0, + /** + * SEH crashes: the SDK's unhandled exception filter returns + * `EXCEPTION_EXECUTE_HANDLER`, the process is terminated, and the crash is + * not propagated to WER. + * Fast-fail crashes: the WER module claims ownership and terminates the + * process, preventing WER to also process them. + */ + SENTRY_WER_MODE_EXCLUSIVE = 1, + /** + * SEH crashes: the SDK's unhandled exception filter returns + * `EXCEPTION_CONTINUE_SEARCH`, which proceeds with normal exception + * handling and lets WER also process the crash. + * Fast-fail crashes: the WER module does not claim ownership, allowing WER + * to also process them. + */ + SENTRY_WER_MODE_SHARED = 2, +} sentry_wer_mode_t; + /** * Creates a new options struct. * Can be freed with `sentry_options_free`. @@ -1924,6 +1954,21 @@ SENTRY_API void sentry_options_set_crash_upload_mode( SENTRY_API sentry_crash_upload_mode_t sentry_options_get_crash_upload_mode( const sentry_options_t *opts); +/** + * Sets the WER (Windows Error Reporting) mode for the native backend. + * + * This setting only has an effect when using the `native` backend. + * Default is `SENTRY_WER_MODE_SHARED`. + */ +SENTRY_EXPERIMENTAL_API void sentry_options_set_wer_mode( + sentry_options_t *opts, sentry_wer_mode_t mode); + +/** + * Gets the WER (Windows Error Reporting) mode. + */ +SENTRY_EXPERIMENTAL_API sentry_wer_mode_t sentry_options_get_wer_mode( + const sentry_options_t *opts); + /** * Enables a wait for the crash report upload to be finished before shutting * down. This is disabled by default. diff --git a/src/backends/native/sentry_crash_context.h b/src/backends/native/sentry_crash_context.h index 754dd6497..e13e2bcd9 100644 --- a/src/backends/native/sentry_crash_context.h +++ b/src/backends/native/sentry_crash_context.h @@ -290,6 +290,7 @@ typedef struct { uint64_t shutdown_timeout; uint64_t transfer_timeout; bool system_crash_reporter_enabled; + int wer_mode; // 0=none, 1=exclusive, 2=shared (see sentry_wer_mode_t) uint32_t max_breadcrumbs; // Atomic user consent (sentry_user_consent_t), updated whenever user diff --git a/src/backends/native/sentry_wer.c b/src/backends/native/sentry_wer.c index 37542528c..ca798049d 100644 --- a/src/backends/native/sentry_wer.c +++ b/src/backends/native/sentry_wer.c @@ -148,7 +148,16 @@ process_wer_exception( InterlockedExchange(&ctx->state, SENTRY_CRASH_STATE_CRASHED); if (SetEvent(event)) { - claimed = TRUE; + BOOL shared = ctx->wer_mode == SENTRY_WER_MODE_SHARED; + if (shared) { + // SHARED: signal the daemon asynchronously, but don't claim + // ownership so WER can also process the crash. + claimed = FALSE; + } else { + // EXCLUSIVE: wait for daemon and terminate process, claiming + // exclusive ownership of the crash. + claimed = TRUE; + } uint64_t timeout_ms = ctx->shutdown_timeout ? ctx->shutdown_timeout : SENTRY_CRASH_HANDLER_WAIT_TIMEOUT_MS; @@ -161,8 +170,10 @@ process_wer_exception( } Sleep(SENTRY_CRASH_HANDLER_POLL_INTERVAL_MS); } - TerminateProcess(exception_info->hProcess, - exception_info->exceptionRecord.ExceptionCode); + if (!shared) { + TerminateProcess(exception_info->hProcess, + exception_info->exceptionRecord.ExceptionCode); + } } } diff --git a/src/backends/sentry_backend_native.c b/src/backends/sentry_backend_native.c index dec427d79..fc4d37eee 100644 --- a/src/backends/sentry_backend_native.c +++ b/src/backends/sentry_backend_native.c @@ -297,6 +297,7 @@ native_backend_startup( ctx->crash_reporting_mode = options->crash_reporting_mode; ctx->system_crash_reporter_enabled = options->system_crash_reporter_enabled; ctx->crash_upload_mode = options->crash_upload_mode; + ctx->wer_mode = options->wer_mode; // Pass debug logging setting to daemon ctx->debug_enabled = options->debug; @@ -527,7 +528,9 @@ native_backend_startup( } # if defined(SENTRY_PLATFORM_WINDOWS) && !defined(SENTRY_PLATFORM_XBOX) - wer_register_module(tid); + if (options->wer_mode != SENTRY_WER_MODE_NONE) { + wer_register_module(tid); + } # endif if (sentry__crash_handler_init(state->ipc) < 0) { diff --git a/src/sentry_options.c b/src/sentry_options.c index 01d1ab1f7..6b9c4002f 100644 --- a/src/sentry_options.c +++ b/src/sentry_options.c @@ -114,6 +114,7 @@ sentry_options_new(void) = SENTRY_CRASH_REPORTING_MODE_NATIVE_WITH_MINIDUMP; // Default: best of // both worlds opts->crash_upload_mode = SENTRY_CRASH_UPLOAD_MODE_SYNC; + opts->wer_mode = SENTRY_WER_MODE_SHARED; opts->enable_app_hang_tracking = false; opts->app_hang_timeout = 5000; opts->http_retry = false; @@ -1038,6 +1039,24 @@ sentry_options_set_handler_strategy( #endif // SENTRY_PLATFORM_LINUX +void +sentry_options_set_wer_mode(sentry_options_t *opts, sentry_wer_mode_t mode) +{ + int imode = (int)mode; + if (imode < SENTRY_WER_MODE_NONE) { + imode = SENTRY_WER_MODE_NONE; + } else if (imode > SENTRY_WER_MODE_SHARED) { + imode = SENTRY_WER_MODE_SHARED; + } + opts->wer_mode = imode; +} + +sentry_wer_mode_t +sentry_options_get_wer_mode(const sentry_options_t *opts) +{ + return (sentry_wer_mode_t)opts->wer_mode; +} + void sentry_options_set_http_retry(sentry_options_t *opts, int enabled) { diff --git a/src/sentry_options.h b/src/sentry_options.h index 0947ef452..a6b368fbc 100644 --- a/src/sentry_options.h +++ b/src/sentry_options.h @@ -105,6 +105,7 @@ struct sentry_options_s { int crash_reporting_mode; // 0=minidump, 1=native, 2=native_with_minidump // (see sentry_crash_reporting_mode_t) int crash_upload_mode; // 0=sync, 1=async (see sentry_crash_upload_mode_t) + int wer_mode; // 0=none, 1=exclusive, 2=shared (see sentry_wer_mode_t) #ifdef SENTRY_PLATFORM_NX void (*network_connect_func)(void);