summaryrefslogtreecommitdiff
path: root/libsanitizer/asan/asan_win.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libsanitizer/asan/asan_win.cc')
-rw-r--r--libsanitizer/asan/asan_win.cc64
1 files changed, 63 insertions, 1 deletions
diff --git a/libsanitizer/asan/asan_win.cc b/libsanitizer/asan/asan_win.cc
index 03d45e3839b..b0028763b11 100644
--- a/libsanitizer/asan/asan_win.cc
+++ b/libsanitizer/asan/asan_win.cc
@@ -19,6 +19,7 @@
#include "asan_interceptors.h"
#include "asan_internal.h"
+#include "asan_report.h"
#include "asan_thread.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_mutex.h"
@@ -68,7 +69,7 @@ void *AsanDoesNotSupportStaticLinkage() {
return 0;
}
-void AsanCheckDynamicRTPrereqs() { UNIMPLEMENTED(); }
+void AsanCheckDynamicRTPrereqs() {}
void AsanCheckIncompatibleRT() {}
@@ -84,6 +85,67 @@ void AsanOnSIGSEGV(int, void *siginfo, void *context) {
UNIMPLEMENTED();
}
+static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
+
+static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
+ EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
+ CONTEXT *context = info->ContextRecord;
+ uptr pc = (uptr)exception_record->ExceptionAddress;
+#ifdef _WIN64
+ uptr bp = (uptr)context->Rbp, sp = (uptr)context->Rsp;
+#else
+ uptr bp = (uptr)context->Ebp, sp = (uptr)context->Esp;
+#endif
+
+ if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
+ exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) {
+ const char *description =
+ (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+ ? "access-violation"
+ : "in-page-error";
+ uptr access_addr = exception_record->ExceptionInformation[1];
+ ReportSIGSEGV(description, pc, sp, bp, context, access_addr);
+ }
+
+ // FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
+
+ 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
+// the floor, so we can't install our handler inside __asan_init.
+// (See crt0dat.c in the CRT sources for the details)
+//
+// Things get even more complicated with the dynamic runtime, as it finishes its
+// initialization before the .exe module CRT begins to initialize.
+//
+// For the static runtime (-MT), it's enough to put a callback to
+// __asan_set_seh_filter in the last section for C initializers.
+//
+// For the dynamic runtime (-MD), we want link the same
+// asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter
+// will be called for each instrumented module. This ensures that at least one
+// __asan_set_seh_filter call happens after the .exe module CRT is initialized.
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+int __asan_set_seh_filter() {
+ // We should only store the previous handler if it's not our own handler in
+ // order to avoid loops in the EH chain.
+ auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
+ if (prev_seh_handler != &SEHHandler)
+ default_seh_handler = prev_seh_handler;
+ return 0;
+}
+
+#if !ASAN_DYNAMIC
+// Put a pointer to __asan_set_seh_filter at the end of the global list
+// of C initializers, after the default EH is set by the CRT.
+#pragma section(".CRT$XIZ", long, read) // NOLINT
+static __declspec(allocate(".CRT$XIZ"))
+ int (*__intercept_seh)() = __asan_set_seh_filter;
+#endif
+
} // namespace __asan
#endif // _WIN32