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