[compiler-rt] r286290 - [asan/win] Add init hooks to .CRT$XLAB

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 8 12:45:46 PST 2016


Author: rnk
Date: Tue Nov  8 14:45:45 2016
New Revision: 286290

URL: http://llvm.org/viewvc/llvm-project?rev=286290&view=rev
Log:
[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

Added:
    compiler-rt/trunk/test/asan/TestCases/Windows/tls_init.cc
Modified:
    compiler-rt/trunk/lib/asan/asan_win.cc
    compiler-rt/trunk/lib/asan/asan_win_dll_thunk.cc
    compiler-rt/trunk/lib/asan/asan_win_dynamic_runtime_thunk.cc

Modified: compiler-rt/trunk/lib/asan/asan_win.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_win.cc?rev=286290&r1=286289&r2=286290&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_win.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_win.cc Tue Nov  8 14:45:45 2016
@@ -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
 

Modified: compiler-rt/trunk/lib/asan/asan_win_dll_thunk.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_win_dll_thunk.cc?rev=286290&r1=286289&r2=286290&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_win_dll_thunk.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_win_dll_thunk.cc Tue Nov  8 14:45:45 2016
@@ -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

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=286290&r1=286289&r2=286290&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 Tue Nov  8 14:45:45 2016
@@ -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

Added: compiler-rt/trunk/test/asan/TestCases/Windows/tls_init.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/Windows/tls_init.cc?rev=286290&view=auto
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/Windows/tls_init.cc (added)
+++ compiler-rt/trunk/test/asan/TestCases/Windows/tls_init.cc Tue Nov  8 14:45:45 2016
@@ -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 <windows.h>
+#include <stdio.h>
+#include <string.h>
+
+#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);
+}




More information about the llvm-commits mailing list