Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/memprof/memprof_interceptors.cpp
35236 views
1
//===-- memprof_interceptors.cpp -----------------------------------------===//
2
//
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
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file is a part of MemProfiler, a memory profiler.
10
//
11
// Intercept various libc functions.
12
//===----------------------------------------------------------------------===//
13
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"
22
23
namespace __memprof {
24
25
#define MEMPROF_READ_STRING(s, n) MEMPROF_READ_RANGE((s), (n))
26
27
static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
28
#if SANITIZER_INTERCEPT_STRNLEN
29
if (REAL(strnlen)) {
30
return REAL(strnlen)(s, maxlen);
31
}
32
#endif
33
return internal_strnlen(s, maxlen);
34
}
35
36
void SetThreadName(const char *name) {
37
MemprofThread *t = GetCurrentThread();
38
if (t)
39
memprofThreadRegistry().SetThreadName(t->tid(), name);
40
}
41
42
int OnExit() {
43
// FIXME: ask frontend whether we need to return failure.
44
return 0;
45
}
46
47
} // namespace __memprof
48
49
// ---------------------- Wrappers ---------------- {{{1
50
using namespace __memprof;
51
52
DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr)
53
DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
54
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); \
65
do { \
66
if (memprof_init_is_running) \
67
return REAL(func)(__VA_ARGS__); \
68
ENSURE_MEMPROF_INITED(); \
69
} while (false)
70
#define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
71
do { \
72
} while (false)
73
#define COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd) \
74
do { \
75
} while (false)
76
#define COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd) \
77
do { \
78
} while (false)
79
#define COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, newfd) \
80
do { \
81
} while (false)
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
86
// can be slow.
87
#define COMMON_INTERCEPTOR_SET_PTHREAD_NAME(ctx, thread, name) \
88
do { \
89
} while (false)
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(); \
99
} else { \
100
*begin = *end = 0; \
101
}
102
103
#include "sanitizer_common/sanitizer_common_interceptors.inc"
104
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) \
108
do { \
109
(void)(p); \
110
(void)(s); \
111
} while (false)
112
#define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) \
113
do { \
114
(void)(p); \
115
(void)(s); \
116
} while (false)
117
#include "sanitizer_common/sanitizer_common_syscalls.inc"
118
119
struct ThreadStartParam {
120
atomic_uintptr_t t;
121
atomic_uintptr_t is_registered;
122
};
123
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(&param->t, memory_order_acquire))) == nullptr)
129
internal_sched_yield();
130
SetCurrentThread(t);
131
return t->ThreadStart(GetTid(), &param->is_registered);
132
}
133
134
INTERCEPTOR(int, pthread_create, void *thread, void *attr,
135
void *(*start_routine)(void *), void *arg) {
136
EnsureMainThreadIDIsCorrect();
137
GET_STACK_TRACE_THREAD;
138
int detached = 0;
139
if (attr)
140
REAL(pthread_attr_getdetachstate)(attr, &detached);
141
ThreadStartParam param;
142
atomic_store(&param.t, 0, memory_order_relaxed);
143
atomic_store(&param.is_registered, 0, memory_order_relaxed);
144
int result;
145
{
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, &param);
151
}
152
if (result == 0) {
153
u32 current_tid = GetCurrentTidOrInvalid();
154
MemprofThread *t = MemprofThread::Create(start_routine, arg, current_tid,
155
&stack, detached);
156
atomic_store(&param.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(&param.is_registered, memory_order_acquire) == 0)
160
internal_sched_yield();
161
}
162
return result;
163
}
164
165
INTERCEPTOR(int, pthread_join, void *t, void **arg) {
166
return REAL(pthread_join)(t, arg);
167
}
168
169
DEFINE_INTERNAL_PTHREAD_FUNCTIONS
170
171
INTERCEPTOR(char *, index, const char *string, int c)
172
ALIAS(WRAP(strchr));
173
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) {
177
void *ctx;
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);
186
}
187
188
INTERCEPTOR(char *, strncat, char *to, const char *from, uptr size) {
189
void *ctx;
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);
199
}
200
201
INTERCEPTOR(char *, strcpy, char *to, const char *from) {
202
void *ctx;
203
MEMPROF_INTERCEPTOR_ENTER(ctx, strcpy);
204
if (memprof_init_is_running) {
205
return REAL(strcpy)(to, from);
206
}
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);
212
}
213
214
INTERCEPTOR(char *, strdup, const char *s) {
215
void *ctx;
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);
226
}
227
228
INTERCEPTOR(char *, __strdup, const char *s) {
229
void *ctx;
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);
240
}
241
242
INTERCEPTOR(char *, strncpy, char *to, const char *from, uptr size) {
243
void *ctx;
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);
250
}
251
252
INTERCEPTOR(long, strtol, const char *nptr, char **endptr, int base) {
253
void *ctx;
254
MEMPROF_INTERCEPTOR_ENTER(ctx, strtol);
255
ENSURE_MEMPROF_INITED();
256
char *real_endptr;
257
long result = REAL(strtol)(nptr, &real_endptr, base);
258
StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
259
return result;
260
}
261
262
INTERCEPTOR(int, atoi, const char *nptr) {
263
void *ctx;
264
MEMPROF_INTERCEPTOR_ENTER(ctx, atoi);
265
ENSURE_MEMPROF_INITED();
266
char *real_endptr;
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);
274
return result;
275
}
276
277
INTERCEPTOR(long, atol, const char *nptr) {
278
void *ctx;
279
MEMPROF_INTERCEPTOR_ENTER(ctx, atol);
280
ENSURE_MEMPROF_INITED();
281
char *real_endptr;
282
long result = REAL(strtol)(nptr, &real_endptr, 10);
283
FixRealStrtolEndptr(nptr, &real_endptr);
284
MEMPROF_READ_STRING(nptr, (real_endptr - nptr) + 1);
285
return result;
286
}
287
288
INTERCEPTOR(long long, strtoll, const char *nptr, char **endptr, int base) {
289
void *ctx;
290
MEMPROF_INTERCEPTOR_ENTER(ctx, strtoll);
291
ENSURE_MEMPROF_INITED();
292
char *real_endptr;
293
long long result = REAL(strtoll)(nptr, &real_endptr, base);
294
StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
295
return result;
296
}
297
298
INTERCEPTOR(long long, atoll, const char *nptr) {
299
void *ctx;
300
MEMPROF_INTERCEPTOR_ENTER(ctx, atoll);
301
ENSURE_MEMPROF_INITED();
302
char *real_endptr;
303
long long result = REAL(strtoll)(nptr, &real_endptr, 10);
304
FixRealStrtolEndptr(nptr, &real_endptr);
305
MEMPROF_READ_STRING(nptr, (real_endptr - nptr) + 1);
306
return result;
307
}
308
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();
316
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);
325
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);
331
332
// Intercept threading-related functions
333
MEMPROF_INTERCEPT_FUNC(pthread_create);
334
MEMPROF_INTERCEPT_FUNC(pthread_join);
335
336
InitializePlatformInterceptors();
337
338
VReport(1, "MemProfiler: libc interceptors initialized\n");
339
}
340
341
} // namespace __memprof
342
343