asan_dll_thunk.cc revision 2d1fdb26e458c4ddc04155c1d421bced3ba90cd0
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 "sanitizer_common/sanitizer_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 void *getRealProcAddressOrDie(const char *name) {
33  void *ret = GetProcAddress(GetModuleHandleA(0), name);
34  if (!ret)
35    abort();
36  return ret;
37}
38
39// We need to intercept some functions (e.g. ASan interface, memory allocator --
40// let's call them "hooks") exported by the DLL thunk and forward the hooks to
41// the runtime in the main module.
42// However, we don't want to keep two lists of these hooks.
43// To avoid that, the list of hooks should be defined using the
44// INTERCEPT_WHEN_POSSIBLE macro. Then, all these hooks can be intercepted
45// at once by calling INTERCEPT_HOOKS().
46
47// Use macro+template magic to automatically generate the list of hooks.
48// Each hook at line LINE defines a template class with a static
49// FunctionInterceptor<LINE>::Execute() method intercepting the hook.
50// The default implementation of FunctionInterceptor<LINE> is to call
51// the Execute() method corresponding to the previous line.
52template<int LINE>
53struct FunctionInterceptor {
54  static void Execute() { FunctionInterceptor<LINE-1>::Execute(); }
55};
56
57// There shouldn't be any hooks with negative definition line number.
58template<>
59struct FunctionInterceptor<0> {
60  static void Execute() {}
61};
62
63#define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function)                   \
64  template<> struct FunctionInterceptor<__LINE__> {                            \
65    static void Execute() {                                                    \
66      void *wrapper = getRealProcAddressOrDie(main_function);                  \
67      if (!__interception::OverrideFunction((uptr)dll_function,                \
68                                            (uptr)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" void name() { __debugbreak(); }                                   \
78  INTERCEPT_WHEN_POSSIBLE(#name, name)
79
80// INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE.
81#define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute
82
83// We can't define our own version of strlen etc. because that would lead to
84// link-time or even type mismatch errors.  Instead, we can declare a function
85// just to be able to get its address.  Me may miss the first few calls to the
86// functions since it can be called before __asan_init, but that would lead to
87// false negatives in the startup code before user's global initializers, which
88// isn't a big deal.
89#define INTERCEPT_LIBRARY_FUNCTION(name)                                       \
90  extern "C" void name();                                                      \
91  INTERCEPT_WHEN_POSSIBLE(WRAPPER_NAME(name), name)
92
93// Disable compiler warnings that show up if we declare our own version
94// of a compiler intrinsic (e.g. strlen).
95#pragma warning(disable: 4391)
96#pragma warning(disable: 4392)
97
98static void InterceptHooks();
99// }}}
100
101// ---------- Function wrapping helpers ----------------------------------- {{{1
102#define WRAP_V_V(name)                                                         \
103  extern "C" void name() {                                                     \
104    typedef void (*fntype)();                                                  \
105    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
106    fn();                                                                      \
107  }                                                                            \
108  INTERCEPT_WHEN_POSSIBLE(#name, name);
109
110#define WRAP_V_W(name)                                                         \
111  extern "C" void name(void *arg) {                                            \
112    typedef void (*fntype)(void *arg);                                         \
113    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
114    fn(arg);                                                                   \
115  }                                                                            \
116  INTERCEPT_WHEN_POSSIBLE(#name, name);
117
118#define WRAP_V_WW(name)                                                        \
119  extern "C" void name(void *arg1, void *arg2) {                               \
120    typedef void (*fntype)(void *, void *);                                    \
121    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
122    fn(arg1, arg2);                                                            \
123  }                                                                            \
124  INTERCEPT_WHEN_POSSIBLE(#name, name);
125
126#define WRAP_V_WWW(name)                                                       \
127  extern "C" void name(void *arg1, void *arg2, void *arg3) {                   \
128    typedef void *(*fntype)(void *, void *, void *);                           \
129    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
130    fn(arg1, arg2, arg3);                                                      \
131  }                                                                            \
132  INTERCEPT_WHEN_POSSIBLE(#name, name);
133
134#define WRAP_W_V(name)                                                         \
135  extern "C" void *name() {                                                    \
136    typedef void *(*fntype)();                                                 \
137    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
138    return fn();                                                               \
139  }                                                                            \
140  INTERCEPT_WHEN_POSSIBLE(#name, name);
141
142#define WRAP_W_W(name)                                                         \
143  extern "C" void *name(void *arg) {                                           \
144    typedef void *(*fntype)(void *arg);                                        \
145    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
146    return fn(arg);                                                            \
147  }                                                                            \
148  INTERCEPT_WHEN_POSSIBLE(#name, name);
149
150#define WRAP_W_WW(name)                                                        \
151  extern "C" void *name(void *arg1, void *arg2) {                              \
152    typedef void *(*fntype)(void *, void *);                                   \
153    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
154    return fn(arg1, arg2);                                                     \
155  }                                                                            \
156  INTERCEPT_WHEN_POSSIBLE(#name, name);
157
158#define WRAP_W_WWW(name)                                                       \
159  extern "C" void *name(void *arg1, void *arg2, void *arg3) {                  \
160    typedef void *(*fntype)(void *, void *, void *);                           \
161    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
162    return fn(arg1, arg2, arg3);                                               \
163  }                                                                            \
164  INTERCEPT_WHEN_POSSIBLE(#name, name);
165
166#define WRAP_W_WWWW(name)                                                      \
167  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) {      \
168    typedef void *(*fntype)(void *, void *, void *, void *);                   \
169    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
170    return fn(arg1, arg2, arg3, arg4);                                         \
171  }                                                                            \
172  INTERCEPT_WHEN_POSSIBLE(#name, name);
173
174#define WRAP_W_WWWWW(name)                                                     \
175  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4,        \
176                        void *arg5) {                                          \
177    typedef void *(*fntype)(void *, void *, void *, void *, void *);           \
178    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
179    return fn(arg1, arg2, arg3, arg4, arg5);                                   \
180  }                                                                            \
181  INTERCEPT_WHEN_POSSIBLE(#name, name);
182
183#define WRAP_W_WWWWWW(name)                                                    \
184  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4,        \
185                        void *arg5, void *arg6) {                              \
186    typedef void *(*fntype)(void *, void *, void *, void *, void *, void *);   \
187    static fntype fn = (fntype)getRealProcAddressOrDie(#name);                 \
188    return fn(arg1, arg2, arg3, arg4, arg5, arg6);                             \
189  }                                                                            \
190  INTERCEPT_WHEN_POSSIBLE(#name, name);
191// }}}
192
193// ----------------- ASan own interface functions --------------------
194// Don't use the INTERFACE_FUNCTION machinery for this function as we actually
195// want to call it in the __asan_init interceptor.
196WRAP_W_V(__asan_should_detect_stack_use_after_return)
197
198extern "C" {
199  int __asan_option_detect_stack_use_after_return;
200
201  // Manually wrap __asan_init as we need to initialize
202  // __asan_option_detect_stack_use_after_return afterwards.
203  void __asan_init_v3() {
204    typedef void (*fntype)();
205    static fntype fn = 0;
206    // __asan_init_v3 is expected to be called by only one thread.
207    if (fn) return;
208
209    fn = (fntype)getRealProcAddressOrDie("__asan_init_v3");
210    fn();
211    __asan_option_detect_stack_use_after_return =
212        (__asan_should_detect_stack_use_after_return() != 0);
213
214    InterceptHooks();
215  }
216}
217
218INTERFACE_FUNCTION(__asan_handle_no_return)
219
220INTERFACE_FUNCTION(__asan_report_store1)
221INTERFACE_FUNCTION(__asan_report_store2)
222INTERFACE_FUNCTION(__asan_report_store4)
223INTERFACE_FUNCTION(__asan_report_store8)
224INTERFACE_FUNCTION(__asan_report_store16)
225INTERFACE_FUNCTION(__asan_report_store_n)
226
227INTERFACE_FUNCTION(__asan_report_load1)
228INTERFACE_FUNCTION(__asan_report_load2)
229INTERFACE_FUNCTION(__asan_report_load4)
230INTERFACE_FUNCTION(__asan_report_load8)
231INTERFACE_FUNCTION(__asan_report_load16)
232INTERFACE_FUNCTION(__asan_report_load_n)
233
234INTERFACE_FUNCTION(__asan_memcpy);
235INTERFACE_FUNCTION(__asan_memset);
236INTERFACE_FUNCTION(__asan_memmove);
237
238INTERFACE_FUNCTION(__asan_register_globals)
239INTERFACE_FUNCTION(__asan_unregister_globals)
240
241INTERFACE_FUNCTION(__asan_before_dynamic_init)
242INTERFACE_FUNCTION(__asan_after_dynamic_init)
243
244INTERFACE_FUNCTION(__asan_poison_stack_memory)
245INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
246
247INTERFACE_FUNCTION(__asan_poison_memory_region)
248INTERFACE_FUNCTION(__asan_unpoison_memory_region)
249
250INTERFACE_FUNCTION(__asan_get_current_fake_stack)
251INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
252
253INTERFACE_FUNCTION(__asan_stack_malloc_0)
254INTERFACE_FUNCTION(__asan_stack_malloc_1)
255INTERFACE_FUNCTION(__asan_stack_malloc_2)
256INTERFACE_FUNCTION(__asan_stack_malloc_3)
257INTERFACE_FUNCTION(__asan_stack_malloc_4)
258INTERFACE_FUNCTION(__asan_stack_malloc_5)
259INTERFACE_FUNCTION(__asan_stack_malloc_6)
260INTERFACE_FUNCTION(__asan_stack_malloc_7)
261INTERFACE_FUNCTION(__asan_stack_malloc_8)
262INTERFACE_FUNCTION(__asan_stack_malloc_9)
263INTERFACE_FUNCTION(__asan_stack_malloc_10)
264
265INTERFACE_FUNCTION(__asan_stack_free_0)
266INTERFACE_FUNCTION(__asan_stack_free_1)
267INTERFACE_FUNCTION(__asan_stack_free_2)
268INTERFACE_FUNCTION(__asan_stack_free_4)
269INTERFACE_FUNCTION(__asan_stack_free_5)
270INTERFACE_FUNCTION(__asan_stack_free_6)
271INTERFACE_FUNCTION(__asan_stack_free_7)
272INTERFACE_FUNCTION(__asan_stack_free_8)
273INTERFACE_FUNCTION(__asan_stack_free_9)
274INTERFACE_FUNCTION(__asan_stack_free_10)
275
276// TODO(timurrrr): Add more interface functions on the as-needed basis.
277
278// ----------------- Memory allocation functions ---------------------
279WRAP_V_W(free)
280WRAP_V_WW(_free_dbg)
281
282WRAP_W_W(malloc)
283WRAP_W_WWWW(_malloc_dbg)
284
285WRAP_W_WW(calloc)
286WRAP_W_WWWWW(_calloc_dbg)
287WRAP_W_WWW(_calloc_impl)
288
289WRAP_W_WW(realloc)
290WRAP_W_WWW(_realloc_dbg)
291WRAP_W_WWW(_recalloc)
292
293WRAP_W_W(_msize)
294WRAP_W_W(_expand)
295WRAP_W_W(_expand_dbg)
296
297// TODO(timurrrr): Might want to add support for _aligned_* allocation
298// functions to detect a bit more bugs.  Those functions seem to wrap malloc().
299
300// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
301
302INTERCEPT_LIBRARY_FUNCTION(atoi);
303INTERCEPT_LIBRARY_FUNCTION(atol);
304INTERCEPT_LIBRARY_FUNCTION(frexp);
305INTERCEPT_LIBRARY_FUNCTION(longjmp);
306INTERCEPT_LIBRARY_FUNCTION(memchr);
307INTERCEPT_LIBRARY_FUNCTION(memcmp);
308INTERCEPT_LIBRARY_FUNCTION(memcpy);
309INTERCEPT_LIBRARY_FUNCTION(memmove);
310INTERCEPT_LIBRARY_FUNCTION(memset);
311INTERCEPT_LIBRARY_FUNCTION(strcat);  // NOLINT
312INTERCEPT_LIBRARY_FUNCTION(strchr);
313INTERCEPT_LIBRARY_FUNCTION(strcmp);
314INTERCEPT_LIBRARY_FUNCTION(strcpy);  // NOLINT
315INTERCEPT_LIBRARY_FUNCTION(strlen);
316INTERCEPT_LIBRARY_FUNCTION(strncat);
317INTERCEPT_LIBRARY_FUNCTION(strncmp);
318INTERCEPT_LIBRARY_FUNCTION(strncpy);
319INTERCEPT_LIBRARY_FUNCTION(strnlen);
320INTERCEPT_LIBRARY_FUNCTION(strtol);
321INTERCEPT_LIBRARY_FUNCTION(wcslen);
322
323// Must be at the end of the file due to the way INTERCEPT_HOOKS is defined.
324void InterceptHooks() {
325  INTERCEPT_HOOKS();
326}
327
328#endif // ASAN_DLL_THUNK
329