blob: d9a0c71a002da799f7a597f1bbf0ab4746a4a8fd [file] [log] [blame]
Alexey Samsonove5f58952012-06-04 13:50:10 +00001//===-- asan_interceptors.cc ----------------------------------------------===//
Kostya Serebryany1e172b42011-11-30 01:07:02 +00002//
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//
Kostya Serebryanyd47189c2012-01-11 02:32:40 +000012// Intercept various libc functions.
Kostya Serebryany1e172b42011-11-30 01:07:02 +000013//===----------------------------------------------------------------------===//
Kostya Serebryany1e172b42011-11-30 01:07:02 +000014
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -080015#include "asan_interceptors.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000016#include "asan_allocator.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000017#include "asan_internal.h"
18#include "asan_mapping.h"
Alexey Samsonov7e843492013-03-28 15:42:43 +000019#include "asan_poisoning.h"
Alexey Samsonov487fee72012-08-09 08:32:33 +000020#include "asan_report.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000021#include "asan_stack.h"
22#include "asan_stats.h"
Stephen Hines86277eb2015-03-23 12:06:32 -070023#include "asan_suppressions.h"
Alexey Samsonovc0d78c12012-06-04 13:27:49 +000024#include "sanitizer_common/sanitizer_libc.h"
25
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -070026#if SANITIZER_POSIX
27#include "sanitizer_common/sanitizer_posix.h"
28#endif
29
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -080030#if defined(__i386) && SANITIZER_LINUX
31#define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.1"
32#elif defined(__mips__) && SANITIZER_LINUX
33#define ASAN_PTHREAD_CREATE_VERSION "GLIBC_2.2"
34#endif
35
Kostya Serebryany1e172b42011-11-30 01:07:02 +000036namespace __asan {
37
Kostya Serebryanya84805f2013-02-21 07:07:39 +000038// Return true if we can quickly decide that the region is unpoisoned.
39static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
40 if (size == 0) return true;
41 if (size <= 32)
42 return !AddressIsPoisoned(beg) &&
43 !AddressIsPoisoned(beg + size - 1) &&
44 !AddressIsPoisoned(beg + size / 2);
45 return false;
46}
47
Stephen Hines86277eb2015-03-23 12:06:32 -070048struct AsanInterceptorContext {
49 const char *interceptor_name;
50};
51
Kostya Serebryany1e172b42011-11-30 01:07:02 +000052// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
53// and ASAN_WRITE_RANGE as macro instead of function so
54// that no extra frames are created, and stack trace contains
55// relevant information only.
Kostya Serebryanyeb280932012-12-28 15:24:16 +000056// We check all shadow bytes.
Stephen Hines86277eb2015-03-23 12:06:32 -070057#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do { \
Evgeniy Stepanov589dcda2013-02-05 14:32:03 +000058 uptr __offset = (uptr)(offset); \
59 uptr __size = (uptr)(size); \
Kostya Serebryany1b057b22013-02-26 07:25:18 +000060 uptr __bad = 0; \
Stephen Hines2d1fdb22014-05-28 23:58:16 -070061 if (__offset > __offset + __size) { \
62 GET_STACK_TRACE_FATAL_HERE; \
63 ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
64 } \
Kostya Serebryanya84805f2013-02-21 07:07:39 +000065 if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \
Kostya Serebryany1b057b22013-02-26 07:25:18 +000066 (__bad = __asan_region_is_poisoned(__offset, __size))) { \
Stephen Hines86277eb2015-03-23 12:06:32 -070067 AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \
68 bool suppressed = false; \
69 if (_ctx) { \
70 suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
71 if (!suppressed && HaveStackTraceBasedSuppressions()) { \
72 GET_STACK_TRACE_FATAL_HERE; \
73 suppressed = IsStackTraceSuppressed(&stack); \
74 } \
75 } \
76 if (!suppressed) { \
77 GET_CURRENT_PC_BP_SP; \
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -080078 ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\
Stephen Hines86277eb2015-03-23 12:06:32 -070079 } \
Evgeniy Stepanov589dcda2013-02-05 14:32:03 +000080 } \
81 } while (0)
Kostya Serebryany1e172b42011-11-30 01:07:02 +000082
Stephen Hines86277eb2015-03-23 12:06:32 -070083#define ASAN_READ_RANGE(ctx, offset, size) \
84 ACCESS_MEMORY_RANGE(ctx, offset, size, false)
85#define ASAN_WRITE_RANGE(ctx, offset, size) \
86 ACCESS_MEMORY_RANGE(ctx, offset, size, true)
Kostya Serebryany1e172b42011-11-30 01:07:02 +000087
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -070088#define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \
89 ASAN_READ_RANGE((ctx), (s), \
90 common_flags()->strict_string_checks ? (len) + 1 : (n))
91
92#define ASAN_READ_STRING(ctx, s, n) \
93 ASAN_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n))
94
Kostya Serebryany1e172b42011-11-30 01:07:02 +000095// Behavior of functions like "memcpy" or "strcpy" is undefined
96// if memory intervals overlap. We report error in this case.
97// Macro is used to avoid creation of new frames.
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000098static inline bool RangesOverlap(const char *offset1, uptr length1,
99 const char *offset2, uptr length2) {
Kostya Serebryany0985ca22011-12-28 19:08:49 +0000100 return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1));
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000101}
Kostya Serebryanyc5e72a32011-12-28 19:24:31 +0000102#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000103 const char *offset1 = (const char*)_offset1; \
104 const char *offset2 = (const char*)_offset2; \
Kostya Serebryany0985ca22011-12-28 19:08:49 +0000105 if (RangesOverlap(offset1, length1, offset2, length2)) { \
Kostya Serebryanya30c8f92012-12-13 09:34:23 +0000106 GET_STACK_TRACE_FATAL_HERE; \
Alexey Samsonov487fee72012-08-09 08:32:33 +0000107 ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \
108 offset2, length2, &stack); \
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000109 } \
Kostya Serebryanye1301912011-12-05 18:56:29 +0000110} while (0)
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000111
Alexey Samsonovc9256972012-06-15 13:09:52 +0000112static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
Alexey Samsonov81a7a4a2012-03-24 09:10:50 +0000113#if ASAN_INTERCEPT_STRNLEN
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800114 if (REAL(strnlen)) {
Alexey Samsonov09672ca2012-02-08 13:45:31 +0000115 return REAL(strnlen)(s, maxlen);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000116 }
Alexey Samsonovf2598fc2012-02-02 10:39:40 +0000117#endif
Alexey Samsonovc9256972012-06-15 13:09:52 +0000118 return internal_strnlen(s, maxlen);
Kostya Serebryanya4ccf872012-01-09 22:20:49 +0000119}
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000120
Kostya Serebryanyc20b3212013-01-18 06:43:13 +0000121void SetThreadName(const char *name) {
Alexey Samsonov89c13842013-03-20 09:23:28 +0000122 AsanThread *t = GetCurrentThread();
Kostya Serebryanyc20b3212013-01-18 06:43:13 +0000123 if (t)
Alexey Samsonovdef1be92013-03-21 11:23:41 +0000124 asanThreadRegistry().SetThreadName(t->tid(), name);
Kostya Serebryanyc20b3212013-01-18 06:43:13 +0000125}
126
Dmitry Vyukov8cde99f2013-10-03 15:43:59 +0000127int OnExit() {
Dmitry Vyukov14dd9802013-10-03 15:22:29 +0000128 // FIXME: ask frontend whether we need to return failure.
129 return 0;
130}
131
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800132} // namespace __asan
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000133
134// ---------------------- Wrappers ---------------- {{{1
135using namespace __asan; // NOLINT
136
Evgeniy Stepanov12eb79d2013-07-09 09:53:37 +0000137DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
138DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
139
Stephen Hines86277eb2015-03-23 12:06:32 -0700140#define ASAN_INTERCEPTOR_ENTER(ctx, func) \
141 AsanInterceptorContext _ctx = {#func}; \
142 ctx = (void *)&_ctx; \
143 (void) ctx; \
144
Evgeniy Stepanova537ea92013-11-11 11:28:30 +0000145#define COMMON_INTERCEPT_FUNCTION(name) ASAN_INTERCEPT_FUNC(name)
Evgeniy Stepanov82a90802013-01-18 13:12:56 +0000146#define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
Stephen Hines86277eb2015-03-23 12:06:32 -0700147 ASAN_WRITE_RANGE(ctx, ptr, size)
148#define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
149 ASAN_READ_RANGE(ctx, ptr, size)
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700150#define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
Stephen Hines86277eb2015-03-23 12:06:32 -0700151 ASAN_INTERCEPTOR_ENTER(ctx, func); \
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700152 do { \
153 if (asan_init_is_running) \
154 return REAL(func)(__VA_ARGS__); \
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700155 if (SANITIZER_MAC && UNLIKELY(!asan_inited)) \
156 return REAL(func)(__VA_ARGS__); \
157 ENSURE_ASAN_INITED(); \
Evgeniy Stepanov82a90802013-01-18 13:12:56 +0000158 } while (false)
Stephen Hines86277eb2015-03-23 12:06:32 -0700159#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
160 do { \
161 } while (false)
Evgeniy Stepanov9d1525e2013-05-29 09:09:58 +0000162#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
163 do { \
164 } while (false)
165#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
166 do { \
167 } while (false)
168#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
169 do { \
170 } while (false)
Evgeniy Stepanov996c4f22013-01-18 11:17:23 +0000171#define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)
Dmitry Vyukove767e352013-11-14 16:48:22 +0000172// Should be asanThreadRegistry().SetThreadNameByUserId(thread, name)
173// But asan does not remember UserId's for threads (pthread_t);
174// and remembers all ever existed threads, so the linear search by UserId
175// can be slow.
Dmitry Vyukov5cf2c462013-10-29 10:30:39 +0000176#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
Dmitry Vyukove767e352013-11-14 16:48:22 +0000177 do { \
178 } while (false)
Evgeniy Stepanove18e3f02013-08-12 13:19:53 +0000179#define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
Stephen Hines86277eb2015-03-23 12:06:32 -0700180// Strict init-order checking is dlopen-hostile:
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800181// https://github.com/google/sanitizers/issues/178
Stephen Hines86277eb2015-03-23 12:06:32 -0700182#define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \
183 if (flags()->strict_init_order) { \
184 StopInitOrderChecking(); \
185 }
Dmitry Vyukov14dd9802013-10-03 15:22:29 +0000186#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
Stephen Hines86277eb2015-03-23 12:06:32 -0700187#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \
188 CoverageUpdateMapping()
189#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CoverageUpdateMapping()
Stephen Hines6d186232014-11-26 17:56:19 -0800190#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited)
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -0700191#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
192 if (AsanThread *t = GetCurrentThread()) { \
193 *begin = t->tls_begin(); \
194 *end = t->tls_end(); \
195 } else { \
196 *begin = *end = 0; \
197 }
Evgeniy Stepanov4f32c0b2013-01-18 13:01:18 +0000198#include "sanitizer_common/sanitizer_common_interceptors.inc"
Kostya Serebryany8530e2b2012-12-12 09:54:35 +0000199
Stephen Hines86277eb2015-03-23 12:06:32 -0700200// Syscall interceptors don't have contexts, we don't support suppressions
201// for them.
202#define COMMON_SYSCALL_PRE_READ_RANGE(p, s) ASAN_READ_RANGE(nullptr, p, s)
203#define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) ASAN_WRITE_RANGE(nullptr, p, s)
Evgeniy Stepanovae4e6fd2013-07-09 09:29:19 +0000204#define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
205 do { \
Evgeniy Stepanovdfab31b2013-10-29 18:29:39 +0000206 (void)(p); \
207 (void)(s); \
Evgeniy Stepanovae4e6fd2013-07-09 09:29:19 +0000208 } while (false)
209#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
210 do { \
Evgeniy Stepanovdfab31b2013-10-29 18:29:39 +0000211 (void)(p); \
212 (void)(s); \
Evgeniy Stepanovae4e6fd2013-07-09 09:29:19 +0000213 } while (false)
Evgeniy Stepanov881b6772013-04-12 14:57:03 +0000214#include "sanitizer_common/sanitizer_common_syscalls.inc"
215
Stephen Hines86277eb2015-03-23 12:06:32 -0700216struct ThreadStartParam {
217 atomic_uintptr_t t;
218 atomic_uintptr_t is_registered;
219};
220
Timur Iskhodzhanov600972e2012-02-24 15:28:43 +0000221static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700222 ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
223 AsanThread *t = nullptr;
224 while ((t = reinterpret_cast<AsanThread *>(
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800225 atomic_load(&param->t, memory_order_acquire))) == nullptr)
Stephen Hines86277eb2015-03-23 12:06:32 -0700226 internal_sched_yield();
227 SetCurrentThread(t);
228 return t->ThreadStart(GetTid(), &param->is_registered);
Kostya Serebryany4803ab92012-01-09 18:53:15 +0000229}
230
Alexey Samsonovfd2ae4f2012-08-01 11:17:00 +0000231#if ASAN_INTERCEPT_PTHREAD_CREATE
Evgeniy Stepanovb8ef9252012-02-22 12:31:25 +0000232INTERCEPTOR(int, pthread_create, void *thread,
233 void *attr, void *(*start_routine)(void*), void *arg) {
Sergey Matveevc6ac98d2013-07-08 12:57:24 +0000234 EnsureMainThreadIDIsCorrect();
Stephen Hines86277eb2015-03-23 12:06:32 -0700235 // Strict init-order checking is thread-hostile.
Alexey Samsonov9465cbd2013-07-01 16:16:41 +0000236 if (flags()->strict_init_order)
237 StopInitOrderChecking();
Kostya Serebryanya30c8f92012-12-13 09:34:23 +0000238 GET_STACK_TRACE_THREAD;
Alexey Samsonovdef1be92013-03-21 11:23:41 +0000239 int detached = 0;
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800240 if (attr)
Evgeniy Stepanovbb6bc9a2013-11-11 08:56:49 +0000241 REAL(pthread_attr_getdetachstate)(attr, &detached);
Stephen Hines86277eb2015-03-23 12:06:32 -0700242 ThreadStartParam param;
243 atomic_store(&param.t, 0, memory_order_relaxed);
244 atomic_store(&param.is_registered, 0, memory_order_relaxed);
245 int result = REAL(pthread_create)(thread, attr, asan_thread_start, &param);
246 if (result == 0) {
247 u32 current_tid = GetCurrentTidOrInvalid();
248 AsanThread *t =
249 AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
250 atomic_store(&param.t, reinterpret_cast<uptr>(t), memory_order_release);
251 // Wait until the AsanThread object is initialized and the ThreadRegistry
252 // entry is in "started" state. One reason for this is that after this
253 // interceptor exits, the child thread's stack may be the only thing holding
254 // the |arg| pointer. This may cause LSan to report a leak if leak checking
255 // happens at a point when the interceptor has already exited, but the stack
256 // range for the child thread is not yet known.
257 while (atomic_load(&param.is_registered, memory_order_acquire) == 0)
258 internal_sched_yield();
259 }
260 return result;
Kostya Serebryany4803ab92012-01-09 18:53:15 +0000261}
Stephen Hines86277eb2015-03-23 12:06:32 -0700262
263INTERCEPTOR(int, pthread_join, void *t, void **arg) {
264 return real_pthread_join(t, arg);
265}
266
267DEFINE_REAL_PTHREAD_FUNCTIONS
Alexey Samsonovfd2ae4f2012-08-01 11:17:00 +0000268#endif // ASAN_INTERCEPT_PTHREAD_CREATE
Kostya Serebryany4803ab92012-01-09 18:53:15 +0000269
Alexey Samsonov34a32022012-03-26 09:07:29 +0000270#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700271
272#if SANITIZER_ANDROID
273INTERCEPTOR(void*, bsd_signal, int signum, void *handler) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700274 if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700275 return REAL(bsd_signal)(signum, handler);
276 }
277 return 0;
278}
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800279#endif
280
Alexey Samsonovf2598fc2012-02-02 10:39:40 +0000281INTERCEPTOR(void*, signal, int signum, void *handler) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700282 if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) {
Alexander Potapenko034bda52012-04-16 08:33:01 +0000283 return REAL(signal)(signum, handler);
Kostya Serebryany4803ab92012-01-09 18:53:15 +0000284 }
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800285 return nullptr;
Kostya Serebryany4803ab92012-01-09 18:53:15 +0000286}
287
Alexey Samsonovda13ba82012-02-16 17:00:45 +0000288INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
289 struct sigaction *oldact) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700290 if (!IsDeadlySignal(signum) || common_flags()->allow_user_segv_handler) {
Alexander Potapenko034bda52012-04-16 08:33:01 +0000291 return REAL(sigaction)(signum, act, oldact);
Kostya Serebryany4803ab92012-01-09 18:53:15 +0000292 }
Alexander Potapenko034bda52012-04-16 08:33:01 +0000293 return 0;
Kostya Serebryany4803ab92012-01-09 18:53:15 +0000294}
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700295
296namespace __sanitizer {
297int real_sigaction(int signum, const void *act, void *oldact) {
Stephen Hines6d186232014-11-26 17:56:19 -0800298 return REAL(sigaction)(signum, (const struct sigaction *)act,
299 (struct sigaction *)oldact);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700300}
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800301} // namespace __sanitizer
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700302
Evgeniy Stepanove1ba0002013-03-19 15:26:41 +0000303#elif SANITIZER_POSIX
Alexey Samsonov34a32022012-03-26 09:07:29 +0000304// We need to have defined REAL(sigaction) on posix systems.
305DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act,
Alexey Samsonovfdde5a92013-06-10 14:17:08 +0000306 struct sigaction *oldact)
Alexey Samsonov34a32022012-03-26 09:07:29 +0000307#endif // ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
Kostya Serebryany4803ab92012-01-09 18:53:15 +0000308
Alexey Samsonov08700282012-11-23 09:46:34 +0000309#if ASAN_INTERCEPT_SWAPCONTEXT
Alexey Samsonov57db4ba2013-01-17 15:45:28 +0000310static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) {
311 // Align to page size.
312 uptr PageSize = GetPageSizeCached();
313 uptr bottom = stack & ~(PageSize - 1);
314 ssize += stack - bottom;
315 ssize = RoundUpTo(ssize, PageSize);
316 static const uptr kMaxSaneContextStackSize = 1 << 22; // 4 Mb
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700317 if (AddrIsInMem(bottom) && ssize && ssize <= kMaxSaneContextStackSize) {
Alexey Samsonov57db4ba2013-01-17 15:45:28 +0000318 PoisonShadow(bottom, ssize, 0);
319 }
320}
321
Alexey Samsonov08700282012-11-23 09:46:34 +0000322INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
323 struct ucontext_t *ucp) {
324 static bool reported_warning = false;
325 if (!reported_warning) {
326 Report("WARNING: ASan doesn't fully support makecontext/swapcontext "
327 "functions and may produce false positives in some cases!\n");
328 reported_warning = true;
329 }
330 // Clear shadow memory for new context (it may share stack
331 // with current context).
Alexey Samsonov57db4ba2013-01-17 15:45:28 +0000332 uptr stack, ssize;
333 ReadContextStack(ucp, &stack, &ssize);
334 ClearShadowMemoryForContextStack(stack, ssize);
Alexey Samsonov08700282012-11-23 09:46:34 +0000335 int res = REAL(swapcontext)(oucp, ucp);
336 // swapcontext technically does not return, but program may swap context to
337 // "oucp" later, that would look as if swapcontext() returned 0.
338 // We need to clear shadow for ucp once again, as it may be in arbitrary
339 // state.
Alexey Samsonov57db4ba2013-01-17 15:45:28 +0000340 ClearShadowMemoryForContextStack(stack, ssize);
Alexey Samsonov08700282012-11-23 09:46:34 +0000341 return res;
342}
Alexey Samsonov57db4ba2013-01-17 15:45:28 +0000343#endif // ASAN_INTERCEPT_SWAPCONTEXT
Alexey Samsonov08700282012-11-23 09:46:34 +0000344
Alexey Samsonovf2598fc2012-02-02 10:39:40 +0000345INTERCEPTOR(void, longjmp, void *env, int val) {
Kostya Serebryanyf54b1f92012-02-08 21:33:27 +0000346 __asan_handle_no_return();
Alexey Samsonov09672ca2012-02-08 13:45:31 +0000347 REAL(longjmp)(env, val);
Kostya Serebryany4803ab92012-01-09 18:53:15 +0000348}
349
Alexey Samsonovfd2ae4f2012-08-01 11:17:00 +0000350#if ASAN_INTERCEPT__LONGJMP
Alexey Samsonovf2598fc2012-02-02 10:39:40 +0000351INTERCEPTOR(void, _longjmp, void *env, int val) {
Kostya Serebryanyf54b1f92012-02-08 21:33:27 +0000352 __asan_handle_no_return();
Alexey Samsonov09672ca2012-02-08 13:45:31 +0000353 REAL(_longjmp)(env, val);
Kostya Serebryany4803ab92012-01-09 18:53:15 +0000354}
Alexey Samsonovfd2ae4f2012-08-01 11:17:00 +0000355#endif
Kostya Serebryany4803ab92012-01-09 18:53:15 +0000356
Alexey Samsonovfd2ae4f2012-08-01 11:17:00 +0000357#if ASAN_INTERCEPT_SIGLONGJMP
Alexey Samsonovf2598fc2012-02-02 10:39:40 +0000358INTERCEPTOR(void, siglongjmp, void *env, int val) {
Kostya Serebryanyf54b1f92012-02-08 21:33:27 +0000359 __asan_handle_no_return();
Alexey Samsonov09672ca2012-02-08 13:45:31 +0000360 REAL(siglongjmp)(env, val);
Kostya Serebryany4803ab92012-01-09 18:53:15 +0000361}
Timur Iskhodzhanov07bb9f12012-02-22 13:59:49 +0000362#endif
Kostya Serebryany4803ab92012-01-09 18:53:15 +0000363
Alexey Samsonovfd2ae4f2012-08-01 11:17:00 +0000364#if ASAN_INTERCEPT___CXA_THROW
Alexey Samsonovf2598fc2012-02-02 10:39:40 +0000365INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
Alexey Samsonov09672ca2012-02-08 13:45:31 +0000366 CHECK(REAL(__cxa_throw));
Kostya Serebryanyf54b1f92012-02-08 21:33:27 +0000367 __asan_handle_no_return();
Alexey Samsonov09672ca2012-02-08 13:45:31 +0000368 REAL(__cxa_throw)(a, b, c);
Kostya Serebryany4803ab92012-01-09 18:53:15 +0000369}
370#endif
371
Stephen Hines86277eb2015-03-23 12:06:32 -0700372// memcpy is called during __asan_init() from the internals of printf(...).
373// We do not treat memcpy with to==from as a bug.
374// See http://llvm.org/bugs/show_bug.cgi?id=11763.
375#define ASAN_MEMCPY_IMPL(ctx, to, from, size) do { \
376 if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \
377 if (asan_init_is_running) { \
378 return REAL(memcpy)(to, from, size); \
379 } \
380 ENSURE_ASAN_INITED(); \
381 if (flags()->replace_intrin) { \
382 if (to != from) { \
383 CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \
384 } \
385 ASAN_READ_RANGE(ctx, from, size); \
386 ASAN_WRITE_RANGE(ctx, to, size); \
387 } \
388 return REAL(memcpy)(to, from, size); \
389 } while (0)
390
391
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700392void *__asan_memcpy(void *to, const void *from, uptr size) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700393 ASAN_MEMCPY_IMPL(nullptr, to, from, size);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000394}
395
Stephen Hines86277eb2015-03-23 12:06:32 -0700396// memset is called inside Printf.
397#define ASAN_MEMSET_IMPL(ctx, block, c, size) do { \
398 if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \
399 if (asan_init_is_running) { \
400 return REAL(memset)(block, c, size); \
401 } \
402 ENSURE_ASAN_INITED(); \
403 if (flags()->replace_intrin) { \
404 ASAN_WRITE_RANGE(ctx, block, size); \
405 } \
406 return REAL(memset)(block, c, size); \
407 } while (0)
408
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700409void *__asan_memset(void *block, int c, uptr size) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700410 ASAN_MEMSET_IMPL(nullptr, block, c, size);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000411}
412
Stephen Hines86277eb2015-03-23 12:06:32 -0700413#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) do { \
414 if (UNLIKELY(!asan_inited)) \
415 return internal_memmove(to, from, size); \
416 ENSURE_ASAN_INITED(); \
417 if (flags()->replace_intrin) { \
418 ASAN_READ_RANGE(ctx, from, size); \
419 ASAN_WRITE_RANGE(ctx, to, size); \
420 } \
421 return internal_memmove(to, from, size); \
422 } while (0)
423
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700424void *__asan_memmove(void *to, const void *from, uptr size) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700425 ASAN_MEMMOVE_IMPL(nullptr, to, from, size);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700426}
427
428INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700429 void *ctx;
430 ASAN_INTERCEPTOR_ENTER(ctx, memmove);
431 ASAN_MEMMOVE_IMPL(ctx, to, from, size);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700432}
433
434INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700435 void *ctx;
436 ASAN_INTERCEPTOR_ENTER(ctx, memcpy);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700437#if !SANITIZER_MAC
Stephen Hines86277eb2015-03-23 12:06:32 -0700438 ASAN_MEMCPY_IMPL(ctx, to, from, size);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700439#else
440 // At least on 10.7 and 10.8 both memcpy() and memmove() are being replaced
441 // with WRAP(memcpy). As a result, false positives are reported for memmove()
442 // calls. If we just disable error reporting with
443 // ASAN_OPTIONS=replace_intrin=0, memmove() is still replaced with
444 // internal_memcpy(), which may lead to crashes, see
445 // http://llvm.org/bugs/show_bug.cgi?id=16362.
Stephen Hines86277eb2015-03-23 12:06:32 -0700446 ASAN_MEMMOVE_IMPL(ctx, to, from, size);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700447#endif // !SANITIZER_MAC
448}
449
450INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700451 void *ctx;
452 ASAN_INTERCEPTOR_ENTER(ctx, memset);
453 ASAN_MEMSET_IMPL(ctx, block, c, size);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700454}
455
Alexey Samsonovf2598fc2012-02-02 10:39:40 +0000456INTERCEPTOR(char*, strchr, const char *str, int c) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700457 void *ctx;
458 ASAN_INTERCEPTOR_ENTER(ctx, strchr);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700459 if (UNLIKELY(!asan_inited)) return internal_strchr(str, c);
Alexander Potapenko8d6e3f72012-09-10 08:35:12 +0000460 // strchr is called inside create_purgeable_zone() when MallocGuardEdges=1 is
461 // used.
462 if (asan_init_is_running) {
463 return REAL(strchr)(str, c);
464 }
Kostya Serebryanye1301912011-12-05 18:56:29 +0000465 ENSURE_ASAN_INITED();
Alexey Samsonov09672ca2012-02-08 13:45:31 +0000466 char *result = REAL(strchr)(str, c);
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +0000467 if (flags()->replace_str) {
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700468 uptr len = REAL(strlen)(str);
469 uptr bytes_read = (result ? result - str : len) + 1;
470 ASAN_READ_STRING_OF_LEN(ctx, str, len, bytes_read);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000471 }
472 return result;
473}
474
Alexey Samsonovfd2ae4f2012-08-01 11:17:00 +0000475#if ASAN_INTERCEPT_INDEX
476# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
Evgeniy Stepanov4b0c5f22012-02-13 12:12:32 +0000477INTERCEPTOR(char*, index, const char *string, int c)
Alexander Potapenko72bbfd42013-02-21 15:15:43 +0000478 ALIAS(WRAPPER_NAME(strchr));
Alexey Samsonovfd2ae4f2012-08-01 11:17:00 +0000479# else
Evgeniy Stepanov24e13722013-03-19 14:33:38 +0000480# if SANITIZER_MAC
Alexander Potapenko50a002e2013-02-21 14:41:16 +0000481DECLARE_REAL(char*, index, const char *string, int c)
482OVERRIDE_FUNCTION(index, strchr);
483# else
Alexey Samsonovfdde5a92013-06-10 14:17:08 +0000484DEFINE_REAL(char*, index, const char *string, int c)
Alexander Potapenko50a002e2013-02-21 14:41:16 +0000485# endif
Alexey Samsonovfd2ae4f2012-08-01 11:17:00 +0000486# endif
487#endif // ASAN_INTERCEPT_INDEX
Kostya Serebryanyaf0f01d2011-12-28 02:24:50 +0000488
Alexander Potapenko37b3fcd2012-08-02 10:25:46 +0000489// For both strcat() and strncat() we need to check the validity of |to|
490// argument irrespective of the |from| length.
Alexey Samsonovf2598fc2012-02-02 10:39:40 +0000491INTERCEPTOR(char*, strcat, char *to, const char *from) { // NOLINT
Stephen Hines86277eb2015-03-23 12:06:32 -0700492 void *ctx;
493 ASAN_INTERCEPTOR_ENTER(ctx, strcat); // NOLINT
Kostya Serebryany0985ca22011-12-28 19:08:49 +0000494 ENSURE_ASAN_INITED();
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +0000495 if (flags()->replace_str) {
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000496 uptr from_length = REAL(strlen)(from);
Stephen Hines86277eb2015-03-23 12:06:32 -0700497 ASAN_READ_RANGE(ctx, from, from_length + 1);
Alexander Potapenko37b3fcd2012-08-02 10:25:46 +0000498 uptr to_length = REAL(strlen)(to);
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700499 ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
Stephen Hines86277eb2015-03-23 12:06:32 -0700500 ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
Alexander Potapenko37b3fcd2012-08-02 10:25:46 +0000501 // If the copying actually happens, the |from| string should not overlap
502 // with the resulting string starting at |to|, which has a length of
503 // to_length + from_length + 1.
Kostya Serebryany0985ca22011-12-28 19:08:49 +0000504 if (from_length > 0) {
Alexander Potapenko37b3fcd2012-08-02 10:25:46 +0000505 CHECK_RANGES_OVERLAP("strcat", to, from_length + to_length + 1,
506 from, from_length + 1);
Kostya Serebryany0985ca22011-12-28 19:08:49 +0000507 }
508 }
Alexey Samsonov09672ca2012-02-08 13:45:31 +0000509 return REAL(strcat)(to, from); // NOLINT
Kostya Serebryany0985ca22011-12-28 19:08:49 +0000510}
511
Alexey Samsonovc1bdd5a2012-06-08 13:27:46 +0000512INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700513 void *ctx;
514 ASAN_INTERCEPTOR_ENTER(ctx, strncat);
Alexey Samsonovc1bdd5a2012-06-08 13:27:46 +0000515 ENSURE_ASAN_INITED();
Alexander Potapenko37b3fcd2012-08-02 10:25:46 +0000516 if (flags()->replace_str) {
Alexey Samsonovc9256972012-06-15 13:09:52 +0000517 uptr from_length = MaybeRealStrnlen(from, size);
Alexander Potapenko37b3fcd2012-08-02 10:25:46 +0000518 uptr copy_length = Min(size, from_length + 1);
Stephen Hines86277eb2015-03-23 12:06:32 -0700519 ASAN_READ_RANGE(ctx, from, copy_length);
Alexey Samsonovc1bdd5a2012-06-08 13:27:46 +0000520 uptr to_length = REAL(strlen)(to);
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700521 ASAN_READ_STRING_OF_LEN(ctx, to, to_length, to_length);
Stephen Hines86277eb2015-03-23 12:06:32 -0700522 ASAN_WRITE_RANGE(ctx, to + to_length, from_length + 1);
Alexey Samsonovc1bdd5a2012-06-08 13:27:46 +0000523 if (from_length > 0) {
Alexander Potapenko37b3fcd2012-08-02 10:25:46 +0000524 CHECK_RANGES_OVERLAP("strncat", to, to_length + copy_length + 1,
525 from, copy_length);
Alexey Samsonovc1bdd5a2012-06-08 13:27:46 +0000526 }
527 }
528 return REAL(strncat)(to, from, size);
529}
530
Alexey Samsonovf2598fc2012-02-02 10:39:40 +0000531INTERCEPTOR(char*, strcpy, char *to, const char *from) { // NOLINT
Stephen Hines86277eb2015-03-23 12:06:32 -0700532 void *ctx;
533 ASAN_INTERCEPTOR_ENTER(ctx, strcpy); // NOLINT
Evgeniy Stepanov24e13722013-03-19 14:33:38 +0000534#if SANITIZER_MAC
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700535 if (UNLIKELY(!asan_inited)) return REAL(strcpy)(to, from); // NOLINT
Alexander Potapenko0ef53102012-08-17 09:00:08 +0000536#endif
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000537 // strcpy is called from malloc_default_purgeable_zone()
538 // in __asan::ReplaceSystemAlloc() on Mac.
539 if (asan_init_is_running) {
Alexey Samsonov09672ca2012-02-08 13:45:31 +0000540 return REAL(strcpy)(to, from); // NOLINT
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000541 }
Kostya Serebryanye1301912011-12-05 18:56:29 +0000542 ENSURE_ASAN_INITED();
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +0000543 if (flags()->replace_str) {
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000544 uptr from_size = REAL(strlen)(from) + 1;
Kostya Serebryanyc5e72a32011-12-28 19:24:31 +0000545 CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);
Stephen Hines86277eb2015-03-23 12:06:32 -0700546 ASAN_READ_RANGE(ctx, from, from_size);
547 ASAN_WRITE_RANGE(ctx, to, from_size);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000548 }
Alexey Samsonov09672ca2012-02-08 13:45:31 +0000549 return REAL(strcpy)(to, from); // NOLINT
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000550}
551
Alexey Samsonovfd2ae4f2012-08-01 11:17:00 +0000552#if ASAN_INTERCEPT_STRDUP
Alexey Samsonovf2598fc2012-02-02 10:39:40 +0000553INTERCEPTOR(char*, strdup, const char *s) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700554 void *ctx;
555 ASAN_INTERCEPTOR_ENTER(ctx, strdup);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700556 if (UNLIKELY(!asan_inited)) return internal_strdup(s);
Kostya Serebryanye1301912011-12-05 18:56:29 +0000557 ENSURE_ASAN_INITED();
Alexey Samsonovd530d892013-06-21 14:41:59 +0000558 uptr length = REAL(strlen)(s);
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +0000559 if (flags()->replace_str) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700560 ASAN_READ_RANGE(ctx, s, length + 1);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000561 }
Alexey Samsonovd530d892013-06-21 14:41:59 +0000562 GET_STACK_TRACE_MALLOC;
563 void *new_mem = asan_malloc(length + 1, &stack);
564 REAL(memcpy)(new_mem, s, length + 1);
565 return reinterpret_cast<char*>(new_mem);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000566}
Alexey Samsonovfd2ae4f2012-08-01 11:17:00 +0000567#endif
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000568
Stephen Hines6d186232014-11-26 17:56:19 -0800569INTERCEPTOR(SIZE_T, strlen, const char *s) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700570 void *ctx;
571 ASAN_INTERCEPTOR_ENTER(ctx, strlen);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700572 if (UNLIKELY(!asan_inited)) return internal_strlen(s);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000573 // strlen is called from malloc_default_purgeable_zone()
574 // in __asan::ReplaceSystemAlloc() on Mac.
575 if (asan_init_is_running) {
Alexey Samsonov09672ca2012-02-08 13:45:31 +0000576 return REAL(strlen)(s);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000577 }
Kostya Serebryanye1301912011-12-05 18:56:29 +0000578 ENSURE_ASAN_INITED();
Stephen Hines6d186232014-11-26 17:56:19 -0800579 SIZE_T length = REAL(strlen)(s);
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +0000580 if (flags()->replace_str) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700581 ASAN_READ_RANGE(ctx, s, length + 1);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000582 }
583 return length;
584}
585
Stephen Hines6d186232014-11-26 17:56:19 -0800586INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700587 void *ctx;
588 ASAN_INTERCEPTOR_ENTER(ctx, wcslen);
Stephen Hines6d186232014-11-26 17:56:19 -0800589 SIZE_T length = REAL(wcslen)(s);
Reid Klecknerb99228d2013-09-05 01:13:49 +0000590 if (!asan_init_is_running) {
591 ENSURE_ASAN_INITED();
Stephen Hines86277eb2015-03-23 12:06:32 -0700592 ASAN_READ_RANGE(ctx, s, (length + 1) * sizeof(wchar_t));
Reid Klecknerb99228d2013-09-05 01:13:49 +0000593 }
594 return length;
595}
596
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000597INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700598 void *ctx;
599 ASAN_INTERCEPTOR_ENTER(ctx, strncpy);
Kostya Serebryanye1301912011-12-05 18:56:29 +0000600 ENSURE_ASAN_INITED();
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +0000601 if (flags()->replace_str) {
Alexey Samsonovc9256972012-06-15 13:09:52 +0000602 uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1);
Kostya Serebryanyc5e72a32011-12-28 19:24:31 +0000603 CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);
Stephen Hines86277eb2015-03-23 12:06:32 -0700604 ASAN_READ_RANGE(ctx, from, from_size);
605 ASAN_WRITE_RANGE(ctx, to, size);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000606 }
Alexey Samsonov09672ca2012-02-08 13:45:31 +0000607 return REAL(strncpy)(to, from, size);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000608}
609
Alexey Samsonov81a7a4a2012-03-24 09:10:50 +0000610#if ASAN_INTERCEPT_STRNLEN
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000611INTERCEPTOR(uptr, strnlen, const char *s, uptr maxlen) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700612 void *ctx;
613 ASAN_INTERCEPTOR_ENTER(ctx, strnlen);
Kostya Serebryanye1301912011-12-05 18:56:29 +0000614 ENSURE_ASAN_INITED();
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000615 uptr length = REAL(strnlen)(s, maxlen);
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +0000616 if (flags()->replace_str) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700617 ASAN_READ_RANGE(ctx, s, Min(length + 1, maxlen));
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000618 }
619 return length;
620}
Alexey Samsonov81a7a4a2012-03-24 09:10:50 +0000621#endif // ASAN_INTERCEPT_STRNLEN
Kostya Serebryany547652c2012-01-09 19:35:11 +0000622
Alexey Samsonov847f9322012-03-29 08:04:35 +0000623INTERCEPTOR(long, strtol, const char *nptr, // NOLINT
624 char **endptr, int base) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700625 void *ctx;
626 ASAN_INTERCEPTOR_ENTER(ctx, strtol);
Alexey Samsonov847f9322012-03-29 08:04:35 +0000627 ENSURE_ASAN_INITED();
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +0000628 if (!flags()->replace_str) {
Alexey Samsonov847f9322012-03-29 08:04:35 +0000629 return REAL(strtol)(nptr, endptr, base);
630 }
631 char *real_endptr;
632 long result = REAL(strtol)(nptr, &real_endptr, base); // NOLINT
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700633 StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
Alexey Samsonov847f9322012-03-29 08:04:35 +0000634 return result;
635}
636
637INTERCEPTOR(int, atoi, const char *nptr) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700638 void *ctx;
639 ASAN_INTERCEPTOR_ENTER(ctx, atoi);
Evgeniy Stepanov24e13722013-03-19 14:33:38 +0000640#if SANITIZER_MAC
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700641 if (UNLIKELY(!asan_inited)) return REAL(atoi)(nptr);
Alexander Potapenko0ef53102012-08-17 09:00:08 +0000642#endif
Alexey Samsonov847f9322012-03-29 08:04:35 +0000643 ENSURE_ASAN_INITED();
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +0000644 if (!flags()->replace_str) {
Alexey Samsonov847f9322012-03-29 08:04:35 +0000645 return REAL(atoi)(nptr);
646 }
647 char *real_endptr;
648 // "man atoi" tells that behavior of atoi(nptr) is the same as
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000649 // strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the
Alexey Samsonov847f9322012-03-29 08:04:35 +0000650 // parsed integer can't be stored in *long* type (even if it's
651 // different from int). So, we just imitate this behavior.
652 int result = REAL(strtol)(nptr, &real_endptr, 10);
653 FixRealStrtolEndptr(nptr, &real_endptr);
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700654 ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
Alexey Samsonov847f9322012-03-29 08:04:35 +0000655 return result;
656}
657
658INTERCEPTOR(long, atol, const char *nptr) { // NOLINT
Stephen Hines86277eb2015-03-23 12:06:32 -0700659 void *ctx;
660 ASAN_INTERCEPTOR_ENTER(ctx, atol);
Evgeniy Stepanov24e13722013-03-19 14:33:38 +0000661#if SANITIZER_MAC
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700662 if (UNLIKELY(!asan_inited)) return REAL(atol)(nptr);
Alexander Potapenko0ef53102012-08-17 09:00:08 +0000663#endif
Alexey Samsonov847f9322012-03-29 08:04:35 +0000664 ENSURE_ASAN_INITED();
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +0000665 if (!flags()->replace_str) {
Alexey Samsonov847f9322012-03-29 08:04:35 +0000666 return REAL(atol)(nptr);
667 }
668 char *real_endptr;
669 long result = REAL(strtol)(nptr, &real_endptr, 10); // NOLINT
670 FixRealStrtolEndptr(nptr, &real_endptr);
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700671 ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
Alexey Samsonov847f9322012-03-29 08:04:35 +0000672 return result;
673}
674
675#if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
Alexey Samsonov84ba3242012-03-24 08:39:14 +0000676INTERCEPTOR(long long, strtoll, const char *nptr, // NOLINT
677 char **endptr, int base) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700678 void *ctx;
679 ASAN_INTERCEPTOR_ENTER(ctx, strtoll);
Alexey Samsonov84ba3242012-03-24 08:39:14 +0000680 ENSURE_ASAN_INITED();
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +0000681 if (!flags()->replace_str) {
Alexey Samsonov84ba3242012-03-24 08:39:14 +0000682 return REAL(strtoll)(nptr, endptr, base);
683 }
684 char *real_endptr;
685 long long result = REAL(strtoll)(nptr, &real_endptr, base); // NOLINT
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700686 StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
Alexey Samsonov84ba3242012-03-24 08:39:14 +0000687 return result;
688}
Alexey Samsonov84ba3242012-03-24 08:39:14 +0000689
Alexey Samsonov847f9322012-03-29 08:04:35 +0000690INTERCEPTOR(long long, atoll, const char *nptr) { // NOLINT
Stephen Hines86277eb2015-03-23 12:06:32 -0700691 void *ctx;
692 ASAN_INTERCEPTOR_ENTER(ctx, atoll);
Alexey Samsonov8f6a77f2012-03-26 16:42:22 +0000693 ENSURE_ASAN_INITED();
Alexey Samsonovcb8c4dc2012-07-09 14:36:04 +0000694 if (!flags()->replace_str) {
Alexey Samsonov847f9322012-03-29 08:04:35 +0000695 return REAL(atoll)(nptr);
Alexey Samsonov8f6a77f2012-03-26 16:42:22 +0000696 }
697 char *real_endptr;
Alexey Samsonov847f9322012-03-29 08:04:35 +0000698 long long result = REAL(strtoll)(nptr, &real_endptr, 10); // NOLINT
699 FixRealStrtolEndptr(nptr, &real_endptr);
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700700 ASAN_READ_STRING(ctx, nptr, (real_endptr - nptr) + 1);
Alexey Samsonov8f6a77f2012-03-26 16:42:22 +0000701 return result;
702}
Alexey Samsonov847f9322012-03-29 08:04:35 +0000703#endif // ASAN_INTERCEPT_ATOLL_AND_STRTOLL
Alexey Samsonov8f6a77f2012-03-26 16:42:22 +0000704
Alexey Samsonov46efcb02013-05-24 11:46:56 +0000705static void AtCxaAtexit(void *unused) {
706 (void)unused;
707 StopInitOrderChecking();
708}
709
710#if ASAN_INTERCEPT___CXA_ATEXIT
711INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
712 void *dso_handle) {
Alexander Potapenkob527f7d2013-11-13 13:34:53 +0000713#if SANITIZER_MAC
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700714 if (UNLIKELY(!asan_inited)) return REAL(__cxa_atexit)(func, arg, dso_handle);
Alexander Potapenkob527f7d2013-11-13 13:34:53 +0000715#endif
Alexey Samsonov46efcb02013-05-24 11:46:56 +0000716 ENSURE_ASAN_INITED();
717 int res = REAL(__cxa_atexit)(func, arg, dso_handle);
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800718 REAL(__cxa_atexit)(AtCxaAtexit, nullptr, nullptr);
Alexey Samsonov46efcb02013-05-24 11:46:56 +0000719 return res;
720}
721#endif // ASAN_INTERCEPT___CXA_ATEXIT
722
Stephen Hines6a211c52014-07-21 00:49:56 -0700723#if ASAN_INTERCEPT_FORK
724INTERCEPTOR(int, fork, void) {
725 ENSURE_ASAN_INITED();
726 if (common_flags()->coverage) CovBeforeFork();
727 int pid = REAL(fork)();
728 if (common_flags()->coverage) CovAfterFork(pid);
729 return pid;
730}
731#endif // ASAN_INTERCEPT_FORK
732
Kostya Serebryany547652c2012-01-09 19:35:11 +0000733// ---------------------- InitializeAsanInterceptors ---------------- {{{1
734namespace __asan {
735void InitializeAsanInterceptors() {
Kostya Serebryanyfdbdab52012-03-16 21:02:13 +0000736 static bool was_called_once;
737 CHECK(was_called_once == false);
738 was_called_once = true;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700739 InitializeCommonInterceptors();
Kostya Serebryany8530e2b2012-12-12 09:54:35 +0000740
Timur Iskhodzhanov07bb9f12012-02-22 13:59:49 +0000741 // Intercept mem* functions.
Dmitry Vyukov580469d2012-05-24 13:54:31 +0000742 ASAN_INTERCEPT_FUNC(memmove);
743 ASAN_INTERCEPT_FUNC(memset);
Alexey Samsonov38dd4ed2012-03-20 10:54:40 +0000744 if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) {
Dmitry Vyukov580469d2012-05-24 13:54:31 +0000745 ASAN_INTERCEPT_FUNC(memcpy);
Alexander Potapenko573fb4b2012-02-01 10:07:52 +0000746 }
Timur Iskhodzhanov07bb9f12012-02-22 13:59:49 +0000747
748 // Intercept str* functions.
Dmitry Vyukov580469d2012-05-24 13:54:31 +0000749 ASAN_INTERCEPT_FUNC(strcat); // NOLINT
750 ASAN_INTERCEPT_FUNC(strchr);
Dmitry Vyukov580469d2012-05-24 13:54:31 +0000751 ASAN_INTERCEPT_FUNC(strcpy); // NOLINT
752 ASAN_INTERCEPT_FUNC(strlen);
Reid Klecknerb99228d2013-09-05 01:13:49 +0000753 ASAN_INTERCEPT_FUNC(wcslen);
Alexey Samsonovc1bdd5a2012-06-08 13:27:46 +0000754 ASAN_INTERCEPT_FUNC(strncat);
Dmitry Vyukov580469d2012-05-24 13:54:31 +0000755 ASAN_INTERCEPT_FUNC(strncpy);
Alexey Samsonovfd2ae4f2012-08-01 11:17:00 +0000756#if ASAN_INTERCEPT_STRDUP
757 ASAN_INTERCEPT_FUNC(strdup);
758#endif
759#if ASAN_INTERCEPT_STRNLEN
760 ASAN_INTERCEPT_FUNC(strnlen);
761#endif
Alexander Potapenko69563982013-02-05 15:57:12 +0000762#if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
Dmitry Vyukov580469d2012-05-24 13:54:31 +0000763 ASAN_INTERCEPT_FUNC(index);
Timur Iskhodzhanov07bb9f12012-02-22 13:59:49 +0000764#endif
Kostya Serebryany547652c2012-01-09 19:35:11 +0000765
Dmitry Vyukov580469d2012-05-24 13:54:31 +0000766 ASAN_INTERCEPT_FUNC(atoi);
767 ASAN_INTERCEPT_FUNC(atol);
768 ASAN_INTERCEPT_FUNC(strtol);
Alexey Samsonov847f9322012-03-29 08:04:35 +0000769#if ASAN_INTERCEPT_ATOLL_AND_STRTOLL
Dmitry Vyukov580469d2012-05-24 13:54:31 +0000770 ASAN_INTERCEPT_FUNC(atoll);
771 ASAN_INTERCEPT_FUNC(strtoll);
Alexey Samsonov84ba3242012-03-24 08:39:14 +0000772#endif
773
Timur Iskhodzhanov07bb9f12012-02-22 13:59:49 +0000774 // Intecept signal- and jump-related functions.
Dmitry Vyukov580469d2012-05-24 13:54:31 +0000775 ASAN_INTERCEPT_FUNC(longjmp);
Alexey Samsonov34a32022012-03-26 09:07:29 +0000776#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
Dmitry Vyukov580469d2012-05-24 13:54:31 +0000777 ASAN_INTERCEPT_FUNC(sigaction);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700778#if SANITIZER_ANDROID
779 ASAN_INTERCEPT_FUNC(bsd_signal);
Evgeniy Stepanov919c2472012-02-13 12:04:36 +0000780#endif
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800781 ASAN_INTERCEPT_FUNC(signal);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700782#endif
Alexey Samsonov08700282012-11-23 09:46:34 +0000783#if ASAN_INTERCEPT_SWAPCONTEXT
784 ASAN_INTERCEPT_FUNC(swapcontext);
785#endif
Alexey Samsonovfd2ae4f2012-08-01 11:17:00 +0000786#if ASAN_INTERCEPT__LONGJMP
Dmitry Vyukov580469d2012-05-24 13:54:31 +0000787 ASAN_INTERCEPT_FUNC(_longjmp);
Alexey Samsonovfd2ae4f2012-08-01 11:17:00 +0000788#endif
789#if ASAN_INTERCEPT_SIGLONGJMP
Dmitry Vyukov580469d2012-05-24 13:54:31 +0000790 ASAN_INTERCEPT_FUNC(siglongjmp);
Alexey Samsonovfd2ae4f2012-08-01 11:17:00 +0000791#endif
792
793 // Intercept exception handling functions.
794#if ASAN_INTERCEPT___CXA_THROW
Stephen Hines6d186232014-11-26 17:56:19 -0800795 ASAN_INTERCEPT_FUNC(__cxa_throw);
Timur Iskhodzhanov3e81fe42012-02-09 17:20:14 +0000796#endif
797
Timur Iskhodzhanov07bb9f12012-02-22 13:59:49 +0000798 // Intercept threading-related functions
Alexey Samsonovfd2ae4f2012-08-01 11:17:00 +0000799#if ASAN_INTERCEPT_PTHREAD_CREATE
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800800#if defined(ASAN_PTHREAD_CREATE_VERSION)
801 ASAN_INTERCEPT_FUNC_VER(pthread_create, ASAN_PTHREAD_CREATE_VERSION);
802#else
Dmitry Vyukov580469d2012-05-24 13:54:31 +0000803 ASAN_INTERCEPT_FUNC(pthread_create);
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800804#endif
Stephen Hines86277eb2015-03-23 12:06:32 -0700805 ASAN_INTERCEPT_FUNC(pthread_join);
Timur Iskhodzhanov07bb9f12012-02-22 13:59:49 +0000806#endif
807
Alexey Samsonov46efcb02013-05-24 11:46:56 +0000808 // Intercept atexit function.
809#if ASAN_INTERCEPT___CXA_ATEXIT
810 ASAN_INTERCEPT_FUNC(__cxa_atexit);
811#endif
812
Stephen Hines6a211c52014-07-21 00:49:56 -0700813#if ASAN_INTERCEPT_FORK
814 ASAN_INTERCEPT_FUNC(fork);
815#endif
816
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700817 InitializePlatformInterceptors();
Timur Iskhodzhanov600972e2012-02-24 15:28:43 +0000818
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700819 VReport(1, "AddressSanitizer: libc interceptors initialized\n");
Kostya Serebryany547652c2012-01-09 19:35:11 +0000820}
821
Pirama Arumuga Nainar799172d2016-03-03 15:50:30 -0800822} // namespace __asan