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.
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://code.google.com/p/address-sanitizer/issues/detail?id=209 for the
16// details.
17//===----------------------------------------------------------------------===//
18
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 "asan_init_version.h"
24#include "sanitizer_common/sanitizer_interception.h"
25
26// ---------- Function interception helper functions and macros ----------- {{{1
27extern "C" {
28void *__stdcall GetModuleHandleA(const char *module_name);
29void *__stdcall GetProcAddress(void *module, const char *proc_name);
30void abort();
31}
32
33static void *getRealProcAddressOrDie(const char *name) {
34  void *ret = GetProcAddress(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      void *wrapper = getRealProcAddressOrDie(main_function);                  \
68      if (!__interception::OverrideFunction((uptr)dll_function,                \
69                                            (uptr)wrapper, 0))                 \
70        abort();                                                               \
71      FunctionInterceptor<__LINE__-1>::Execute();                              \
72    }                                                                          \
73  };
74
75// Special case of hooks -- ASan own interface functions.  Those are only called
76// after __asan_init, thus an empty implementation is sufficient.
77#define INTERFACE_FUNCTION(name)                                               \
78  extern "C" void name() {                                                     \
79    volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf;             \
80    __debugbreak();                                                            \
81  }                                                                            \
82  INTERCEPT_WHEN_POSSIBLE(#name, name)
83
84// INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE.
85#define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute
86
87// We can't define our own version of strlen etc. because that would lead to
88// link-time or even type mismatch errors.  Instead, we can declare a function
89// just to be able to get its address.  Me may miss the first few calls to the
90// functions since it can be called before __asan_init, but that would lead to
91// false negatives in the startup code before user's global initializers, which
92// isn't a big deal.
93#define INTERCEPT_LIBRARY_FUNCTION(name)                                       \
94  extern "C" void name();                                                      \
95  INTERCEPT_WHEN_POSSIBLE(WRAPPER_NAME(name), name)
96
97// Disable compiler warnings that show up if we declare our own version
98// of a compiler intrinsic (e.g. strlen).
99#pragma warning(disable: 4391)
100#pragma warning(disable: 4392)
101
102static void InterceptHooks();
103// }}}
104
105// ---------- Function wrapping helpers ----------------------------------- {{{1
106#define WRAP_V_V(name)                                                         \
107  extern "C" void name() {                                                     \
108    typedef void (*fntype)();                                                  \
109    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
110    fn();                                                                      \
111  }                                                                            \
112  INTERCEPT_WHEN_POSSIBLE(#name, name);
113
114#define WRAP_V_W(name)                                                         \
115  extern "C" void name(void *arg) {                                            \
116    typedef void (*fntype)(void *arg);                                         \
117    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
118    fn(arg);                                                                   \
119  }                                                                            \
120  INTERCEPT_WHEN_POSSIBLE(#name, name);
121
122#define WRAP_V_WW(name)                                                        \
123  extern "C" void name(void *arg1, void *arg2) {                               \
124    typedef void (*fntype)(void *, void *);                                    \
125    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
126    fn(arg1, arg2);                                                            \
127  }                                                                            \
128  INTERCEPT_WHEN_POSSIBLE(#name, name);
129
130#define WRAP_V_WWW(name)                                                       \
131  extern "C" void name(void *arg1, void *arg2, void *arg3) {                   \
132    typedef void *(*fntype)(void *, void *, void *);                           \
133    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
134    fn(arg1, arg2, arg3);                                                      \
135  }                                                                            \
136  INTERCEPT_WHEN_POSSIBLE(#name, name);
137
138#define WRAP_W_V(name)                                                         \
139  extern "C" void *name() {                                                    \
140    typedef void *(*fntype)();                                                 \
141    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
142    return fn();                                                               \
143  }                                                                            \
144  INTERCEPT_WHEN_POSSIBLE(#name, name);
145
146#define WRAP_W_W(name)                                                         \
147  extern "C" void *name(void *arg) {                                           \
148    typedef void *(*fntype)(void *arg);                                        \
149    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
150    return fn(arg);                                                            \
151  }                                                                            \
152  INTERCEPT_WHEN_POSSIBLE(#name, name);
153
154#define WRAP_W_WW(name)                                                        \
155  extern "C" void *name(void *arg1, void *arg2) {                              \
156    typedef void *(*fntype)(void *, void *);                                   \
157    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
158    return fn(arg1, arg2);                                                     \
159  }                                                                            \
160  INTERCEPT_WHEN_POSSIBLE(#name, name);
161
162#define WRAP_W_WWW(name)                                                       \
163  extern "C" void *name(void *arg1, void *arg2, void *arg3) {                  \
164    typedef void *(*fntype)(void *, void *, void *);                           \
165    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
166    return fn(arg1, arg2, arg3);                                               \
167  }                                                                            \
168  INTERCEPT_WHEN_POSSIBLE(#name, name);
169
170#define WRAP_W_WWWW(name)                                                      \
171  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) {      \
172    typedef void *(*fntype)(void *, void *, void *, void *);                   \
173    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
174    return fn(arg1, arg2, arg3, arg4);                                         \
175  }                                                                            \
176  INTERCEPT_WHEN_POSSIBLE(#name, name);
177
178#define WRAP_W_WWWWW(name)                                                     \
179  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4,        \
180                        void *arg5) {                                          \
181    typedef void *(*fntype)(void *, void *, void *, void *, void *);           \
182    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
183    return fn(arg1, arg2, arg3, arg4, arg5);                                   \
184  }                                                                            \
185  INTERCEPT_WHEN_POSSIBLE(#name, name);
186
187#define WRAP_W_WWWWWW(name)                                                    \
188  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4,        \
189                        void *arg5, void *arg6) {                              \
190    typedef void *(*fntype)(void *, void *, void *, void *, void *, void *);   \
191    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
192    return fn(arg1, arg2, arg3, arg4, arg5, arg6);                             \
193  }                                                                            \
194  INTERCEPT_WHEN_POSSIBLE(#name, name);
195// }}}
196
197// ----------------- ASan own interface functions --------------------
198// Don't use the INTERFACE_FUNCTION machinery for this function as we actually
199// want to call it in the __asan_init interceptor.
200WRAP_W_V(__asan_should_detect_stack_use_after_return)
201
202extern "C" {
203  int __asan_option_detect_stack_use_after_return;
204
205  // Manually wrap __asan_init as we need to initialize
206  // __asan_option_detect_stack_use_after_return afterwards.
207  void __asan_init() {
208    typedef void (*fntype)();
209    static fntype fn = 0;
210    // __asan_init is expected to be called by only one thread.
211    if (fn) return;
212
213    fn = (fntype)getRealProcAddressOrDie(__asan_init_name);
214    fn();
215    __asan_option_detect_stack_use_after_return =
216        (__asan_should_detect_stack_use_after_return() != 0);
217
218    InterceptHooks();
219  }
220}
221
222INTERFACE_FUNCTION(__asan_handle_no_return)
223
224INTERFACE_FUNCTION(__asan_report_store1)
225INTERFACE_FUNCTION(__asan_report_store2)
226INTERFACE_FUNCTION(__asan_report_store4)
227INTERFACE_FUNCTION(__asan_report_store8)
228INTERFACE_FUNCTION(__asan_report_store16)
229INTERFACE_FUNCTION(__asan_report_store_n)
230
231INTERFACE_FUNCTION(__asan_report_load1)
232INTERFACE_FUNCTION(__asan_report_load2)
233INTERFACE_FUNCTION(__asan_report_load4)
234INTERFACE_FUNCTION(__asan_report_load8)
235INTERFACE_FUNCTION(__asan_report_load16)
236INTERFACE_FUNCTION(__asan_report_load_n)
237
238INTERFACE_FUNCTION(__asan_memcpy);
239INTERFACE_FUNCTION(__asan_memset);
240INTERFACE_FUNCTION(__asan_memmove);
241
242INTERFACE_FUNCTION(__asan_register_globals)
243INTERFACE_FUNCTION(__asan_unregister_globals)
244
245INTERFACE_FUNCTION(__asan_before_dynamic_init)
246INTERFACE_FUNCTION(__asan_after_dynamic_init)
247
248INTERFACE_FUNCTION(__asan_poison_stack_memory)
249INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
250
251INTERFACE_FUNCTION(__asan_poison_memory_region)
252INTERFACE_FUNCTION(__asan_unpoison_memory_region)
253
254INTERFACE_FUNCTION(__asan_get_current_fake_stack)
255INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
256
257INTERFACE_FUNCTION(__asan_stack_malloc_0)
258INTERFACE_FUNCTION(__asan_stack_malloc_1)
259INTERFACE_FUNCTION(__asan_stack_malloc_2)
260INTERFACE_FUNCTION(__asan_stack_malloc_3)
261INTERFACE_FUNCTION(__asan_stack_malloc_4)
262INTERFACE_FUNCTION(__asan_stack_malloc_5)
263INTERFACE_FUNCTION(__asan_stack_malloc_6)
264INTERFACE_FUNCTION(__asan_stack_malloc_7)
265INTERFACE_FUNCTION(__asan_stack_malloc_8)
266INTERFACE_FUNCTION(__asan_stack_malloc_9)
267INTERFACE_FUNCTION(__asan_stack_malloc_10)
268
269INTERFACE_FUNCTION(__asan_stack_free_0)
270INTERFACE_FUNCTION(__asan_stack_free_1)
271INTERFACE_FUNCTION(__asan_stack_free_2)
272INTERFACE_FUNCTION(__asan_stack_free_4)
273INTERFACE_FUNCTION(__asan_stack_free_5)
274INTERFACE_FUNCTION(__asan_stack_free_6)
275INTERFACE_FUNCTION(__asan_stack_free_7)
276INTERFACE_FUNCTION(__asan_stack_free_8)
277INTERFACE_FUNCTION(__asan_stack_free_9)
278INTERFACE_FUNCTION(__asan_stack_free_10)
279
280INTERFACE_FUNCTION(__sanitizer_cov_module_init)
281
282// TODO(timurrrr): Add more interface functions on the as-needed basis.
283
284// ----------------- Memory allocation functions ---------------------
285WRAP_V_W(free)
286WRAP_V_WW(_free_dbg)
287
288WRAP_W_W(malloc)
289WRAP_W_WWWW(_malloc_dbg)
290
291WRAP_W_WW(calloc)
292WRAP_W_WWWWW(_calloc_dbg)
293WRAP_W_WWW(_calloc_impl)
294
295WRAP_W_WW(realloc)
296WRAP_W_WWW(_realloc_dbg)
297WRAP_W_WWW(_recalloc)
298
299WRAP_W_W(_msize)
300WRAP_W_W(_expand)
301WRAP_W_W(_expand_dbg)
302
303// TODO(timurrrr): Might want to add support for _aligned_* allocation
304// functions to detect a bit more bugs.  Those functions seem to wrap malloc().
305
306// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
307
308INTERCEPT_LIBRARY_FUNCTION(atoi);
309INTERCEPT_LIBRARY_FUNCTION(atol);
310INTERCEPT_LIBRARY_FUNCTION(frexp);
311INTERCEPT_LIBRARY_FUNCTION(longjmp);
312INTERCEPT_LIBRARY_FUNCTION(memchr);
313INTERCEPT_LIBRARY_FUNCTION(memcmp);
314INTERCEPT_LIBRARY_FUNCTION(memcpy);
315INTERCEPT_LIBRARY_FUNCTION(memmove);
316INTERCEPT_LIBRARY_FUNCTION(memset);
317INTERCEPT_LIBRARY_FUNCTION(strcat);  // NOLINT
318INTERCEPT_LIBRARY_FUNCTION(strchr);
319INTERCEPT_LIBRARY_FUNCTION(strcmp);
320INTERCEPT_LIBRARY_FUNCTION(strcpy);  // NOLINT
321INTERCEPT_LIBRARY_FUNCTION(strlen);
322INTERCEPT_LIBRARY_FUNCTION(strncat);
323INTERCEPT_LIBRARY_FUNCTION(strncmp);
324INTERCEPT_LIBRARY_FUNCTION(strncpy);
325INTERCEPT_LIBRARY_FUNCTION(strnlen);
326INTERCEPT_LIBRARY_FUNCTION(strtol);
327INTERCEPT_LIBRARY_FUNCTION(wcslen);
328
329// Must be after all the interceptor declarations due to the way INTERCEPT_HOOKS
330// is defined.
331void InterceptHooks() {
332  INTERCEPT_HOOKS();
333}
334
335// We want to call __asan_init before C/C++ initializers/constructors are
336// executed, otherwise functions like memset might be invoked.
337// For some strange reason, merely linking in asan_preinit.cc doesn't work
338// as the callback is never called...  Is link.exe doing something too smart?
339
340// In DLLs, the callbacks are expected to return 0,
341// otherwise CRT initialization fails.
342static int call_asan_init() {
343  __asan_init();
344  return 0;
345}
346#pragma section(".CRT$XIB", long, read)  // NOLINT
347__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init;
348
349#endif // ASAN_DLL_THUNK
350