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