1 //===-- asan_win_dll_thunk.cc ---------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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://github.com/google/sanitizers/issues/209 for the details.
16 //===----------------------------------------------------------------------===//
18 // Only compile this code when building asan_dll_thunk.lib
19 // Using #ifdef rather than relying on Makefiles etc.
20 // simplifies the build procedure.
22 #include "asan_init_version.h"
23 #include "asan_globals_win.h"
24 #include "interception/interception.h"
25 #include "sanitizer_common/sanitizer_platform_interceptors.h"
28 #define WINAPI __stdcall
33 // ---------- Function interception helper functions and macros ----------- {{{1
35 void *WINAPI
GetModuleHandleA(const char *module_name
);
36 void *WINAPI
GetProcAddress(void *module
, const char *proc_name
);
40 using namespace __sanitizer
;
42 static uptr
getRealProcAddressOrDie(const char *name
) {
44 __interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name
);
50 // We need to intercept some functions (e.g. ASan interface, memory allocator --
51 // let's call them "hooks") exported by the DLL thunk and forward the hooks to
52 // the runtime in the main module.
53 // However, we don't want to keep two lists of these hooks.
54 // To avoid that, the list of hooks should be defined using the
55 // INTERCEPT_WHEN_POSSIBLE macro. Then, all these hooks can be intercepted
56 // at once by calling INTERCEPT_HOOKS().
58 // Use macro+template magic to automatically generate the list of hooks.
59 // Each hook at line LINE defines a template class with a static
60 // FunctionInterceptor<LINE>::Execute() method intercepting the hook.
61 // The default implementation of FunctionInterceptor<LINE> is to call
62 // the Execute() method corresponding to the previous line.
64 struct FunctionInterceptor
{
65 static void Execute() { FunctionInterceptor
<LINE
-1>::Execute(); }
68 // There shouldn't be any hooks with negative definition line number.
70 struct FunctionInterceptor
<0> {
71 static void Execute() {}
74 #define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \
75 template <> struct FunctionInterceptor<__LINE__> { \
76 static void Execute() { \
77 uptr wrapper = getRealProcAddressOrDie(main_function); \
78 if (!__interception::OverrideFunction((uptr)dll_function, wrapper, 0)) \
80 FunctionInterceptor<__LINE__ - 1>::Execute(); \
84 // Special case of hooks -- ASan own interface functions. Those are only called
85 // after __asan_init, thus an empty implementation is sufficient.
86 #define INTERFACE_FUNCTION(name) \
87 extern "C" __declspec(noinline) void name() { \
88 volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf; \
91 INTERCEPT_WHEN_POSSIBLE(#name, name)
93 // INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE.
94 #define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute
96 // We can't define our own version of strlen etc. because that would lead to
97 // link-time or even type mismatch errors. Instead, we can declare a function
98 // just to be able to get its address. Me may miss the first few calls to the
99 // functions since it can be called before __asan_init, but that would lead to
100 // false negatives in the startup code before user's global initializers, which
102 #define INTERCEPT_LIBRARY_FUNCTION(name) \
103 extern "C" void name(); \
104 INTERCEPT_WHEN_POSSIBLE(WRAPPER_NAME(name), name)
106 // Disable compiler warnings that show up if we declare our own version
107 // of a compiler intrinsic (e.g. strlen).
108 #pragma warning(disable: 4391)
109 #pragma warning(disable: 4392)
111 static void InterceptHooks();
114 // ---------- Function wrapping helpers ----------------------------------- {{{1
115 #define WRAP_V_V(name) \
116 extern "C" void name() { \
117 typedef decltype(name) *fntype; \
118 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
121 INTERCEPT_WHEN_POSSIBLE(#name, name);
123 #define WRAP_V_W(name) \
124 extern "C" void name(void *arg) { \
125 typedef decltype(name) *fntype; \
126 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
129 INTERCEPT_WHEN_POSSIBLE(#name, name);
131 #define WRAP_V_WW(name) \
132 extern "C" void name(void *arg1, void *arg2) { \
133 typedef decltype(name) *fntype; \
134 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
137 INTERCEPT_WHEN_POSSIBLE(#name, name);
139 #define WRAP_V_WWW(name) \
140 extern "C" void name(void *arg1, void *arg2, void *arg3) { \
141 typedef decltype(name) *fntype; \
142 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
143 fn(arg1, arg2, arg3); \
145 INTERCEPT_WHEN_POSSIBLE(#name, name);
147 #define WRAP_W_V(name) \
148 extern "C" void *name() { \
149 typedef decltype(name) *fntype; \
150 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
153 INTERCEPT_WHEN_POSSIBLE(#name, name);
155 #define WRAP_W_W(name) \
156 extern "C" void *name(void *arg) { \
157 typedef decltype(name) *fntype; \
158 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
161 INTERCEPT_WHEN_POSSIBLE(#name, name);
163 #define WRAP_W_WW(name) \
164 extern "C" void *name(void *arg1, void *arg2) { \
165 typedef decltype(name) *fntype; \
166 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
167 return fn(arg1, arg2); \
169 INTERCEPT_WHEN_POSSIBLE(#name, name);
171 #define WRAP_W_WWW(name) \
172 extern "C" void *name(void *arg1, void *arg2, void *arg3) { \
173 typedef decltype(name) *fntype; \
174 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
175 return fn(arg1, arg2, arg3); \
177 INTERCEPT_WHEN_POSSIBLE(#name, name);
179 #define WRAP_W_WWWW(name) \
180 extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \
181 typedef decltype(name) *fntype; \
182 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
183 return fn(arg1, arg2, arg3, arg4); \
185 INTERCEPT_WHEN_POSSIBLE(#name, name);
187 #define WRAP_W_WWWWW(name) \
188 extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
190 typedef decltype(name) *fntype; \
191 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
192 return fn(arg1, arg2, arg3, arg4, arg5); \
194 INTERCEPT_WHEN_POSSIBLE(#name, name);
196 #define WRAP_W_WWWWWW(name) \
197 extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
198 void *arg5, void *arg6) { \
199 typedef decltype(name) *fntype; \
200 static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
201 return fn(arg1, arg2, arg3, arg4, arg5, arg6); \
203 INTERCEPT_WHEN_POSSIBLE(#name, name);
206 // ----------------- ASan own interface functions --------------------
207 // Don't use the INTERFACE_FUNCTION machinery for this function as we actually
208 // want to call it in the __asan_init interceptor.
209 WRAP_W_V(__asan_should_detect_stack_use_after_return
)
210 WRAP_W_V(__asan_get_shadow_memory_dynamic_address
)
213 int __asan_option_detect_stack_use_after_return
;
214 uptr __asan_shadow_memory_dynamic_address
;
216 // Manually wrap __asan_init as we need to initialize
217 // __asan_option_detect_stack_use_after_return afterwards.
219 typedef void (*fntype
)();
220 static fntype fn
= 0;
221 // __asan_init is expected to be called by only one thread.
224 fn
= (fntype
)getRealProcAddressOrDie("__asan_init");
226 __asan_option_detect_stack_use_after_return
=
227 (__asan_should_detect_stack_use_after_return() != 0);
228 __asan_shadow_memory_dynamic_address
=
229 (uptr
)__asan_get_shadow_memory_dynamic_address();
234 extern "C" void __asan_version_mismatch_check() {
238 INTERFACE_FUNCTION(__asan_handle_no_return
)
239 INTERFACE_FUNCTION(__asan_unhandled_exception_filter
)
241 INTERFACE_FUNCTION(__asan_report_store1
)
242 INTERFACE_FUNCTION(__asan_report_store2
)
243 INTERFACE_FUNCTION(__asan_report_store4
)
244 INTERFACE_FUNCTION(__asan_report_store8
)
245 INTERFACE_FUNCTION(__asan_report_store16
)
246 INTERFACE_FUNCTION(__asan_report_store_n
)
248 INTERFACE_FUNCTION(__asan_report_load1
)
249 INTERFACE_FUNCTION(__asan_report_load2
)
250 INTERFACE_FUNCTION(__asan_report_load4
)
251 INTERFACE_FUNCTION(__asan_report_load8
)
252 INTERFACE_FUNCTION(__asan_report_load16
)
253 INTERFACE_FUNCTION(__asan_report_load_n
)
255 INTERFACE_FUNCTION(__asan_store1
)
256 INTERFACE_FUNCTION(__asan_store2
)
257 INTERFACE_FUNCTION(__asan_store4
)
258 INTERFACE_FUNCTION(__asan_store8
)
259 INTERFACE_FUNCTION(__asan_store16
)
260 INTERFACE_FUNCTION(__asan_storeN
)
262 INTERFACE_FUNCTION(__asan_load1
)
263 INTERFACE_FUNCTION(__asan_load2
)
264 INTERFACE_FUNCTION(__asan_load4
)
265 INTERFACE_FUNCTION(__asan_load8
)
266 INTERFACE_FUNCTION(__asan_load16
)
267 INTERFACE_FUNCTION(__asan_loadN
)
269 INTERFACE_FUNCTION(__asan_memcpy
);
270 INTERFACE_FUNCTION(__asan_memset
);
271 INTERFACE_FUNCTION(__asan_memmove
);
273 INTERFACE_FUNCTION(__asan_set_shadow_00
);
274 INTERFACE_FUNCTION(__asan_set_shadow_f1
);
275 INTERFACE_FUNCTION(__asan_set_shadow_f2
);
276 INTERFACE_FUNCTION(__asan_set_shadow_f3
);
277 INTERFACE_FUNCTION(__asan_set_shadow_f5
);
278 INTERFACE_FUNCTION(__asan_set_shadow_f8
);
280 INTERFACE_FUNCTION(__asan_alloca_poison
);
281 INTERFACE_FUNCTION(__asan_allocas_unpoison
);
283 INTERFACE_FUNCTION(__asan_register_globals
)
284 INTERFACE_FUNCTION(__asan_unregister_globals
)
286 INTERFACE_FUNCTION(__asan_before_dynamic_init
)
287 INTERFACE_FUNCTION(__asan_after_dynamic_init
)
289 INTERFACE_FUNCTION(__asan_poison_stack_memory
)
290 INTERFACE_FUNCTION(__asan_unpoison_stack_memory
)
292 INTERFACE_FUNCTION(__asan_poison_memory_region
)
293 INTERFACE_FUNCTION(__asan_unpoison_memory_region
)
295 INTERFACE_FUNCTION(__asan_address_is_poisoned
)
296 INTERFACE_FUNCTION(__asan_region_is_poisoned
)
298 INTERFACE_FUNCTION(__asan_get_current_fake_stack
)
299 INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack
)
301 INTERFACE_FUNCTION(__asan_stack_malloc_0
)
302 INTERFACE_FUNCTION(__asan_stack_malloc_1
)
303 INTERFACE_FUNCTION(__asan_stack_malloc_2
)
304 INTERFACE_FUNCTION(__asan_stack_malloc_3
)
305 INTERFACE_FUNCTION(__asan_stack_malloc_4
)
306 INTERFACE_FUNCTION(__asan_stack_malloc_5
)
307 INTERFACE_FUNCTION(__asan_stack_malloc_6
)
308 INTERFACE_FUNCTION(__asan_stack_malloc_7
)
309 INTERFACE_FUNCTION(__asan_stack_malloc_8
)
310 INTERFACE_FUNCTION(__asan_stack_malloc_9
)
311 INTERFACE_FUNCTION(__asan_stack_malloc_10
)
313 INTERFACE_FUNCTION(__asan_stack_free_0
)
314 INTERFACE_FUNCTION(__asan_stack_free_1
)
315 INTERFACE_FUNCTION(__asan_stack_free_2
)
316 INTERFACE_FUNCTION(__asan_stack_free_4
)
317 INTERFACE_FUNCTION(__asan_stack_free_5
)
318 INTERFACE_FUNCTION(__asan_stack_free_6
)
319 INTERFACE_FUNCTION(__asan_stack_free_7
)
320 INTERFACE_FUNCTION(__asan_stack_free_8
)
321 INTERFACE_FUNCTION(__asan_stack_free_9
)
322 INTERFACE_FUNCTION(__asan_stack_free_10
)
324 // FIXME: we might want to have a sanitizer_win_dll_thunk?
325 INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container
)
326 INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address
)
327 INTERFACE_FUNCTION(__sanitizer_cov
)
328 INTERFACE_FUNCTION(__sanitizer_cov_dump
)
329 INTERFACE_FUNCTION(__sanitizer_dump_coverage
)
330 INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage
)
331 INTERFACE_FUNCTION(__sanitizer_cov_indir_call16
)
332 INTERFACE_FUNCTION(__sanitizer_cov_init
)
333 INTERFACE_FUNCTION(__sanitizer_cov_module_init
)
334 INTERFACE_FUNCTION(__sanitizer_cov_trace_basic_block
)
335 INTERFACE_FUNCTION(__sanitizer_cov_trace_func_enter
)
336 INTERFACE_FUNCTION(__sanitizer_cov_trace_pc_guard
)
337 INTERFACE_FUNCTION(__sanitizer_cov_trace_pc_guard_init
)
338 INTERFACE_FUNCTION(__sanitizer_cov_with_check
)
339 INTERFACE_FUNCTION(__sanitizer_get_allocated_size
)
340 INTERFACE_FUNCTION(__sanitizer_get_coverage_guards
)
341 INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes
)
342 INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size
)
343 INTERFACE_FUNCTION(__sanitizer_get_free_bytes
)
344 INTERFACE_FUNCTION(__sanitizer_get_heap_size
)
345 INTERFACE_FUNCTION(__sanitizer_get_ownership
)
346 INTERFACE_FUNCTION(__sanitizer_get_total_unique_caller_callee_pairs
)
347 INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage
)
348 INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes
)
349 INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file
)
350 INTERFACE_FUNCTION(__sanitizer_print_stack_trace
)
351 INTERFACE_FUNCTION(__sanitizer_symbolize_pc
)
352 INTERFACE_FUNCTION(__sanitizer_symbolize_global
)
353 INTERFACE_FUNCTION(__sanitizer_ptr_cmp
)
354 INTERFACE_FUNCTION(__sanitizer_ptr_sub
)
355 INTERFACE_FUNCTION(__sanitizer_report_error_summary
)
356 INTERFACE_FUNCTION(__sanitizer_reset_coverage
)
357 INTERFACE_FUNCTION(__sanitizer_get_number_of_counters
)
358 INTERFACE_FUNCTION(__sanitizer_update_counter_bitset_and_clear_counters
)
359 INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify
)
360 INTERFACE_FUNCTION(__sanitizer_set_death_callback
)
361 INTERFACE_FUNCTION(__sanitizer_set_report_path
)
362 INTERFACE_FUNCTION(__sanitizer_set_report_fd
)
363 INTERFACE_FUNCTION(__sanitizer_unaligned_load16
)
364 INTERFACE_FUNCTION(__sanitizer_unaligned_load32
)
365 INTERFACE_FUNCTION(__sanitizer_unaligned_load64
)
366 INTERFACE_FUNCTION(__sanitizer_unaligned_store16
)
367 INTERFACE_FUNCTION(__sanitizer_unaligned_store32
)
368 INTERFACE_FUNCTION(__sanitizer_unaligned_store64
)
369 INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container
)
370 INTERFACE_FUNCTION(__sanitizer_install_malloc_and_free_hooks
)
371 INTERFACE_FUNCTION(__sanitizer_start_switch_fiber
)
372 INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber
)
373 INTERFACE_FUNCTION(__sanitizer_get_module_and_offset_for_pc
)
375 // TODO(timurrrr): Add more interface functions on the as-needed basis.
377 // ----------------- Memory allocation functions ---------------------
383 WRAP_W_W(_malloc_base
)
384 WRAP_W_WWWW(_malloc_dbg
)
387 WRAP_W_WW(_calloc_base
)
388 WRAP_W_WWWWW(_calloc_dbg
)
389 WRAP_W_WWW(_calloc_impl
)
392 WRAP_W_WW(_realloc_base
)
393 WRAP_W_WWW(_realloc_dbg
)
394 WRAP_W_WWW(_recalloc
)
395 WRAP_W_WWW(_recalloc_base
)
399 WRAP_W_W(_expand_dbg
)
401 // TODO(timurrrr): Might want to add support for _aligned_* allocation
402 // functions to detect a bit more bugs. Those functions seem to wrap malloc().
404 // TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
406 INTERCEPT_LIBRARY_FUNCTION(atoi
);
407 INTERCEPT_LIBRARY_FUNCTION(atol
);
410 INTERCEPT_LIBRARY_FUNCTION(__C_specific_handler
);
412 INTERCEPT_LIBRARY_FUNCTION(_except_handler3
);
414 // _except_handler4 checks -GS cookie which is different for each module, so we
415 // can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4).
416 INTERCEPTOR(int, _except_handler4
, void *a
, void *b
, void *c
, void *d
) {
417 __asan_handle_no_return();
418 return REAL(_except_handler4
)(a
, b
, c
, d
);
422 INTERCEPT_LIBRARY_FUNCTION(frexp
);
423 INTERCEPT_LIBRARY_FUNCTION(longjmp
);
424 #if SANITIZER_INTERCEPT_MEMCHR
425 INTERCEPT_LIBRARY_FUNCTION(memchr
);
427 INTERCEPT_LIBRARY_FUNCTION(memcmp
);
428 INTERCEPT_LIBRARY_FUNCTION(memcpy
);
429 INTERCEPT_LIBRARY_FUNCTION(memmove
);
430 INTERCEPT_LIBRARY_FUNCTION(memset
);
431 INTERCEPT_LIBRARY_FUNCTION(strcat
); // NOLINT
432 INTERCEPT_LIBRARY_FUNCTION(strchr
);
433 INTERCEPT_LIBRARY_FUNCTION(strcmp
);
434 INTERCEPT_LIBRARY_FUNCTION(strcpy
); // NOLINT
435 INTERCEPT_LIBRARY_FUNCTION(strcspn
);
436 INTERCEPT_LIBRARY_FUNCTION(strdup
);
437 INTERCEPT_LIBRARY_FUNCTION(strlen
);
438 INTERCEPT_LIBRARY_FUNCTION(strncat
);
439 INTERCEPT_LIBRARY_FUNCTION(strncmp
);
440 INTERCEPT_LIBRARY_FUNCTION(strncpy
);
441 INTERCEPT_LIBRARY_FUNCTION(strnlen
);
442 INTERCEPT_LIBRARY_FUNCTION(strpbrk
);
443 INTERCEPT_LIBRARY_FUNCTION(strrchr
);
444 INTERCEPT_LIBRARY_FUNCTION(strspn
);
445 INTERCEPT_LIBRARY_FUNCTION(strstr
);
446 INTERCEPT_LIBRARY_FUNCTION(strtol
);
447 INTERCEPT_LIBRARY_FUNCTION(wcslen
);
449 // Must be after all the interceptor declarations due to the way INTERCEPT_HOOKS
451 void InterceptHooks() {
454 INTERCEPT_FUNCTION(_except_handler4
);
458 // We want to call __asan_init before C/C++ initializers/constructors are
459 // executed, otherwise functions like memset might be invoked.
460 // For some strange reason, merely linking in asan_preinit.cc doesn't work
461 // as the callback is never called... Is link.exe doing something too smart?
463 // In DLLs, the callbacks are expected to return 0,
464 // otherwise CRT initialization fails.
465 static int call_asan_init() {
469 #pragma section(".CRT$XIB", long, read) // NOLINT
470 __declspec(allocate(".CRT$XIB")) int (*__asan_preinit
)() = call_asan_init
;
472 static void WINAPI
asan_thread_init(void *mod
, unsigned long reason
,
474 if (reason
== /*DLL_PROCESS_ATTACH=*/1) __asan_init();
477 #pragma section(".CRT$XLAB", long, read) // NOLINT
478 __declspec(allocate(".CRT$XLAB")) void (WINAPI
*__asan_tls_init
)(void *,
479 unsigned long, void *) = asan_thread_init
;
481 ASAN_LINK_GLOBALS_WIN()
483 #endif // ASAN_DLL_THUNK