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