[ASan Win] Simplify and improve the way we forward ASan interface calls from DLLs
[blocksruntime.git] / lib / asan / asan_dll_thunk.cc
blob82b3a91092c284ae5257a578ef7abf1314e72196
1 //===-- asan_dll_thunk.cc -------------------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file is a part of AddressSanitizer, an address sanity checker.
12 // This file defines a family of thunks that should be statically linked into
13 // the DLLs that have ASan instrumentation in order to delegate the calls to the
14 // shared runtime that lives in the main binary.
15 // See https://code.google.com/p/address-sanitizer/issues/detail?id=209 for the
16 // details.
17 //===----------------------------------------------------------------------===//
19 // Only compile this code when buidling asan_dll_thunk.lib
20 // Using #ifdef rather than relying on Makefiles etc.
21 // simplifies the build procedure.
22 #ifdef ASAN_DLL_THUNK
23 #include "sanitizer_common/sanitizer_interception.h"
25 // ----------------- Helper functions and macros --------------------- {{{1
26 extern "C" {
27 void *__stdcall GetModuleHandleA(const char *module_name);
28 void *__stdcall GetProcAddress(void *module, const char *proc_name);
29 void abort();
32 static void *getRealProcAddressOrDie(const char *name) {
33 void *ret = GetProcAddress(GetModuleHandleA(0), name);
34 if (!ret)
35 abort();
36 return ret;
39 #define WRAP_V_V(name) \
40 extern "C" void name() { \
41 typedef void (*fntype)(); \
42 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
43 fn(); \
46 #define WRAP_V_W(name) \
47 extern "C" void name(void *arg) { \
48 typedef void (*fntype)(void *arg); \
49 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
50 fn(arg); \
53 #define WRAP_V_WW(name) \
54 extern "C" void name(void *arg1, void *arg2) { \
55 typedef void (*fntype)(void *, void *); \
56 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
57 fn(arg1, arg2); \
60 #define WRAP_V_WWW(name) \
61 extern "C" void name(void *arg1, void *arg2, void *arg3) { \
62 typedef void *(*fntype)(void *, void *, void *); \
63 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
64 fn(arg1, arg2, arg3); \
67 #define WRAP_W_V(name) \
68 extern "C" void *name() { \
69 typedef void *(*fntype)(); \
70 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
71 return fn(); \
74 #define WRAP_W_W(name) \
75 extern "C" void *name(void *arg) { \
76 typedef void *(*fntype)(void *arg); \
77 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
78 return fn(arg); \
81 #define WRAP_W_WW(name) \
82 extern "C" void *name(void *arg1, void *arg2) { \
83 typedef void *(*fntype)(void *, void *); \
84 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
85 return fn(arg1, arg2); \
88 #define WRAP_W_WWW(name) \
89 extern "C" void *name(void *arg1, void *arg2, void *arg3) { \
90 typedef void *(*fntype)(void *, void *, void *); \
91 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
92 return fn(arg1, arg2, arg3); \
95 #define WRAP_W_WWWW(name) \
96 extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \
97 typedef void *(*fntype)(void *, void *, void *, void *); \
98 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
99 return fn(arg1, arg2, arg3, arg4); \
102 #define WRAP_W_WWWWW(name) \
103 extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
104 void *arg5) { \
105 typedef void *(*fntype)(void *, void *, void *, void *, void *); \
106 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
107 return fn(arg1, arg2, arg3, arg4, arg5); \
110 #define WRAP_W_WWWWWW(name) \
111 extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
112 void *arg5, void *arg6) { \
113 typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \
114 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
115 return fn(arg1, arg2, arg3, arg4, arg5, arg6); \
117 // }}}
119 // --------- Interface interception helper functions and macros ----------- {{{1
120 // We need to intercept the ASan interface exported by the DLL thunk and forward
121 // all the functions to the runtime in the main module.
122 // However, we don't want to keep two lists of interface functions.
123 // To avoid that, the list of interface functions should be defined using the
124 // INTERFACE_FUNCTION macro. Then, all the interface can be intercepted at once
125 // by calling INTERCEPT_ASAN_INTERFACE().
127 // Use macro+template magic to automatically generate the list of interface
128 // functions. Each interface function at line LINE defines a template class
129 // with a static InterfaceInteceptor<LINE>::Execute() method intercepting the
130 // function. The default implementation of InterfaceInteceptor<LINE> is to call
131 // the Execute() method corresponding to the previous line.
132 template<int LINE>
133 struct InterfaceInteceptor {
134 static void Execute() { InterfaceInteceptor<LINE-1>::Execute(); }
137 // There shouldn't be any interface function with negative line number.
138 template<>
139 struct InterfaceInteceptor<0> {
140 static void Execute() {}
143 #define INTERFACE_FUNCTION(name) \
144 extern "C" void name() { __debugbreak(); } \
145 template<> struct InterfaceInteceptor<__LINE__> { \
146 static void Execute() { \
147 void *wrapper = getRealProcAddressOrDie(#name); \
148 if (!__interception::OverrideFunction((uptr)name, (uptr)wrapper, 0)) \
149 abort(); \
150 InterfaceInteceptor<__LINE__-1>::Execute(); \
154 // INTERCEPT_ASAN_INTERFACE must be used after the last INTERFACE_FUNCTION.
155 #define INTERCEPT_ASAN_INTERFACE InterfaceInteceptor<__LINE__>::Execute
157 static void InterceptASanInterface();
158 // }}}
160 // ----------------- ASan own interface functions --------------------
161 // Don't use the INTERFACE_FUNCTION machinery for this function as we actually
162 // want to call it in the __asan_init interceptor.
163 WRAP_W_V(__asan_should_detect_stack_use_after_return)
165 extern "C" {
166 int __asan_option_detect_stack_use_after_return;
168 // Manually wrap __asan_init as we need to initialize
169 // __asan_option_detect_stack_use_after_return afterwards.
170 void __asan_init_v3() {
171 typedef void (*fntype)();
172 static fntype fn = 0;
173 if (fn) return;
175 fn = (fntype)getRealProcAddressOrDie("__asan_init_v3");
176 fn();
177 __asan_option_detect_stack_use_after_return =
178 (__asan_should_detect_stack_use_after_return() != 0);
180 InterceptASanInterface();
184 INTERFACE_FUNCTION(__asan_handle_no_return)
186 INTERFACE_FUNCTION(__asan_report_store1)
187 INTERFACE_FUNCTION(__asan_report_store2)
188 INTERFACE_FUNCTION(__asan_report_store4)
189 INTERFACE_FUNCTION(__asan_report_store8)
190 INTERFACE_FUNCTION(__asan_report_store16)
191 INTERFACE_FUNCTION(__asan_report_store_n)
193 INTERFACE_FUNCTION(__asan_report_load1)
194 INTERFACE_FUNCTION(__asan_report_load2)
195 INTERFACE_FUNCTION(__asan_report_load4)
196 INTERFACE_FUNCTION(__asan_report_load8)
197 INTERFACE_FUNCTION(__asan_report_load16)
198 INTERFACE_FUNCTION(__asan_report_load_n)
200 INTERFACE_FUNCTION(__asan_memcpy);
201 INTERFACE_FUNCTION(__asan_memset);
202 INTERFACE_FUNCTION(__asan_memmove);
204 INTERFACE_FUNCTION(__asan_register_globals)
205 INTERFACE_FUNCTION(__asan_unregister_globals)
207 INTERFACE_FUNCTION(__asan_before_dynamic_init)
208 INTERFACE_FUNCTION(__asan_after_dynamic_init)
210 INTERFACE_FUNCTION(__asan_poison_stack_memory)
211 INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
213 INTERFACE_FUNCTION(__asan_poison_memory_region)
214 INTERFACE_FUNCTION(__asan_unpoison_memory_region)
216 INTERFACE_FUNCTION(__asan_get_current_fake_stack)
217 INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
219 INTERFACE_FUNCTION(__asan_stack_malloc_0)
220 INTERFACE_FUNCTION(__asan_stack_malloc_1)
221 INTERFACE_FUNCTION(__asan_stack_malloc_2)
222 INTERFACE_FUNCTION(__asan_stack_malloc_3)
223 INTERFACE_FUNCTION(__asan_stack_malloc_4)
224 INTERFACE_FUNCTION(__asan_stack_malloc_5)
225 INTERFACE_FUNCTION(__asan_stack_malloc_6)
226 INTERFACE_FUNCTION(__asan_stack_malloc_7)
227 INTERFACE_FUNCTION(__asan_stack_malloc_8)
228 INTERFACE_FUNCTION(__asan_stack_malloc_9)
229 INTERFACE_FUNCTION(__asan_stack_malloc_10)
231 INTERFACE_FUNCTION(__asan_stack_free_0)
232 INTERFACE_FUNCTION(__asan_stack_free_1)
233 INTERFACE_FUNCTION(__asan_stack_free_2)
234 INTERFACE_FUNCTION(__asan_stack_free_4)
235 INTERFACE_FUNCTION(__asan_stack_free_5)
236 INTERFACE_FUNCTION(__asan_stack_free_6)
237 INTERFACE_FUNCTION(__asan_stack_free_7)
238 INTERFACE_FUNCTION(__asan_stack_free_8)
239 INTERFACE_FUNCTION(__asan_stack_free_9)
240 INTERFACE_FUNCTION(__asan_stack_free_10)
242 // TODO(timurrrr): Add more interface functions on the as-needed basis.
244 // ----------------- Memory allocation functions ---------------------
245 WRAP_V_W(free)
246 WRAP_V_WW(_free_dbg)
248 WRAP_W_W(malloc)
249 WRAP_W_WWWW(_malloc_dbg)
251 WRAP_W_WW(calloc)
252 WRAP_W_WWWWW(_calloc_dbg)
253 WRAP_W_WWW(_calloc_impl)
255 WRAP_W_WW(realloc)
256 WRAP_W_WWW(_realloc_dbg)
257 WRAP_W_WWW(_recalloc)
259 WRAP_W_W(_msize)
260 WRAP_W_W(_expand)
261 WRAP_W_W(_expand_dbg)
263 // TODO(timurrrr): Might want to add support for _aligned_* allocation
264 // functions to detect a bit more bugs. Those functions seem to wrap malloc().
266 // TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
268 void InterceptASanInterface() {
269 INTERCEPT_ASAN_INTERFACE();
272 #endif // ASAN_DLL_THUNK