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 "asan_mapping.h"
28#include "sanitizer_common/sanitizer_libc.h"
29#include "sanitizer_common/sanitizer_mutex.h"
30
31using namespace __asan;  // NOLINT
32
33extern "C" {
34SANITIZER_INTERFACE_ATTRIBUTE
35int __asan_should_detect_stack_use_after_return() {
36  __asan_init();
37  return __asan_option_detect_stack_use_after_return;
38}
39
40// -------------------- A workaround for the abscence of weak symbols ----- {{{
41// We don't have a direct equivalent of weak symbols when using MSVC, but we can
42// use the /alternatename directive to tell the linker to default a specific
43// symbol to a specific value, which works nicely for allocator hooks and
44// __asan_default_options().
45void __sanitizer_default_malloc_hook(void *ptr, uptr size) { }
46void __sanitizer_default_free_hook(void *ptr) { }
47const char* __asan_default_default_options() { return ""; }
48const char* __asan_default_default_suppressions() { return ""; }
49void __asan_default_on_error() {}
50// 64-bit msvc will not prepend an underscore for symbols.
51#ifdef _WIN64
52#pragma comment(linker, "/alternatename:__sanitizer_malloc_hook=__sanitizer_default_malloc_hook")  // NOLINT
53#pragma comment(linker, "/alternatename:__sanitizer_free_hook=__sanitizer_default_free_hook")      // NOLINT
54#pragma comment(linker, "/alternatename:__asan_default_options=__asan_default_default_options")    // NOLINT
55#pragma comment(linker, "/alternatename:__asan_default_suppressions=__asan_default_default_suppressions")    // NOLINT
56#pragma comment(linker, "/alternatename:__asan_on_error=__asan_default_on_error")                  // NOLINT
57#else
58#pragma comment(linker, "/alternatename:___sanitizer_malloc_hook=___sanitizer_default_malloc_hook")  // NOLINT
59#pragma comment(linker, "/alternatename:___sanitizer_free_hook=___sanitizer_default_free_hook")      // NOLINT
60#pragma comment(linker, "/alternatename:___asan_default_options=___asan_default_default_options")    // NOLINT
61#pragma comment(linker, "/alternatename:___asan_default_suppressions=___asan_default_default_suppressions")    // NOLINT
62#pragma comment(linker, "/alternatename:___asan_on_error=___asan_default_on_error")                  // NOLINT
63#endif
64// }}}
65}  // extern "C"
66
67// ---------------------- Windows-specific inteceptors ---------------- {{{
68INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) {
69  CHECK(REAL(RaiseException));
70  __asan_handle_no_return();
71  REAL(RaiseException)(a, b, c, d);
72}
73
74// TODO(wwchrome): Win64 has no _except_handler3/4.
75// Need to implement _C_specific_handler instead.
76#ifndef _WIN64
77INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) {
78  CHECK(REAL(_except_handler3));
79  __asan_handle_no_return();
80  return REAL(_except_handler3)(a, b, c, d);
81}
82
83#if ASAN_DYNAMIC
84// This handler is named differently in -MT and -MD CRTs.
85#define _except_handler4 _except_handler4_common
86#endif
87INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
88  CHECK(REAL(_except_handler4));
89  __asan_handle_no_return();
90  return REAL(_except_handler4)(a, b, c, d);
91}
92#endif
93
94static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
95  AsanThread *t = (AsanThread*)arg;
96  SetCurrentThread(t);
97  return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr);
98}
99
100INTERCEPTOR_WINAPI(DWORD, CreateThread,
101                   void* security, uptr stack_size,
102                   DWORD (__stdcall *start_routine)(void*), void* arg,
103                   DWORD thr_flags, void* tid) {
104  // Strict init-order checking is thread-hostile.
105  if (flags()->strict_init_order)
106    StopInitOrderChecking();
107  GET_STACK_TRACE_THREAD;
108  // FIXME: The CreateThread interceptor is not the same as a pthread_create
109  // one.  This is a bandaid fix for PR22025.
110  bool detached = false;  // FIXME: how can we determine it on Windows?
111  u32 current_tid = GetCurrentTidOrInvalid();
112  AsanThread *t =
113        AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
114  return REAL(CreateThread)(security, stack_size,
115                            asan_thread_start, t, thr_flags, tid);
116}
117
118namespace {
119BlockingMutex mu_for_thread_tracking(LINKER_INITIALIZED);
120
121void EnsureWorkerThreadRegistered() {
122  // FIXME: GetCurrentThread relies on TSD, which might not play well with
123  // system thread pools.  We might want to use something like reference
124  // counting to zero out GetCurrentThread() underlying storage when the last
125  // work item finishes?  Or can we disable reclaiming of threads in the pool?
126  BlockingMutexLock l(&mu_for_thread_tracking);
127  if (__asan::GetCurrentThread())
128    return;
129
130  AsanThread *t = AsanThread::Create(
131      /* start_routine */ nullptr, /* arg */ nullptr,
132      /* parent_tid */ -1, /* stack */ nullptr, /* detached */ true);
133  t->Init();
134  asanThreadRegistry().StartThread(t->tid(), 0, 0);
135  SetCurrentThread(t);
136}
137}  // namespace
138
139INTERCEPTOR_WINAPI(DWORD, NtWaitForWorkViaWorkerFactory, DWORD a, DWORD b) {
140  // NtWaitForWorkViaWorkerFactory is called from system worker pool threads to
141  // query work scheduled by BindIoCompletionCallback, QueueUserWorkItem, etc.
142  // System worker pool threads are created at arbitraty point in time and
143  // without using CreateThread, so we wrap NtWaitForWorkViaWorkerFactory
144  // instead and don't register a specific parent_tid/stack.
145  EnsureWorkerThreadRegistered();
146  return REAL(NtWaitForWorkViaWorkerFactory)(a, b);
147}
148
149// }}}
150
151namespace __asan {
152
153void InitializePlatformInterceptors() {
154  ASAN_INTERCEPT_FUNC(CreateThread);
155  ASAN_INTERCEPT_FUNC(RaiseException);
156
157// TODO(wwchrome): Win64 uses _C_specific_handler instead.
158#ifndef _WIN64
159  ASAN_INTERCEPT_FUNC(_except_handler3);
160  ASAN_INTERCEPT_FUNC(_except_handler4);
161#endif
162
163  // NtWaitForWorkViaWorkerFactory is always linked dynamically.
164  CHECK(::__interception::OverrideFunction(
165      "NtWaitForWorkViaWorkerFactory",
166      (uptr)WRAP(NtWaitForWorkViaWorkerFactory),
167      (uptr *)&REAL(NtWaitForWorkViaWorkerFactory)));
168}
169
170void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
171  UNIMPLEMENTED();
172}
173
174// ---------------------- TSD ---------------- {{{
175static bool tsd_key_inited = false;
176
177static __declspec(thread) void *fake_tsd = 0;
178
179void AsanTSDInit(void (*destructor)(void *tsd)) {
180  // FIXME: we're ignoring the destructor for now.
181  tsd_key_inited = true;
182}
183
184void *AsanTSDGet() {
185  CHECK(tsd_key_inited);
186  return fake_tsd;
187}
188
189void AsanTSDSet(void *tsd) {
190  CHECK(tsd_key_inited);
191  fake_tsd = tsd;
192}
193
194void PlatformTSDDtor(void *tsd) {
195  AsanThread::TSDDtor(tsd);
196}
197// }}}
198
199// ---------------------- Various stuff ---------------- {{{
200void *AsanDoesNotSupportStaticLinkage() {
201#if defined(_DEBUG)
202#error Please build the runtime with a non-debug CRT: /MD or /MT
203#endif
204  return 0;
205}
206
207void AsanCheckDynamicRTPrereqs() {}
208
209void AsanCheckIncompatibleRT() {}
210
211void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
212  UNIMPLEMENTED();
213}
214
215void AsanOnDeadlySignal(int, void *siginfo, void *context) {
216  UNIMPLEMENTED();
217}
218
219#if SANITIZER_WINDOWS64
220// Exception handler for dealing with shadow memory.
221static LONG CALLBACK
222ShadowExceptionHandler(PEXCEPTION_POINTERS exception_pointers) {
223  static uptr page_size = GetPageSizeCached();
224  static uptr alloc_granularity = GetMmapGranularity();
225  // Only handle access violations.
226  if (exception_pointers->ExceptionRecord->ExceptionCode !=
227      EXCEPTION_ACCESS_VIOLATION) {
228    return EXCEPTION_CONTINUE_SEARCH;
229  }
230
231  // Only handle access violations that land within the shadow memory.
232  uptr addr =
233      (uptr)(exception_pointers->ExceptionRecord->ExceptionInformation[1]);
234
235  // Check valid shadow range.
236  if (!AddrIsInShadow(addr)) return EXCEPTION_CONTINUE_SEARCH;
237
238  // This is an access violation while trying to read from the shadow. Commit
239  // the relevant page and let execution continue.
240
241  // Determine the address of the page that is being accessed.
242  uptr page = RoundDownTo(addr, page_size);
243
244  // Query the existing page.
245  MEMORY_BASIC_INFORMATION mem_info = {};
246  if (::VirtualQuery((LPVOID)page, &mem_info, sizeof(mem_info)) == 0)
247    return EXCEPTION_CONTINUE_SEARCH;
248
249  // Commit the page.
250  uptr result =
251      (uptr)::VirtualAlloc((LPVOID)page, page_size, MEM_COMMIT, PAGE_READWRITE);
252  if (result != page) return EXCEPTION_CONTINUE_SEARCH;
253
254  // The page mapping succeeded, so continue execution as usual.
255  return EXCEPTION_CONTINUE_EXECUTION;
256}
257
258#endif
259
260void InitializePlatformExceptionHandlers() {
261#if SANITIZER_WINDOWS64
262  // On Win64, we map memory on demand with access violation handler.
263  // Install our exception handler.
264  CHECK(AddVectoredExceptionHandler(TRUE, &ShadowExceptionHandler));
265#endif
266}
267
268static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
269
270static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
271  EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
272  CONTEXT *context = info->ContextRecord;
273
274  if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION ||
275      exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) {
276    const char *description =
277        (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
278            ? "access-violation"
279            : "in-page-error";
280    SignalContext sig = SignalContext::Create(exception_record, context);
281    ReportDeadlySignal(description, sig);
282  }
283
284  // FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
285
286  return default_seh_handler(info);
287}
288
289// We want to install our own exception handler (EH) to print helpful reports
290// on access violations and whatnot.  Unfortunately, the CRT initializers assume
291// they are run before any user code and drop any previously-installed EHs on
292// the floor, so we can't install our handler inside __asan_init.
293// (See crt0dat.c in the CRT sources for the details)
294//
295// Things get even more complicated with the dynamic runtime, as it finishes its
296// initialization before the .exe module CRT begins to initialize.
297//
298// For the static runtime (-MT), it's enough to put a callback to
299// __asan_set_seh_filter in the last section for C initializers.
300//
301// For the dynamic runtime (-MD), we want link the same
302// asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter
303// will be called for each instrumented module.  This ensures that at least one
304// __asan_set_seh_filter call happens after the .exe module CRT is initialized.
305extern "C" SANITIZER_INTERFACE_ATTRIBUTE
306int __asan_set_seh_filter() {
307  // We should only store the previous handler if it's not our own handler in
308  // order to avoid loops in the EH chain.
309  auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler);
310  if (prev_seh_handler != &SEHHandler)
311    default_seh_handler = prev_seh_handler;
312  return 0;
313}
314
315#if !ASAN_DYNAMIC
316// The CRT runs initializers in this order:
317// - C initializers, from XIA to XIZ
318// - C++ initializers, from XCA to XCZ
319// Prior to 2015, the CRT set the unhandled exception filter at priority XIY,
320// near the end of C initialization. Starting in 2015, it was moved to the
321// beginning of C++ initialization. We set our priority to XCAB to run
322// immediately after the CRT runs. This way, our exception filter is called
323// first and we can delegate to their filter if appropriate.
324#pragma section(".CRT$XCAB", long, read)  // NOLINT
325__declspec(allocate(".CRT$XCAB"))
326    int (*__intercept_seh)() = __asan_set_seh_filter;
327#endif
328// }}}
329}  // namespace __asan
330
331#endif  // _WIN32
332