[compiler-rt] r245377 - [windows] Implement GetProcAddress internally to avoid initializing the CRT

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 18 15:38:27 PDT 2015


Author: rnk
Date: Tue Aug 18 17:38:27 2015
New Revision: 245377

URL: http://llvm.org/viewvc/llvm-project?rev=245377&view=rev
Log:
[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

Modified:
    compiler-rt/trunk/lib/asan/asan_win_dll_thunk.cc
    compiler-rt/trunk/lib/interception/interception_win.cc
    compiler-rt/trunk/lib/interception/interception_win.h

Modified: compiler-rt/trunk/lib/asan/asan_win_dll_thunk.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_win_dll_thunk.cc?rev=245377&r1=245376&r2=245377&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_win_dll_thunk.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_win_dll_thunk.cc Tue Aug 18 17:38:27 2015
@@ -30,8 +30,9 @@ void *__stdcall GetProcAddress(void *mod
 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();                            \
     }                                                                          \
   };
 

Modified: compiler-rt/trunk/lib/interception/interception_win.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/interception/interception_win.cc?rev=245377&r1=245376&r2=245377&view=diff
==============================================================================
--- compiler-rt/trunk/lib/interception/interception_win.cc (original)
+++ compiler-rt/trunk/lib/interception/interception_win.cc Tue Aug 18 17:38:27 2015
@@ -182,7 +182,7 @@ bool OverrideFunction(uptr old_func, upt
   return true;
 }
 
-static const void **InterestingDLLsAvailable() {
+static void **InterestingDLLsAvailable() {
   const char *InterestingDLLs[] = {
     "kernel32.dll",
     "msvcr110.dll", // VS2012
@@ -198,14 +198,65 @@ static const void **InterestingDLLsAvail
         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);
 }
 

Modified: compiler-rt/trunk/lib/interception/interception_win.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/interception/interception_win.h?rev=245377&r1=245376&r2=245377&view=diff
==============================================================================
--- compiler-rt/trunk/lib/interception/interception_win.h (original)
+++ compiler-rt/trunk/lib/interception/interception_win.h Tue Aug 18 17:38:27 2015
@@ -30,6 +30,10 @@ bool OverrideFunction(uptr old_func, upt
 
 // 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)




More information about the llvm-commits mailing list