gcc/
[official-gcc.git] / libsanitizer / asan / asan_win.cc
blobb0028763b11f3c11a1e9aee631a037bf611044bf
1 //===-- asan_win.cc -------------------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is a part of AddressSanitizer, an address sanity checker.
9 //
10 // Windows-specific details.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_common/sanitizer_platform.h"
14 #if SANITIZER_WINDOWS
15 #include <windows.h>
17 #include <dbghelp.h>
18 #include <stdlib.h>
20 #include "asan_interceptors.h"
21 #include "asan_internal.h"
22 #include "asan_report.h"
23 #include "asan_thread.h"
24 #include "sanitizer_common/sanitizer_libc.h"
25 #include "sanitizer_common/sanitizer_mutex.h"
27 extern "C" {
28 SANITIZER_INTERFACE_ATTRIBUTE
29 int __asan_should_detect_stack_use_after_return() {
30 __asan_init();
31 return __asan_option_detect_stack_use_after_return;
35 namespace __asan {
37 // ---------------------- TSD ---------------- {{{1
38 static bool tsd_key_inited = false;
40 static __declspec(thread) void *fake_tsd = 0;
42 void AsanTSDInit(void (*destructor)(void *tsd)) {
43 // FIXME: we're ignoring the destructor for now.
44 tsd_key_inited = true;
47 void *AsanTSDGet() {
48 CHECK(tsd_key_inited);
49 return fake_tsd;
52 void AsanTSDSet(void *tsd) {
53 CHECK(tsd_key_inited);
54 fake_tsd = tsd;
57 void PlatformTSDDtor(void *tsd) {
58 AsanThread::TSDDtor(tsd);
60 // ---------------------- Various stuff ---------------- {{{1
61 void MaybeReexec() {
62 // No need to re-exec on Windows.
65 void *AsanDoesNotSupportStaticLinkage() {
66 #if defined(_DEBUG)
67 #error Please build the runtime with a non-debug CRT: /MD or /MT
68 #endif
69 return 0;
72 void AsanCheckDynamicRTPrereqs() {}
74 void AsanCheckIncompatibleRT() {}
76 void AsanPlatformThreadInit() {
77 // Nothing here for now.
80 void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
81 UNIMPLEMENTED();
84 void AsanOnSIGSEGV(int, void *siginfo, void *context) {
85 UNIMPLEMENTED();
88 static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
90 static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
91 EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
92 CONTEXT *context = info->ContextRecord;
93 uptr pc = (uptr)exception_record->ExceptionAddress;
94 #ifdef _WIN64
95 uptr bp = (uptr)context->Rbp, sp = (uptr)context->Rsp;
96 #else
97 uptr bp = (uptr)context->Ebp, sp = (uptr)context->Esp;
98 #endif
100 if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
101 exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) {
102 const char *description =
103 (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
104 ? "access-violation"
105 : "in-page-error";
106 uptr access_addr = exception_record->ExceptionInformation[1];
107 ReportSIGSEGV(description, pc, sp, bp, context, access_addr);
110 // FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
112 return default_seh_handler(info);
115 // We want to install our own exception handler (EH) to print helpful reports
116 // on access violations and whatnot. Unfortunately, the CRT initializers assume
117 // they are run before any user code and drop any previously-installed EHs on
118 // the floor, so we can't install our handler inside __asan_init.
119 // (See crt0dat.c in the CRT sources for the details)
121 // Things get even more complicated with the dynamic runtime, as it finishes its
122 // initialization before the .exe module CRT begins to initialize.
124 // For the static runtime (-MT), it's enough to put a callback to
125 // __asan_set_seh_filter in the last section for C initializers.
127 // For the dynamic runtime (-MD), we want link the same
128 // asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter
129 // will be called for each instrumented module. This ensures that at least one
130 // __asan_set_seh_filter call happens after the .exe module CRT is initialized.
131 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
132 int __asan_set_seh_filter() {
133 // We should only store the previous handler if it's not our own handler in
134 // order to avoid loops in the EH chain.
135 auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
136 if (prev_seh_handler != &SEHHandler)
137 default_seh_handler = prev_seh_handler;
138 return 0;
141 #if !ASAN_DYNAMIC
142 // Put a pointer to __asan_set_seh_filter at the end of the global list
143 // of C initializers, after the default EH is set by the CRT.
144 #pragma section(".CRT$XIZ", long, read) // NOLINT
145 static __declspec(allocate(".CRT$XIZ"))
146 int (*__intercept_seh)() = __asan_set_seh_filter;
147 #endif
149 } // namespace __asan
151 #endif // _WIN32