asan_interceptors.cc revision 9cfa194cc62026fc7c6e82f7303eee8ad4d10cf4
1//===-- asan_interceptors.cc ------------------------------------*- C++ -*-===//
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// Intercept various libc functions.
13//===----------------------------------------------------------------------===//
14#include "asan_interceptors.h"
15
16#include "asan_allocator.h"
17#include "asan_interface.h"
18#include "asan_internal.h"
19#include "asan_mac.h"
20#include "asan_mapping.h"
21#include "asan_stack.h"
22#include "asan_stats.h"
23#include "asan_thread_registry.h"
24
25#include <new>
26#include <ctype.h>
27#include <dlfcn.h>
28
29#include <string.h>
30#include <strings.h>
31#include <pthread.h>
32
33// To replace weak system functions on Linux we just need to declare functions
34// with same names in our library and then obtain the real function pointers
35// using dlsym(). This is not so on Mac OS, where the two-level namespace makes
36// our replacement functions invisible to other libraries. This may be overcomed
37// using the DYLD_FORCE_FLAT_NAMESPACE, but some errors loading the shared
38// libraries in Chromium were noticed when doing so.
39// Instead we use mach_override, a handy framework for patching functions at
40// runtime. To avoid possible name clashes, our replacement functions have
41// the "wrap_" prefix on Mac.
42//
43// After interception, the calls to system functions will be substituted by
44// calls to our interceptors. We store pointers to system function f()
45// in __asan::real_f().
46#ifdef __APPLE__
47#include "mach_override/mach_override.h"
48#define WRAPPER_NAME(x) "wrap_"#x
49
50#define OVERRIDE_FUNCTION(oldfunc, newfunc)                                   \
51  do {CHECK(0 == __asan_mach_override_ptr_custom((void*)(oldfunc),            \
52                                                 (void*)(newfunc),            \
53                                                 (void**)&real_##oldfunc,     \
54                                                 __asan_allocate_island,      \
55                                                 __asan_deallocate_island));  \
56  CHECK(real_##oldfunc != NULL);   } while (0)
57
58#define OVERRIDE_FUNCTION_IF_EXISTS(oldfunc, newfunc)               \
59  do { __asan_mach_override_ptr_custom((void*)(oldfunc),            \
60                                       (void*)(newfunc),            \
61                                       (void**)&real_##oldfunc,     \
62                                       __asan_allocate_island,      \
63                                       __asan_deallocate_island);   \
64  } while (0)
65
66#define INTERCEPT_FUNCTION(func)                                        \
67  OVERRIDE_FUNCTION(func, WRAP(func))
68
69#define INTERCEPT_FUNCTION_IF_EXISTS(func)                              \
70  OVERRIDE_FUNCTION_IF_EXISTS(func, WRAP(func))
71
72#else  // __linux__
73#define WRAPPER_NAME(x) #x
74
75#define INTERCEPT_FUNCTION(func)                                        \
76  CHECK((real_##func = (func##_f)dlsym(RTLD_NEXT, #func)));
77
78#define INTERCEPT_FUNCTION_IF_EXISTS(func)                              \
79  do { real_##func = (func##_f)dlsym(RTLD_NEXT, #func); } while (0)
80#endif
81
82namespace __asan {
83
84typedef void (*longjmp_f)(void *env, int val);
85typedef longjmp_f _longjmp_f;
86typedef longjmp_f siglongjmp_f;
87typedef void (*__cxa_throw_f)(void *, void *, void *);
88typedef int (*pthread_create_f)(void *thread, const void *attr,
89                                void *(*start_routine) (void *), void *arg);
90#ifdef __APPLE__
91dispatch_async_f_f real_dispatch_async_f;
92dispatch_sync_f_f real_dispatch_sync_f;
93dispatch_after_f_f real_dispatch_after_f;
94dispatch_barrier_async_f_f real_dispatch_barrier_async_f;
95dispatch_group_async_f_f real_dispatch_group_async_f;
96pthread_workqueue_additem_np_f real_pthread_workqueue_additem_np;
97#endif
98
99sigaction_f             real_sigaction;
100signal_f                real_signal;
101longjmp_f               real_longjmp;
102_longjmp_f              real__longjmp;
103siglongjmp_f            real_siglongjmp;
104__cxa_throw_f           real___cxa_throw;
105pthread_create_f        real_pthread_create;
106
107index_f       real_index;
108memcmp_f      real_memcmp;
109memcpy_f      real_memcpy;
110memmove_f     real_memmove;
111memset_f      real_memset;
112strcasecmp_f  real_strcasecmp;
113strcat_f      real_strcat;
114strchr_f      real_strchr;
115strcmp_f      real_strcmp;
116strcpy_f      real_strcpy;
117strdup_f      real_strdup;
118strlen_f      real_strlen;
119strncasecmp_f real_strncasecmp;
120strncmp_f     real_strncmp;
121strncpy_f     real_strncpy;
122strnlen_f     real_strnlen;
123
124// Instruments read/write access to a single byte in memory.
125// On error calls __asan_report_error, which aborts the program.
126__attribute__((noinline))
127static void AccessAddress(uintptr_t address, bool isWrite) {
128  if (__asan_address_is_poisoned((void*)address)) {
129    GET_BP_PC_SP;
130    __asan_report_error(pc, bp, sp, address, isWrite, /* access_size */ 1);
131  }
132}
133
134// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
135// and ASAN_WRITE_RANGE as macro instead of function so
136// that no extra frames are created, and stack trace contains
137// relevant information only.
138
139// Instruments read/write access to a memory range.
140// More complex implementation is possible, for now just
141// checking the first and the last byte of a range.
142#define ACCESS_MEMORY_RANGE(offset, size, isWrite) do { \
143  if (size > 0) { \
144    uintptr_t ptr = (uintptr_t)(offset); \
145    AccessAddress(ptr, isWrite); \
146    AccessAddress(ptr + (size) - 1, isWrite); \
147  } \
148} while (0)
149
150#define ASAN_READ_RANGE(offset, size) do { \
151  ACCESS_MEMORY_RANGE(offset, size, false); \
152} while (0)
153
154#define ASAN_WRITE_RANGE(offset, size) do { \
155  ACCESS_MEMORY_RANGE(offset, size, true); \
156} while (0)
157
158// Behavior of functions like "memcpy" or "strcpy" is undefined
159// if memory intervals overlap. We report error in this case.
160// Macro is used to avoid creation of new frames.
161static inline bool RangesOverlap(const char *offset1, size_t length1,
162                                 const char *offset2, size_t length2) {
163  return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1));
164}
165#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \
166  const char *offset1 = (const char*)_offset1; \
167  const char *offset2 = (const char*)_offset2; \
168  if (RangesOverlap(offset1, length1, offset2, length2)) { \
169    Report("ERROR: AddressSanitizer %s-param-overlap: " \
170           "memory ranges [%p,%p) and [%p, %p) overlap\n", \
171           name, offset1, offset1 + length1, offset2, offset2 + length2); \
172    PRINT_CURRENT_STACK(); \
173    ShowStatsAndAbort(); \
174  } \
175} while (0)
176
177#define ENSURE_ASAN_INITED() do { \
178  CHECK(!asan_init_is_running); \
179  if (!asan_inited) { \
180    __asan_init(); \
181  } \
182} while (0)
183
184size_t internal_strlen(const char *s) {
185  size_t i = 0;
186  while (s[i]) i++;
187  return i;
188}
189
190size_t internal_strnlen(const char *s, size_t maxlen) {
191  if (real_strnlen != NULL) {
192    return real_strnlen(s, maxlen);
193  }
194  size_t i = 0;
195  while (i < maxlen && s[i]) i++;
196  return i;
197}
198
199void* internal_memchr(const void* s, int c, size_t n) {
200  const char* t = (char*)s;
201  for (size_t i = 0; i < n; ++i, ++t)
202    if (*t == c)
203      return (void*)t;
204  return NULL;
205}
206
207int internal_memcmp(const void* s1, const void* s2, size_t n) {
208  const char* t1 = (char*)s1;
209  const char* t2 = (char*)s2;
210  for (size_t i = 0; i < n; ++i, ++t1, ++t2)
211    if (*t1 != *t2)
212      return *t1 < *t2 ? -1 : 1;
213  return 0;
214}
215
216char *internal_strstr(const char *haystack, const char *needle) {
217  // This is O(N^2), but we are not using it in hot places.
218  size_t len1 = internal_strlen(haystack);
219  size_t len2 = internal_strlen(needle);
220  if (len1 < len2) return 0;
221  for (size_t pos = 0; pos <= len1 - len2; pos++) {
222    if (internal_memcmp(haystack + pos, needle, len2) == 0)
223      return (char*)haystack + pos;
224  }
225  return 0;
226}
227
228char *internal_strncat(char *dst, const char *src, size_t n) {
229  size_t len = internal_strlen(dst);
230  size_t i;
231  for (i = 0; i < n && src[i]; i++)
232    dst[len + i] = src[i];
233  dst[len + i] = 0;
234  return dst;
235}
236
237}  // namespace __asan
238
239// ---------------------- Wrappers ---------------- {{{1
240using namespace __asan;  // NOLINT
241
242#define OPERATOR_NEW_BODY \
243  GET_STACK_TRACE_HERE_FOR_MALLOC;\
244  return asan_memalign(0, size, &stack);
245
246#ifdef ANDROID
247void *operator new(size_t size) { OPERATOR_NEW_BODY; }
248void *operator new[](size_t size) { OPERATOR_NEW_BODY; }
249#else
250void *operator new(size_t size) throw(std::bad_alloc) { OPERATOR_NEW_BODY; }
251void *operator new[](size_t size) throw(std::bad_alloc) { OPERATOR_NEW_BODY; }
252void *operator new(size_t size, std::nothrow_t const&) throw()
253{ OPERATOR_NEW_BODY; }
254void *operator new[](size_t size, std::nothrow_t const&) throw()
255{ OPERATOR_NEW_BODY; }
256#endif
257
258#define OPERATOR_DELETE_BODY \
259  GET_STACK_TRACE_HERE_FOR_FREE(ptr);\
260  asan_free(ptr, &stack);
261
262void operator delete(void *ptr) throw() { OPERATOR_DELETE_BODY; }
263void operator delete[](void *ptr) throw() { OPERATOR_DELETE_BODY; }
264void operator delete(void *ptr, std::nothrow_t const&) throw()
265{ OPERATOR_DELETE_BODY; }
266void operator delete[](void *ptr, std::nothrow_t const&) throw()
267{ OPERATOR_DELETE_BODY;}
268
269static void *asan_thread_start(void *arg) {
270  AsanThread *t = (AsanThread*)arg;
271  asanThreadRegistry().SetCurrent(t);
272  return t->ThreadStart();
273}
274
275extern "C"
276#ifndef __APPLE__
277__attribute__((visibility("default")))
278#endif
279int WRAP(pthread_create)(pthread_t *thread, const pthread_attr_t *attr,
280                         void *(*start_routine) (void *), void *arg) {
281  GET_STACK_TRACE_HERE(kStackTraceMax);
282  int current_tid = asanThreadRegistry().GetCurrentTidOrMinusOne();
283  AsanThread *t = AsanThread::Create(current_tid, start_routine, arg, &stack);
284  asanThreadRegistry().RegisterThread(t);
285  return real_pthread_create(thread, attr, asan_thread_start, t);
286}
287
288extern "C"
289void *WRAP(signal)(int signum, void *handler) {
290  if (!AsanInterceptsSignal(signum)) {
291    return real_signal(signum, handler);
292  }
293  return NULL;
294}
295
296extern "C"
297extern int (sigaction)(int signum, const void *act, void *oldact);
298
299extern "C"
300int WRAP(sigaction)(int signum, const void *act, void *oldact) {
301  if (!AsanInterceptsSignal(signum)) {
302    return real_sigaction(signum, act, oldact);
303  }
304  return 0;
305}
306
307
308static void UnpoisonStackFromHereToTop() {
309  int local_stack;
310  AsanThread *curr_thread = asanThreadRegistry().GetCurrent();
311  CHECK(curr_thread);
312  uintptr_t top = curr_thread->stack_top();
313  uintptr_t bottom = ((uintptr_t)&local_stack - kPageSize) & ~(kPageSize-1);
314  PoisonShadow(bottom, top - bottom, 0);
315}
316
317extern "C" void WRAP(longjmp)(void *env, int val) {
318  UnpoisonStackFromHereToTop();
319  real_longjmp(env, val);
320}
321
322extern "C" void WRAP(_longjmp)(void *env, int val) {
323  UnpoisonStackFromHereToTop();
324  real__longjmp(env, val);
325}
326
327extern "C" void WRAP(siglongjmp)(void *env, int val) {
328  UnpoisonStackFromHereToTop();
329  real_siglongjmp(env, val);
330}
331
332extern "C" void __cxa_throw(void *a, void *b, void *c);
333
334#if ASAN_HAS_EXCEPTIONS == 1
335extern "C" void WRAP(__cxa_throw)(void *a, void *b, void *c) {
336  CHECK(&real___cxa_throw);
337  UnpoisonStackFromHereToTop();
338  real___cxa_throw(a, b, c);
339}
340#endif
341
342extern "C" {
343// intercept mlock and friends.
344// Since asan maps 16T of RAM, mlock is completely unfriendly to asan.
345// All functions return 0 (success).
346static void MlockIsUnsupported() {
347  static bool printed = 0;
348  if (printed) return;
349  printed = true;
350  Printf("INFO: AddressSanitizer ignores mlock/mlockall/munlock/munlockall\n");
351}
352int mlock(const void *addr, size_t len) {
353  MlockIsUnsupported();
354  return 0;
355}
356int munlock(const void *addr, size_t len) {
357  MlockIsUnsupported();
358  return 0;
359}
360int mlockall(int flags) {
361  MlockIsUnsupported();
362  return 0;
363}
364int munlockall(void) {
365  MlockIsUnsupported();
366  return 0;
367}
368}  // extern "C"
369
370
371
372static inline int CharCmp(unsigned char c1, unsigned char c2) {
373  return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1;
374}
375
376static inline int CharCaseCmp(unsigned char c1, unsigned char c2) {
377  int c1_low = tolower(c1);
378  int c2_low = tolower(c2);
379  return c1_low - c2_low;
380}
381
382extern "C"
383int WRAP(memcmp)(const void *a1, const void *a2, size_t size) {
384  ENSURE_ASAN_INITED();
385  unsigned char c1 = 0, c2 = 0;
386  const unsigned char *s1 = (const unsigned char*)a1;
387  const unsigned char *s2 = (const unsigned char*)a2;
388  size_t i;
389  for (i = 0; i < size; i++) {
390    c1 = s1[i];
391    c2 = s2[i];
392    if (c1 != c2) break;
393  }
394  ASAN_READ_RANGE(s1, Min(i + 1, size));
395  ASAN_READ_RANGE(s2, Min(i + 1, size));
396  return CharCmp(c1, c2);
397}
398
399extern "C"
400void *WRAP(memcpy)(void *to, const void *from, size_t size) {
401  // memcpy is called during __asan_init() from the internals
402  // of printf(...).
403  if (asan_init_is_running) {
404    return real_memcpy(to, from, size);
405  }
406  ENSURE_ASAN_INITED();
407  if (FLAG_replace_intrin) {
408    if (to != from) {
409      // We do not treat memcpy with to==from as a bug.
410      // See http://llvm.org/bugs/show_bug.cgi?id=11763.
411      CHECK_RANGES_OVERLAP("memcpy", to, size, from, size);
412    }
413    ASAN_WRITE_RANGE(from, size);
414    ASAN_READ_RANGE(to, size);
415  }
416  return real_memcpy(to, from, size);
417}
418
419extern "C"
420void *WRAP(memmove)(void *to, const void *from, size_t size) {
421  ENSURE_ASAN_INITED();
422  if (FLAG_replace_intrin) {
423    ASAN_WRITE_RANGE(from, size);
424    ASAN_READ_RANGE(to, size);
425  }
426  return real_memmove(to, from, size);
427}
428
429extern "C"
430void *WRAP(memset)(void *block, int c, size_t size) {
431  // memset is called inside INTERCEPT_FUNCTION on Mac.
432  if (asan_init_is_running) {
433    return real_memset(block, c, size);
434  }
435  ENSURE_ASAN_INITED();
436  if (FLAG_replace_intrin) {
437    ASAN_WRITE_RANGE(block, size);
438  }
439  return real_memset(block, c, size);
440}
441
442#ifndef __APPLE__
443extern "C"
444char *WRAP(index)(const char *str, int c)
445  __attribute__((alias(WRAPPER_NAME(strchr))));
446#endif
447
448extern "C"
449char *WRAP(strchr)(const char *str, int c) {
450  ENSURE_ASAN_INITED();
451  char *result = real_strchr(str, c);
452  if (FLAG_replace_str) {
453    size_t bytes_read = (result ? result - str : real_strlen(str)) + 1;
454    ASAN_READ_RANGE(str, bytes_read);
455  }
456  return result;
457}
458
459extern "C"
460int WRAP(strcasecmp)(const char *s1, const char *s2) {
461  ENSURE_ASAN_INITED();
462  unsigned char c1, c2;
463  size_t i;
464  for (i = 0; ; i++) {
465    c1 = (unsigned char)s1[i];
466    c2 = (unsigned char)s2[i];
467    if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
468  }
469  ASAN_READ_RANGE(s1, i + 1);
470  ASAN_READ_RANGE(s2, i + 1);
471  return CharCaseCmp(c1, c2);
472}
473
474extern "C"
475char *WRAP(strcat)(char *to, const char *from) {  // NOLINT
476  ENSURE_ASAN_INITED();
477  if (FLAG_replace_str) {
478    size_t from_length = real_strlen(from);
479    ASAN_READ_RANGE(from, from_length + 1);
480    if (from_length > 0) {
481      size_t to_length = real_strlen(to);
482      ASAN_READ_RANGE(to, to_length);
483      ASAN_WRITE_RANGE(to + to_length, from_length + 1);
484      CHECK_RANGES_OVERLAP("strcat", to, to_length + 1, from, from_length + 1);
485    }
486  }
487  return real_strcat(to, from);
488}
489
490extern "C"
491int WRAP(strcmp)(const char *s1, const char *s2) {
492  // strcmp is called from malloc_default_purgeable_zone()
493  // in __asan::ReplaceSystemAlloc() on Mac.
494  if (asan_init_is_running) {
495    return real_strcmp(s1, s2);
496  }
497  unsigned char c1, c2;
498  size_t i;
499  for (i = 0; ; i++) {
500    c1 = (unsigned char)s1[i];
501    c2 = (unsigned char)s2[i];
502    if (c1 != c2 || c1 == '\0') break;
503  }
504  ASAN_READ_RANGE(s1, i + 1);
505  ASAN_READ_RANGE(s2, i + 1);
506  return CharCmp(c1, c2);
507}
508
509extern "C"
510char *WRAP(strcpy)(char *to, const char *from) {  // NOLINT
511  // strcpy is called from malloc_default_purgeable_zone()
512  // in __asan::ReplaceSystemAlloc() on Mac.
513  if (asan_init_is_running) {
514    return real_strcpy(to, from);
515  }
516  ENSURE_ASAN_INITED();
517  if (FLAG_replace_str) {
518    size_t from_size = real_strlen(from) + 1;
519    CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);
520    ASAN_READ_RANGE(from, from_size);
521    ASAN_WRITE_RANGE(to, from_size);
522  }
523  return real_strcpy(to, from);
524}
525
526extern "C"
527char *WRAP(strdup)(const char *s) {
528  ENSURE_ASAN_INITED();
529  if (FLAG_replace_str) {
530    size_t length = real_strlen(s);
531    ASAN_READ_RANGE(s, length + 1);
532  }
533  return real_strdup(s);
534}
535
536extern "C"
537size_t WRAP(strlen)(const char *s) {
538  // strlen is called from malloc_default_purgeable_zone()
539  // in __asan::ReplaceSystemAlloc() on Mac.
540  if (asan_init_is_running) {
541    return real_strlen(s);
542  }
543  ENSURE_ASAN_INITED();
544  size_t length = real_strlen(s);
545  if (FLAG_replace_str) {
546    ASAN_READ_RANGE(s, length + 1);
547  }
548  return length;
549}
550
551extern "C"
552int WRAP(strncasecmp)(const char *s1, const char *s2, size_t size) {
553  ENSURE_ASAN_INITED();
554  unsigned char c1 = 0, c2 = 0;
555  size_t i;
556  for (i = 0; i < size; i++) {
557    c1 = (unsigned char)s1[i];
558    c2 = (unsigned char)s2[i];
559    if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
560  }
561  ASAN_READ_RANGE(s1, Min(i + 1, size));
562  ASAN_READ_RANGE(s2, Min(i + 1, size));
563  return CharCaseCmp(c1, c2);
564}
565
566extern "C"
567int WRAP(strncmp)(const char *s1, const char *s2, size_t size) {
568  // strncmp is called from malloc_default_purgeable_zone()
569  // in __asan::ReplaceSystemAlloc() on Mac.
570  if (asan_init_is_running) {
571    return real_strncmp(s1, s2, size);
572  }
573  unsigned char c1 = 0, c2 = 0;
574  size_t i;
575  for (i = 0; i < size; i++) {
576    c1 = (unsigned char)s1[i];
577    c2 = (unsigned char)s2[i];
578    if (c1 != c2 || c1 == '\0') break;
579  }
580  ASAN_READ_RANGE(s1, Min(i + 1, size));
581  ASAN_READ_RANGE(s2, Min(i + 1, size));
582  return CharCmp(c1, c2);
583}
584
585extern "C"
586char *WRAP(strncpy)(char *to, const char *from, size_t size) {
587  ENSURE_ASAN_INITED();
588  if (FLAG_replace_str) {
589    size_t from_size = Min(size, internal_strnlen(from, size) + 1);
590    CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);
591    ASAN_READ_RANGE(from, from_size);
592    ASAN_WRITE_RANGE(to, size);
593  }
594  return real_strncpy(to, from, size);
595}
596
597#ifndef __APPLE__
598extern "C"
599size_t WRAP(strnlen)(const char *s, size_t maxlen) {
600  ENSURE_ASAN_INITED();
601  size_t length = real_strnlen(s, maxlen);
602  if (FLAG_replace_str) {
603    ASAN_READ_RANGE(s, Min(length + 1, maxlen));
604  }
605  return length;
606}
607#endif
608
609// ---------------------- InitializeAsanInterceptors ---------------- {{{1
610namespace __asan {
611void InitializeAsanInterceptors() {
612#ifndef __APPLE__
613  INTERCEPT_FUNCTION(index);
614#else
615  OVERRIDE_FUNCTION(index, WRAP(strchr));
616#endif
617  INTERCEPT_FUNCTION(memcmp);
618  INTERCEPT_FUNCTION(memcpy);
619  INTERCEPT_FUNCTION(memmove);
620  INTERCEPT_FUNCTION(memset);
621  INTERCEPT_FUNCTION(strcasecmp);
622  INTERCEPT_FUNCTION(strcat);  // NOLINT
623  INTERCEPT_FUNCTION(strchr);
624  INTERCEPT_FUNCTION(strcmp);
625  INTERCEPT_FUNCTION(strcpy);  // NOLINT
626  INTERCEPT_FUNCTION(strdup);
627  INTERCEPT_FUNCTION(strlen);
628  INTERCEPT_FUNCTION(strncasecmp);
629  INTERCEPT_FUNCTION(strncmp);
630  INTERCEPT_FUNCTION(strncpy);
631
632  INTERCEPT_FUNCTION(sigaction);
633  INTERCEPT_FUNCTION(signal);
634  INTERCEPT_FUNCTION(longjmp);
635  INTERCEPT_FUNCTION(_longjmp);
636  INTERCEPT_FUNCTION_IF_EXISTS(__cxa_throw);
637  INTERCEPT_FUNCTION(pthread_create);
638
639#ifdef __APPLE__
640  INTERCEPT_FUNCTION(dispatch_async_f);
641  INTERCEPT_FUNCTION(dispatch_sync_f);
642  INTERCEPT_FUNCTION(dispatch_after_f);
643  INTERCEPT_FUNCTION(dispatch_barrier_async_f);
644  INTERCEPT_FUNCTION(dispatch_group_async_f);
645  // We don't need to intercept pthread_workqueue_additem_np() to support the
646  // libdispatch API, but it helps us to debug the unsupported functions. Let's
647  // intercept it only during verbose runs.
648  if (FLAG_v >= 2) {
649    INTERCEPT_FUNCTION(pthread_workqueue_additem_np);
650  }
651#else
652  // On Darwin siglongjmp tailcalls longjmp, so we don't want to intercept it
653  // there.
654  INTERCEPT_FUNCTION(siglongjmp);
655#endif
656
657#ifndef __APPLE__
658  INTERCEPT_FUNCTION(strnlen);
659#endif
660  if (FLAG_v > 0) {
661    Printf("AddressSanitizer: libc interceptors initialized\n");
662  }
663}
664
665}  // namespace __asan
666