1 //===-- sanitizer_common.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 shared between AddressSanitizer and ThreadSanitizer
10 // run-time libraries.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_common.h"
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"
23 namespace __sanitizer
{
25 const char *SanitizerToolName
= "SanitizerTool";
27 atomic_uint32_t current_verbosity
;
29 u32 NumberOfCPUsCached
;
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;
38 void NORETURN
ReportMmapFailureAndDie(uptr size
, const char *mem_type
,
39 const char *mmap_type
, error_t err
,
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");
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
);
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
);
61 UNREACHABLE("unable to mmap");
64 void NORETURN
ReportMunmapFailureAndDie(void *addr
, uptr size
, error_t err
,
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");
75 "ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p (error "
77 SanitizerToolName
, size
, size
, addr
, err
);
81 UNREACHABLE("unable to unmmap");
84 typedef bool UptrComparisonFunction(const uptr
&a
, const uptr
&b
);
85 typedef bool U32ComparisonFunction(const u32
&a
, const u32
&b
);
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] == '/')
99 const char *StripModuleName(const char *module
) {
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);
108 if (const char *slash_pos
= internal_strrchr(module
, '/')) {
109 return slash_pos
+ 1;
114 void ReportErrorSummary(const char *error_message
, const char *alt_tool_name
) {
115 if (!common_flags()->print_summary
)
117 InternalScopedString buff
;
118 buff
.AppendF("SUMMARY: %s: %s",
119 alt_tool_name
? alt_tool_name
: SanitizerToolName
,
121 __sanitizer_report_error_summary(buff
.data());
124 // Removes the ANSI escape sequences from the input string (in-place).
125 void RemoveANSIEscapeSequencesFromString(char *str
) {
129 // We are going to remove the escape sequences in place.
134 // Skip over ANSI escape sequences with pointer 's'.
135 if (*s
== '\033' && *(s
+ 1) == '[') {
136 s
= internal_strchrnul(s
, 'm');
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
149 // If we have not seen an escape sequence, just advance both pointers.
154 // Null terminate the string.
158 void LoadedModule::set(const char *module_name
, uptr base_address
) {
160 full_name_
= internal_strdup(module_name
);
161 base_address_
= base_address
;
164 void LoadedModule::set(const char *module_name
, uptr base_address
,
165 ModuleArch arch
, u8 uuid
[kModuleUUIDSize
],
167 set(module_name
, base_address
);
169 internal_memcpy(uuid_
, uuid
, sizeof(uuid_
));
170 uuid_size_
= kModuleUUIDSize
;
171 instrumented_
= instrumented
;
174 void LoadedModule::setUuid(const char *uuid
, uptr size
) {
175 if (size
> kModuleUUIDSize
)
176 size
= kModuleUUIDSize
;
177 internal_memcpy(uuid_
, uuid
, size
);
181 void LoadedModule::clear() {
182 InternalFree(full_name_
);
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();
196 void LoadedModule::addAddressRange(uptr beg
, uptr end
, bool executable
,
197 bool writable
, const char *name
) {
198 void *mem
= InternalAlloc(sizeof(AddressRange
));
200 new(mem
) AddressRange(beg
, end
, executable
, writable
, name
);
201 ranges_
.push_back(r
);
202 max_address_
= Max(max_address_
, end
);
205 bool LoadedModule::containsAddress(uptr address
) const {
206 for (const AddressRange
&r
: ranges()) {
207 if (r
.beg
<= address
&& address
< r
.end
)
213 static atomic_uintptr_t g_total_mmaped
;
215 void IncreaseTotalMmap(uptr size
) {
216 if (!common_flags()->mmap_limit_mb
) return;
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
);
224 void DecreaseTotalMmap(uptr size
) {
225 if (!common_flags()->mmap_limit_mb
) return;
226 atomic_fetch_sub(&g_total_mmaped
, size
, memory_order_relaxed
);
229 bool TemplateMatch(const char *templ
, const char *str
) {
230 if ((!str
) || str
[0] == 0)
233 if (templ
&& templ
[0] == '^') {
237 bool asterisk
= false;
238 while (templ
&& templ
[0]) {
239 if (templ
[0] == '*') {
246 return str
[0] == 0 || asterisk
;
249 char *tpos
= (char*)internal_strchr(templ
, '*');
250 char *tpos1
= (char*)internal_strchr(templ
, '$');
251 if ((!tpos
) || (tpos1
&& tpos1
< tpos
))
255 const char *str0
= str
;
256 const char *spos
= internal_strstr(str
, templ
);
257 str
= spos
+ internal_strlen(templ
);
260 tpos
[0] = tpos
== tpos1
? '$' : '*';
263 if (start
&& spos
!= str0
)
271 static char binary_name_cache_str
[kMaxPathLength
];
272 static char process_name_cache_str
[kMaxPathLength
];
274 const char *GetProcessName() {
275 return process_name_cache_str
;
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
);
283 internal_memmove(buf
, s
, len
);
289 void UpdateProcessName() {
290 ReadProcessName(process_name_cache_str
, sizeof(process_name_cache_str
));
293 // Call once to make sure that binary_name_cache_str is initialized
294 void CacheBinaryName() {
295 if (binary_name_cache_str
[0] != '\0')
297 ReadBinaryName(binary_name_cache_str
, sizeof(binary_name_cache_str
));
298 ReadProcessName(process_name_cache_str
, sizeof(process_name_cache_str
));
301 uptr
ReadBinaryNameCached(/*out*/char *buf
, uptr buf_len
) {
303 uptr name_len
= internal_strlen(binary_name_cache_str
);
304 name_len
= (name_len
< buf_len
- 1) ? name_len
: buf_len
- 1;
307 internal_memcpy(buf
, binary_name_cache_str
, name_len
);
308 buf
[name_len
] = '\0';
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';
321 void PrintCmdline() {
322 char **argv
= GetArgv();
324 Printf("\nCommand: ");
325 for (uptr i
= 0; argv
[i
]; ++i
)
326 Printf("%s ", argv
[i
]);
332 static const int kMaxMallocFreeHooks
= 5;
333 struct MallocFreeHook
{
334 void (*malloc_hook
)(const void *, uptr
);
335 void (*free_hook
)(const void *);
338 static MallocFreeHook MFHooks
[kMaxMallocFreeHooks
];
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
;
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
)) {
357 __sanitizer_free_hook(ptr
);
358 for (int i
= 0; i
< kMaxMallocFreeHooks
; i
++) {
359 auto hook
= MFHooks
[i
].free_hook
;
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
;
381 void internal_sleep(unsigned seconds
) {
382 internal_usleep((u64
)seconds
* 1000 * 1000);
384 void SleepForSeconds(unsigned seconds
) {
385 internal_usleep((u64
)seconds
* 1000 * 1000);
387 void SleepForMillis(unsigned millis
) { internal_usleep((u64
)millis
* 1000); }
389 void WaitForDebugger(unsigned seconds
, const char *label
) {
391 Report("Sleeping for %u second(s) %s\n", seconds
, label
);
392 SleepForSeconds(seconds
);
396 } // namespace __sanitizer
398 using namespace __sanitizer
;
401 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary
,
402 const char *error_summary
) {
403 Printf("%s\n", error_summary
);
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
);
412 SANITIZER_INTERFACE_ATTRIBUTE
413 int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook
)(const void *,
415 void (*free_hook
)(const void *)) {
416 return InstallMallocFreeHooks(malloc_hook
, free_hook
);
419 // Provide default (no-op) implementation of malloc hooks.
420 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook
, void *ptr
,
426 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook
, void *ptr
) {
430 SANITIZER_INTERFACE_WEAK_DEF(int, __sanitizer_ignore_free_hook
, void *ptr
) {