1//===-- sanitizer_win_thunk_interception.cpp ----------------------- -----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines things that need to be present in the application modules
10// to interact with sanitizer DLL correctly and cannot be implemented using the
11// default "import library" generated when linking the DLL.
12//
13// This includes the common infrastructure required to intercept local functions
14// that must be replaced with sanitizer-aware versions, as well as the
15// registration of weak functions with the sanitizer DLL. With this in-place,
16// other sanitizer components can simply write to the .INTR and .WEAK sections.
17//
18//===----------------------------------------------------------------------===//
19
20#if defined(SANITIZER_STATIC_RUNTIME_THUNK) || \
21 defined(SANITIZER_DYNAMIC_RUNTIME_THUNK)
22# include "sanitizer_win_thunk_interception.h"
23
24extern "C" void abort();
25
26namespace __sanitizer {
27
28int override_function(const char *export_name, const uptr user_function) {
29 if (!__sanitizer_override_function(export_name, user_function)) {
30 abort();
31 }
32
33 return 0;
34}
35
36int register_weak(const char *export_name, const uptr user_function) {
37 if (!__sanitizer_register_weak_function(export_name, user_function)) {
38 abort();
39 }
40
41 return 0;
42}
43
44void initialize_thunks(const sanitizer_thunk *first,
45 const sanitizer_thunk *last) {
46 for (const sanitizer_thunk *it = first; it < last; ++it) {
47 if (*it) {
48 (*it)();
49 }
50 }
51}
52} // namespace __sanitizer
53
54# define INTERFACE_FUNCTION(Name)
55# define INTERFACE_WEAK_FUNCTION(Name) REGISTER_WEAK_FUNCTION(Name)
56# include "sanitizer_common_interface.inc"
57
58# pragma section(".INTR$A", read) // intercept begin
59# pragma section(".INTR$Z", read) // intercept end
60# pragma section(".WEAK$A", read) // weak begin
61# pragma section(".WEAK$Z", read) // weak end
62
63extern "C" {
64__declspec(allocate(
65 ".INTR$A")) sanitizer_thunk __sanitizer_intercept_thunk_begin;
66__declspec(allocate(".INTR$Z")) sanitizer_thunk __sanitizer_intercept_thunk_end;
67
68__declspec(allocate(
69 ".WEAK$A")) sanitizer_thunk __sanitizer_register_weak_thunk_begin;
70__declspec(allocate(
71 ".WEAK$Z")) sanitizer_thunk __sanitizer_register_weak_thunk_end;
72}
73
74extern "C" int __sanitizer_thunk_init() {
75 // __sanitizer_static_thunk_init is expected to be called by only one thread.
76 static bool flag = false;
77 if (flag) {
78 return 0;
79 }
80 flag = true;
81
82 __sanitizer::initialize_thunks(&__sanitizer_intercept_thunk_begin,
83 &__sanitizer_intercept_thunk_end);
84 __sanitizer::initialize_thunks(&__sanitizer_register_weak_thunk_begin,
85 &__sanitizer_register_weak_thunk_end);
86
87 // In DLLs, the callbacks are expected to return 0,
88 // otherwise CRT initialization fails.
89 return 0;
90}
91
92// We want to call dll_thunk_init before C/C++ initializers / constructors are
93// executed, otherwise functions like memset might be invoked.
94# pragma section(".CRT$XIB", long, read)
95__declspec(allocate(".CRT$XIB")) int (*__sanitizer_thunk_init_ptr)() =
96 __sanitizer_thunk_init;
97
98static void WINAPI sanitizer_thunk_thread_init(void *mod, unsigned long reason,
99 void *reserved) {
100 if (reason == /*DLL_PROCESS_ATTACH=*/1)
101 __sanitizer_thunk_init();
102}
103
104# pragma section(".CRT$XLAB", long, read)
105__declspec(allocate(".CRT$XLAB")) void(
106 WINAPI *__sanitizer_thunk_thread_init_ptr)(void *, unsigned long, void *) =
107 sanitizer_thunk_thread_init;
108
109#endif // defined(SANITIZER_STATIC_RUNTIME_THUNK) ||
110 // defined(SANITIZER_DYNAMIC_RUNTIME_THUNK)

source code of compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.cpp