Index: compiler-rt/trunk/lib/asan/asan_win.cc =================================================================== --- compiler-rt/trunk/lib/asan/asan_win.cc +++ compiler-rt/trunk/lib/asan/asan_win.cc @@ -47,6 +47,47 @@ } // extern "C" // ---------------------- Windows-specific interceptors ---------------- {{{ +static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler; +static LPTOP_LEVEL_EXCEPTION_FILTER user_seh_handler; + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE +long __asan_unhandled_exception_filter(EXCEPTION_POINTERS *info) { + EXCEPTION_RECORD *exception_record = info->ExceptionRecord; + CONTEXT *context = info->ContextRecord; + + // FIXME: Handle EXCEPTION_STACK_OVERFLOW here. + + SignalContext sig = SignalContext::Create(exception_record, context); + ReportDeadlySignal(exception_record->ExceptionCode, sig); + UNREACHABLE("returned from reporting deadly signal"); +} + +// Wrapper SEH Handler. If the exception should be handled by asan, we call +// __asan_unhandled_exception_filter, otherwise, we execute the user provided +// exception handler or the default. +static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) { + DWORD exception_code = info->ExceptionRecord->ExceptionCode; + if (__sanitizer::IsHandledDeadlyException(exception_code)) + return __asan_unhandled_exception_filter(info); + if (user_seh_handler) + return user_seh_handler(info); + // Bubble out to the default exception filter. + if (default_seh_handler) + return default_seh_handler(info); + return EXCEPTION_CONTINUE_SEARCH; +} + +INTERCEPTOR_WINAPI(LPTOP_LEVEL_EXCEPTION_FILTER, SetUnhandledExceptionFilter, + LPTOP_LEVEL_EXCEPTION_FILTER ExceptionFilter) { + CHECK(REAL(SetUnhandledExceptionFilter)); + if (ExceptionFilter == &SEHHandler || common_flags()->allow_user_segv_handler) + return REAL(SetUnhandledExceptionFilter)(ExceptionFilter); + // We record the user provided exception handler to be called for all the + // exceptions unhandled by asan. + Swap(ExceptionFilter, user_seh_handler); + return ExceptionFilter; +} + INTERCEPTOR_WINAPI(void, RtlRaiseException, EXCEPTION_RECORD *ExceptionRecord) { CHECK(REAL(RtlRaiseException)); // This is a noreturn function, unless it's one of the exceptions raised to @@ -119,6 +160,7 @@ void InitializePlatformInterceptors() { ASAN_INTERCEPT_FUNC(CreateThread); + ASAN_INTERCEPT_FUNC(SetUnhandledExceptionFilter); #ifdef _WIN64 ASAN_INTERCEPT_FUNC(__C_specific_handler); @@ -235,30 +277,6 @@ #endif } -static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler; - -extern "C" SANITIZER_INTERFACE_ATTRIBUTE -long __asan_unhandled_exception_filter(EXCEPTION_POINTERS *info) { - EXCEPTION_RECORD *exception_record = info->ExceptionRecord; - CONTEXT *context = info->ContextRecord; - - // Continue the search if the signal wasn't deadly. - if (!IsHandledDeadlyException(exception_record->ExceptionCode)) - return EXCEPTION_CONTINUE_SEARCH; - // FIXME: Handle EXCEPTION_STACK_OVERFLOW here. - - SignalContext sig = SignalContext::Create(exception_record, context); - ReportDeadlySignal(exception_record->ExceptionCode, sig); - UNREACHABLE("returned from reporting deadly signal"); -} - -static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) { - __asan_unhandled_exception_filter(info); - - // Bubble out to the default exception filter. - return default_seh_handler(info); -} - // We want to install our own exception handler (EH) to print helpful reports // on access violations and whatnot. Unfortunately, the CRT initializers assume // they are run before any user code and drop any previously-installed EHs on Index: compiler-rt/trunk/test/asan/TestCases/Windows/dll_host.cc =================================================================== --- compiler-rt/trunk/test/asan/TestCases/Windows/dll_host.cc +++ compiler-rt/trunk/test/asan/TestCases/Windows/dll_host.cc @@ -31,6 +31,7 @@ // IMPORT: __asan_wrap_CreateThread // IMPORT: __asan_wrap_RaiseException // IMPORT: __asan_wrap_RtlRaiseException +// IMPORT: __asan_wrap_SetUnhandledExceptionFilter // // RUN: cat %t.imports1 %t.imports2 | sort | uniq > %t.imports-sorted // RUN: cat %t.exports1 %t.exports2 | sort | uniq > %t.exports-sorted