xref: /llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_win_thunk_interception.cpp (revision 0265981b6ec0f46fc372897fef7f945d8f4625c2)
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 
24 extern "C" void abort();
25 
26 namespace __sanitizer {
27 
28 int 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 
36 int 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 
44 void 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 
63 extern "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 
74 extern "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 
98 static 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)