diff --git a/compiler-rt/lib/asan/asan_win_dll_thunk.cc b/compiler-rt/lib/asan/asan_win_dll_thunk.cc index 08118882ca5f..b8d0798960c1 100644 --- a/compiler-rt/lib/asan/asan_win_dll_thunk.cc +++ b/compiler-rt/lib/asan/asan_win_dll_thunk.cc @@ -30,8 +30,9 @@ void *__stdcall GetProcAddress(void *module, const char *proc_name); void abort(); } -static void *getRealProcAddressOrDie(const char *name) { - void *ret = GetProcAddress(GetModuleHandleA(0), name); +static uptr getRealProcAddressOrDie(const char *name) { + uptr ret = + __interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name); if (!ret) abort(); return ret; @@ -62,13 +63,12 @@ struct FunctionInterceptor<0> { }; #define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \ - template<> struct FunctionInterceptor<__LINE__> { \ + template <> struct FunctionInterceptor<__LINE__> { \ static void Execute() { \ - void *wrapper = getRealProcAddressOrDie(main_function); \ - if (!__interception::OverrideFunction((uptr)dll_function, \ - (uptr)wrapper, 0)) \ + uptr wrapper = getRealProcAddressOrDie(main_function); \ + if (!__interception::OverrideFunction((uptr)dll_function, wrapper, 0)) \ abort(); \ - FunctionInterceptor<__LINE__-1>::Execute(); \ + FunctionInterceptor<__LINE__ - 1>::Execute(); \ } \ }; diff --git a/compiler-rt/lib/interception/interception_win.cc b/compiler-rt/lib/interception/interception_win.cc index 19cf184948b9..e3197ddc1a54 100644 --- a/compiler-rt/lib/interception/interception_win.cc +++ b/compiler-rt/lib/interception/interception_win.cc @@ -182,7 +182,7 @@ bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func) { return true; } -static const void **InterestingDLLsAvailable() { +static void **InterestingDLLsAvailable() { const char *InterestingDLLs[] = { "kernel32.dll", "msvcr110.dll", // VS2012 @@ -198,14 +198,65 @@ static const void **InterestingDLLsAvailable() { result[j++] = (void *)h; } } - return (const void **)&result[0]; + return &result[0]; +} + +namespace { +// Utility for reading loaded PE images. +template class RVAPtr { + public: + RVAPtr(void *module, uptr rva) + : ptr_(reinterpret_cast(reinterpret_cast(module) + rva)) {} + operator T *() { return ptr_; } + T *operator->() { return ptr_; } + T *operator++() { return ++ptr_; } + + private: + T *ptr_; +}; +} // namespace + +// Internal implementation of GetProcAddress. At least since Windows 8, +// GetProcAddress appears to initialize DLLs before returning function pointers +// into them. This is problematic for the sanitizers, because they typically +// want to intercept malloc *before* MSVCRT initializes. Our internal +// implementation walks the export list manually without doing initialization. +uptr InternalGetProcAddress(void *module, const char *func_name) { + // Check that the module header is full and present. + RVAPtr dos_stub(module, 0); + RVAPtr headers(module, dos_stub->e_lfanew); + if (!module || dos_stub->e_magic != IMAGE_DOS_SIGNATURE || // "MZ" + headers->Signature != IMAGE_NT_SIGNATURE || // "PE\0\0" + headers->FileHeader.SizeOfOptionalHeader < + sizeof(IMAGE_OPTIONAL_HEADER)) { + return 0; + } + + IMAGE_DATA_DIRECTORY *export_directory = + &headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + RVAPtr exports(module, + export_directory->VirtualAddress); + RVAPtr functions(module, exports->AddressOfFunctions); + RVAPtr names(module, exports->AddressOfNames); + RVAPtr ordinals(module, exports->AddressOfNameOrdinals); + + for (DWORD i = 0; i < exports->NumberOfNames; i++) { + RVAPtr name(module, names[i]); + if (!strcmp(func_name, name)) { + DWORD index = ordinals[i]; + RVAPtr func(module, functions[index]); + return (uptr)(char *)func; + } + } + + return 0; } static bool GetFunctionAddressInDLLs(const char *func_name, uptr *func_addr) { *func_addr = 0; - const void **DLLs = InterestingDLLsAvailable(); + void **DLLs = InterestingDLLsAvailable(); for (size_t i = 0; *func_addr == 0 && DLLs[i]; ++i) - *func_addr = (uptr)GetProcAddress((HMODULE)DLLs[i], func_name); + *func_addr = InternalGetProcAddress(DLLs[i], func_name); return (*func_addr != 0); } diff --git a/compiler-rt/lib/interception/interception_win.h b/compiler-rt/lib/interception/interception_win.h index ba768a7233f9..96c4a0c0f5a3 100644 --- a/compiler-rt/lib/interception/interception_win.h +++ b/compiler-rt/lib/interception/interception_win.h @@ -30,6 +30,10 @@ bool OverrideFunction(uptr old_func, uptr new_func, uptr *orig_old_func = 0); // Overrides a function in a system DLL or DLL CRT by its exported name. bool OverrideFunction(const char *name, uptr new_func, uptr *orig_old_func = 0); + +// Windows-only replacement for GetProcAddress. Useful for some sanitizers. +uptr InternalGetProcAddress(void *module, const char *func_name); + } // namespace __interception #if defined(INTERCEPTION_DYNAMIC_CRT)