[ASan/Win] Make sure the list of wrappers exported by the main module and imported...
[blocksruntime.git] / lib / asan / asan_dll_thunk.cc
blob40d0e5de326afd7dd256f122669c74f0d9e111c1
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.
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 //===----------------------------------------------------------------------===//
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"
25 // ---------- Function interception helper functions and macros ----------- {{{1
26 extern "C" {
27 void *__stdcall GetModuleHandleA(const char *module_name);
28 void *__stdcall GetProcAddress(void *module, const char *proc_name);
29 void abort();
32 static void *getRealProcAddressOrDie(const char *name) {
33 void *ret = GetProcAddress(GetModuleHandleA(0), name);
34 if (!ret)
35 abort();
36 return ret;
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().
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.
52 template<int LINE>
53 struct FunctionInterceptor {
54 static void Execute() { FunctionInterceptor<LINE-1>::Execute(); }
57 // There shouldn't be any hooks with negative definition line number.
58 template<>
59 struct FunctionInterceptor<0> {
60 static void Execute() {}
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 } \
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)
80 // INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE.
81 #define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute
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)
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)
98 static void InterceptHooks();
99 // }}}
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(); \
108 INTERCEPT_WHEN_POSSIBLE(#name, name);
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); \
116 INTERCEPT_WHEN_POSSIBLE(#name, name);
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); \
124 INTERCEPT_WHEN_POSSIBLE(#name, name);
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); \
132 INTERCEPT_WHEN_POSSIBLE(#name, name);
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(); \
140 INTERCEPT_WHEN_POSSIBLE(#name, name);
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); \
148 INTERCEPT_WHEN_POSSIBLE(#name, name);
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); \
156 INTERCEPT_WHEN_POSSIBLE(#name, name);
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); \
164 INTERCEPT_WHEN_POSSIBLE(#name, name);
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); \
172 INTERCEPT_WHEN_POSSIBLE(#name, name);
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); \
181 INTERCEPT_WHEN_POSSIBLE(#name, name);
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); \
190 INTERCEPT_WHEN_POSSIBLE(#name, name);
191 // }}}
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.
196 WRAP_W_V(__asan_should_detect_stack_use_after_return)
198 extern "C" {
199 int __asan_option_detect_stack_use_after_return;
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;
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);
214 InterceptHooks();
218 INTERFACE_FUNCTION(__asan_handle_no_return)
220 INTERFACE_FUNCTION(__asan_report_store1)
221 INTERFACE_FUNCTION(__asan_report_store2)
222 INTERFACE_FUNCTION(__asan_report_store4)
223 INTERFACE_FUNCTION(__asan_report_store8)
224 INTERFACE_FUNCTION(__asan_report_store16)
225 INTERFACE_FUNCTION(__asan_report_store_n)
227 INTERFACE_FUNCTION(__asan_report_load1)
228 INTERFACE_FUNCTION(__asan_report_load2)
229 INTERFACE_FUNCTION(__asan_report_load4)
230 INTERFACE_FUNCTION(__asan_report_load8)
231 INTERFACE_FUNCTION(__asan_report_load16)
232 INTERFACE_FUNCTION(__asan_report_load_n)
234 INTERFACE_FUNCTION(__asan_memcpy);
235 INTERFACE_FUNCTION(__asan_memset);
236 INTERFACE_FUNCTION(__asan_memmove);
238 INTERFACE_FUNCTION(__asan_register_globals)
239 INTERFACE_FUNCTION(__asan_unregister_globals)
241 INTERFACE_FUNCTION(__asan_before_dynamic_init)
242 INTERFACE_FUNCTION(__asan_after_dynamic_init)
244 INTERFACE_FUNCTION(__asan_poison_stack_memory)
245 INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
247 INTERFACE_FUNCTION(__asan_poison_memory_region)
248 INTERFACE_FUNCTION(__asan_unpoison_memory_region)
250 INTERFACE_FUNCTION(__asan_get_current_fake_stack)
251 INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
253 INTERFACE_FUNCTION(__asan_stack_malloc_0)
254 INTERFACE_FUNCTION(__asan_stack_malloc_1)
255 INTERFACE_FUNCTION(__asan_stack_malloc_2)
256 INTERFACE_FUNCTION(__asan_stack_malloc_3)
257 INTERFACE_FUNCTION(__asan_stack_malloc_4)
258 INTERFACE_FUNCTION(__asan_stack_malloc_5)
259 INTERFACE_FUNCTION(__asan_stack_malloc_6)
260 INTERFACE_FUNCTION(__asan_stack_malloc_7)
261 INTERFACE_FUNCTION(__asan_stack_malloc_8)
262 INTERFACE_FUNCTION(__asan_stack_malloc_9)
263 INTERFACE_FUNCTION(__asan_stack_malloc_10)
265 INTERFACE_FUNCTION(__asan_stack_free_0)
266 INTERFACE_FUNCTION(__asan_stack_free_1)
267 INTERFACE_FUNCTION(__asan_stack_free_2)
268 INTERFACE_FUNCTION(__asan_stack_free_4)
269 INTERFACE_FUNCTION(__asan_stack_free_5)
270 INTERFACE_FUNCTION(__asan_stack_free_6)
271 INTERFACE_FUNCTION(__asan_stack_free_7)
272 INTERFACE_FUNCTION(__asan_stack_free_8)
273 INTERFACE_FUNCTION(__asan_stack_free_9)
274 INTERFACE_FUNCTION(__asan_stack_free_10)
276 // TODO(timurrrr): Add more interface functions on the as-needed basis.
278 // ----------------- Memory allocation functions ---------------------
279 WRAP_V_W(free)
280 WRAP_V_WW(_free_dbg)
282 WRAP_W_W(malloc)
283 WRAP_W_WWWW(_malloc_dbg)
285 WRAP_W_WW(calloc)
286 WRAP_W_WWWWW(_calloc_dbg)
287 WRAP_W_WWW(_calloc_impl)
289 WRAP_W_WW(realloc)
290 WRAP_W_WWW(_realloc_dbg)
291 WRAP_W_WWW(_recalloc)
293 WRAP_W_W(_msize)
294 WRAP_W_W(_expand)
295 WRAP_W_W(_expand_dbg)
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().
300 // TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cc).
302 INTERCEPT_LIBRARY_FUNCTION(atoi);
303 INTERCEPT_LIBRARY_FUNCTION(atol);
304 INTERCEPT_LIBRARY_FUNCTION(frexp);
305 INTERCEPT_LIBRARY_FUNCTION(longjmp);
306 INTERCEPT_LIBRARY_FUNCTION(memchr);
307 INTERCEPT_LIBRARY_FUNCTION(memcmp);
308 INTERCEPT_LIBRARY_FUNCTION(memcpy);
309 INTERCEPT_LIBRARY_FUNCTION(memmove);
310 INTERCEPT_LIBRARY_FUNCTION(memset);
311 INTERCEPT_LIBRARY_FUNCTION(strcat); // NOLINT
312 INTERCEPT_LIBRARY_FUNCTION(strchr);
313 INTERCEPT_LIBRARY_FUNCTION(strcmp);
314 INTERCEPT_LIBRARY_FUNCTION(strcpy); // NOLINT
315 INTERCEPT_LIBRARY_FUNCTION(strlen);
316 INTERCEPT_LIBRARY_FUNCTION(strncat);
317 INTERCEPT_LIBRARY_FUNCTION(strncmp);
318 INTERCEPT_LIBRARY_FUNCTION(strncpy);
319 INTERCEPT_LIBRARY_FUNCTION(strnlen);
320 INTERCEPT_LIBRARY_FUNCTION(strtol);
321 INTERCEPT_LIBRARY_FUNCTION(wcslen);
323 // Must be at the end of the file due to the way INTERCEPT_HOOKS is defined.
324 void InterceptHooks() {
325 INTERCEPT_HOOKS();
328 #endif // ASAN_DLL_THUNK