-
-
Notifications
You must be signed in to change notification settings - Fork 205
fix(native): capture WER crash exceptions #1710
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
1278d31
fix(native): capture WER crash exceptions
jpnurmi 539d5e2
Update CHANGELOG.md
jpnurmi 21adffa
fix(native): keep WER callback ownership claim
jpnurmi 7ba3742
Fix style
jpnurmi baa9b0d
sentry_add_version_resource
jpnurmi 00ad41e
sentry_native_wer_registration_t
jpnurmi 5ba0727
ExceptionRecord
jpnurmi 3895c77
fix(native): clean up WER registry value
jpnurmi f0817a0
fix(native): clean up failed WER registration
jpnurmi 238041d
sentry_wer_registration_t
jpnurmi 7fed4aa
unregister
jpnurmi 1581cab
assert_native_crash
jpnurmi 91c70bd
timeout
jpnurmi e13e1ef
fix(native): claim WER crashes after signaling daemon
jpnurmi 2685faa
fix(native): terminate claimed WER crashes
jpnurmi c40d991
skipif
jpnurmi 0bca2b9
script
jpnurmi d330064
WithoutCrashpadWer
jpnurmi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
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
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
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,229 @@ | ||
| #include "sentry_crash_context.h" | ||
|
|
||
| #include <stddef.h> | ||
| #include <stdint.h> | ||
| #include <stdio.h> | ||
| #include <werapi.h> | ||
| #include <windows.h> | ||
|
|
||
| #ifndef STATUS_FAIL_FAST_EXCEPTION | ||
| # define STATUS_FAIL_FAST_EXCEPTION ((DWORD)0xC0000602) | ||
| #endif | ||
|
|
||
| #ifndef STATUS_STACK_BUFFER_OVERRUN | ||
| # define STATUS_STACK_BUFFER_OVERRUN ((DWORD)0xC0000409) | ||
| #endif | ||
|
|
||
| static BOOL | ||
| is_fatal_wer_exception(const WER_RUNTIME_EXCEPTION_INFORMATION *info) | ||
| { | ||
| // bIsFatal is missing in older SDKs; guard access with dwSize. | ||
| typedef struct { | ||
| DWORD dwSize; | ||
| HANDLE hProcess; | ||
| HANDLE hThread; | ||
| EXCEPTION_RECORD exceptionRecord; | ||
| CONTEXT context; | ||
| PCWSTR pwszReportId; | ||
| BOOL bIsFatal; | ||
| DWORD dwReserved; | ||
| } WER_RUNTIME_EXCEPTION_INFORMATION_19041; | ||
|
|
||
| if (!info | ||
| || info->dwSize | ||
| <= offsetof(WER_RUNTIME_EXCEPTION_INFORMATION_19041, bIsFatal)) { | ||
| return FALSE; | ||
| } | ||
|
|
||
| return ((const WER_RUNTIME_EXCEPTION_INFORMATION_19041 *)info)->bIsFatal; | ||
| } | ||
|
|
||
| static BOOL | ||
| is_native_wer_exception(DWORD code) | ||
| { | ||
| return code == STATUS_FAIL_FAST_EXCEPTION | ||
| || code == STATUS_STACK_BUFFER_OVERRUN; | ||
| } | ||
|
|
||
| static BOOL | ||
| read_registration( | ||
| HANDLE process, PVOID context, sentry_wer_registration_t *registration) | ||
| { | ||
| if (!process || !context || !registration) { | ||
| return FALSE; | ||
| } | ||
|
|
||
| if (!ReadProcessMemory( | ||
| process, context, registration, sizeof(*registration), NULL)) { | ||
| return FALSE; | ||
| } | ||
|
|
||
| return registration->version == 1 && registration->app_pid != 0; | ||
| } | ||
|
|
||
| static BOOL | ||
| open_native_crash_objects(const sentry_wer_registration_t *registration, | ||
| HANDLE *mapping, HANDLE *event, sentry_crash_context_t **ctx) | ||
| { | ||
| wchar_t shm_name[SENTRY_CRASH_IPC_NAME_SIZE]; | ||
| wchar_t event_name[SENTRY_CRASH_IPC_NAME_SIZE]; | ||
|
|
||
| swprintf(shm_name, SENTRY_CRASH_IPC_NAME_SIZE, | ||
| L"Local\\SentryCrash-%lu-%llx", (unsigned long)registration->app_pid, | ||
| (unsigned long long)registration->app_tid); | ||
| swprintf(event_name, SENTRY_CRASH_IPC_NAME_SIZE, | ||
| L"Local\\SentryCrashEvent-%lu-%llx", | ||
| (unsigned long)registration->app_pid, | ||
| (unsigned long long)registration->app_tid); | ||
|
|
||
| *mapping = OpenFileMappingW(FILE_MAP_ALL_ACCESS, FALSE, shm_name); | ||
| if (!*mapping) { | ||
| return FALSE; | ||
| } | ||
|
|
||
| *ctx = MapViewOfFile( | ||
| *mapping, FILE_MAP_ALL_ACCESS, 0, 0, SENTRY_CRASH_SHM_SIZE); | ||
| if (!*ctx) { | ||
| CloseHandle(*mapping); | ||
| *mapping = NULL; | ||
| return FALSE; | ||
| } | ||
|
|
||
| if ((*ctx)->magic != SENTRY_CRASH_MAGIC) { | ||
| UnmapViewOfFile(*ctx); | ||
| CloseHandle(*mapping); | ||
| *ctx = NULL; | ||
| *mapping = NULL; | ||
| return FALSE; | ||
| } | ||
|
|
||
| *event = OpenEventW(EVENT_MODIFY_STATE, FALSE, event_name); | ||
| if (!*event) { | ||
| UnmapViewOfFile(*ctx); | ||
| CloseHandle(*mapping); | ||
| *ctx = NULL; | ||
| *mapping = NULL; | ||
| return FALSE; | ||
| } | ||
|
|
||
| return TRUE; | ||
| } | ||
|
|
||
| static BOOL | ||
| process_wer_exception( | ||
| PVOID context, const WER_RUNTIME_EXCEPTION_INFORMATION *exception_info) | ||
| { | ||
| if (!exception_info || !is_fatal_wer_exception(exception_info) | ||
| || !is_native_wer_exception( | ||
| exception_info->exceptionRecord.ExceptionCode)) { | ||
| return FALSE; | ||
| } | ||
|
|
||
| sentry_wer_registration_t registration = { 0 }; | ||
| if (!read_registration(exception_info->hProcess, context, ®istration)) { | ||
| return FALSE; | ||
| } | ||
|
|
||
| HANDLE mapping = NULL; | ||
| HANDLE event = NULL; | ||
| sentry_crash_context_t *ctx = NULL; | ||
| if (!open_native_crash_objects(®istration, &mapping, &event, &ctx)) { | ||
| return FALSE; | ||
| } | ||
|
|
||
| BOOL claimed = FALSE; | ||
| if (InterlockedCompareExchange(&ctx->state, SENTRY_CRASH_STATE_PROCESSING, | ||
| SENTRY_CRASH_STATE_READY) | ||
| == SENTRY_CRASH_STATE_READY) { | ||
| ctx->crashed_pid = GetProcessId(exception_info->hProcess); | ||
| ctx->crashed_tid = GetThreadId(exception_info->hThread); | ||
| ctx->platform.exception_code | ||
| = exception_info->exceptionRecord.ExceptionCode; | ||
| ctx->platform.exception_record = exception_info->exceptionRecord; | ||
| ctx->platform.context = exception_info->context; | ||
| ctx->platform.exception_pointers = NULL; | ||
| ctx->platform.num_threads = 1; | ||
| ctx->platform.threads[0].thread_id = ctx->crashed_tid; | ||
| ctx->platform.threads[0].context = exception_info->context; | ||
|
|
||
| InterlockedExchange(&ctx->state, SENTRY_CRASH_STATE_CRASHED); | ||
| if (SetEvent(event)) { | ||
| claimed = TRUE; | ||
| uint64_t timeout_ms = ctx->shutdown_timeout | ||
| ? ctx->shutdown_timeout | ||
| : SENTRY_CRASH_HANDLER_WAIT_TIMEOUT_MS; | ||
| for (uint64_t waited_ms = 0; waited_ms < timeout_ms; | ||
| waited_ms += SENTRY_CRASH_HANDLER_POLL_INTERVAL_MS) { | ||
| if (InterlockedCompareExchange(&ctx->state, | ||
| SENTRY_CRASH_STATE_DONE, SENTRY_CRASH_STATE_DONE) | ||
| == SENTRY_CRASH_STATE_DONE) { | ||
| break; | ||
| } | ||
| Sleep(SENTRY_CRASH_HANDLER_POLL_INTERVAL_MS); | ||
| } | ||
| TerminateProcess(exception_info->hProcess, | ||
| exception_info->exceptionRecord.ExceptionCode); | ||
| } | ||
|
sentry[bot] marked this conversation as resolved.
|
||
| } | ||
|
|
||
| CloseHandle(event); | ||
| UnmapViewOfFile(ctx); | ||
| CloseHandle(mapping); | ||
| return claimed; | ||
| } | ||
|
|
||
| BOOL WINAPI | ||
| DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) | ||
| { | ||
| (void)instance; | ||
| (void)reason; | ||
| (void)reserved; | ||
| return TRUE; | ||
| } | ||
|
|
||
| HRESULT WINAPI | ||
| OutOfProcessExceptionEventCallback(PVOID context, | ||
| const PWER_RUNTIME_EXCEPTION_INFORMATION exception_info, | ||
| BOOL *ownership_claimed, PWSTR event_name, PDWORD event_name_size, | ||
| PDWORD signature_count) | ||
| { | ||
| (void)event_name; | ||
| (void)event_name_size; | ||
| (void)signature_count; | ||
|
|
||
| *ownership_claimed = FALSE; | ||
| if (process_wer_exception(context, exception_info)) { | ||
| *ownership_claimed = TRUE; | ||
| } | ||
| return S_OK; | ||
|
sentry[bot] marked this conversation as resolved.
|
||
| } | ||
|
|
||
| HRESULT WINAPI | ||
| OutOfProcessExceptionEventSignatureCallback(PVOID context, | ||
| const PWER_RUNTIME_EXCEPTION_INFORMATION exception_info, DWORD index, | ||
| PWSTR name, PDWORD name_size, PWSTR value, PDWORD value_size) | ||
| { | ||
| (void)context; | ||
| (void)exception_info; | ||
| (void)index; | ||
| (void)name; | ||
| (void)name_size; | ||
| (void)value; | ||
| (void)value_size; | ||
| return E_FAIL; | ||
| } | ||
|
|
||
| HRESULT WINAPI | ||
| OutOfProcessExceptionEventDebuggerLaunchCallback(PVOID context, | ||
| const PWER_RUNTIME_EXCEPTION_INFORMATION exception_info, | ||
| PBOOL is_custom_debugger, PWSTR debugger_launch, | ||
| PDWORD debugger_launch_size, PBOOL is_debugger_autolaunch) | ||
| { | ||
| (void)context; | ||
| (void)exception_info; | ||
| (void)is_custom_debugger; | ||
| (void)debugger_launch; | ||
| (void)debugger_launch_size; | ||
| (void)is_debugger_autolaunch; | ||
| return E_FAIL; | ||
| } | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| LIBRARY "sentry-wer.dll" | ||
|
|
||
| EXPORTS | ||
| OutOfProcessExceptionEventCallback | ||
| OutOfProcessExceptionEventSignatureCallback | ||
| OutOfProcessExceptionEventDebuggerLaunchCallback |
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.