From 426cb567e0220f9a501c1b6992301e45b1bbdcbd Mon Sep 17 00:00:00 2001 From: Timur Iskhodzhanov Date: Fri, 20 Feb 2015 15:34:16 +0000 Subject: [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 --- lib/asan/asan_win_dynamic_runtime_thunk.cc | 85 ++++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 9 deletions(-) (limited to 'lib/asan/asan_win_dynamic_runtime_thunk.cc') 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 +#include +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 -- cgit v1.2.3