Home | History | Annotate | Download | only in asan
      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 
     30 using namespace __asan;  // NOLINT
     31 
     32 extern "C" {
     33 SANITIZER_INTERFACE_ATTRIBUTE
     34 int __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().
     44 void __sanitizer_default_malloc_hook(void *ptr, uptr size) { }
     45 void __sanitizer_default_free_hook(void *ptr) { }
     46 const char* __asan_default_default_options() { return ""; }
     47 const char* __asan_default_default_suppressions() { return ""; }
     48 void __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 ---------------- {{{
     58 INTERCEPTOR_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 
     64 INTERCEPTOR(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
     74 INTERCEPTOR(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 
     80 static 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 
     86 INTERCEPTOR_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 
    104 namespace {
    105 BlockingMutex mu_for_thread_tracking(LINKER_INITIALIZED);
    106 
    107 void 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 
    125 INTERCEPTOR_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 
    137 namespace __asan {
    138 
    139 void 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 ---------------- {{{
    153 static bool tsd_key_inited = false;
    154 
    155 static __declspec(thread) void *fake_tsd = 0;
    156 
    157 void AsanTSDInit(void (*destructor)(void *tsd)) {
    158   // FIXME: we're ignoring the destructor for now.
    159   tsd_key_inited = true;
    160 }
    161 
    162 void *AsanTSDGet() {
    163   CHECK(tsd_key_inited);
    164   return fake_tsd;
    165 }
    166 
    167 void AsanTSDSet(void *tsd) {
    168   CHECK(tsd_key_inited);
    169   fake_tsd = tsd;
    170 }
    171 
    172 void PlatformTSDDtor(void *tsd) {
    173   AsanThread::TSDDtor(tsd);
    174 }
    175 // }}}
    176 
    177 // ---------------------- Various stuff ---------------- {{{
    178 void *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 
    185 void AsanCheckDynamicRTPrereqs() {}
    186 
    187 void AsanCheckIncompatibleRT() {}
    188 
    189 void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
    190   UNIMPLEMENTED();
    191 }
    192 
    193 void AsanOnDeadlySignal(int, void *siginfo, void *context) {
    194   UNIMPLEMENTED();
    195 }
    196 
    197 static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
    198 
    199 static 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.
    234 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
    235 int __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