Skip to content

Commit d092107

Browse files
committedNov 8, 2016
[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
1 parent 6cddfc1 commit d092107

File tree

4 files changed

+94
-5
lines changed

4 files changed

+94
-5
lines changed
 

‎compiler-rt/lib/asan/asan_win.cc

+16-2
Original file line numberDiff line numberDiff line change
@@ -343,9 +343,23 @@ int __asan_set_seh_filter() {
343343
// immediately after the CRT runs. This way, our exception filter is called
344344
// first and we can delegate to their filter if appropriate.
345345
#pragma section(".CRT$XCAB", long, read) // NOLINT
346-
__declspec(allocate(".CRT$XCAB"))
347-
int (*__intercept_seh)() = __asan_set_seh_filter;
346+
__declspec(allocate(".CRT$XCAB")) int (*__intercept_seh)() =
347+
__asan_set_seh_filter;
348+
349+
// Piggyback on the TLS initialization callback directory to initialize asan as
350+
// early as possible. Initializers in .CRT$XL* are called directly by ntdll,
351+
// which run before the CRT. Users also add code to .CRT$XLC, so it's important
352+
// to run our initializers first.
353+
static void NTAPI asan_thread_init(void *module, DWORD reason, void *reserved) {
354+
if (reason == DLL_PROCESS_ATTACH) __asan_init();
355+
}
356+
357+
#pragma section(".CRT$XLAB", long, read) // NOLINT
358+
__declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(
359+
void *, unsigned long, void *) = asan_thread_init;
348360
#endif
361+
362+
349363
// }}}
350364
} // namespace __asan
351365

‎compiler-rt/lib/asan/asan_win_dll_thunk.cc

+15
Original file line numberDiff line numberDiff line change
@@ -456,4 +456,19 @@ static int call_asan_init() {
456456
#pragma section(".CRT$XIB", long, read) // NOLINT
457457
__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init;
458458

459+
#ifdef _M_IX86
460+
#define NTAPI __stdcall
461+
#else
462+
#define NTAPI
463+
#endif
464+
465+
static void NTAPI asan_thread_init(void *mod, unsigned long reason,
466+
void *reserved) {
467+
if (reason == /*DLL_PROCESS_ATTACH=*/1) __asan_init();
468+
}
469+
470+
#pragma section(".CRT$XLAB", long, read) // NOLINT
471+
__declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(
472+
void *, unsigned long, void *) = asan_thread_init;
473+
459474
#endif // ASAN_DLL_THUNK

‎compiler-rt/lib/asan/asan_win_dynamic_runtime_thunk.cc

+12-3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#pragma section(".CRT$XCAB", long, read) // NOLINT
3434
#pragma section(".CRT$XTW", long, read) // NOLINT
3535
#pragma section(".CRT$XTY", long, read) // NOLINT
36+
#pragma section(".CRT$XLAB", long, read) // NOLINT
3637

3738
////////////////////////////////////////////////////////////////////////////////
3839
// Define a copy of __asan_option_detect_stack_use_after_return that should be
@@ -61,9 +62,17 @@ static int InitializeClonedVariables() {
6162
return 0;
6263
}
6364

64-
// Our cloned variables must be initialized before C/C++ constructors.
65-
__declspec(allocate(".CRT$XIB"))
66-
int (*__asan_initialize_cloned_variables)() = InitializeClonedVariables;
65+
static void NTAPI asan_thread_init(void *mod, unsigned long reason, void *reserved) {
66+
if (reason == DLL_PROCESS_ATTACH) InitializeClonedVariables();
67+
}
68+
69+
// Our cloned variables must be initialized before C/C++ constructors. If TLS
70+
// is used, our .CRT$XLAB initializer will run first. If not, our .CRT$XIB
71+
// initializer is needed as a backup.
72+
__declspec(allocate(".CRT$XIB")) int (*__asan_initialize_cloned_variables)() =
73+
InitializeClonedVariables;
74+
__declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(
75+
void *, unsigned long, void *) = asan_thread_init;
6776

6877
////////////////////////////////////////////////////////////////////////////////
6978
// For some reason, the MD CRT doesn't call the C/C++ terminators during on DLL
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// RUN: %clang_cl_asan %s -Fe%t.exe
2+
// RUN: %run %t.exe | FileCheck %s
3+
4+
// CHECK: my_thread_callback
5+
// CHECK: ran_before_main: 1
6+
7+
#include <windows.h>
8+
#include <stdio.h>
9+
#include <string.h>
10+
11+
#pragma comment (lib, "dbghelp")
12+
13+
static bool ran_before_main = false;
14+
15+
extern "C" void __asan_init(void);
16+
17+
static void NTAPI /*__attribute__((no_sanitize_address))*/
18+
my_thread_callback(PVOID module, DWORD reason, PVOID reserved) {
19+
ran_before_main = true;
20+
static const char str[] = "my_thread_callback\n";
21+
22+
// Fail the test if we aren't called for the expected reason or we can't write
23+
// stdout.
24+
if (reason != DLL_PROCESS_ATTACH)
25+
return;
26+
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
27+
if (!out || out == INVALID_HANDLE_VALUE)
28+
return;
29+
30+
DWORD written = 0;
31+
WriteFile(out, &str[0], sizeof(str), &written, NULL);
32+
}
33+
34+
extern "C" {
35+
#pragma const_seg(".CRT$XLC")
36+
extern const PIMAGE_TLS_CALLBACK p_thread_callback;
37+
const PIMAGE_TLS_CALLBACK p_thread_callback = my_thread_callback;
38+
#pragma const_seg()
39+
}
40+
41+
#ifdef _WIN64
42+
#pragma comment(linker, "/INCLUDE:_tls_used")
43+
#pragma comment(linker, "/INCLUDE:p_thread_callback")
44+
#else
45+
#pragma comment(linker, "/INCLUDE:__tls_used")
46+
#pragma comment(linker, "/INCLUDE:_p_thread_callback")
47+
#endif
48+
49+
int main() {
50+
printf("ran_before_main: %d\n", ran_before_main);
51+
}

0 commit comments

Comments
 (0)
Please sign in to comment.