1 //===-- memprof_interceptors.cpp -----------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file is a part of MemProfiler, a memory profiler.
11 // Intercept various libc functions.
12 //===----------------------------------------------------------------------===//
14 #include "memprof_interceptors.h"
15 #include "memprof_allocator.h"
16 #include "memprof_internal.h"
17 #include "memprof_mapping.h"
18 #include "memprof_stack.h"
19 #include "memprof_stats.h"
20 #include "sanitizer_common/sanitizer_libc.h"
21 #include "sanitizer_common/sanitizer_posix.h"
25 #define MEMPROF_READ_STRING(s, n) MEMPROF_READ_RANGE((s), (n))
27 static inline uptr
MaybeRealStrnlen(const char *s
, uptr maxlen
) {
28 #if SANITIZER_INTERCEPT_STRNLEN
30 return REAL(strnlen
)(s
, maxlen
);
33 return internal_strnlen(s
, maxlen
);
36 void SetThreadName(const char *name
) {
37 MemprofThread
*t
= GetCurrentThread();
39 memprofThreadRegistry().SetThreadName(t
->tid(), name
);
43 // FIXME: ask frontend whether we need to return failure.
47 } // namespace __memprof
49 // ---------------------- Wrappers ---------------- {{{1
50 using namespace __memprof
;
52 DECLARE_REAL_AND_INTERCEPTOR(void *, malloc
, uptr
)
53 DECLARE_REAL_AND_INTERCEPTOR(void, free
, void *)
55 #define MEMPROF_INTERCEPTOR_ENTER(ctx, func) \
59 #define COMMON_INTERCEPT_FUNCTION(name) MEMPROF_INTERCEPT_FUNC(name)
60 #define COMMON_INTERCEPT_FUNCTION_VER(name, ver) \
61 MEMPROF_INTERCEPT_FUNC_VER(name, ver)
62 #define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver) \
63 MEMPROF_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver)
64 #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
65 MEMPROF_WRITE_RANGE(ptr, size)
66 #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
67 MEMPROF_READ_RANGE(ptr, size)
68 #define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
69 MEMPROF_INTERCEPTOR_ENTER(ctx, func); \
71 if (memprof_init_is_running) \
72 return REAL(func)(__VA_ARGS__); \
73 ENSURE_MEMPROF_INITED(); \
75 #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
78 #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
81 #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
84 #define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
87 #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)
88 // Should be memprofThreadRegistry().SetThreadNameByUserId(thread, name)
89 // But memprof does not remember UserId's for threads (pthread_t);
90 // and remembers all ever existed threads, so the linear search by UserId
92 #define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
95 #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
96 #define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
97 #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle)
98 #define COMMON_INTERCEPTOR_LIBRARY_UNLOADED()
99 #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!memprof_inited)
100 #define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
101 if (MemprofThread *t = GetCurrentThread()) { \
102 *begin = t->tls_begin(); \
103 *end = t->tls_end(); \
108 #define COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size) \
110 MEMPROF_INTERCEPTOR_ENTER(ctx, memmove); \
111 MEMPROF_MEMMOVE_IMPL(to, from, size); \
114 #define COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size) \
116 MEMPROF_INTERCEPTOR_ENTER(ctx, memcpy); \
117 MEMPROF_MEMCPY_IMPL(to, from, size); \
120 #define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size) \
122 MEMPROF_INTERCEPTOR_ENTER(ctx, memset); \
123 MEMPROF_MEMSET_IMPL(block, c, size); \
126 #include "sanitizer_common/sanitizer_common_interceptors.inc"
128 #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) MEMPROF_READ_RANGE(p, s)
129 #define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) MEMPROF_WRITE_RANGE(p, s)
130 #define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
135 #define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
140 #include "sanitizer_common/sanitizer_common_syscalls.inc"
142 struct ThreadStartParam
{
144 atomic_uintptr_t is_registered
;
147 static thread_return_t THREAD_CALLING_CONV
memprof_thread_start(void *arg
) {
148 ThreadStartParam
*param
= reinterpret_cast<ThreadStartParam
*>(arg
);
149 MemprofThread
*t
= nullptr;
150 while ((t
= reinterpret_cast<MemprofThread
*>(
151 atomic_load(¶m
->t
, memory_order_acquire
))) == nullptr)
152 internal_sched_yield();
154 return t
->ThreadStart(GetTid(), ¶m
->is_registered
);
157 INTERCEPTOR(int, pthread_create
, void *thread
, void *attr
,
158 void *(*start_routine
)(void *), void *arg
) {
159 EnsureMainThreadIDIsCorrect();
160 GET_STACK_TRACE_THREAD
;
163 REAL(pthread_attr_getdetachstate
)(attr
, &detached
);
164 ThreadStartParam param
;
165 atomic_store(¶m
.t
, 0, memory_order_relaxed
);
166 atomic_store(¶m
.is_registered
, 0, memory_order_relaxed
);
169 // Ignore all allocations made by pthread_create: thread stack/TLS may be
170 // stored by pthread for future reuse even after thread destruction, and
171 // the linked list it's stored in doesn't even hold valid pointers to the
172 // objects, the latter are calculated by obscure pointer arithmetic.
173 result
= REAL(pthread_create
)(thread
, attr
, memprof_thread_start
, ¶m
);
176 u32 current_tid
= GetCurrentTidOrInvalid();
177 MemprofThread
*t
= MemprofThread::Create(start_routine
, arg
, current_tid
,
179 atomic_store(¶m
.t
, reinterpret_cast<uptr
>(t
), memory_order_release
);
180 // Wait until the MemprofThread object is initialized and the
181 // ThreadRegistry entry is in "started" state.
182 while (atomic_load(¶m
.is_registered
, memory_order_acquire
) == 0)
183 internal_sched_yield();
188 INTERCEPTOR(int, pthread_join
, void *t
, void **arg
) {
189 return real_pthread_join(t
, arg
);
192 DEFINE_REAL_PTHREAD_FUNCTIONS
194 INTERCEPTOR(char *, index
, const char *string
, int c
)
195 ALIAS(WRAPPER_NAME(strchr
));
197 // For both strcat() and strncat() we need to check the validity of |to|
198 // argument irrespective of the |from| length.
199 INTERCEPTOR(char *, strcat
, char *to
, const char *from
) {
201 MEMPROF_INTERCEPTOR_ENTER(ctx
, strcat
);
202 ENSURE_MEMPROF_INITED();
203 uptr from_length
= internal_strlen(from
);
204 MEMPROF_READ_RANGE(from
, from_length
+ 1);
205 uptr to_length
= internal_strlen(to
);
206 MEMPROF_READ_STRING(to
, to_length
);
207 MEMPROF_WRITE_RANGE(to
+ to_length
, from_length
+ 1);
208 return REAL(strcat
)(to
, from
);
211 INTERCEPTOR(char *, strncat
, char *to
, const char *from
, uptr size
) {
213 MEMPROF_INTERCEPTOR_ENTER(ctx
, strncat
);
214 ENSURE_MEMPROF_INITED();
215 uptr from_length
= MaybeRealStrnlen(from
, size
);
216 uptr copy_length
= Min(size
, from_length
+ 1);
217 MEMPROF_READ_RANGE(from
, copy_length
);
218 uptr to_length
= internal_strlen(to
);
219 MEMPROF_READ_STRING(to
, to_length
);
220 MEMPROF_WRITE_RANGE(to
+ to_length
, from_length
+ 1);
221 return REAL(strncat
)(to
, from
, size
);
224 INTERCEPTOR(char *, strcpy
, char *to
, const char *from
) {
226 MEMPROF_INTERCEPTOR_ENTER(ctx
, strcpy
);
227 if (memprof_init_is_running
) {
228 return REAL(strcpy
)(to
, from
);
230 ENSURE_MEMPROF_INITED();
231 uptr from_size
= internal_strlen(from
) + 1;
232 MEMPROF_READ_RANGE(from
, from_size
);
233 MEMPROF_WRITE_RANGE(to
, from_size
);
234 return REAL(strcpy
)(to
, from
);
237 INTERCEPTOR(char *, strdup
, const char *s
) {
239 MEMPROF_INTERCEPTOR_ENTER(ctx
, strdup
);
240 if (UNLIKELY(!memprof_inited
))
241 return internal_strdup(s
);
242 ENSURE_MEMPROF_INITED();
243 uptr length
= internal_strlen(s
);
244 MEMPROF_READ_RANGE(s
, length
+ 1);
245 GET_STACK_TRACE_MALLOC
;
246 void *new_mem
= memprof_malloc(length
+ 1, &stack
);
247 REAL(memcpy
)(new_mem
, s
, length
+ 1);
248 return reinterpret_cast<char *>(new_mem
);
251 INTERCEPTOR(char *, __strdup
, const char *s
) {
253 MEMPROF_INTERCEPTOR_ENTER(ctx
, strdup
);
254 if (UNLIKELY(!memprof_inited
))
255 return internal_strdup(s
);
256 ENSURE_MEMPROF_INITED();
257 uptr length
= internal_strlen(s
);
258 MEMPROF_READ_RANGE(s
, length
+ 1);
259 GET_STACK_TRACE_MALLOC
;
260 void *new_mem
= memprof_malloc(length
+ 1, &stack
);
261 REAL(memcpy
)(new_mem
, s
, length
+ 1);
262 return reinterpret_cast<char *>(new_mem
);
265 INTERCEPTOR(char *, strncpy
, char *to
, const char *from
, uptr size
) {
267 MEMPROF_INTERCEPTOR_ENTER(ctx
, strncpy
);
268 ENSURE_MEMPROF_INITED();
269 uptr from_size
= Min(size
, MaybeRealStrnlen(from
, size
) + 1);
270 MEMPROF_READ_RANGE(from
, from_size
);
271 MEMPROF_WRITE_RANGE(to
, size
);
272 return REAL(strncpy
)(to
, from
, size
);
275 INTERCEPTOR(long, strtol
, const char *nptr
, char **endptr
, int base
) {
277 MEMPROF_INTERCEPTOR_ENTER(ctx
, strtol
);
278 ENSURE_MEMPROF_INITED();
280 long result
= REAL(strtol
)(nptr
, &real_endptr
, base
);
281 StrtolFixAndCheck(ctx
, nptr
, endptr
, real_endptr
, base
);
285 INTERCEPTOR(int, atoi
, const char *nptr
) {
287 MEMPROF_INTERCEPTOR_ENTER(ctx
, atoi
);
288 ENSURE_MEMPROF_INITED();
290 // "man atoi" tells that behavior of atoi(nptr) is the same as
291 // strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the
292 // parsed integer can't be stored in *long* type (even if it's
293 // different from int). So, we just imitate this behavior.
294 int result
= REAL(strtol
)(nptr
, &real_endptr
, 10);
295 FixRealStrtolEndptr(nptr
, &real_endptr
);
296 MEMPROF_READ_STRING(nptr
, (real_endptr
- nptr
) + 1);
300 INTERCEPTOR(long, atol
, const char *nptr
) {
302 MEMPROF_INTERCEPTOR_ENTER(ctx
, atol
);
303 ENSURE_MEMPROF_INITED();
305 long result
= REAL(strtol
)(nptr
, &real_endptr
, 10);
306 FixRealStrtolEndptr(nptr
, &real_endptr
);
307 MEMPROF_READ_STRING(nptr
, (real_endptr
- nptr
) + 1);
311 INTERCEPTOR(long long, strtoll
, const char *nptr
, char **endptr
, int base
) {
313 MEMPROF_INTERCEPTOR_ENTER(ctx
, strtoll
);
314 ENSURE_MEMPROF_INITED();
316 long long result
= REAL(strtoll
)(nptr
, &real_endptr
, base
);
317 StrtolFixAndCheck(ctx
, nptr
, endptr
, real_endptr
, base
);
321 INTERCEPTOR(long long, atoll
, const char *nptr
) {
323 MEMPROF_INTERCEPTOR_ENTER(ctx
, atoll
);
324 ENSURE_MEMPROF_INITED();
326 long long result
= REAL(strtoll
)(nptr
, &real_endptr
, 10);
327 FixRealStrtolEndptr(nptr
, &real_endptr
);
328 MEMPROF_READ_STRING(nptr
, (real_endptr
- nptr
) + 1);
332 // ---------------------- InitializeMemprofInterceptors ---------------- {{{1
333 namespace __memprof
{
334 void InitializeMemprofInterceptors() {
335 static bool was_called_once
;
336 CHECK(!was_called_once
);
337 was_called_once
= true;
338 InitializeCommonInterceptors();
340 // Intercept str* functions.
341 MEMPROF_INTERCEPT_FUNC(strcat
);
342 MEMPROF_INTERCEPT_FUNC(strcpy
);
343 MEMPROF_INTERCEPT_FUNC(strncat
);
344 MEMPROF_INTERCEPT_FUNC(strncpy
);
345 MEMPROF_INTERCEPT_FUNC(strdup
);
346 MEMPROF_INTERCEPT_FUNC(__strdup
);
347 MEMPROF_INTERCEPT_FUNC(index
);
349 MEMPROF_INTERCEPT_FUNC(atoi
);
350 MEMPROF_INTERCEPT_FUNC(atol
);
351 MEMPROF_INTERCEPT_FUNC(strtol
);
352 MEMPROF_INTERCEPT_FUNC(atoll
);
353 MEMPROF_INTERCEPT_FUNC(strtoll
);
355 // Intercept threading-related functions
356 MEMPROF_INTERCEPT_FUNC(pthread_create
);
357 MEMPROF_INTERCEPT_FUNC(pthread_join
);
359 InitializePlatformInterceptors();
361 VReport(1, "MemProfiler: libc interceptors initialized\n");
364 } // namespace __memprof