1//===-- asan_win_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.
11//
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//===----------------------------------------------------------------------===//
17
18// Only compile this code when buidling asan_dll_thunk.lib
19// Using #ifdef rather than relying on Makefiles etc.
20// simplifies the build procedure.
21#ifdef ASAN_DLL_THUNK
22#include "asan_init_version.h"
23#include "interception/interception.h"
24
25// ---------- Function interception helper functions and macros ----------- {{{1
26extern "C" {
27void *__stdcall GetModuleHandleA(const char *module_name);
28void *__stdcall GetProcAddress(void *module, const char *proc_name);
29void abort();
30}
31
32static uptr getRealProcAddressOrDie(const char *name) {
33  uptr ret =
34      __interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name);
35  if (!ret)
36    abort();
37  return ret;
38}
39
40// We need to intercept some functions (e.g. ASan interface, memory allocator --
41// let's call them "hooks") exported by the DLL thunk and forward the hooks to
42// the runtime in the main module.
43// However, we don't want to keep two lists of these hooks.
44// To avoid that, the list of hooks should be defined using the
45// INTERCEPT_WHEN_POSSIBLE macro. Then, all these hooks can be intercepted
46// at once by calling INTERCEPT_HOOKS().
47
48// Use macro+template magic to automatically generate the list of hooks.
49// Each hook at line LINE defines a template class with a static
50// FunctionInterceptor<LINE>::Execute() method intercepting the hook.
51// The default implementation of FunctionInterceptor<LINE> is to call
52// the Execute() method corresponding to the previous line.
53template<int LINE>
54struct FunctionInterceptor {
55  static void Execute() { FunctionInterceptor<LINE-1>::Execute(); }
56};
57
58// There shouldn't be any hooks with negative definition line number.
59template<>
60struct FunctionInterceptor<0> {
61  static void Execute() {}
62};
63
64#define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function)                   \
65  template <> struct FunctionInterceptor<__LINE__> {                           \
66    static void Execute() {                                                    \
67      uptr wrapper = getRealProcAddressOrDie(main_function);                   \
68      if (!__interception::OverrideFunction((uptr)dll_function, wrapper, 0))   \
69        abort();                                                               \
70      FunctionInterceptor<__LINE__ - 1>::Execute();                            \
71    }                                                                          \
72  };
73
74// Special case of hooks -- ASan own interface functions.  Those are only called
75// after __asan_init, thus an empty implementation is sufficient.
76#define INTERFACE_FUNCTION(name)                                               \
77  extern "C" __declspec(noinline) void name() {                                \
78    volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf;             \
79    __debugbreak();                                                            \
80  }                                                                            \
81  INTERCEPT_WHEN_POSSIBLE(#name, name)
82
83// INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE.
84#define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute
85
86// We can't define our own version of strlen etc. because that would lead to
87// link-time or even type mismatch errors.  Instead, we can declare a function
88// just to be able to get its address.  Me may miss the first few calls to the
89// functions since it can be called before __asan_init, but that would lead to
90// false negatives in the startup code before user's global initializers, which
91// isn't a big deal.
92#define INTERCEPT_LIBRARY_FUNCTION(name)                                       \
93  extern "C" void name();                                                      \
94  INTERCEPT_WHEN_POSSIBLE(WRAPPER_NAME(name), name)
95
96// Disable compiler warnings that show up if we declare our own version
97// of a compiler intrinsic (e.g. strlen).
98#pragma warning(disable: 4391)
99#pragma warning(disable: 4392)
100
101static void InterceptHooks();
102// }}}
103
104// ---------- Function wrapping helpers ----------------------------------- {{{1
105#define WRAP_V_V(name)                                                         \
106  extern "C" void name() {                                                     \
107    typedef void (*fntype)();                                                  \
108    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
109    fn();                                                                      \
110  }                                                                            \
111  INTERCEPT_WHEN_POSSIBLE(#name, name);
112
113#define WRAP_V_W(name)                                                         \
114  extern "C" void name(void *arg) {                                            \
115    typedef void (*fntype)(void *arg);                                         \
116    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
117    fn(arg);                                                                   \
118  }                                                                            \
119  INTERCEPT_WHEN_POSSIBLE(#name, name);
120
121#define WRAP_V_WW(name)                                                        \
122  extern "C" void name(void *arg1, void *arg2) {                               \
123    typedef void (*fntype)(void *, void *);                                    \
124    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
125    fn(arg1, arg2);                                                            \
126  }                                                                            \
127  INTERCEPT_WHEN_POSSIBLE(#name, name);
128
129#define WRAP_V_WWW(name)                                                       \
130  extern "C" void name(void *arg1, void *arg2, void *arg3) {                   \
131    typedef void *(*fntype)(void *, void *, void *);                           \
132    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
133    fn(arg1, arg2, arg3);                                                      \
134  }                                                                            \
135  INTERCEPT_WHEN_POSSIBLE(#name, name);
136
137#define WRAP_W_V(name)                                                         \
138  extern "C" void *name() {                                                    \
139    typedef void *(*fntype)();                                                 \
140    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
141    return fn();                                                               \
142  }                                                                            \
143  INTERCEPT_WHEN_POSSIBLE(#name, name);
144
145#define WRAP_W_W(name)                                                         \
146  extern "C" void *name(void *arg) {                                           \
147    typedef void *(*fntype)(void *arg);                                        \
148    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
149    return fn(arg);                                                            \
150  }                                                                            \
151  INTERCEPT_WHEN_POSSIBLE(#name, name);
152
153#define WRAP_W_WW(name)                                                        \
154  extern "C" void *name(void *arg1, void *arg2) {                              \
155    typedef void *(*fntype)(void *, void *);                                   \
156    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
157    return fn(arg1, arg2);                                                     \
158  }                                                                            \
159  INTERCEPT_WHEN_POSSIBLE(#name, name);
160
161#define WRAP_W_WWW(name)                                                       \
162  extern "C" void *name(void *arg1, void *arg2, void *arg3) {                  \
163    typedef void *(*fntype)(void *, void *, void *);                           \
164    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
165    return fn(arg1, arg2, arg3);                                               \
166  }                                                                            \
167  INTERCEPT_WHEN_POSSIBLE(#name, name);
168
169#define WRAP_W_WWWW(name)                                                      \
170  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) {      \
171    typedef void *(*fntype)(void *, void *, void *, void *);                   \
172    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
173    return fn(arg1, arg2, arg3, arg4);                                         \
174  }                                                                            \
175  INTERCEPT_WHEN_POSSIBLE(#name, name);
176
177#define WRAP_W_WWWWW(name)                                                     \
178  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4,        \
179                        void *arg5) {                                          \
180    typedef void *(*fntype)(void *, void *, void *, void *, void *);           \
181    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
182    return fn(arg1, arg2, arg3, arg4, arg5);                                   \
183  }                                                                            \
184  INTERCEPT_WHEN_POSSIBLE(#name, name);
185
186#define WRAP_W_WWWWWW(name)                                                    \
187  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4,        \
188                        void *arg5, void *arg6) {                              \
189    typedef void *(*fntype)(void *, void *, void *, void *, void *, void *);   \
190    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
191    return fn(arg1, arg2, arg3, arg4, arg5, arg6);                             \
192  }                                                                            \
193  INTERCEPT_WHEN_POSSIBLE(#name, name);
194// }}}
195
196// ----------------- ASan own interface functions --------------------
197// Don't use the INTERFACE_FUNCTION machinery for this function as we actually
198// want to call it in the __asan_init interceptor.
199WRAP_W_V(__asan_should_detect_stack_use_after_return)
200
201extern "C" {
202  int __asan_option_detect_stack_use_after_return;
203
204  // Manually wrap __asan_init as we need to initialize
205  // __asan_option_detect_stack_use_after_return afterwards.
206  void __asan_init() {
207    typedef void (*fntype)();
208    static fntype fn = 0;
209    // __asan_init is expected to be called by only one thread.
210    if (fn) return;
211
212    fn = (fntype)getRealProcAddressOrDie("__asan_init");
213    fn();
214    __asan_option_detect_stack_use_after_return =
215        (__asan_should_detect_stack_use_after_return() != 0);
216
217    InterceptHooks();
218  }
219}
220
221extern "C" void __asan_version_mismatch_check() {
222  // Do nothing.
223}
224
225INTERFACE_FUNCTION(__asan_handle_no_return)
226
227INTERFACE_FUNCTION(__asan_report_store1)
228INTERFACE_FUNCTION(__asan_report_store2)
229INTERFACE_FUNCTION(__asan_report_store4)
230INTERFACE_FUNCTION(__asan_report_store8)
231INTERFACE_FUNCTION(__asan_report_store16)
232INTERFACE_FUNCTION(__asan_report_store_n)
233
234INTERFACE_FUNCTION(__asan_report_load1)
235INTERFACE_FUNCTION(__asan_report_load2)
236INTERFACE_FUNCTION(__asan_report_load4)
237INTERFACE_FUNCTION(__asan_report_load8)
238INTERFACE_FUNCTION(__asan_report_load16)
239INTERFACE_FUNCTION(__asan_report_load_n)
240
241INTERFACE_FUNCTION(__asan_store1)
242INTERFACE_FUNCTION(__asan_store2)
243INTERFACE_FUNCTION(__asan_store4)
244INTERFACE_FUNCTION(__asan_store8)
245INTERFACE_FUNCTION(__asan_store16)
246INTERFACE_FUNCTION(__asan_storeN)
247
248INTERFACE_FUNCTION(__asan_load1)
249INTERFACE_FUNCTION(__asan_load2)
250INTERFACE_FUNCTION(__asan_load4)
251INTERFACE_FUNCTION(__asan_load8)
252INTERFACE_FUNCTION(__asan_load16)
253INTERFACE_FUNCTION(__asan_loadN)
254
255INTERFACE_FUNCTION(__asan_memcpy);
256INTERFACE_FUNCTION(__asan_memset);
257INTERFACE_FUNCTION(__asan_memmove);
258
259INTERFACE_FUNCTION(__asan_alloca_poison);
260INTERFACE_FUNCTION(__asan_allocas_unpoison);
261
262INTERFACE_FUNCTION(__asan_register_globals)
263INTERFACE_FUNCTION(__asan_unregister_globals)
264
265INTERFACE_FUNCTION(__asan_before_dynamic_init)
266INTERFACE_FUNCTION(__asan_after_dynamic_init)
267
268INTERFACE_FUNCTION(__asan_poison_stack_memory)
269INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
270
271INTERFACE_FUNCTION(__asan_poison_memory_region)
272INTERFACE_FUNCTION(__asan_unpoison_memory_region)
273
274INTERFACE_FUNCTION(__asan_address_is_poisoned)
275INTERFACE_FUNCTION(__asan_region_is_poisoned)
276
277INTERFACE_FUNCTION(__asan_get_current_fake_stack)
278INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
279
280INTERFACE_FUNCTION(__asan_stack_malloc_0)
281INTERFACE_FUNCTION(__asan_stack_malloc_1)
282INTERFACE_FUNCTION(__asan_stack_malloc_2)
283INTERFACE_FUNCTION(__asan_stack_malloc_3)
284INTERFACE_FUNCTION(__asan_stack_malloc_4)
285INTERFACE_FUNCTION(__asan_stack_malloc_5)
286INTERFACE_FUNCTION(__asan_stack_malloc_6)
287INTERFACE_FUNCTION(__asan_stack_malloc_7)
288INTERFACE_FUNCTION(__asan_stack_malloc_8)
289INTERFACE_FUNCTION(__asan_stack_malloc_9)
290INTERFACE_FUNCTION(__asan_stack_malloc_10)
291
292INTERFACE_FUNCTION(__asan_stack_free_0)
293INTERFACE_FUNCTION(__asan_stack_free_1)
294INTERFACE_FUNCTION(__asan_stack_free_2)
295INTERFACE_FUNCTION(__asan_stack_free_4)
296INTERFACE_FUNCTION(__asan_stack_free_5)
297INTERFACE_FUNCTION(__asan_stack_free_6)
298INTERFACE_FUNCTION(__asan_stack_free_7)
299INTERFACE_FUNCTION(__asan_stack_free_8)
300INTERFACE_FUNCTION(__asan_stack_free_9)
301INTERFACE_FUNCTION(__asan_stack_free_10)
302
303// FIXME: we might want to have a sanitizer_win_dll_thunk?
304INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container)
305INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
306INTERFACE_FUNCTION(__sanitizer_cov)
307INTERFACE_FUNCTION(__sanitizer_cov_dump)
308INTERFACE_FUNCTION(__sanitizer_cov_indir_call16)
309INTERFACE_FUNCTION(__sanitizer_cov_init)
310INTERFACE_FUNCTION(__sanitizer_cov_module_init)
311INTERFACE_FUNCTION(__sanitizer_cov_trace_basic_block)
312INTERFACE_FUNCTION(__sanitizer_cov_trace_func_enter)
313INTERFACE_FUNCTION(__sanitizer_cov_trace_cmp)
314INTERFACE_FUNCTION(__sanitizer_cov_trace_switch)
315INTERFACE_FUNCTION(__sanitizer_cov_with_check)
316INTERFACE_FUNCTION(__sanitizer_get_allocated_size)
317INTERFACE_FUNCTION(__sanitizer_get_coverage_guards)
318INTERFACE_FUNCTION(__sanitizer_get_coverage_pc_buffer)
319INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes)
320INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size)
321INTERFACE_FUNCTION(__sanitizer_get_free_bytes)
322INTERFACE_FUNCTION(__sanitizer_get_heap_size)
323INTERFACE_FUNCTION(__sanitizer_get_ownership)
324INTERFACE_FUNCTION(__sanitizer_get_total_unique_caller_callee_pairs)
325INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage)
326INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes)
327INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file)
328INTERFACE_FUNCTION(__sanitizer_print_stack_trace)
329INTERFACE_FUNCTION(__sanitizer_ptr_cmp)
330INTERFACE_FUNCTION(__sanitizer_ptr_sub)
331INTERFACE_FUNCTION(__sanitizer_report_error_summary)
332INTERFACE_FUNCTION(__sanitizer_reset_coverage)
333INTERFACE_FUNCTION(__sanitizer_get_number_of_counters)
334INTERFACE_FUNCTION(__sanitizer_update_counter_bitset_and_clear_counters)
335INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify)
336INTERFACE_FUNCTION(__sanitizer_set_death_callback)
337INTERFACE_FUNCTION(__sanitizer_set_report_path)
338INTERFACE_FUNCTION(__sanitizer_set_report_fd)
339INTERFACE_FUNCTION(__sanitizer_unaligned_load16)
340INTERFACE_FUNCTION(__sanitizer_unaligned_load32)
341INTERFACE_FUNCTION(__sanitizer_unaligned_load64)
342INTERFACE_FUNCTION(__sanitizer_unaligned_store16)
343INTERFACE_FUNCTION(__sanitizer_unaligned_store32)
344INTERFACE_FUNCTION(__sanitizer_unaligned_store64)
345INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
346INTERFACE_FUNCTION(__sanitizer_install_malloc_and_free_hooks)
347INTERFACE_FUNCTION(__sanitizer_start_switch_fiber)
348INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber)
349
350// TODO(timurrrr): Add more interface functions on the as-needed basis.
351
352// ----------------- Memory allocation functions ---------------------
353WRAP_V_W(free)
354WRAP_V_W(_free_base)
355WRAP_V_WW(_free_dbg)
356
357WRAP_W_W(malloc)
358WRAP_W_W(_malloc_base)
359WRAP_W_WWWW(_malloc_dbg)
360
361WRAP_W_WW(calloc)
362WRAP_W_WW(_calloc_base)
363WRAP_W_WWWWW(_calloc_dbg)
364WRAP_W_WWW(_calloc_impl)
365
366WRAP_W_WW(realloc)
367WRAP_W_WW(_realloc_base)
368WRAP_W_WWW(_realloc_dbg)
369WRAP_W_WWW(_recalloc)
370
371WRAP_W_W(_msize)
372WRAP_W_W(_expand)
373WRAP_W_W(_expand_dbg)
374
375// TODO(timurrrr): Might want to add support for _aligned_* allocation
376// functions to detect a bit more bugs.  Those functions seem to wrap malloc().
377
378// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
379
380INTERCEPT_LIBRARY_FUNCTION(atoi);
381INTERCEPT_LIBRARY_FUNCTION(atol);
382INTERCEPT_LIBRARY_FUNCTION(_except_handler3);
383
384// _except_handler4 checks -GS cookie which is different for each module, so we
385// can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4).
386INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
387  __asan_handle_no_return();
388  return REAL(_except_handler4)(a, b, c, d);
389}
390
391INTERCEPT_LIBRARY_FUNCTION(frexp);
392INTERCEPT_LIBRARY_FUNCTION(longjmp);
393INTERCEPT_LIBRARY_FUNCTION(memchr);
394INTERCEPT_LIBRARY_FUNCTION(memcmp);
395INTERCEPT_LIBRARY_FUNCTION(memcpy);
396INTERCEPT_LIBRARY_FUNCTION(memmove);
397INTERCEPT_LIBRARY_FUNCTION(memset);
398INTERCEPT_LIBRARY_FUNCTION(strcat);  // NOLINT
399INTERCEPT_LIBRARY_FUNCTION(strchr);
400INTERCEPT_LIBRARY_FUNCTION(strcmp);
401INTERCEPT_LIBRARY_FUNCTION(strcpy);  // NOLINT
402INTERCEPT_LIBRARY_FUNCTION(strcspn);
403INTERCEPT_LIBRARY_FUNCTION(strdup);
404INTERCEPT_LIBRARY_FUNCTION(strlen);
405INTERCEPT_LIBRARY_FUNCTION(strncat);
406INTERCEPT_LIBRARY_FUNCTION(strncmp);
407INTERCEPT_LIBRARY_FUNCTION(strncpy);
408INTERCEPT_LIBRARY_FUNCTION(strnlen);
409INTERCEPT_LIBRARY_FUNCTION(strpbrk);
410INTERCEPT_LIBRARY_FUNCTION(strrchr);
411INTERCEPT_LIBRARY_FUNCTION(strspn);
412INTERCEPT_LIBRARY_FUNCTION(strstr);
413INTERCEPT_LIBRARY_FUNCTION(strtol);
414INTERCEPT_LIBRARY_FUNCTION(wcslen);
415
416// Must be after all the interceptor declarations due to the way INTERCEPT_HOOKS
417// is defined.
418void InterceptHooks() {
419  INTERCEPT_HOOKS();
420  INTERCEPT_FUNCTION(_except_handler4);
421}
422
423// We want to call __asan_init before C/C++ initializers/constructors are
424// executed, otherwise functions like memset might be invoked.
425// For some strange reason, merely linking in asan_preinit.cc doesn't work
426// as the callback is never called...  Is link.exe doing something too smart?
427
428// In DLLs, the callbacks are expected to return 0,
429// otherwise CRT initialization fails.
430static int call_asan_init() {
431  __asan_init();
432  return 0;
433}
434#pragma section(".CRT$XIB", long, read)  // NOLINT
435__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init;
436
437#endif // ASAN_DLL_THUNK
438