diff options
author | Timur Iskhodzhanov <timurrrr@google.com> | 2015-02-20 15:34:16 +0000 |
---|---|---|
committer | Timur Iskhodzhanov <timurrrr@google.com> | 2015-02-20 15:34:16 +0000 |
commit | 426cb567e0220f9a501c1b6992301e45b1bbdcbd (patch) | |
tree | bd0d7e0409611afe155445f60b26309484efe69c /lib/asan | |
parent | 52814b38d6d3f5798fc9c939401b3a911c078488 (diff) |
[ASan/Win] Work around PR22545 - unregister globals when using the MD runtime
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@230018 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/asan')
-rw-r--r-- | lib/asan/asan_globals.cc | 14 | ||||
-rw-r--r-- | lib/asan/asan_win_dynamic_runtime_thunk.cc | 85 |
2 files changed, 90 insertions, 9 deletions
diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc index e5d4417aa..06140bbb3 100644 --- a/lib/asan/asan_globals.cc +++ b/lib/asan/asan_globals.cc @@ -210,6 +210,20 @@ 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 diff --git a/lib/asan/asan_win_dynamic_runtime_thunk.cc b/lib/asan/asan_win_dynamic_runtime_thunk.cc index 3a4de7dbf..19456141c 100644 --- a/lib/asan/asan_win_dynamic_runtime_thunk.cc +++ b/lib/asan/asan_win_dynamic_runtime_thunk.cc @@ -23,10 +23,11 @@ // Using #ifdef rather than relying on Makefiles etc. // simplifies the build procedure. #ifdef ASAN_DYNAMIC_RUNTIME_THUNK -extern "C" { -__declspec(dllimport) int __asan_set_seh_filter(); -__declspec(dllimport) int __asan_should_detect_stack_use_after_return(); +#include <windows.h> +#include <psapi.h> +extern "C" { +//////////////////////////////////////////////////////////////////////////////// // 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. // @@ -37,16 +38,82 @@ __declspec(dllimport) int __asan_should_detect_stack_use_after_return(); // 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. +__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); +} + +namespace { +void *this_module_base, *this_module_end; + +void UnregisterGlobals() { + __asan::UnregisterGlobalsInRange(this_module_base, this_module_end); +} + +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; -// Set the ASan-specific SEH handler at the end of CRT initialization of each -// module (see asan_win.cc for the details). + 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). +__declspec(allocate(".CRT$XID")) +static int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals; + +// We need to set the ASan-specific SEH handler at the end of CRT initialization +// of each module (see also asan_win.cc). // // Unfortunately, putting a pointer to __asan_set_seh_filter into // __asan_intercept_seh gets optimized out, so we have to use an extra function. -static int SetSEHFilter() { return __asan_set_seh_filter(); } -#pragma section(".CRT$XIZ", long, read) // NOLINT -__declspec(allocate(".CRT$XIZ")) int (*__asan_seh_interceptor)() = SetSEHFilter; -} +extern "C" __declspec(allocate(".CRT$XIZ")) +int (*__asan_seh_interceptor)() = SetSEHFilter; + #endif // ASAN_DYNAMIC_RUNTIME_THUNK |