From: Reid Kleckner Date: Tue, 8 Nov 2016 20:45:45 +0000 (+0000) Subject: [asan/win] Add init hooks to .CRT$XLAB X-Git-Tag: llvmorg-4.0.0-rc1~5198 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d092107b0e07b1861e541e5f21b342a74218ccb9;p=platform%2Fupstream%2Fllvm.git [asan/win] Add init hooks to .CRT$XLAB Summary: User applications may register hooks in the .CRT$XL* callback list, which is called very early by the loader. This is very common in Chromium: https://cs.chromium.org/search/?q=CRT.XL&sq=package:chromium&type=cs This has flown under the radar for a long time because the loader appears to catch exceptions originating from these callbacks. It's a real problem when you're debugging an asan application, though, since it makes the program crash early. The solution is to add our own callback to this list, and sort it very early in the list like we do elsewhere. Also add a test with such an instrumented callback, and test that it gets called with asan. Reviewers: etienneb Subscribers: llvm-commits, kubabrecka Differential Revision: https://reviews.llvm.org/D26404 llvm-svn: 286290 --- diff --git a/compiler-rt/lib/asan/asan_win.cc b/compiler-rt/lib/asan/asan_win.cc index c3f7943..54f622f 100644 --- a/compiler-rt/lib/asan/asan_win.cc +++ b/compiler-rt/lib/asan/asan_win.cc @@ -343,9 +343,23 @@ int __asan_set_seh_filter() { // immediately after the CRT runs. This way, our exception filter is called // first and we can delegate to their filter if appropriate. #pragma section(".CRT$XCAB", long, read) // NOLINT -__declspec(allocate(".CRT$XCAB")) - int (*__intercept_seh)() = __asan_set_seh_filter; +__declspec(allocate(".CRT$XCAB")) int (*__intercept_seh)() = + __asan_set_seh_filter; + +// Piggyback on the TLS initialization callback directory to initialize asan as +// early as possible. Initializers in .CRT$XL* are called directly by ntdll, +// which run before the CRT. Users also add code to .CRT$XLC, so it's important +// to run our initializers first. +static void NTAPI asan_thread_init(void *module, DWORD reason, void *reserved) { + if (reason == DLL_PROCESS_ATTACH) __asan_init(); +} + +#pragma section(".CRT$XLAB", long, read) // NOLINT +__declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)( + void *, unsigned long, void *) = asan_thread_init; #endif + + // }}} } // namespace __asan diff --git a/compiler-rt/lib/asan/asan_win_dll_thunk.cc b/compiler-rt/lib/asan/asan_win_dll_thunk.cc index 545a7d1..297a91a 100644 --- a/compiler-rt/lib/asan/asan_win_dll_thunk.cc +++ b/compiler-rt/lib/asan/asan_win_dll_thunk.cc @@ -456,4 +456,19 @@ static int call_asan_init() { #pragma section(".CRT$XIB", long, read) // NOLINT __declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init; +#ifdef _M_IX86 +#define NTAPI __stdcall +#else +#define NTAPI +#endif + +static void NTAPI asan_thread_init(void *mod, unsigned long reason, + void *reserved) { + if (reason == /*DLL_PROCESS_ATTACH=*/1) __asan_init(); +} + +#pragma section(".CRT$XLAB", long, read) // NOLINT +__declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)( + void *, unsigned long, void *) = asan_thread_init; + #endif // ASAN_DLL_THUNK 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 3b06e8b..96ca47e 100644 --- a/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc +++ b/compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc @@ -33,6 +33,7 @@ #pragma section(".CRT$XCAB", long, read) // NOLINT #pragma section(".CRT$XTW", long, read) // NOLINT #pragma section(".CRT$XTY", long, read) // NOLINT +#pragma section(".CRT$XLAB", long, read) // NOLINT //////////////////////////////////////////////////////////////////////////////// // Define a copy of __asan_option_detect_stack_use_after_return that should be @@ -61,9 +62,17 @@ static int InitializeClonedVariables() { return 0; } -// Our cloned variables must be initialized before C/C++ constructors. -__declspec(allocate(".CRT$XIB")) -int (*__asan_initialize_cloned_variables)() = InitializeClonedVariables; +static void NTAPI asan_thread_init(void *mod, unsigned long reason, void *reserved) { + if (reason == DLL_PROCESS_ATTACH) InitializeClonedVariables(); +} + +// Our cloned variables must be initialized before C/C++ constructors. If TLS +// is used, our .CRT$XLAB initializer will run first. If not, our .CRT$XIB +// initializer is needed as a backup. +__declspec(allocate(".CRT$XIB")) int (*__asan_initialize_cloned_variables)() = + InitializeClonedVariables; +__declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)( + void *, unsigned long, void *) = asan_thread_init; //////////////////////////////////////////////////////////////////////////////// // For some reason, the MD CRT doesn't call the C/C++ terminators during on DLL diff --git a/compiler-rt/test/asan/TestCases/Windows/tls_init.cc b/compiler-rt/test/asan/TestCases/Windows/tls_init.cc new file mode 100644 index 0000000..c29c4a3 --- /dev/null +++ b/compiler-rt/test/asan/TestCases/Windows/tls_init.cc @@ -0,0 +1,51 @@ +// RUN: %clang_cl_asan %s -Fe%t.exe +// RUN: %run %t.exe | FileCheck %s + +// CHECK: my_thread_callback +// CHECK: ran_before_main: 1 + +#include +#include +#include + +#pragma comment (lib, "dbghelp") + +static bool ran_before_main = false; + +extern "C" void __asan_init(void); + +static void NTAPI /*__attribute__((no_sanitize_address))*/ +my_thread_callback(PVOID module, DWORD reason, PVOID reserved) { + ran_before_main = true; + static const char str[] = "my_thread_callback\n"; + + // Fail the test if we aren't called for the expected reason or we can't write + // stdout. + if (reason != DLL_PROCESS_ATTACH) + return; + HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); + if (!out || out == INVALID_HANDLE_VALUE) + return; + + DWORD written = 0; + WriteFile(out, &str[0], sizeof(str), &written, NULL); +} + +extern "C" { +#pragma const_seg(".CRT$XLC") +extern const PIMAGE_TLS_CALLBACK p_thread_callback; +const PIMAGE_TLS_CALLBACK p_thread_callback = my_thread_callback; +#pragma const_seg() +} + +#ifdef _WIN64 +#pragma comment(linker, "/INCLUDE:_tls_used") +#pragma comment(linker, "/INCLUDE:p_thread_callback") +#else +#pragma comment(linker, "/INCLUDE:__tls_used") +#pragma comment(linker, "/INCLUDE:_p_thread_callback") +#endif + +int main() { + printf("ran_before_main: %d\n", ran_before_main); +}