Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp
35233 views
1
//===-- sanitizer_common.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 shared between AddressSanitizer and ThreadSanitizer
10
// run-time libraries.
11
//===----------------------------------------------------------------------===//
12
13
#include "sanitizer_common.h"
14
15
#include "sanitizer_allocator_interface.h"
16
#include "sanitizer_allocator_internal.h"
17
#include "sanitizer_atomic.h"
18
#include "sanitizer_flags.h"
19
#include "sanitizer_interface_internal.h"
20
#include "sanitizer_libc.h"
21
#include "sanitizer_placement_new.h"
22
23
namespace __sanitizer {
24
25
const char *SanitizerToolName = "SanitizerTool";
26
27
atomic_uint32_t current_verbosity;
28
uptr PageSizeCached;
29
u32 NumberOfCPUsCached;
30
31
// PID of the tracer task in StopTheWorld. It shares the address space with the
32
// main process, but has a different PID and thus requires special handling.
33
uptr stoptheworld_tracer_pid = 0;
34
// Cached pid of parent process - if the parent process dies, we want to keep
35
// writing to the same log file.
36
uptr stoptheworld_tracer_ppid = 0;
37
38
void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
39
const char *mmap_type, error_t err,
40
bool raw_report) {
41
static int recursion_count;
42
if (raw_report || recursion_count) {
43
// If raw report is requested or we went into recursion just die. The
44
// Report() and CHECK calls below may call mmap recursively and fail.
45
RawWrite("ERROR: Failed to mmap\n");
46
Die();
47
}
48
recursion_count++;
49
if (ErrorIsOOM(err)) {
50
ERROR_OOM("failed to %s 0x%zx (%zd) bytes of %s (error code: %d)\n",
51
mmap_type, size, size, mem_type, err);
52
} else {
53
Report(
54
"ERROR: %s failed to "
55
"%s 0x%zx (%zd) bytes of %s (error code: %d)\n",
56
SanitizerToolName, mmap_type, size, size, mem_type, err);
57
}
58
#if !SANITIZER_GO
59
DumpProcessMap();
60
#endif
61
UNREACHABLE("unable to mmap");
62
}
63
64
void NORETURN ReportMunmapFailureAndDie(void *addr, uptr size, error_t err,
65
bool raw_report) {
66
static int recursion_count;
67
if (raw_report || recursion_count) {
68
// If raw report is requested or we went into recursion just die. The
69
// Report() and CHECK calls below may call munmap recursively and fail.
70
RawWrite("ERROR: Failed to munmap\n");
71
Die();
72
}
73
recursion_count++;
74
Report(
75
"ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p (error "
76
"code: %d)\n",
77
SanitizerToolName, size, size, addr, err);
78
#if !SANITIZER_GO
79
DumpProcessMap();
80
#endif
81
UNREACHABLE("unable to unmmap");
82
}
83
84
typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
85
typedef bool U32ComparisonFunction(const u32 &a, const u32 &b);
86
87
const char *StripPathPrefix(const char *filepath,
88
const char *strip_path_prefix) {
89
if (!filepath) return nullptr;
90
if (!strip_path_prefix) return filepath;
91
const char *res = filepath;
92
if (const char *pos = internal_strstr(filepath, strip_path_prefix))
93
res = pos + internal_strlen(strip_path_prefix);
94
if (res[0] == '.' && res[1] == '/')
95
res += 2;
96
return res;
97
}
98
99
const char *StripModuleName(const char *module) {
100
if (!module)
101
return nullptr;
102
if (SANITIZER_WINDOWS) {
103
// On Windows, both slash and backslash are possible.
104
// Pick the one that goes last.
105
if (const char *bslash_pos = internal_strrchr(module, '\\'))
106
return StripModuleName(bslash_pos + 1);
107
}
108
if (const char *slash_pos = internal_strrchr(module, '/')) {
109
return slash_pos + 1;
110
}
111
return module;
112
}
113
114
void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {
115
if (!common_flags()->print_summary)
116
return;
117
InternalScopedString buff;
118
buff.AppendF("SUMMARY: %s: %s",
119
alt_tool_name ? alt_tool_name : SanitizerToolName,
120
error_message);
121
__sanitizer_report_error_summary(buff.data());
122
}
123
124
// Removes the ANSI escape sequences from the input string (in-place).
125
void RemoveANSIEscapeSequencesFromString(char *str) {
126
if (!str)
127
return;
128
129
// We are going to remove the escape sequences in place.
130
char *s = str;
131
char *z = str;
132
while (*s != '\0') {
133
CHECK_GE(s, z);
134
// Skip over ANSI escape sequences with pointer 's'.
135
if (*s == '\033' && *(s + 1) == '[') {
136
s = internal_strchrnul(s, 'm');
137
if (*s == '\0') {
138
break;
139
}
140
s++;
141
continue;
142
}
143
// 's' now points at a character we want to keep. Copy over the buffer
144
// content if the escape sequence has been perviously skipped andadvance
145
// both pointers.
146
if (s != z)
147
*z = *s;
148
149
// If we have not seen an escape sequence, just advance both pointers.
150
z++;
151
s++;
152
}
153
154
// Null terminate the string.
155
*z = '\0';
156
}
157
158
void LoadedModule::set(const char *module_name, uptr base_address) {
159
clear();
160
full_name_ = internal_strdup(module_name);
161
base_address_ = base_address;
162
}
163
164
void LoadedModule::set(const char *module_name, uptr base_address,
165
ModuleArch arch, u8 uuid[kModuleUUIDSize],
166
bool instrumented) {
167
set(module_name, base_address);
168
arch_ = arch;
169
internal_memcpy(uuid_, uuid, sizeof(uuid_));
170
uuid_size_ = kModuleUUIDSize;
171
instrumented_ = instrumented;
172
}
173
174
void LoadedModule::setUuid(const char *uuid, uptr size) {
175
if (size > kModuleUUIDSize)
176
size = kModuleUUIDSize;
177
internal_memcpy(uuid_, uuid, size);
178
uuid_size_ = size;
179
}
180
181
void LoadedModule::clear() {
182
InternalFree(full_name_);
183
base_address_ = 0;
184
max_address_ = 0;
185
full_name_ = nullptr;
186
arch_ = kModuleArchUnknown;
187
internal_memset(uuid_, 0, kModuleUUIDSize);
188
instrumented_ = false;
189
while (!ranges_.empty()) {
190
AddressRange *r = ranges_.front();
191
ranges_.pop_front();
192
InternalFree(r);
193
}
194
}
195
196
void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable,
197
bool writable, const char *name) {
198
void *mem = InternalAlloc(sizeof(AddressRange));
199
AddressRange *r =
200
new(mem) AddressRange(beg, end, executable, writable, name);
201
ranges_.push_back(r);
202
max_address_ = Max(max_address_, end);
203
}
204
205
bool LoadedModule::containsAddress(uptr address) const {
206
for (const AddressRange &r : ranges()) {
207
if (r.beg <= address && address < r.end)
208
return true;
209
}
210
return false;
211
}
212
213
static atomic_uintptr_t g_total_mmaped;
214
215
void IncreaseTotalMmap(uptr size) {
216
if (!common_flags()->mmap_limit_mb) return;
217
uptr total_mmaped =
218
atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
219
// Since for now mmap_limit_mb is not a user-facing flag, just kill
220
// a program. Use RAW_CHECK to avoid extra mmaps in reporting.
221
RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);
222
}
223
224
void DecreaseTotalMmap(uptr size) {
225
if (!common_flags()->mmap_limit_mb) return;
226
atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
227
}
228
229
bool TemplateMatch(const char *templ, const char *str) {
230
if ((!str) || str[0] == 0)
231
return false;
232
bool start = false;
233
if (templ && templ[0] == '^') {
234
start = true;
235
templ++;
236
}
237
bool asterisk = false;
238
while (templ && templ[0]) {
239
if (templ[0] == '*') {
240
templ++;
241
start = false;
242
asterisk = true;
243
continue;
244
}
245
if (templ[0] == '$')
246
return str[0] == 0 || asterisk;
247
if (str[0] == 0)
248
return false;
249
char *tpos = (char*)internal_strchr(templ, '*');
250
char *tpos1 = (char*)internal_strchr(templ, '$');
251
if ((!tpos) || (tpos1 && tpos1 < tpos))
252
tpos = tpos1;
253
if (tpos)
254
tpos[0] = 0;
255
const char *str0 = str;
256
const char *spos = internal_strstr(str, templ);
257
str = spos + internal_strlen(templ);
258
templ = tpos;
259
if (tpos)
260
tpos[0] = tpos == tpos1 ? '$' : '*';
261
if (!spos)
262
return false;
263
if (start && spos != str0)
264
return false;
265
start = false;
266
asterisk = false;
267
}
268
return true;
269
}
270
271
static char binary_name_cache_str[kMaxPathLength];
272
static char process_name_cache_str[kMaxPathLength];
273
274
const char *GetProcessName() {
275
return process_name_cache_str;
276
}
277
278
static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) {
279
ReadLongProcessName(buf, buf_len);
280
char *s = const_cast<char *>(StripModuleName(buf));
281
uptr len = internal_strlen(s);
282
if (s != buf) {
283
internal_memmove(buf, s, len);
284
buf[len] = '\0';
285
}
286
return len;
287
}
288
289
void UpdateProcessName() {
290
ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
291
}
292
293
// Call once to make sure that binary_name_cache_str is initialized
294
void CacheBinaryName() {
295
if (binary_name_cache_str[0] != '\0')
296
return;
297
ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str));
298
ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
299
}
300
301
uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
302
CacheBinaryName();
303
uptr name_len = internal_strlen(binary_name_cache_str);
304
name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1;
305
if (buf_len == 0)
306
return 0;
307
internal_memcpy(buf, binary_name_cache_str, name_len);
308
buf[name_len] = '\0';
309
return name_len;
310
}
311
312
uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len) {
313
ReadBinaryNameCached(buf, buf_len);
314
const char *exec_name_pos = StripModuleName(buf);
315
uptr name_len = exec_name_pos - buf;
316
buf[name_len] = '\0';
317
return name_len;
318
}
319
320
#if !SANITIZER_GO
321
void PrintCmdline() {
322
char **argv = GetArgv();
323
if (!argv) return;
324
Printf("\nCommand: ");
325
for (uptr i = 0; argv[i]; ++i)
326
Printf("%s ", argv[i]);
327
Printf("\n\n");
328
}
329
#endif
330
331
// Malloc hooks.
332
static const int kMaxMallocFreeHooks = 5;
333
struct MallocFreeHook {
334
void (*malloc_hook)(const void *, uptr);
335
void (*free_hook)(const void *);
336
};
337
338
static MallocFreeHook MFHooks[kMaxMallocFreeHooks];
339
340
void RunMallocHooks(void *ptr, uptr size) {
341
__sanitizer_malloc_hook(ptr, size);
342
for (int i = 0; i < kMaxMallocFreeHooks; i++) {
343
auto hook = MFHooks[i].malloc_hook;
344
if (!hook)
345
break;
346
hook(ptr, size);
347
}
348
}
349
350
// Returns '1' if the call to free() should be ignored (based on
351
// __sanitizer_ignore_free_hook), or '0' otherwise.
352
int RunFreeHooks(void *ptr) {
353
if (__sanitizer_ignore_free_hook(ptr)) {
354
return 1;
355
}
356
357
__sanitizer_free_hook(ptr);
358
for (int i = 0; i < kMaxMallocFreeHooks; i++) {
359
auto hook = MFHooks[i].free_hook;
360
if (!hook)
361
break;
362
hook(ptr);
363
}
364
365
return 0;
366
}
367
368
static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr),
369
void (*free_hook)(const void *)) {
370
if (!malloc_hook || !free_hook) return 0;
371
for (int i = 0; i < kMaxMallocFreeHooks; i++) {
372
if (MFHooks[i].malloc_hook == nullptr) {
373
MFHooks[i].malloc_hook = malloc_hook;
374
MFHooks[i].free_hook = free_hook;
375
return i + 1;
376
}
377
}
378
return 0;
379
}
380
381
void internal_sleep(unsigned seconds) {
382
internal_usleep((u64)seconds * 1000 * 1000);
383
}
384
void SleepForSeconds(unsigned seconds) {
385
internal_usleep((u64)seconds * 1000 * 1000);
386
}
387
void SleepForMillis(unsigned millis) { internal_usleep((u64)millis * 1000); }
388
389
void WaitForDebugger(unsigned seconds, const char *label) {
390
if (seconds) {
391
Report("Sleeping for %u second(s) %s\n", seconds, label);
392
SleepForSeconds(seconds);
393
}
394
}
395
396
} // namespace __sanitizer
397
398
using namespace __sanitizer;
399
400
extern "C" {
401
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary,
402
const char *error_summary) {
403
Printf("%s\n", error_summary);
404
}
405
406
SANITIZER_INTERFACE_ATTRIBUTE
407
int __sanitizer_acquire_crash_state() {
408
static atomic_uint8_t in_crash_state = {};
409
return !atomic_exchange(&in_crash_state, 1, memory_order_relaxed);
410
}
411
412
SANITIZER_INTERFACE_ATTRIBUTE
413
int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *,
414
uptr),
415
void (*free_hook)(const void *)) {
416
return InstallMallocFreeHooks(malloc_hook, free_hook);
417
}
418
419
// Provide default (no-op) implementation of malloc hooks.
420
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook, void *ptr,
421
uptr size) {
422
(void)ptr;
423
(void)size;
424
}
425
426
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook, void *ptr) {
427
(void)ptr;
428
}
429
430
SANITIZER_INTERFACE_WEAK_DEF(int, __sanitizer_ignore_free_hook, void *ptr) {
431
(void)ptr;
432
return 0;
433
}
434
435
} // extern "C"
436
437