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#define WIN32_LEAN_AND_MEAN
18#include <windows.h>
19
20#include <stdlib.h>
21
22#include "asan_interceptors.h"
23#include "asan_internal.h"
24#include "asan_report.h"
25#include "asan_stack.h"
26#include "asan_thread.h"
27#include "sanitizer_common/sanitizer_libc.h"
28#include "sanitizer_common/sanitizer_mutex.h"
29
30using namespace __asan;  // NOLINT
31
32extern "C" {
33SANITIZER_INTERFACE_ATTRIBUTE
34int __asan_should_detect_stack_use_after_return() {
35  __asan_init();
36  return __asan_option_detect_stack_use_after_return;
37}
38
39// -------------------- A workaround for the abscence of weak symbols ----- {{{
40// We don't have a direct equivalent of weak symbols when using MSVC, but we can
41// use the /alternatename directive to tell the linker to default a specific
42// symbol to a specific value, which works nicely for allocator hooks and
43// __asan_default_options().
44void __sanitizer_default_malloc_hook(void *ptr, uptr size) { }
45void __sanitizer_default_free_hook(void *ptr) { }
46const char* __asan_default_default_options() { return ""; }
47const char* __asan_default_default_suppressions() { return ""; }
48void __asan_default_on_error() {}
49#pragma comment(linker, "/alternatename:___sanitizer_malloc_hook=___sanitizer_default_malloc_hook")  // NOLINT
50#pragma comment(linker, "/alternatename:___sanitizer_free_hook=___sanitizer_default_free_hook")      // NOLINT
51#pragma comment(linker, "/alternatename:___asan_default_options=___asan_default_default_options")    // NOLINT
52#pragma comment(linker, "/alternatename:___asan_default_suppressions=___asan_default_default_suppressions")    // NOLINT
53#pragma comment(linker, "/alternatename:___asan_on_error=___asan_default_on_error")                  // NOLINT
54// }}}
55}  // extern "C"
56
57// ---------------------- Windows-specific inteceptors ---------------- {{{
58INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) {
59  CHECK(REAL(RaiseException));
60  __asan_handle_no_return();
61  REAL(RaiseException)(a, b, c, d);
62}
63
64INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) {
65  CHECK(REAL(_except_handler3));
66  __asan_handle_no_return();
67  return REAL(_except_handler3)(a, b, c, d);
68}
69
70#if ASAN_DYNAMIC
71// This handler is named differently in -MT and -MD CRTs.
72#define _except_handler4 _except_handler4_common
73#endif
74INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
75  CHECK(REAL(_except_handler4));
76  __asan_handle_no_return();
77  return REAL(_except_handler4)(a, b, c, d);
78}
79
80static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
81  AsanThread *t = (AsanThread*)arg;
82  SetCurrentThread(t);
83  return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr);
84}
85
86INTERCEPTOR_WINAPI(DWORD, CreateThread,
87                   void* security, uptr stack_size,
88                   DWORD (__stdcall *start_routine)(void*), void* arg,
89                   DWORD thr_flags, void* tid) {
90  // Strict init-order checking is thread-hostile.
91  if (flags()->strict_init_order)
92    StopInitOrderChecking();
93  GET_STACK_TRACE_THREAD;
94  // FIXME: The CreateThread interceptor is not the same as a pthread_create
95  // one.  This is a bandaid fix for PR22025.
96  bool detached = false;  // FIXME: how can we determine it on Windows?
97  u32 current_tid = GetCurrentTidOrInvalid();
98  AsanThread *t =
99        AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
100  return REAL(CreateThread)(security, stack_size,
101                            asan_thread_start, t, thr_flags, tid);
102}
103
104namespace {
105BlockingMutex mu_for_thread_tracking(LINKER_INITIALIZED);
106
107void EnsureWorkerThreadRegistered() {
108  // FIXME: GetCurrentThread relies on TSD, which might not play well with
109  // system thread pools.  We might want to use something like reference
110  // counting to zero out GetCurrentThread() underlying storage when the last
111  // work item finishes?  Or can we disable reclaiming of threads in the pool?
112  BlockingMutexLock l(&mu_for_thread_tracking);
113  if (__asan::GetCurrentThread())
114    return;
115
116  AsanThread *t = AsanThread::Create(
117      /* start_routine */ nullptr, /* arg */ nullptr,
118      /* parent_tid */ -1, /* stack */ nullptr, /* detached */ true);
119  t->Init();
120  asanThreadRegistry().StartThread(t->tid(), 0, 0);
121  SetCurrentThread(t);
122}
123}  // namespace
124
125INTERCEPTOR_WINAPI(DWORD, NtWaitForWorkViaWorkerFactory, DWORD a, DWORD b) {
126  // NtWaitForWorkViaWorkerFactory is called from system worker pool threads to
127  // query work scheduled by BindIoCompletionCallback, QueueUserWorkItem, etc.
128  // System worker pool threads are created at arbitraty point in time and
129  // without using CreateThread, so we wrap NtWaitForWorkViaWorkerFactory
130  // instead and don't register a specific parent_tid/stack.
131  EnsureWorkerThreadRegistered();
132  return REAL(NtWaitForWorkViaWorkerFactory)(a, b);
133}
134
135// }}}
136
137namespace __asan {
138
139void InitializePlatformInterceptors() {
140  ASAN_INTERCEPT_FUNC(CreateThread);
141  ASAN_INTERCEPT_FUNC(RaiseException);
142  ASAN_INTERCEPT_FUNC(_except_handler3);
143  ASAN_INTERCEPT_FUNC(_except_handler4);
144
145  // NtWaitForWorkViaWorkerFactory is always linked dynamically.
146  CHECK(::__interception::OverrideFunction(
147      "NtWaitForWorkViaWorkerFactory",
148      (uptr)WRAP(NtWaitForWorkViaWorkerFactory),
149      (uptr *)&REAL(NtWaitForWorkViaWorkerFactory)));
150}
151
152// ---------------------- TSD ---------------- {{{
153static bool tsd_key_inited = false;
154
155static __declspec(thread) void *fake_tsd = 0;
156
157void AsanTSDInit(void (*destructor)(void *tsd)) {
158  // FIXME: we're ignoring the destructor for now.
159  tsd_key_inited = true;
160}
161
162void *AsanTSDGet() {
163  CHECK(tsd_key_inited);
164  return fake_tsd;
165}
166
167void AsanTSDSet(void *tsd) {
168  CHECK(tsd_key_inited);
169  fake_tsd = tsd;
170}
171
172void PlatformTSDDtor(void *tsd) {
173  AsanThread::TSDDtor(tsd);
174}
175// }}}
176
177// ---------------------- Various stuff ---------------- {{{
178void *AsanDoesNotSupportStaticLinkage() {
179#if defined(_DEBUG)
180#error Please build the runtime with a non-debug CRT: /MD or /MT
181#endif
182  return 0;
183}
184
185void AsanCheckDynamicRTPrereqs() {}
186
187void AsanCheckIncompatibleRT() {}
188
189void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
190  UNIMPLEMENTED();
191}
192
193void AsanOnDeadlySignal(int, void *siginfo, void *context) {
194  UNIMPLEMENTED();
195}
196
197static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
198
199static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
200  EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
201  CONTEXT *context = info->ContextRecord;
202
203  if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
204      exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) {
205    const char *description =
206        (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
207            ? "access-violation"
208            : "in-page-error";
209    SignalContext sig = SignalContext::Create(exception_record, context);
210    ReportDeadlySignal(description, sig);
211  }
212
213  // FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
214
215  return default_seh_handler(info);
216}
217
218// We want to install our own exception handler (EH) to print helpful reports
219// on access violations and whatnot.  Unfortunately, the CRT initializers assume
220// they are run before any user code and drop any previously-installed EHs on
221// the floor, so we can't install our handler inside __asan_init.
222// (See crt0dat.c in the CRT sources for the details)
223//
224// Things get even more complicated with the dynamic runtime, as it finishes its
225// initialization before the .exe module CRT begins to initialize.
226//
227// For the static runtime (-MT), it's enough to put a callback to
228// __asan_set_seh_filter in the last section for C initializers.
229//
230// For the dynamic runtime (-MD), we want link the same
231// asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter
232// will be called for each instrumented module.  This ensures that at least one
233// __asan_set_seh_filter call happens after the .exe module CRT is initialized.
234extern "C" SANITIZER_INTERFACE_ATTRIBUTE
235int __asan_set_seh_filter() {
236  // We should only store the previous handler if it's not our own handler in
237  // order to avoid loops in the EH chain.
238  auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
239  if (prev_seh_handler != &SEHHandler)
240    default_seh_handler = prev_seh_handler;
241  return 0;
242}
243
244#if !ASAN_DYNAMIC
245// Put a pointer to __asan_set_seh_filter at the end of the global list
246// of C initializers, after the default EH is set by the CRT.
247#pragma section(".CRT$XIZ", long, read)  // NOLINT
248__declspec(allocate(".CRT$XIZ"))
249    int (*__intercept_seh)() = __asan_set_seh_filter;
250#endif
251// }}}
252}  // namespace __asan
253
254#endif  // _WIN32
255