[compiler-rt] r231000 - [ASan/Win] Work around PR22545: call LLVM global_dtors in the MD atexit()

Timur Iskhodzhanov timurrrr at google.com
Mon Mar 2 11:41:10 PST 2015


Author: timurrrr
Date: Mon Mar  2 13:41:09 2015
New Revision: 231000

URL: http://llvm.org/viewvc/llvm-project?rev=231000&view=rev
Log:
[ASan/Win] Work around PR22545: call LLVM global_dtors in the MD atexit()

Added:
    compiler-rt/trunk/test/asan/TestCases/Windows/dll_report_globals_symbolization_at_startup.cc
    compiler-rt/trunk/test/asan/TestCases/Windows/report_globals_reload_dll.cc
Modified:
    compiler-rt/trunk/lib/asan/asan_globals.cc
    compiler-rt/trunk/lib/asan/asan_win_dynamic_runtime_thunk.cc
    compiler-rt/trunk/test/asan/TestCases/Windows/report_globals_vs_freelibrary.cc

Modified: compiler-rt/trunk/lib/asan/asan_globals.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_globals.cc?rev=231000&r1=230999&r2=231000&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_globals.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_globals.cc Mon Mar  2 13:41:09 2015
@@ -212,20 +212,6 @@ void StopInitOrderChecking() {
   }
 }
 
-#if SANITIZER_WINDOWS  // Should only be called on Windows.
-SANITIZER_INTERFACE_ATTRIBUTE
-void UnregisterGlobalsInRange(void *beg, void *end) {
-  if (!flags()->report_globals)
-    return;
-  BlockingMutexLock lock(&mu_for_globals);
-  for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
-    void *address = (void *)l->g->beg;
-    if (beg <= address && address < end)
-      UnregisterGlobal(l->g);
-  }
-}
-#endif
-
 }  // namespace __asan
 
 // ---------------------- Interface ---------------- {{{1

Modified: compiler-rt/trunk/lib/asan/asan_win_dynamic_runtime_thunk.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_win_dynamic_runtime_thunk.cc?rev=231000&r1=230999&r2=231000&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_win_dynamic_runtime_thunk.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_win_dynamic_runtime_thunk.cc Mon Mar  2 13:41:09 2015
@@ -15,7 +15,8 @@
 //
 // This includes:
 //  - forwarding the detect_stack_use_after_return runtime option
-//  - installing a custom SEH handler
+//  - working around deficiencies of the MD runtime
+//  - installing a custom SEH handlerx
 //
 //===----------------------------------------------------------------------===//
 
@@ -24,9 +25,13 @@
 // simplifies the build procedure.
 #ifdef ASAN_DYNAMIC_RUNTIME_THUNK
 #include <windows.h>
-#include <psapi.h>
 
-extern "C" {
+// First, declare CRT sections we'll be using in this file
+#pragma section(".CRT$XID", long, read)  // NOLINT
+#pragma section(".CRT$XIZ", long, read)  // NOLINT
+#pragma section(".CRT$XTW", long, read)  // NOLINT
+#pragma section(".CRT$XTY", long, read)  // NOLINT
+
 ////////////////////////////////////////////////////////////////////////////////
 // Define a copy of __asan_option_detect_stack_use_after_return that should be
 // used when linking an MD runtime with a set of object files on Windows.
@@ -38,82 +43,55 @@ extern "C" {
 // with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows
 // just to work around this issue, let's clone the a variable that is
 // constant after initialization anyways.
+extern "C" {
 __declspec(dllimport) int __asan_should_detect_stack_use_after_return();
 int __asan_option_detect_stack_use_after_return =
     __asan_should_detect_stack_use_after_return();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// For some reason, the MD CRT doesn't call the C/C++ terminators as MT does.
-// To work around this, for each DLL we schedule a call to
-// UnregisterGlobalsInRange atexit() specifying the address range of the DLL
-// image to unregister globals in that range.   We don't do the same
-// for the main module (.exe) as the asan_globals.cc allocator is destroyed
-// by the time UnregisterGlobalsInRange is executed.
-// See PR22545 for the details.
-namespace __asan {
-__declspec(dllimport)
-void UnregisterGlobalsInRange(void *beg, void *end);
-}
+// For some reason, the MD CRT doesn't call the C/C++ terminators during on DLL
+// unload or on exit.  ASan relies on LLVM global_dtors to call
+// __asan_unregister_globals on these events, which unfortunately doesn't work
+// with the MD runtime, see PR22545 for the details.
+// To work around this, for each DLL we schedule a call to UnregisterGlobals
+// using atexit() that calls a small subset of C terminators
+// where LLVM global_dtors is placed.  Fingers crossed, no other C terminators
+// are there.
+extern "C" void __cdecl _initterm(void *a, void *b);
 
 namespace {
-void *this_module_base, *this_module_end;
+__declspec(allocate(".CRT$XTW")) void* before_global_dtors = 0;
+__declspec(allocate(".CRT$XTY")) void* after_global_dtors = 0;
 
 void UnregisterGlobals() {
-  __asan::UnregisterGlobalsInRange(this_module_base, this_module_end);
+  _initterm(&before_global_dtors, &after_global_dtors);
 }
 
 int ScheduleUnregisterGlobals() {
-  HMODULE this_module = 0;
-  // Increments the reference counter of the DLL module, so need to call
-  // FreeLibrary later.
-  if (!GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
-                         (LPCTSTR)&UnregisterGlobals, &this_module))
-    return 1;
-
-  // Skip the main module.
-  if (this_module == GetModuleHandle(0))
-    return 0;
-
-  MODULEINFO mi;
-  bool success =
-      GetModuleInformation(GetCurrentProcess(), this_module, &mi, sizeof(mi));
-  if (!FreeLibrary(this_module))
-    return 2;
-  if (!success)
-    return 3;
-
-  this_module_base = mi.lpBaseOfDll;
-  this_module_end = (char*)mi.lpBaseOfDll + mi.SizeOfImage;
-
   return atexit(UnregisterGlobals);
 }
-}  // namespace
-
-///////////////////////////////////////////////////////////////////////////////
-// ASan SEH handling.
-extern "C" __declspec(dllimport) int __asan_set_seh_filter();
-static int SetSEHFilter() { return __asan_set_seh_filter(); }
 
-///////////////////////////////////////////////////////////////////////////////
-// We schedule some work at start-up by placing callbacks to our code to the
-// list of CRT C initializers.
-//
-// First, declare sections we'll be using:
-#pragma section(".CRT$XID", long, read)  // NOLINT
-#pragma section(".CRT$XIZ", long, read)  // NOLINT
-
-// We need to call 'atexit(UnregisterGlobals);' after atexit() is initialized
-// (.CRT$XIC) but before the C++ constructors (.CRT$XCA).
+// We need to call 'atexit(UnregisterGlobals);' as early as possible, but after
+// atexit() is initialized (.CRT$XIC).  As this is executed before C++
+// initializers (think ctors for globals), UnregisterGlobals gets executed after
+// dtors for C++ globals.
 __declspec(allocate(".CRT$XID"))
-static int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals;
+int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals;
 
+}  // namespace
+
+////////////////////////////////////////////////////////////////////////////////
+// ASan SEH handling.
 // We need to set the ASan-specific SEH handler at the end of CRT initialization
 // of each module (see also asan_win.cc).
-//
+extern "C" {
+__declspec(dllimport) int __asan_set_seh_filter();
+static int SetSEHFilter() { return __asan_set_seh_filter(); }
+
 // Unfortunately, putting a pointer to __asan_set_seh_filter into
 // __asan_intercept_seh gets optimized out, so we have to use an extra function.
-extern "C" __declspec(allocate(".CRT$XIZ"))
-int (*__asan_seh_interceptor)() = SetSEHFilter;
+__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter;
+}
 
 #endif // ASAN_DYNAMIC_RUNTIME_THUNK

Added: compiler-rt/trunk/test/asan/TestCases/Windows/dll_report_globals_symbolization_at_startup.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Windows/dll_report_globals_symbolization_at_startup.cc?rev=231000&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Windows/dll_report_globals_symbolization_at_startup.cc (added)
+++ compiler-rt/trunk/test/asan/TestCases/Windows/dll_report_globals_symbolization_at_startup.cc Mon Mar  2 13:41:09 2015
@@ -0,0 +1,40 @@
+// RUN: %clang_cl_asan -LD -O0 -DDLL %s -Fe%t.dll
+// RUN: %clang_cl_asan -O0 -DEXE %s %t.lib -Fe%te.exe
+// RUN: env ASAN_OPTIONS=report_globals=2 %run %te.exe 2>&1 | FileCheck %s
+
+// FIXME: Currently, the MT runtime build crashes on startup due to dbghelp.dll
+// initialization failure.
+// REQUIRES: asan-dynamic-runtime
+
+#include <windows.h>
+#include <stdio.h>
+
+extern "C" {
+#if defined(EXE)
+__declspec(dllimport) int foo_from_dll();
+
+// CHECK: in DLL(reason=1)
+int main(int argc, char **argv) {
+  foo_from_dll();
+// CHECK: hello!
+  printf("hello!\n");
+  fflush(0);
+// CHECK: in DLL(reason=0)
+}
+#elif defined(DLL)
+// This global is registered at startup.
+int x[42];
+
+__declspec(dllexport) int foo_from_dll() {
+  return x[2];
+}
+
+BOOL WINAPI DllMain(HMODULE, DWORD reason, LPVOID) {
+  printf("in DLL(reason=%d)\n", (int)reason);
+  fflush(0);
+  return TRUE;
+}
+#else
+# error oops!
+#endif
+}

Added: compiler-rt/trunk/test/asan/TestCases/Windows/report_globals_reload_dll.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Windows/report_globals_reload_dll.cc?rev=231000&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Windows/report_globals_reload_dll.cc (added)
+++ compiler-rt/trunk/test/asan/TestCases/Windows/report_globals_reload_dll.cc Mon Mar  2 13:41:09 2015
@@ -0,0 +1,51 @@
+// Make sure we can handle reloading the same DLL multiple times.
+// RUN: %clang_cl_asan -LD -O0 -DDLL %s -Fe%t.dll
+// RUN: %clang_cl_asan -O0 -DEXE %s -Fe%te.exe
+// RUN: env ASAN_OPTIONS=report_globals=1 %run %te.exe %t.dll 2>&1 | FileCheck %s
+
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+
+extern "C" {
+#if defined(EXE)
+int main(int argc, char **argv) {
+  if (argc != 2) {
+    printf("Usage: %s [client].dll\n", argv[0]);
+    return 101;
+  }
+  const char *dll_name = argv[1];
+
+// CHECK: time to load DLL
+  printf("time to load DLL\n");
+  fflush(0);
+
+// CHECK: in DLL(reason=1)
+// CHECK: in DLL(reason=0)
+// CHECK: in DLL(reason=1)
+// CHECK: in DLL(reason=0)
+// CHECK: in DLL(reason=1)
+// CHECK: in DLL(reason=0)
+  for (int i = 0; i < 30; ++i) {
+    HMODULE dll = LoadLibrary(dll_name);
+    if (dll == NULL)
+      return 3;
+
+    if (!FreeLibrary(dll))
+      return 4;
+  }
+
+// CHECK: All OK!
+  printf("All OK!\n");
+  fflush(0);
+}
+#elif defined(DLL)
+BOOL WINAPI DllMain(HMODULE, DWORD reason, LPVOID) {
+  printf("in DLL(reason=%d)\n", (int)reason);
+  fflush(0);
+  return TRUE;
+}
+#else
+# error oops!
+#endif
+}

Modified: compiler-rt/trunk/test/asan/TestCases/Windows/report_globals_vs_freelibrary.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Windows/report_globals_vs_freelibrary.cc?rev=231000&r1=230999&r2=231000&view=diff
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Windows/report_globals_vs_freelibrary.cc (original)
+++ compiler-rt/trunk/test/asan/TestCases/Windows/report_globals_vs_freelibrary.cc Mon Mar  2 13:41:09 2015
@@ -1,7 +1,3 @@
-// Make sure everything works even if the main module doesn't have any stack
-// variables, thus doesn't explicitly reference any symbol exported by the
-// runtime thunk.
-//
 // RUN: %clang_cl_asan -LD -O0 -DDLL %s -Fe%t.dll
 // RUN: %clang_cl_asan -O0 -DEXE %s -Fe%te.exe
 // RUN: env ASAN_OPTIONS=report_globals=2 %run %te.exe %t.dll 2>&1 | FileCheck %s





More information about the llvm-commits mailing list