]>
Commit | Line | Data |
---|---|---|
5bcae85e SL |
1 | //===-- esan_interceptors.cpp ---------------------------------------------===// |
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 EfficiencySanitizer, a family of performance tuners. | |
11 | // | |
12 | // Interception routines for the esan run-time. | |
13 | //===----------------------------------------------------------------------===// | |
14 | ||
15 | #include "esan.h" | |
16 | #include "esan_shadow.h" | |
17 | #include "interception/interception.h" | |
18 | #include "sanitizer_common/sanitizer_common.h" | |
19 | #include "sanitizer_common/sanitizer_libc.h" | |
20 | #include "sanitizer_common/sanitizer_linux.h" | |
21 | #include "sanitizer_common/sanitizer_stacktrace.h" | |
22 | ||
23 | using namespace __esan; // NOLINT | |
24 | ||
25 | #define CUR_PC() (StackTrace::GetCurrentPc()) | |
26 | ||
27 | //===----------------------------------------------------------------------===// | |
28 | // Interception via sanitizer common interceptors | |
29 | //===----------------------------------------------------------------------===// | |
30 | ||
31 | // Get the per-platform defines for what is possible to intercept | |
32 | #include "sanitizer_common/sanitizer_platform_interceptors.h" | |
33 | ||
2c00a5a8 XL |
34 | DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr) |
35 | ||
5bcae85e SL |
36 | // TODO(bruening): tsan disables several interceptors (getpwent, etc.) claiming |
37 | // that interception is a perf hit: should we do the same? | |
38 | ||
39 | // We have no need to intercept: | |
40 | #undef SANITIZER_INTERCEPT_TLS_GET_ADDR | |
41 | ||
42 | // TODO(bruening): the common realpath interceptor assumes malloc is | |
43 | // intercepted! We should try to parametrize that, though we'll | |
44 | // intercept malloc soon ourselves and can then remove this undef. | |
45 | #undef SANITIZER_INTERCEPT_REALPATH | |
46 | ||
47 | // We provide our own version: | |
48 | #undef SANITIZER_INTERCEPT_SIGPROCMASK | |
49 | ||
50 | #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!EsanIsInitialized) | |
51 | ||
52 | #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) | |
53 | #define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \ | |
54 | INTERCEPT_FUNCTION_VER(name, ver) | |
55 | ||
56 | // We must initialize during early interceptors, to support tcmalloc. | |
57 | // This means that for some apps we fully initialize prior to | |
58 | // __esan_init() being called. | |
59 | // We currently do not use ctx. | |
60 | #define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \ | |
61 | do { \ | |
62 | if (UNLIKELY(COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)) { \ | |
63 | if (!UNLIKELY(EsanDuringInit)) \ | |
64 | initializeLibrary(__esan_which_tool); \ | |
65 | return REAL(func)(__VA_ARGS__); \ | |
66 | } \ | |
67 | ctx = nullptr; \ | |
68 | (void)ctx; \ | |
69 | } while (false) | |
70 | ||
71 | #define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, func, ...) \ | |
72 | COMMON_INTERCEPTOR_ENTER(ctx, func, __VA_ARGS__) | |
73 | ||
74 | #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \ | |
75 | processRangeAccess(CUR_PC(), (uptr)ptr, size, true) | |
76 | ||
77 | #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \ | |
78 | processRangeAccess(CUR_PC(), (uptr)ptr, size, false) | |
79 | ||
80 | // This is only called if the app explicitly calls exit(), not on | |
81 | // a normal exit. | |
82 | #define COMMON_INTERCEPTOR_ON_EXIT(ctx) finalizeLibrary() | |
83 | ||
84 | #define COMMON_INTERCEPTOR_FILE_OPEN(ctx, file, path) \ | |
85 | do { \ | |
86 | (void)(ctx); \ | |
87 | (void)(file); \ | |
88 | (void)(path); \ | |
89 | } while (false) | |
90 | #define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) \ | |
91 | do { \ | |
92 | (void)(ctx); \ | |
93 | (void)(file); \ | |
94 | } while (false) | |
95 | #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ | |
96 | do { \ | |
97 | (void)(filename); \ | |
98 | (void)(handle); \ | |
99 | } while (false) | |
100 | #define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() \ | |
101 | do { \ | |
102 | } while (false) | |
103 | #define COMMON_INTERCEPTOR_ACQUIRE(ctx, u) \ | |
104 | do { \ | |
105 | (void)(ctx); \ | |
106 | (void)(u); \ | |
107 | } while (false) | |
108 | #define COMMON_INTERCEPTOR_RELEASE(ctx, u) \ | |
109 | do { \ | |
110 | (void)(ctx); \ | |
111 | (void)(u); \ | |
112 | } while (false) | |
113 | #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \ | |
114 | do { \ | |
115 | (void)(ctx); \ | |
116 | (void)(path); \ | |
117 | } while (false) | |
118 | #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \ | |
119 | do { \ | |
120 | (void)(ctx); \ | |
121 | (void)(fd); \ | |
122 | } while (false) | |
123 | #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \ | |
124 | do { \ | |
125 | (void)(ctx); \ | |
126 | (void)(fd); \ | |
127 | } while (false) | |
128 | #define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) \ | |
129 | do { \ | |
130 | (void)(ctx); \ | |
131 | (void)(fd); \ | |
132 | } while (false) | |
133 | #define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \ | |
134 | do { \ | |
135 | (void)(ctx); \ | |
136 | (void)(fd); \ | |
137 | (void)(newfd); \ | |
138 | } while (false) | |
139 | #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) \ | |
140 | do { \ | |
141 | (void)(ctx); \ | |
142 | (void)(name); \ | |
143 | } while (false) | |
144 | #define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \ | |
145 | do { \ | |
146 | (void)(ctx); \ | |
147 | (void)(thread); \ | |
148 | (void)(name); \ | |
149 | } while (false) | |
150 | #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name) | |
151 | #define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) \ | |
152 | do { \ | |
153 | (void)(ctx); \ | |
154 | (void)(m); \ | |
155 | } while (false) | |
156 | #define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) \ | |
157 | do { \ | |
158 | (void)(ctx); \ | |
159 | (void)(m); \ | |
160 | } while (false) | |
161 | #define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) \ | |
162 | do { \ | |
163 | (void)(ctx); \ | |
164 | (void)(m); \ | |
165 | } while (false) | |
166 | #define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) \ | |
167 | do { \ | |
168 | (void)(ctx); \ | |
169 | (void)(msg); \ | |
170 | } while (false) | |
171 | #define COMMON_INTERCEPTOR_USER_CALLBACK_START() \ | |
172 | do { \ | |
173 | } while (false) | |
174 | #define COMMON_INTERCEPTOR_USER_CALLBACK_END() \ | |
175 | do { \ | |
176 | } while (false) | |
177 | ||
178 | #include "sanitizer_common/sanitizer_common_interceptors.inc" | |
179 | ||
180 | //===----------------------------------------------------------------------===// | |
181 | // Syscall interception | |
182 | //===----------------------------------------------------------------------===// | |
183 | ||
184 | // We want the caller's PC b/c unlike the other function interceptors these | |
185 | // are separate pre and post functions called around the app's syscall(). | |
186 | ||
187 | #define COMMON_SYSCALL_PRE_READ_RANGE(ptr, size) \ | |
188 | processRangeAccess(GET_CALLER_PC(), (uptr)ptr, size, false) | |
189 | ||
190 | #define COMMON_SYSCALL_PRE_WRITE_RANGE(ptr, size) \ | |
191 | do { \ | |
192 | (void)(ptr); \ | |
193 | (void)(size); \ | |
194 | } while (false) | |
195 | ||
196 | #define COMMON_SYSCALL_POST_READ_RANGE(ptr, size) \ | |
197 | do { \ | |
198 | (void)(ptr); \ | |
199 | (void)(size); \ | |
200 | } while (false) | |
201 | ||
202 | // The actual amount written is in post, not pre. | |
203 | #define COMMON_SYSCALL_POST_WRITE_RANGE(ptr, size) \ | |
204 | processRangeAccess(GET_CALLER_PC(), (uptr)ptr, size, true) | |
205 | ||
206 | #define COMMON_SYSCALL_ACQUIRE(addr) \ | |
207 | do { \ | |
208 | (void)(addr); \ | |
209 | } while (false) | |
210 | #define COMMON_SYSCALL_RELEASE(addr) \ | |
211 | do { \ | |
212 | (void)(addr); \ | |
213 | } while (false) | |
214 | #define COMMON_SYSCALL_FD_CLOSE(fd) \ | |
215 | do { \ | |
216 | (void)(fd); \ | |
217 | } while (false) | |
218 | #define COMMON_SYSCALL_FD_ACQUIRE(fd) \ | |
219 | do { \ | |
220 | (void)(fd); \ | |
221 | } while (false) | |
222 | #define COMMON_SYSCALL_FD_RELEASE(fd) \ | |
223 | do { \ | |
224 | (void)(fd); \ | |
225 | } while (false) | |
226 | #define COMMON_SYSCALL_PRE_FORK() \ | |
227 | do { \ | |
228 | } while (false) | |
229 | #define COMMON_SYSCALL_POST_FORK(res) \ | |
230 | do { \ | |
231 | (void)(res); \ | |
232 | } while (false) | |
233 | ||
234 | #include "sanitizer_common/sanitizer_common_syscalls.inc" | |
235 | ||
236 | //===----------------------------------------------------------------------===// | |
237 | // Custom interceptors | |
238 | //===----------------------------------------------------------------------===// | |
239 | ||
240 | // TODO(bruening): move more of these to the common interception pool as they | |
241 | // are shared with tsan and asan. | |
242 | // While our other files match LLVM style, here we match sanitizer style as we | |
243 | // expect to move these to the common pool. | |
244 | ||
245 | INTERCEPTOR(char *, strcpy, char *dst, const char *src) { // NOLINT | |
246 | void *ctx; | |
247 | COMMON_INTERCEPTOR_ENTER(ctx, strcpy, dst, src); | |
248 | uptr srclen = internal_strlen(src); | |
249 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, srclen + 1); | |
250 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, srclen + 1); | |
251 | return REAL(strcpy)(dst, src); // NOLINT | |
252 | } | |
253 | ||
254 | INTERCEPTOR(char *, strncpy, char *dst, char *src, uptr n) { | |
255 | void *ctx; | |
256 | COMMON_INTERCEPTOR_ENTER(ctx, strncpy, dst, src, n); | |
257 | uptr srclen = internal_strnlen(src, n); | |
258 | uptr copied_size = srclen + 1 > n ? n : srclen + 1; | |
259 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, copied_size); | |
260 | COMMON_INTERCEPTOR_READ_RANGE(ctx, src, copied_size); | |
261 | return REAL(strncpy)(dst, src, n); | |
262 | } | |
263 | ||
264 | INTERCEPTOR(int, open, const char *name, int flags, int mode) { | |
265 | void *ctx; | |
266 | COMMON_INTERCEPTOR_ENTER(ctx, open, name, flags, mode); | |
267 | COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); | |
268 | return REAL(open)(name, flags, mode); | |
269 | } | |
270 | ||
271 | #if SANITIZER_LINUX | |
272 | INTERCEPTOR(int, open64, const char *name, int flags, int mode) { | |
273 | void *ctx; | |
274 | COMMON_INTERCEPTOR_ENTER(ctx, open64, name, flags, mode); | |
275 | COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); | |
276 | return REAL(open64)(name, flags, mode); | |
277 | } | |
278 | #define ESAN_MAYBE_INTERCEPT_OPEN64 INTERCEPT_FUNCTION(open64) | |
279 | #else | |
280 | #define ESAN_MAYBE_INTERCEPT_OPEN64 | |
281 | #endif | |
282 | ||
283 | INTERCEPTOR(int, creat, const char *name, int mode) { | |
284 | void *ctx; | |
285 | COMMON_INTERCEPTOR_ENTER(ctx, creat, name, mode); | |
286 | COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); | |
287 | return REAL(creat)(name, mode); | |
288 | } | |
289 | ||
290 | #if SANITIZER_LINUX | |
291 | INTERCEPTOR(int, creat64, const char *name, int mode) { | |
292 | void *ctx; | |
293 | COMMON_INTERCEPTOR_ENTER(ctx, creat64, name, mode); | |
294 | COMMON_INTERCEPTOR_READ_STRING(ctx, name, 0); | |
295 | return REAL(creat64)(name, mode); | |
296 | } | |
297 | #define ESAN_MAYBE_INTERCEPT_CREAT64 INTERCEPT_FUNCTION(creat64) | |
298 | #else | |
299 | #define ESAN_MAYBE_INTERCEPT_CREAT64 | |
300 | #endif | |
301 | ||
302 | INTERCEPTOR(int, unlink, char *path) { | |
303 | void *ctx; | |
304 | COMMON_INTERCEPTOR_ENTER(ctx, unlink, path); | |
305 | COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); | |
306 | return REAL(unlink)(path); | |
307 | } | |
308 | ||
5bcae85e SL |
309 | INTERCEPTOR(int, puts, const char *s) { |
310 | void *ctx; | |
311 | COMMON_INTERCEPTOR_ENTER(ctx, puts, s); | |
312 | COMMON_INTERCEPTOR_READ_RANGE(ctx, s, internal_strlen(s)); | |
313 | return REAL(puts)(s); | |
314 | } | |
315 | ||
316 | INTERCEPTOR(int, rmdir, char *path) { | |
317 | void *ctx; | |
318 | COMMON_INTERCEPTOR_ENTER(ctx, rmdir, path); | |
319 | COMMON_INTERCEPTOR_READ_STRING(ctx, path, 0); | |
320 | return REAL(rmdir)(path); | |
321 | } | |
322 | ||
323 | //===----------------------------------------------------------------------===// | |
324 | // Shadow-related interceptors | |
325 | //===----------------------------------------------------------------------===// | |
326 | ||
327 | // These are candidates for sharing with all sanitizers if shadow memory | |
328 | // support is also standardized. | |
329 | ||
330 | INTERCEPTOR(void *, mmap, void *addr, SIZE_T sz, int prot, int flags, | |
331 | int fd, OFF_T off) { | |
332 | if (UNLIKELY(REAL(mmap) == nullptr)) { | |
333 | // With esan init during interceptor init and a static libc preventing | |
334 | // our early-calloc from triggering, we can end up here before our | |
335 | // REAL pointer is set up. | |
336 | return (void *)internal_mmap(addr, sz, prot, flags, fd, off); | |
337 | } | |
338 | void *ctx; | |
339 | COMMON_INTERCEPTOR_ENTER(ctx, mmap, addr, sz, prot, flags, fd, off); | |
340 | if (!fixMmapAddr(&addr, sz, flags)) | |
341 | return (void *)-1; | |
342 | void *result = REAL(mmap)(addr, sz, prot, flags, fd, off); | |
343 | return (void *)checkMmapResult((uptr)result, sz); | |
344 | } | |
345 | ||
346 | #if SANITIZER_LINUX | |
347 | INTERCEPTOR(void *, mmap64, void *addr, SIZE_T sz, int prot, int flags, | |
348 | int fd, OFF64_T off) { | |
349 | void *ctx; | |
350 | COMMON_INTERCEPTOR_ENTER(ctx, mmap64, addr, sz, prot, flags, fd, off); | |
351 | if (!fixMmapAddr(&addr, sz, flags)) | |
352 | return (void *)-1; | |
353 | void *result = REAL(mmap64)(addr, sz, prot, flags, fd, off); | |
354 | return (void *)checkMmapResult((uptr)result, sz); | |
355 | } | |
356 | #define ESAN_MAYBE_INTERCEPT_MMAP64 INTERCEPT_FUNCTION(mmap64) | |
357 | #else | |
358 | #define ESAN_MAYBE_INTERCEPT_MMAP64 | |
359 | #endif | |
360 | ||
361 | //===----------------------------------------------------------------------===// | |
362 | // Signal-related interceptors | |
363 | //===----------------------------------------------------------------------===// | |
364 | ||
365 | #if SANITIZER_LINUX | |
366 | typedef void (*signal_handler_t)(int); | |
367 | INTERCEPTOR(signal_handler_t, signal, int signum, signal_handler_t handler) { | |
368 | void *ctx; | |
369 | COMMON_INTERCEPTOR_ENTER(ctx, signal, signum, handler); | |
370 | signal_handler_t result; | |
371 | if (!processSignal(signum, handler, &result)) | |
372 | return result; | |
373 | else | |
374 | return REAL(signal)(signum, handler); | |
375 | } | |
376 | #define ESAN_MAYBE_INTERCEPT_SIGNAL INTERCEPT_FUNCTION(signal) | |
377 | #else | |
378 | #error Platform not supported | |
379 | #define ESAN_MAYBE_INTERCEPT_SIGNAL | |
380 | #endif | |
381 | ||
382 | #if SANITIZER_LINUX | |
383 | DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act, | |
384 | struct sigaction *oldact) | |
385 | INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act, | |
386 | struct sigaction *oldact) { | |
387 | void *ctx; | |
388 | COMMON_INTERCEPTOR_ENTER(ctx, sigaction, signum, act, oldact); | |
389 | if (!processSigaction(signum, act, oldact)) | |
390 | return 0; | |
391 | else | |
392 | return REAL(sigaction)(signum, act, oldact); | |
393 | } | |
394 | ||
395 | // This is required to properly use internal_sigaction. | |
396 | namespace __sanitizer { | |
397 | int real_sigaction(int signum, const void *act, void *oldact) { | |
398 | if (REAL(sigaction) == nullptr) { | |
399 | // With an instrumented allocator, this is called during interceptor init | |
400 | // and we need a raw syscall solution. | |
401 | return internal_sigaction_syscall(signum, act, oldact); | |
402 | } | |
403 | return REAL(sigaction)(signum, (const struct sigaction *)act, | |
404 | (struct sigaction *)oldact); | |
405 | } | |
406 | } // namespace __sanitizer | |
407 | ||
408 | #define ESAN_MAYBE_INTERCEPT_SIGACTION INTERCEPT_FUNCTION(sigaction) | |
409 | #else | |
410 | #error Platform not supported | |
411 | #define ESAN_MAYBE_INTERCEPT_SIGACTION | |
412 | #endif | |
413 | ||
414 | #if SANITIZER_LINUX | |
415 | INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set, | |
416 | __sanitizer_sigset_t *oldset) { | |
417 | void *ctx; | |
418 | COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset); | |
419 | int res = 0; | |
420 | if (processSigprocmask(how, set, oldset)) | |
421 | res = REAL(sigprocmask)(how, set, oldset); | |
422 | if (!res && oldset) | |
423 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); | |
424 | return res; | |
425 | } | |
426 | #define ESAN_MAYBE_INTERCEPT_SIGPROCMASK INTERCEPT_FUNCTION(sigprocmask) | |
427 | #else | |
428 | #define ESAN_MAYBE_INTERCEPT_SIGPROCMASK | |
429 | #endif | |
430 | ||
431 | #if !SANITIZER_WINDOWS | |
432 | INTERCEPTOR(int, pthread_sigmask, int how, __sanitizer_sigset_t *set, | |
433 | __sanitizer_sigset_t *oldset) { | |
434 | void *ctx; | |
435 | COMMON_INTERCEPTOR_ENTER(ctx, pthread_sigmask, how, set, oldset); | |
436 | int res = 0; | |
437 | if (processSigprocmask(how, set, oldset)) | |
438 | res = REAL(sigprocmask)(how, set, oldset); | |
439 | if (!res && oldset) | |
440 | COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); | |
441 | return res; | |
442 | } | |
443 | #define ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK INTERCEPT_FUNCTION(pthread_sigmask) | |
444 | #else | |
445 | #define ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK | |
446 | #endif | |
447 | ||
448 | //===----------------------------------------------------------------------===// | |
449 | // Malloc interceptors | |
450 | //===----------------------------------------------------------------------===// | |
451 | ||
7cac9316 XL |
452 | static const uptr early_alloc_buf_size = 4096; |
453 | static uptr allocated_bytes; | |
454 | static char early_alloc_buf[early_alloc_buf_size]; | |
455 | ||
456 | static bool isInEarlyAllocBuf(const void *ptr) { | |
457 | return ((uptr)ptr >= (uptr)early_alloc_buf && | |
458 | ((uptr)ptr - (uptr)early_alloc_buf) < sizeof(early_alloc_buf)); | |
459 | } | |
5bcae85e SL |
460 | |
461 | static void *handleEarlyAlloc(uptr size) { | |
462 | // If esan is initialized during an interceptor (which happens with some | |
463 | // tcmalloc implementations that call pthread_mutex_lock), the call from | |
7cac9316 XL |
464 | // dlsym to calloc will deadlock. |
465 | // dlsym may also call malloc before REAL(malloc) is retrieved from dlsym. | |
466 | // We work around it by using a static buffer for the early malloc/calloc | |
467 | // requests. | |
5bcae85e SL |
468 | // This solution will also allow us to deliberately intercept malloc & family |
469 | // in the future (to perform tool actions on each allocation, without | |
470 | // replacing the allocator), as it also solves the problem of intercepting | |
471 | // calloc when it will itself be called before its REAL pointer is | |
472 | // initialized. | |
5bcae85e SL |
473 | // We do not handle multiple threads here. This only happens at process init |
474 | // time, and while it's possible for a shared library to create early threads | |
475 | // that race here, we consider that to be a corner case extreme enough that | |
476 | // it's not worth the effort to handle. | |
7cac9316 XL |
477 | void *mem = (void *)&early_alloc_buf[allocated_bytes]; |
478 | allocated_bytes += size; | |
479 | CHECK_LT(allocated_bytes, early_alloc_buf_size); | |
480 | return mem; | |
5bcae85e SL |
481 | } |
482 | ||
483 | INTERCEPTOR(void*, calloc, uptr size, uptr n) { | |
484 | if (EsanDuringInit && REAL(calloc) == nullptr) | |
485 | return handleEarlyAlloc(size * n); | |
486 | void *ctx; | |
487 | COMMON_INTERCEPTOR_ENTER(ctx, calloc, size, n); | |
488 | void *res = REAL(calloc)(size, n); | |
489 | // The memory is zeroed and thus is all written. | |
490 | COMMON_INTERCEPTOR_WRITE_RANGE(nullptr, (uptr)res, size * n); | |
491 | return res; | |
492 | } | |
493 | ||
7cac9316 XL |
494 | INTERCEPTOR(void*, malloc, uptr size) { |
495 | if (EsanDuringInit && REAL(malloc) == nullptr) | |
496 | return handleEarlyAlloc(size); | |
497 | void *ctx; | |
498 | COMMON_INTERCEPTOR_ENTER(ctx, malloc, size); | |
499 | return REAL(malloc)(size); | |
500 | } | |
501 | ||
5bcae85e SL |
502 | INTERCEPTOR(void, free, void *p) { |
503 | void *ctx; | |
7cac9316 XL |
504 | // There are only a few early allocation requests, so we simply skip the free. |
505 | if (isInEarlyAllocBuf(p)) | |
5bcae85e | 506 | return; |
7cac9316 | 507 | COMMON_INTERCEPTOR_ENTER(ctx, free, p); |
5bcae85e SL |
508 | REAL(free)(p); |
509 | } | |
510 | ||
511 | namespace __esan { | |
512 | ||
513 | void initializeInterceptors() { | |
514 | InitializeCommonInterceptors(); | |
515 | ||
516 | INTERCEPT_FUNCTION(strcpy); // NOLINT | |
517 | INTERCEPT_FUNCTION(strncpy); | |
518 | ||
519 | INTERCEPT_FUNCTION(open); | |
520 | ESAN_MAYBE_INTERCEPT_OPEN64; | |
521 | INTERCEPT_FUNCTION(creat); | |
522 | ESAN_MAYBE_INTERCEPT_CREAT64; | |
523 | INTERCEPT_FUNCTION(unlink); | |
524 | INTERCEPT_FUNCTION(fread); | |
525 | INTERCEPT_FUNCTION(fwrite); | |
526 | INTERCEPT_FUNCTION(puts); | |
527 | INTERCEPT_FUNCTION(rmdir); | |
528 | ||
529 | INTERCEPT_FUNCTION(mmap); | |
530 | ESAN_MAYBE_INTERCEPT_MMAP64; | |
531 | ||
532 | ESAN_MAYBE_INTERCEPT_SIGNAL; | |
533 | ESAN_MAYBE_INTERCEPT_SIGACTION; | |
534 | ESAN_MAYBE_INTERCEPT_SIGPROCMASK; | |
535 | ESAN_MAYBE_INTERCEPT_PTHREAD_SIGMASK; | |
536 | ||
537 | INTERCEPT_FUNCTION(calloc); | |
7cac9316 | 538 | INTERCEPT_FUNCTION(malloc); |
5bcae85e SL |
539 | INTERCEPT_FUNCTION(free); |
540 | ||
541 | // TODO(bruening): intercept routines that other sanitizers intercept that | |
542 | // are not in the common pool or here yet, ideally by adding to the common | |
543 | // pool. Examples include wcslen and bcopy. | |
544 | ||
545 | // TODO(bruening): there are many more libc routines that read or write data | |
546 | // structures that no sanitizer is intercepting: sigaction, strtol, etc. | |
547 | } | |
548 | ||
549 | } // namespace __esan |