summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorReid Kleckner <rnk@google.com>2015-08-18 22:38:27 +0000
committerReid Kleckner <rnk@google.com>2015-08-18 22:38:27 +0000
commitd85f7010ccf965399f6b1e4e3e708b041f70a7ed (patch)
tree5f4140cc4ef6c9007db7fa0fa3c1f63755da904a
parent6dc8d583b9656f2d28dd58bd4347c92caf793168 (diff)
downloadbcm5719-llvm-d85f7010ccf965399f6b1e4e3e708b041f70a7ed.tar.gz
bcm5719-llvm-d85f7010ccf965399f6b1e4e3e708b041f70a7ed.zip
[windows] Implement GetProcAddress internally to avoid initializing the CRT
ASan uses GetProcAddress to get the address of malloc so it can patch it. Newer versions of Windows make GetProcAddress initialize the DLL before returning a function pointer into it. That's perfectly reasonable, but ASan needs to finish patching malloc before CRT initialization. So now we roll our own GetProcAddress. Fixes PR24237 Based on a patch by David Major Originally written by David Major as part of: https://hg.mozilla.org/mozilla-central/file/tip/toolkit/xre/WindowsCrtPatch.h llvm-svn: 245377
-rw-r--r--compiler-rt/lib/asan/asan_win_dll_thunk.cc14
-rw-r--r--compiler-rt/lib/interception/interception_win.cc59
-rw-r--r--compiler-rt/lib/interception/interception_win.h4
3 files changed, 66 insertions, 11 deletions
diff --git a/compiler-rt/lib/asan/asan_win_dll_thunk.cc b/compiler-rt/lib/asan/asan_win_dll_thunk.cc
index 08118882ca5..b8d0798960c 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 19cf184948b..e3197ddc1a5 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 <typename T> class RVAPtr {
+ public:
+ RVAPtr(void *module, uptr rva)
+ : ptr_(reinterpret_cast<T *>(reinterpret_cast<char *>(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<IMAGE_DOS_HEADER> dos_stub(module, 0);
+ RVAPtr<IMAGE_NT_HEADERS> 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<IMAGE_EXPORT_DIRECTORY> exports(module,
+ export_directory->VirtualAddress);
+ RVAPtr<DWORD> functions(module, exports->AddressOfFunctions);
+ RVAPtr<DWORD> names(module, exports->AddressOfNames);
+ RVAPtr<WORD> ordinals(module, exports->AddressOfNameOrdinals);
+
+ for (DWORD i = 0; i < exports->NumberOfNames; i++) {
+ RVAPtr<char> name(module, names[i]);
+ if (!strcmp(func_name, name)) {
+ DWORD index = ordinals[i];
+ RVAPtr<char> 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 ba768a7233f..96c4a0c0f5a 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)
OpenPOWER on IntegriCloud