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 "asan_mapping.h"
     28 #include "sanitizer_common/sanitizer_libc.h"
     29 #include "sanitizer_common/sanitizer_mutex.h"
     30 
     31 using namespace __asan;  // NOLINT
     32 
     33 extern "C" {
     34 SANITIZER_INTERFACE_ATTRIBUTE
     35 int __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().
     45 void __sanitizer_default_malloc_hook(void *ptr, uptr size) { }
     46 void __sanitizer_default_free_hook(void *ptr) { }
     47 const char* __asan_default_default_options() { return ""; }
     48 const char* __asan_default_default_suppressions() { return ""; }
     49 void __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 ---------------- {{{
     68 INTERCEPTOR_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
     77 INTERCEPTOR(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
     87 INTERCEPTOR(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 
     94 static 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 
    100 INTERCEPTOR_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 
    118 namespace {
    119 BlockingMutex mu_for_thread_tracking(LINKER_INITIALIZED);
    120 
    121 void 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 
    139 INTERCEPTOR_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 
    151 namespace __asan {
    152 
    153 void 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 
    170 void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
    171   UNIMPLEMENTED();
    172 }
    173 
    174 // ---------------------- TSD ---------------- {{{
    175 static bool tsd_key_inited = false;
    176 
    177 static __declspec(thread) void *fake_tsd = 0;
    178 
    179 void AsanTSDInit(void (*destructor)(void *tsd)) {
    180   // FIXME: we're ignoring the destructor for now.
    181   tsd_key_inited = true;
    182 }
    183 
    184 void *AsanTSDGet() {
    185   CHECK(tsd_key_inited);
    186   return fake_tsd;
    187 }
    188 
    189 void AsanTSDSet(void *tsd) {
    190   CHECK(tsd_key_inited);
    191   fake_tsd = tsd;
    192 }
    193 
    194 void PlatformTSDDtor(void *tsd) {
    195   AsanThread::TSDDtor(tsd);
    196 }
    197 // }}}
    198 
    199 // ---------------------- Various stuff ---------------- {{{
    200 void *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 
    207 void AsanCheckDynamicRTPrereqs() {}
    208 
    209 void AsanCheckIncompatibleRT() {}
    210 
    211 void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
    212   UNIMPLEMENTED();
    213 }
    214 
    215 void AsanOnDeadlySignal(int, void *siginfo, void *context) {
    216   UNIMPLEMENTED();
    217 }
    218 
    219 #if SANITIZER_WINDOWS64
    220 // Exception handler for dealing with shadow memory.
    221 static LONG CALLBACK
    222 ShadowExceptionHandler(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 
    260 void 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 
    268 static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
    269 
    270 static 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.
    305 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
    306 int __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