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 COMMON_INTERCEPT_FUNCTION_VER(name, ver) \
56 MEMPROF_INTERCEPT_FUNC_VER(name, ver)
57 #define COMMON_INTERCEPT_FUNCTION_VER_UNVERSIONED_FALLBACK(name, ver) \
58 MEMPROF_INTERCEPT_FUNC_VER_UNVERSIONED_FALLBACK(name, ver)
59 #define COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, size) \
60 MEMPROF_WRITE_RANGE(ptr, size)
61 #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
62 MEMPROF_READ_RANGE(ptr, size)
63 #define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
64 MEMPROF_INTERCEPTOR_ENTER(ctx, func); \
66 if (memprof_init_is_running) \
67 return REAL(func)(__VA_ARGS__); \
68 ENSURE_MEMPROF_INITED(); \
70 #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
73 #define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
76 #define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
79 #define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
82 #define COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, name) SetThreadName(name)
83 // Should be memprofThreadRegistry().SetThreadNameByUserId(thread, name)
84 // But memprof does not remember UserId's for threads (pthread_t);
85 // and remembers all ever existed threads, so the linear search by UserId
87 #define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
90 #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
91 #define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
92 #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle)
93 #define COMMON_INTERCEPTOR_LIBRARY_UNLOADED()
94 #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!memprof_inited)
95 #define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
96 if (MemprofThread *t = GetCurrentThread()) { \
97 *begin = t->tls_begin(); \
98 *end = t->tls_end(); \
103 #include "sanitizer_common/sanitizer_common_interceptors.inc"
105 #define COMMON_SYSCALL_PRE_READ_RANGE(p, s) MEMPROF_READ_RANGE(p, s)
106 #define COMMON_SYSCALL_PRE_WRITE_RANGE(p, s) MEMPROF_WRITE_RANGE(p, s)
107 #define COMMON_SYSCALL_POST_READ_RANGE(p, s) \
112 #define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
117 #include "sanitizer_common/sanitizer_common_syscalls.inc"
119 struct ThreadStartParam
{
121 atomic_uintptr_t is_registered
;
124 static thread_return_t THREAD_CALLING_CONV
memprof_thread_start(void *arg
) {
125 ThreadStartParam
*param
= reinterpret_cast<ThreadStartParam
*>(arg
);
126 MemprofThread
*t
= nullptr;
127 while ((t
= reinterpret_cast<MemprofThread
*>(
128 atomic_load(¶m
->t
, memory_order_acquire
))) == nullptr)
129 internal_sched_yield();
131 return t
->ThreadStart(GetTid(), ¶m
->is_registered
);
134 INTERCEPTOR(int, pthread_create
, void *thread
, void *attr
,
135 void *(*start_routine
)(void *), void *arg
) {
136 EnsureMainThreadIDIsCorrect();
137 GET_STACK_TRACE_THREAD
;
140 REAL(pthread_attr_getdetachstate
)(attr
, &detached
);
141 ThreadStartParam param
;
142 atomic_store(¶m
.t
, 0, memory_order_relaxed
);
143 atomic_store(¶m
.is_registered
, 0, memory_order_relaxed
);
146 // Ignore all allocations made by pthread_create: thread stack/TLS may be
147 // stored by pthread for future reuse even after thread destruction, and
148 // the linked list it's stored in doesn't even hold valid pointers to the
149 // objects, the latter are calculated by obscure pointer arithmetic.
150 result
= REAL(pthread_create
)(thread
, attr
, memprof_thread_start
, ¶m
);
153 u32 current_tid
= GetCurrentTidOrInvalid();
154 MemprofThread
*t
= MemprofThread::Create(start_routine
, arg
, current_tid
,
156 atomic_store(¶m
.t
, reinterpret_cast<uptr
>(t
), memory_order_release
);
157 // Wait until the MemprofThread object is initialized and the
158 // ThreadRegistry entry is in "started" state.
159 while (atomic_load(¶m
.is_registered
, memory_order_acquire
) == 0)
160 internal_sched_yield();
165 INTERCEPTOR(int, pthread_join
, void *t
, void **arg
) {
166 return REAL(pthread_join
)(t
, arg
);
169 DEFINE_INTERNAL_PTHREAD_FUNCTIONS
171 INTERCEPTOR(char *, index
, const char *string
, int c
)
174 // For both strcat() and strncat() we need to check the validity of |to|
175 // argument irrespective of the |from| length.
176 INTERCEPTOR(char *, strcat
, char *to
, const char *from
) {
178 MEMPROF_INTERCEPTOR_ENTER(ctx
, strcat
);
179 ENSURE_MEMPROF_INITED();
180 uptr from_length
= internal_strlen(from
);
181 MEMPROF_READ_RANGE(from
, from_length
+ 1);
182 uptr to_length
= internal_strlen(to
);
183 MEMPROF_READ_STRING(to
, to_length
);
184 MEMPROF_WRITE_RANGE(to
+ to_length
, from_length
+ 1);
185 return REAL(strcat
)(to
, from
);
188 INTERCEPTOR(char *, strncat
, char *to
, const char *from
, uptr size
) {
190 MEMPROF_INTERCEPTOR_ENTER(ctx
, strncat
);
191 ENSURE_MEMPROF_INITED();
192 uptr from_length
= MaybeRealStrnlen(from
, size
);
193 uptr copy_length
= Min(size
, from_length
+ 1);
194 MEMPROF_READ_RANGE(from
, copy_length
);
195 uptr to_length
= internal_strlen(to
);
196 MEMPROF_READ_STRING(to
, to_length
);
197 MEMPROF_WRITE_RANGE(to
+ to_length
, from_length
+ 1);
198 return REAL(strncat
)(to
, from
, size
);
201 INTERCEPTOR(char *, strcpy
, char *to
, const char *from
) {
203 MEMPROF_INTERCEPTOR_ENTER(ctx
, strcpy
);
204 if (memprof_init_is_running
) {
205 return REAL(strcpy
)(to
, from
);
207 ENSURE_MEMPROF_INITED();
208 uptr from_size
= internal_strlen(from
) + 1;
209 MEMPROF_READ_RANGE(from
, from_size
);
210 MEMPROF_WRITE_RANGE(to
, from_size
);
211 return REAL(strcpy
)(to
, from
);
214 INTERCEPTOR(char *, strdup
, const char *s
) {
216 MEMPROF_INTERCEPTOR_ENTER(ctx
, strdup
);
217 if (UNLIKELY(!memprof_inited
))
218 return internal_strdup(s
);
219 ENSURE_MEMPROF_INITED();
220 uptr length
= internal_strlen(s
);
221 MEMPROF_READ_RANGE(s
, length
+ 1);
222 GET_STACK_TRACE_MALLOC
;
223 void *new_mem
= memprof_malloc(length
+ 1, &stack
);
224 REAL(memcpy
)(new_mem
, s
, length
+ 1);
225 return reinterpret_cast<char *>(new_mem
);
228 INTERCEPTOR(char *, __strdup
, const char *s
) {
230 MEMPROF_INTERCEPTOR_ENTER(ctx
, strdup
);
231 if (UNLIKELY(!memprof_inited
))
232 return internal_strdup(s
);
233 ENSURE_MEMPROF_INITED();
234 uptr length
= internal_strlen(s
);
235 MEMPROF_READ_RANGE(s
, length
+ 1);
236 GET_STACK_TRACE_MALLOC
;
237 void *new_mem
= memprof_malloc(length
+ 1, &stack
);
238 REAL(memcpy
)(new_mem
, s
, length
+ 1);
239 return reinterpret_cast<char *>(new_mem
);
242 INTERCEPTOR(char *, strncpy
, char *to
, const char *from
, uptr size
) {
244 MEMPROF_INTERCEPTOR_ENTER(ctx
, strncpy
);
245 ENSURE_MEMPROF_INITED();
246 uptr from_size
= Min(size
, MaybeRealStrnlen(from
, size
) + 1);
247 MEMPROF_READ_RANGE(from
, from_size
);
248 MEMPROF_WRITE_RANGE(to
, size
);
249 return REAL(strncpy
)(to
, from
, size
);
252 INTERCEPTOR(long, strtol
, const char *nptr
, char **endptr
, int base
) {
254 MEMPROF_INTERCEPTOR_ENTER(ctx
, strtol
);
255 ENSURE_MEMPROF_INITED();
257 long result
= REAL(strtol
)(nptr
, &real_endptr
, base
);
258 StrtolFixAndCheck(ctx
, nptr
, endptr
, real_endptr
, base
);
262 INTERCEPTOR(int, atoi
, const char *nptr
) {
264 MEMPROF_INTERCEPTOR_ENTER(ctx
, atoi
);
265 ENSURE_MEMPROF_INITED();
267 // "man atoi" tells that behavior of atoi(nptr) is the same as
268 // strtol(nptr, 0, 10), i.e. it sets errno to ERANGE if the
269 // parsed integer can't be stored in *long* type (even if it's
270 // different from int). So, we just imitate this behavior.
271 int result
= REAL(strtol
)(nptr
, &real_endptr
, 10);
272 FixRealStrtolEndptr(nptr
, &real_endptr
);
273 MEMPROF_READ_STRING(nptr
, (real_endptr
- nptr
) + 1);
277 INTERCEPTOR(long, atol
, const char *nptr
) {
279 MEMPROF_INTERCEPTOR_ENTER(ctx
, atol
);
280 ENSURE_MEMPROF_INITED();
282 long result
= REAL(strtol
)(nptr
, &real_endptr
, 10);
283 FixRealStrtolEndptr(nptr
, &real_endptr
);
284 MEMPROF_READ_STRING(nptr
, (real_endptr
- nptr
) + 1);
288 INTERCEPTOR(long long, strtoll
, const char *nptr
, char **endptr
, int base
) {
290 MEMPROF_INTERCEPTOR_ENTER(ctx
, strtoll
);
291 ENSURE_MEMPROF_INITED();
293 long long result
= REAL(strtoll
)(nptr
, &real_endptr
, base
);
294 StrtolFixAndCheck(ctx
, nptr
, endptr
, real_endptr
, base
);
298 INTERCEPTOR(long long, atoll
, const char *nptr
) {
300 MEMPROF_INTERCEPTOR_ENTER(ctx
, atoll
);
301 ENSURE_MEMPROF_INITED();
303 long long result
= REAL(strtoll
)(nptr
, &real_endptr
, 10);
304 FixRealStrtolEndptr(nptr
, &real_endptr
);
305 MEMPROF_READ_STRING(nptr
, (real_endptr
- nptr
) + 1);
309 // ---------------------- InitializeMemprofInterceptors ---------------- {{{1
310 namespace __memprof
{
311 void InitializeMemprofInterceptors() {
312 static bool was_called_once
;
313 CHECK(!was_called_once
);
314 was_called_once
= true;
315 InitializeCommonInterceptors();
317 // Intercept str* functions.
318 MEMPROF_INTERCEPT_FUNC(strcat
);
319 MEMPROF_INTERCEPT_FUNC(strcpy
);
320 MEMPROF_INTERCEPT_FUNC(strncat
);
321 MEMPROF_INTERCEPT_FUNC(strncpy
);
322 MEMPROF_INTERCEPT_FUNC(strdup
);
323 MEMPROF_INTERCEPT_FUNC(__strdup
);
324 MEMPROF_INTERCEPT_FUNC(index
);
326 MEMPROF_INTERCEPT_FUNC(atoi
);
327 MEMPROF_INTERCEPT_FUNC(atol
);
328 MEMPROF_INTERCEPT_FUNC(strtol
);
329 MEMPROF_INTERCEPT_FUNC(atoll
);
330 MEMPROF_INTERCEPT_FUNC(strtoll
);
332 // Intercept threading-related functions
333 MEMPROF_INTERCEPT_FUNC(pthread_create
);
334 MEMPROF_INTERCEPT_FUNC(pthread_join
);
336 InitializePlatformInterceptors();
338 VReport(1, "MemProfiler: libc interceptors initialized\n");
341 } // namespace __memprof