diff options
Diffstat (limited to 'compiler-rt')
5 files changed, 127 insertions, 76 deletions
diff --git a/compiler-rt/lib/asan/asan_globals.cc b/compiler-rt/lib/asan/asan_globals.cc index 853a1810247..8906d1eedde 100644 --- a/compiler-rt/lib/asan/asan_globals.cc +++ b/compiler-rt/lib/asan/asan_globals.cc @@ -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 diff --git a/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc b/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc index 19456141c1e..d59f9f5768a 100644 --- a/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc +++ b/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc @@ -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 diff --git a/compiler-rt/test/asan/TestCases/Windows/dll_report_globals_symbolization_at_startup.cc b/compiler-rt/test/asan/TestCases/Windows/dll_report_globals_symbolization_at_startup.cc new file mode 100644 index 00000000000..fbdb1c145bb --- /dev/null +++ b/compiler-rt/test/asan/TestCases/Windows/dll_report_globals_symbolization_at_startup.cc @@ -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 +} diff --git a/compiler-rt/test/asan/TestCases/Windows/report_globals_reload_dll.cc b/compiler-rt/test/asan/TestCases/Windows/report_globals_reload_dll.cc new file mode 100644 index 00000000000..8b050975aac --- /dev/null +++ b/compiler-rt/test/asan/TestCases/Windows/report_globals_reload_dll.cc @@ -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 +} diff --git a/compiler-rt/test/asan/TestCases/Windows/report_globals_vs_freelibrary.cc b/compiler-rt/test/asan/TestCases/Windows/report_globals_vs_freelibrary.cc index 634e5782796..72bf36ad0be 100644 --- a/compiler-rt/test/asan/TestCases/Windows/report_globals_vs_freelibrary.cc +++ b/compiler-rt/test/asan/TestCases/Windows/report_globals_vs_freelibrary.cc @@ -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 |

