1*68d75effSDimitry Andric //===-- asan_win.cpp ------------------------------------------------------===// 2*68d75effSDimitry Andric // 3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*68d75effSDimitry Andric // 7*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 8*68d75effSDimitry Andric // 9*68d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker. 10*68d75effSDimitry Andric // 11*68d75effSDimitry Andric // Windows-specific details. 12*68d75effSDimitry Andric //===----------------------------------------------------------------------===// 13*68d75effSDimitry Andric 14*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_platform.h" 15*68d75effSDimitry Andric #if SANITIZER_WINDOWS 16*68d75effSDimitry Andric #define WIN32_LEAN_AND_MEAN 17*68d75effSDimitry Andric #include <windows.h> 18*68d75effSDimitry Andric 19*68d75effSDimitry Andric #include <stdlib.h> 20*68d75effSDimitry Andric 21*68d75effSDimitry Andric #include "asan_interceptors.h" 22*68d75effSDimitry Andric #include "asan_internal.h" 23*68d75effSDimitry Andric #include "asan_mapping.h" 24*68d75effSDimitry Andric #include "asan_report.h" 25*68d75effSDimitry Andric #include "asan_stack.h" 26*68d75effSDimitry Andric #include "asan_thread.h" 27*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_libc.h" 28*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_mutex.h" 29*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_win.h" 30*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_win_defs.h" 31*68d75effSDimitry Andric 32*68d75effSDimitry Andric using namespace __asan; 33*68d75effSDimitry Andric 34*68d75effSDimitry Andric extern "C" { 35*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 36*68d75effSDimitry Andric int __asan_should_detect_stack_use_after_return() { 37*68d75effSDimitry Andric __asan_init(); 38*68d75effSDimitry Andric return __asan_option_detect_stack_use_after_return; 39*68d75effSDimitry Andric } 40*68d75effSDimitry Andric 41*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE 42*68d75effSDimitry Andric uptr __asan_get_shadow_memory_dynamic_address() { 43*68d75effSDimitry Andric __asan_init(); 44*68d75effSDimitry Andric return __asan_shadow_memory_dynamic_address; 45*68d75effSDimitry Andric } 46*68d75effSDimitry Andric } // extern "C" 47*68d75effSDimitry Andric 48*68d75effSDimitry Andric // ---------------------- Windows-specific interceptors ---------------- {{{ 49*68d75effSDimitry Andric static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler; 50*68d75effSDimitry Andric static LPTOP_LEVEL_EXCEPTION_FILTER user_seh_handler; 51*68d75effSDimitry Andric 52*68d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE 53*68d75effSDimitry Andric long __asan_unhandled_exception_filter(EXCEPTION_POINTERS *info) { 54*68d75effSDimitry Andric EXCEPTION_RECORD *exception_record = info->ExceptionRecord; 55*68d75effSDimitry Andric CONTEXT *context = info->ContextRecord; 56*68d75effSDimitry Andric 57*68d75effSDimitry Andric // FIXME: Handle EXCEPTION_STACK_OVERFLOW here. 58*68d75effSDimitry Andric 59*68d75effSDimitry Andric SignalContext sig(exception_record, context); 60*68d75effSDimitry Andric ReportDeadlySignal(sig); 61*68d75effSDimitry Andric UNREACHABLE("returned from reporting deadly signal"); 62*68d75effSDimitry Andric } 63*68d75effSDimitry Andric 64*68d75effSDimitry Andric // Wrapper SEH Handler. If the exception should be handled by asan, we call 65*68d75effSDimitry Andric // __asan_unhandled_exception_filter, otherwise, we execute the user provided 66*68d75effSDimitry Andric // exception handler or the default. 67*68d75effSDimitry Andric static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) { 68*68d75effSDimitry Andric DWORD exception_code = info->ExceptionRecord->ExceptionCode; 69*68d75effSDimitry Andric if (__sanitizer::IsHandledDeadlyException(exception_code)) 70*68d75effSDimitry Andric return __asan_unhandled_exception_filter(info); 71*68d75effSDimitry Andric if (user_seh_handler) 72*68d75effSDimitry Andric return user_seh_handler(info); 73*68d75effSDimitry Andric // Bubble out to the default exception filter. 74*68d75effSDimitry Andric if (default_seh_handler) 75*68d75effSDimitry Andric return default_seh_handler(info); 76*68d75effSDimitry Andric return EXCEPTION_CONTINUE_SEARCH; 77*68d75effSDimitry Andric } 78*68d75effSDimitry Andric 79*68d75effSDimitry Andric INTERCEPTOR_WINAPI(LPTOP_LEVEL_EXCEPTION_FILTER, SetUnhandledExceptionFilter, 80*68d75effSDimitry Andric LPTOP_LEVEL_EXCEPTION_FILTER ExceptionFilter) { 81*68d75effSDimitry Andric CHECK(REAL(SetUnhandledExceptionFilter)); 82*68d75effSDimitry Andric if (ExceptionFilter == &SEHHandler) 83*68d75effSDimitry Andric return REAL(SetUnhandledExceptionFilter)(ExceptionFilter); 84*68d75effSDimitry Andric // We record the user provided exception handler to be called for all the 85*68d75effSDimitry Andric // exceptions unhandled by asan. 86*68d75effSDimitry Andric Swap(ExceptionFilter, user_seh_handler); 87*68d75effSDimitry Andric return ExceptionFilter; 88*68d75effSDimitry Andric } 89*68d75effSDimitry Andric 90*68d75effSDimitry Andric INTERCEPTOR_WINAPI(void, RtlRaiseException, EXCEPTION_RECORD *ExceptionRecord) { 91*68d75effSDimitry Andric CHECK(REAL(RtlRaiseException)); 92*68d75effSDimitry Andric // This is a noreturn function, unless it's one of the exceptions raised to 93*68d75effSDimitry Andric // communicate with the debugger, such as the one from OutputDebugString. 94*68d75effSDimitry Andric if (ExceptionRecord->ExceptionCode != DBG_PRINTEXCEPTION_C) 95*68d75effSDimitry Andric __asan_handle_no_return(); 96*68d75effSDimitry Andric REAL(RtlRaiseException)(ExceptionRecord); 97*68d75effSDimitry Andric } 98*68d75effSDimitry Andric 99*68d75effSDimitry Andric INTERCEPTOR_WINAPI(void, RaiseException, void *a, void *b, void *c, void *d) { 100*68d75effSDimitry Andric CHECK(REAL(RaiseException)); 101*68d75effSDimitry Andric __asan_handle_no_return(); 102*68d75effSDimitry Andric REAL(RaiseException)(a, b, c, d); 103*68d75effSDimitry Andric } 104*68d75effSDimitry Andric 105*68d75effSDimitry Andric #ifdef _WIN64 106*68d75effSDimitry Andric 107*68d75effSDimitry Andric INTERCEPTOR_WINAPI(EXCEPTION_DISPOSITION, __C_specific_handler, 108*68d75effSDimitry Andric _EXCEPTION_RECORD *a, void *b, _CONTEXT *c, 109*68d75effSDimitry Andric _DISPATCHER_CONTEXT *d) { 110*68d75effSDimitry Andric CHECK(REAL(__C_specific_handler)); 111*68d75effSDimitry Andric __asan_handle_no_return(); 112*68d75effSDimitry Andric return REAL(__C_specific_handler)(a, b, c, d); 113*68d75effSDimitry Andric } 114*68d75effSDimitry Andric 115*68d75effSDimitry Andric #else 116*68d75effSDimitry Andric 117*68d75effSDimitry Andric INTERCEPTOR(int, _except_handler3, void *a, void *b, void *c, void *d) { 118*68d75effSDimitry Andric CHECK(REAL(_except_handler3)); 119*68d75effSDimitry Andric __asan_handle_no_return(); 120*68d75effSDimitry Andric return REAL(_except_handler3)(a, b, c, d); 121*68d75effSDimitry Andric } 122*68d75effSDimitry Andric 123*68d75effSDimitry Andric #if ASAN_DYNAMIC 124*68d75effSDimitry Andric // This handler is named differently in -MT and -MD CRTs. 125*68d75effSDimitry Andric #define _except_handler4 _except_handler4_common 126*68d75effSDimitry Andric #endif 127*68d75effSDimitry Andric INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) { 128*68d75effSDimitry Andric CHECK(REAL(_except_handler4)); 129*68d75effSDimitry Andric __asan_handle_no_return(); 130*68d75effSDimitry Andric return REAL(_except_handler4)(a, b, c, d); 131*68d75effSDimitry Andric } 132*68d75effSDimitry Andric #endif 133*68d75effSDimitry Andric 134*68d75effSDimitry Andric static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) { 135*68d75effSDimitry Andric AsanThread *t = (AsanThread *)arg; 136*68d75effSDimitry Andric SetCurrentThread(t); 137*68d75effSDimitry Andric return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr); 138*68d75effSDimitry Andric } 139*68d75effSDimitry Andric 140*68d75effSDimitry Andric INTERCEPTOR_WINAPI(HANDLE, CreateThread, LPSECURITY_ATTRIBUTES security, 141*68d75effSDimitry Andric SIZE_T stack_size, LPTHREAD_START_ROUTINE start_routine, 142*68d75effSDimitry Andric void *arg, DWORD thr_flags, DWORD *tid) { 143*68d75effSDimitry Andric // Strict init-order checking is thread-hostile. 144*68d75effSDimitry Andric if (flags()->strict_init_order) 145*68d75effSDimitry Andric StopInitOrderChecking(); 146*68d75effSDimitry Andric GET_STACK_TRACE_THREAD; 147*68d75effSDimitry Andric // FIXME: The CreateThread interceptor is not the same as a pthread_create 148*68d75effSDimitry Andric // one. This is a bandaid fix for PR22025. 149*68d75effSDimitry Andric bool detached = false; // FIXME: how can we determine it on Windows? 150*68d75effSDimitry Andric u32 current_tid = GetCurrentTidOrInvalid(); 151*68d75effSDimitry Andric AsanThread *t = 152*68d75effSDimitry Andric AsanThread::Create(start_routine, arg, current_tid, &stack, detached); 153*68d75effSDimitry Andric return REAL(CreateThread)(security, stack_size, asan_thread_start, t, 154*68d75effSDimitry Andric thr_flags, tid); 155*68d75effSDimitry Andric } 156*68d75effSDimitry Andric 157*68d75effSDimitry Andric // }}} 158*68d75effSDimitry Andric 159*68d75effSDimitry Andric namespace __asan { 160*68d75effSDimitry Andric 161*68d75effSDimitry Andric void InitializePlatformInterceptors() { 162*68d75effSDimitry Andric // The interceptors were not designed to be removable, so we have to keep this 163*68d75effSDimitry Andric // module alive for the life of the process. 164*68d75effSDimitry Andric HMODULE pinned; 165*68d75effSDimitry Andric CHECK(GetModuleHandleExW( 166*68d75effSDimitry Andric GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, 167*68d75effSDimitry Andric (LPCWSTR)&InitializePlatformInterceptors, &pinned)); 168*68d75effSDimitry Andric 169*68d75effSDimitry Andric ASAN_INTERCEPT_FUNC(CreateThread); 170*68d75effSDimitry Andric ASAN_INTERCEPT_FUNC(SetUnhandledExceptionFilter); 171*68d75effSDimitry Andric 172*68d75effSDimitry Andric #ifdef _WIN64 173*68d75effSDimitry Andric ASAN_INTERCEPT_FUNC(__C_specific_handler); 174*68d75effSDimitry Andric #else 175*68d75effSDimitry Andric ASAN_INTERCEPT_FUNC(_except_handler3); 176*68d75effSDimitry Andric ASAN_INTERCEPT_FUNC(_except_handler4); 177*68d75effSDimitry Andric #endif 178*68d75effSDimitry Andric 179*68d75effSDimitry Andric // Try to intercept kernel32!RaiseException, and if that fails, intercept 180*68d75effSDimitry Andric // ntdll!RtlRaiseException instead. 181*68d75effSDimitry Andric if (!::__interception::OverrideFunction("RaiseException", 182*68d75effSDimitry Andric (uptr)WRAP(RaiseException), 183*68d75effSDimitry Andric (uptr *)&REAL(RaiseException))) { 184*68d75effSDimitry Andric CHECK(::__interception::OverrideFunction("RtlRaiseException", 185*68d75effSDimitry Andric (uptr)WRAP(RtlRaiseException), 186*68d75effSDimitry Andric (uptr *)&REAL(RtlRaiseException))); 187*68d75effSDimitry Andric } 188*68d75effSDimitry Andric } 189*68d75effSDimitry Andric 190*68d75effSDimitry Andric void AsanApplyToGlobals(globals_op_fptr op, const void *needle) { 191*68d75effSDimitry Andric UNIMPLEMENTED(); 192*68d75effSDimitry Andric } 193*68d75effSDimitry Andric 194*68d75effSDimitry Andric // ---------------------- TSD ---------------- {{{ 195*68d75effSDimitry Andric static bool tsd_key_inited = false; 196*68d75effSDimitry Andric 197*68d75effSDimitry Andric static __declspec(thread) void *fake_tsd = 0; 198*68d75effSDimitry Andric 199*68d75effSDimitry Andric // https://docs.microsoft.com/en-us/windows/desktop/api/winternl/ns-winternl-_teb 200*68d75effSDimitry Andric // "[This structure may be altered in future versions of Windows. Applications 201*68d75effSDimitry Andric // should use the alternate functions listed in this topic.]" 202*68d75effSDimitry Andric typedef struct _TEB { 203*68d75effSDimitry Andric PVOID Reserved1[12]; 204*68d75effSDimitry Andric // PVOID ThreadLocalStoragePointer; is here, at the last field in Reserved1. 205*68d75effSDimitry Andric PVOID ProcessEnvironmentBlock; 206*68d75effSDimitry Andric PVOID Reserved2[399]; 207*68d75effSDimitry Andric BYTE Reserved3[1952]; 208*68d75effSDimitry Andric PVOID TlsSlots[64]; 209*68d75effSDimitry Andric BYTE Reserved4[8]; 210*68d75effSDimitry Andric PVOID Reserved5[26]; 211*68d75effSDimitry Andric PVOID ReservedForOle; 212*68d75effSDimitry Andric PVOID Reserved6[4]; 213*68d75effSDimitry Andric PVOID TlsExpansionSlots; 214*68d75effSDimitry Andric } TEB, *PTEB; 215*68d75effSDimitry Andric 216*68d75effSDimitry Andric constexpr size_t TEB_RESERVED_FIELDS_THREAD_LOCAL_STORAGE_OFFSET = 11; 217*68d75effSDimitry Andric BOOL IsTlsInitialized() { 218*68d75effSDimitry Andric PTEB teb = (PTEB)NtCurrentTeb(); 219*68d75effSDimitry Andric return teb->Reserved1[TEB_RESERVED_FIELDS_THREAD_LOCAL_STORAGE_OFFSET] != 220*68d75effSDimitry Andric nullptr; 221*68d75effSDimitry Andric } 222*68d75effSDimitry Andric 223*68d75effSDimitry Andric void AsanTSDInit(void (*destructor)(void *tsd)) { 224*68d75effSDimitry Andric // FIXME: we're ignoring the destructor for now. 225*68d75effSDimitry Andric tsd_key_inited = true; 226*68d75effSDimitry Andric } 227*68d75effSDimitry Andric 228*68d75effSDimitry Andric void *AsanTSDGet() { 229*68d75effSDimitry Andric CHECK(tsd_key_inited); 230*68d75effSDimitry Andric return IsTlsInitialized() ? fake_tsd : nullptr; 231*68d75effSDimitry Andric } 232*68d75effSDimitry Andric 233*68d75effSDimitry Andric void AsanTSDSet(void *tsd) { 234*68d75effSDimitry Andric CHECK(tsd_key_inited); 235*68d75effSDimitry Andric fake_tsd = tsd; 236*68d75effSDimitry Andric } 237*68d75effSDimitry Andric 238*68d75effSDimitry Andric void PlatformTSDDtor(void *tsd) { AsanThread::TSDDtor(tsd); } 239*68d75effSDimitry Andric // }}} 240*68d75effSDimitry Andric 241*68d75effSDimitry Andric // ---------------------- Various stuff ---------------- {{{ 242*68d75effSDimitry Andric void *AsanDoesNotSupportStaticLinkage() { 243*68d75effSDimitry Andric #if defined(_DEBUG) 244*68d75effSDimitry Andric #error Please build the runtime with a non-debug CRT: /MD or /MT 245*68d75effSDimitry Andric #endif 246*68d75effSDimitry Andric return 0; 247*68d75effSDimitry Andric } 248*68d75effSDimitry Andric 249*68d75effSDimitry Andric uptr FindDynamicShadowStart() { 250*68d75effSDimitry Andric uptr granularity = GetMmapGranularity(); 251*68d75effSDimitry Andric uptr alignment = 8 * granularity; 252*68d75effSDimitry Andric uptr left_padding = granularity; 253*68d75effSDimitry Andric uptr space_size = kHighShadowEnd + left_padding; 254*68d75effSDimitry Andric uptr shadow_start = FindAvailableMemoryRange(space_size, alignment, 255*68d75effSDimitry Andric granularity, nullptr, nullptr); 256*68d75effSDimitry Andric CHECK_NE((uptr)0, shadow_start); 257*68d75effSDimitry Andric CHECK(IsAligned(shadow_start, alignment)); 258*68d75effSDimitry Andric return shadow_start; 259*68d75effSDimitry Andric } 260*68d75effSDimitry Andric 261*68d75effSDimitry Andric void AsanCheckDynamicRTPrereqs() {} 262*68d75effSDimitry Andric 263*68d75effSDimitry Andric void AsanCheckIncompatibleRT() {} 264*68d75effSDimitry Andric 265*68d75effSDimitry Andric void ReadContextStack(void *context, uptr *stack, uptr *ssize) { 266*68d75effSDimitry Andric UNIMPLEMENTED(); 267*68d75effSDimitry Andric } 268*68d75effSDimitry Andric 269*68d75effSDimitry Andric void AsanOnDeadlySignal(int, void *siginfo, void *context) { UNIMPLEMENTED(); } 270*68d75effSDimitry Andric 271*68d75effSDimitry Andric #if SANITIZER_WINDOWS64 272*68d75effSDimitry Andric // Exception handler for dealing with shadow memory. 273*68d75effSDimitry Andric static LONG CALLBACK 274*68d75effSDimitry Andric ShadowExceptionHandler(PEXCEPTION_POINTERS exception_pointers) { 275*68d75effSDimitry Andric uptr page_size = GetPageSizeCached(); 276*68d75effSDimitry Andric // Only handle access violations. 277*68d75effSDimitry Andric if (exception_pointers->ExceptionRecord->ExceptionCode != 278*68d75effSDimitry Andric EXCEPTION_ACCESS_VIOLATION || 279*68d75effSDimitry Andric exception_pointers->ExceptionRecord->NumberParameters < 2) { 280*68d75effSDimitry Andric __asan_handle_no_return(); 281*68d75effSDimitry Andric return EXCEPTION_CONTINUE_SEARCH; 282*68d75effSDimitry Andric } 283*68d75effSDimitry Andric 284*68d75effSDimitry Andric // Only handle access violations that land within the shadow memory. 285*68d75effSDimitry Andric uptr addr = 286*68d75effSDimitry Andric (uptr)(exception_pointers->ExceptionRecord->ExceptionInformation[1]); 287*68d75effSDimitry Andric 288*68d75effSDimitry Andric // Check valid shadow range. 289*68d75effSDimitry Andric if (!AddrIsInShadow(addr)) { 290*68d75effSDimitry Andric __asan_handle_no_return(); 291*68d75effSDimitry Andric return EXCEPTION_CONTINUE_SEARCH; 292*68d75effSDimitry Andric } 293*68d75effSDimitry Andric 294*68d75effSDimitry Andric // This is an access violation while trying to read from the shadow. Commit 295*68d75effSDimitry Andric // the relevant page and let execution continue. 296*68d75effSDimitry Andric 297*68d75effSDimitry Andric // Determine the address of the page that is being accessed. 298*68d75effSDimitry Andric uptr page = RoundDownTo(addr, page_size); 299*68d75effSDimitry Andric 300*68d75effSDimitry Andric // Commit the page. 301*68d75effSDimitry Andric uptr result = 302*68d75effSDimitry Andric (uptr)::VirtualAlloc((LPVOID)page, page_size, MEM_COMMIT, PAGE_READWRITE); 303*68d75effSDimitry Andric if (result != page) 304*68d75effSDimitry Andric return EXCEPTION_CONTINUE_SEARCH; 305*68d75effSDimitry Andric 306*68d75effSDimitry Andric // The page mapping succeeded, so continue execution as usual. 307*68d75effSDimitry Andric return EXCEPTION_CONTINUE_EXECUTION; 308*68d75effSDimitry Andric } 309*68d75effSDimitry Andric 310*68d75effSDimitry Andric #endif 311*68d75effSDimitry Andric 312*68d75effSDimitry Andric void InitializePlatformExceptionHandlers() { 313*68d75effSDimitry Andric #if SANITIZER_WINDOWS64 314*68d75effSDimitry Andric // On Win64, we map memory on demand with access violation handler. 315*68d75effSDimitry Andric // Install our exception handler. 316*68d75effSDimitry Andric CHECK(AddVectoredExceptionHandler(TRUE, &ShadowExceptionHandler)); 317*68d75effSDimitry Andric #endif 318*68d75effSDimitry Andric } 319*68d75effSDimitry Andric 320*68d75effSDimitry Andric bool IsSystemHeapAddress(uptr addr) { 321*68d75effSDimitry Andric return ::HeapValidate(GetProcessHeap(), 0, (void *)addr) != FALSE; 322*68d75effSDimitry Andric } 323*68d75effSDimitry Andric 324*68d75effSDimitry Andric // We want to install our own exception handler (EH) to print helpful reports 325*68d75effSDimitry Andric // on access violations and whatnot. Unfortunately, the CRT initializers assume 326*68d75effSDimitry Andric // they are run before any user code and drop any previously-installed EHs on 327*68d75effSDimitry Andric // the floor, so we can't install our handler inside __asan_init. 328*68d75effSDimitry Andric // (See crt0dat.c in the CRT sources for the details) 329*68d75effSDimitry Andric // 330*68d75effSDimitry Andric // Things get even more complicated with the dynamic runtime, as it finishes its 331*68d75effSDimitry Andric // initialization before the .exe module CRT begins to initialize. 332*68d75effSDimitry Andric // 333*68d75effSDimitry Andric // For the static runtime (-MT), it's enough to put a callback to 334*68d75effSDimitry Andric // __asan_set_seh_filter in the last section for C initializers. 335*68d75effSDimitry Andric // 336*68d75effSDimitry Andric // For the dynamic runtime (-MD), we want link the same 337*68d75effSDimitry Andric // asan_dynamic_runtime_thunk.lib to all the modules, thus __asan_set_seh_filter 338*68d75effSDimitry Andric // will be called for each instrumented module. This ensures that at least one 339*68d75effSDimitry Andric // __asan_set_seh_filter call happens after the .exe module CRT is initialized. 340*68d75effSDimitry Andric extern "C" SANITIZER_INTERFACE_ATTRIBUTE int __asan_set_seh_filter() { 341*68d75effSDimitry Andric // We should only store the previous handler if it's not our own handler in 342*68d75effSDimitry Andric // order to avoid loops in the EH chain. 343*68d75effSDimitry Andric auto prev_seh_handler = SetUnhandledExceptionFilter(SEHHandler); 344*68d75effSDimitry Andric if (prev_seh_handler != &SEHHandler) 345*68d75effSDimitry Andric default_seh_handler = prev_seh_handler; 346*68d75effSDimitry Andric return 0; 347*68d75effSDimitry Andric } 348*68d75effSDimitry Andric 349*68d75effSDimitry Andric bool HandleDlopenInit() { 350*68d75effSDimitry Andric // Not supported on this platform. 351*68d75effSDimitry Andric static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN, 352*68d75effSDimitry Andric "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false"); 353*68d75effSDimitry Andric return false; 354*68d75effSDimitry Andric } 355*68d75effSDimitry Andric 356*68d75effSDimitry Andric #if !ASAN_DYNAMIC 357*68d75effSDimitry Andric // The CRT runs initializers in this order: 358*68d75effSDimitry Andric // - C initializers, from XIA to XIZ 359*68d75effSDimitry Andric // - C++ initializers, from XCA to XCZ 360*68d75effSDimitry Andric // Prior to 2015, the CRT set the unhandled exception filter at priority XIY, 361*68d75effSDimitry Andric // near the end of C initialization. Starting in 2015, it was moved to the 362*68d75effSDimitry Andric // beginning of C++ initialization. We set our priority to XCAB to run 363*68d75effSDimitry Andric // immediately after the CRT runs. This way, our exception filter is called 364*68d75effSDimitry Andric // first and we can delegate to their filter if appropriate. 365*68d75effSDimitry Andric #pragma section(".CRT$XCAB", long, read) 366*68d75effSDimitry Andric __declspec(allocate(".CRT$XCAB")) int (*__intercept_seh)() = 367*68d75effSDimitry Andric __asan_set_seh_filter; 368*68d75effSDimitry Andric 369*68d75effSDimitry Andric // Piggyback on the TLS initialization callback directory to initialize asan as 370*68d75effSDimitry Andric // early as possible. Initializers in .CRT$XL* are called directly by ntdll, 371*68d75effSDimitry Andric // which run before the CRT. Users also add code to .CRT$XLC, so it's important 372*68d75effSDimitry Andric // to run our initializers first. 373*68d75effSDimitry Andric static void NTAPI asan_thread_init(void *module, DWORD reason, void *reserved) { 374*68d75effSDimitry Andric if (reason == DLL_PROCESS_ATTACH) 375*68d75effSDimitry Andric __asan_init(); 376*68d75effSDimitry Andric } 377*68d75effSDimitry Andric 378*68d75effSDimitry Andric #pragma section(".CRT$XLAB", long, read) 379*68d75effSDimitry Andric __declspec(allocate(".CRT$XLAB")) void(NTAPI *__asan_tls_init)( 380*68d75effSDimitry Andric void *, unsigned long, void *) = asan_thread_init; 381*68d75effSDimitry Andric #endif 382*68d75effSDimitry Andric 383*68d75effSDimitry Andric static void NTAPI asan_thread_exit(void *module, DWORD reason, void *reserved) { 384*68d75effSDimitry Andric if (reason == DLL_THREAD_DETACH) { 385*68d75effSDimitry Andric // Unpoison the thread's stack because the memory may be re-used. 386*68d75effSDimitry Andric NT_TIB *tib = (NT_TIB *)NtCurrentTeb(); 387*68d75effSDimitry Andric uptr stackSize = (uptr)tib->StackBase - (uptr)tib->StackLimit; 388*68d75effSDimitry Andric __asan_unpoison_memory_region(tib->StackLimit, stackSize); 389*68d75effSDimitry Andric } 390*68d75effSDimitry Andric } 391*68d75effSDimitry Andric 392*68d75effSDimitry Andric #pragma section(".CRT$XLY", long, read) 393*68d75effSDimitry Andric __declspec(allocate(".CRT$XLY")) void(NTAPI *__asan_tls_exit)( 394*68d75effSDimitry Andric void *, unsigned long, void *) = asan_thread_exit; 395*68d75effSDimitry Andric 396*68d75effSDimitry Andric WIN_FORCE_LINK(__asan_dso_reg_hook) 397*68d75effSDimitry Andric 398*68d75effSDimitry Andric // }}} 399*68d75effSDimitry Andric } // namespace __asan 400*68d75effSDimitry Andric 401*68d75effSDimitry Andric #endif // SANITIZER_WINDOWS 402