1 //===-- sanitizer_common.cc -----------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is shared between AddressSanitizer and ThreadSanitizer
10 //===----------------------------------------------------------------------===//
12 #include "sanitizer_common.h"
13 #include "sanitizer_allocator_interface.h"
14 #include "sanitizer_allocator_internal.h"
15 #include "sanitizer_flags.h"
16 #include "sanitizer_libc.h"
17 #include "sanitizer_placement_new.h"
18 #include "sanitizer_stacktrace_printer.h"
19 #include "sanitizer_symbolizer.h"
21 namespace __sanitizer
{
23 const char *SanitizerToolName
= "SanitizerTool";
25 atomic_uint32_t current_verbosity
;
28 StaticSpinMutex report_file_mu
;
29 ReportFile report_file
= {&report_file_mu
, kStderrFd
, "", "", 0};
31 void RawWrite(const char *buffer
) {
32 report_file
.Write(buffer
, internal_strlen(buffer
));
35 void ReportFile::ReopenIfNecessary() {
37 if (fd
== kStdoutFd
|| fd
== kStderrFd
) return;
39 uptr pid
= internal_getpid();
40 // If in tracer, use the parent's file.
41 if (pid
== stoptheworld_tracer_pid
)
42 pid
= stoptheworld_tracer_ppid
;
43 if (fd
!= kInvalidFd
) {
44 // If the report file is already opened by the current process,
45 // do nothing. Otherwise the report file was opened by the parent
46 // process, close it now.
53 const char *exe_name
= GetProcessName();
54 if (common_flags()->log_exe_name
&& exe_name
) {
55 internal_snprintf(full_path
, kMaxPathLength
, "%s.%s.%zu", path_prefix
,
58 internal_snprintf(full_path
, kMaxPathLength
, "%s.%zu", path_prefix
, pid
);
60 fd
= OpenFile(full_path
, WrOnly
);
61 if (fd
== kInvalidFd
) {
62 const char *ErrorMsgPrefix
= "ERROR: Can't open file: ";
63 WriteToFile(kStderrFd
, ErrorMsgPrefix
, internal_strlen(ErrorMsgPrefix
));
64 WriteToFile(kStderrFd
, full_path
, internal_strlen(full_path
));
70 void ReportFile::SetReportPath(const char *path
) {
73 uptr len
= internal_strlen(path
);
74 if (len
> sizeof(path_prefix
) - 100) {
75 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
76 path
[0], path
[1], path
[2], path
[3],
77 path
[4], path
[5], path
[6], path
[7]);
82 if (fd
!= kStdoutFd
&& fd
!= kStderrFd
&& fd
!= kInvalidFd
)
85 if (internal_strcmp(path
, "stdout") == 0) {
87 } else if (internal_strcmp(path
, "stderr") == 0) {
90 internal_snprintf(path_prefix
, kMaxPathLength
, "%s", path
);
94 // PID of the tracer task in StopTheWorld. It shares the address space with the
95 // main process, but has a different PID and thus requires special handling.
96 uptr stoptheworld_tracer_pid
= 0;
97 // Cached pid of parent process - if the parent process dies, we want to keep
98 // writing to the same log file.
99 uptr stoptheworld_tracer_ppid
= 0;
101 void NORETURN
ReportMmapFailureAndDie(uptr size
, const char *mem_type
,
102 const char *mmap_type
, error_t err
,
104 static int recursion_count
;
105 if (raw_report
|| recursion_count
) {
106 // If raw report is requested or we went into recursion, just die.
107 // The Report() and CHECK calls below may call mmap recursively and fail.
108 RawWrite("ERROR: Failed to mmap\n");
112 Report("ERROR: %s failed to "
113 "%s 0x%zx (%zd) bytes of %s (error code: %d)\n",
114 SanitizerToolName
, mmap_type
, size
, size
, mem_type
, err
);
118 UNREACHABLE("unable to mmap");
121 bool ReadFileToBuffer(const char *file_name
, char **buff
, uptr
*buff_size
,
122 uptr
*read_len
, uptr max_len
, error_t
*errno_p
) {
123 uptr PageSize
= GetPageSizeCached();
124 uptr kMinFileLen
= PageSize
;
128 // The files we usually open are not seekable, so try different buffer sizes.
129 for (uptr size
= kMinFileLen
; size
<= max_len
; size
*= 2) {
130 fd_t fd
= OpenFile(file_name
, RdOnly
, errno_p
);
131 if (fd
== kInvalidFd
) return false;
132 UnmapOrDie(*buff
, *buff_size
);
133 *buff
= (char*)MmapOrDie(size
, __func__
);
136 // Read up to one page at a time.
137 bool reached_eof
= false;
138 while (*read_len
+ PageSize
<= size
) {
140 if (!ReadFromFile(fd
, *buff
+ *read_len
, PageSize
, &just_read
, errno_p
)) {
141 UnmapOrDie(*buff
, *buff_size
);
144 if (just_read
== 0) {
148 *read_len
+= just_read
;
151 if (reached_eof
) // We've read the whole file.
157 typedef bool UptrComparisonFunction(const uptr
&a
, const uptr
&b
);
158 typedef bool U32ComparisonFunction(const u32
&a
, const u32
&b
);
161 static inline bool CompareLess(const T
&a
, const T
&b
) {
165 void SortArray(uptr
*array
, uptr size
) {
166 InternalSort
<uptr
*, UptrComparisonFunction
>(&array
, size
, CompareLess
);
169 void SortArray(u32
*array
, uptr size
) {
170 InternalSort
<u32
*, U32ComparisonFunction
>(&array
, size
, CompareLess
);
173 const char *StripPathPrefix(const char *filepath
,
174 const char *strip_path_prefix
) {
175 if (!filepath
) return nullptr;
176 if (!strip_path_prefix
) return filepath
;
177 const char *res
= filepath
;
178 if (const char *pos
= internal_strstr(filepath
, strip_path_prefix
))
179 res
= pos
+ internal_strlen(strip_path_prefix
);
180 if (res
[0] == '.' && res
[1] == '/')
185 const char *StripModuleName(const char *module
) {
188 if (SANITIZER_WINDOWS
) {
189 // On Windows, both slash and backslash are possible.
190 // Pick the one that goes last.
191 if (const char *bslash_pos
= internal_strrchr(module
, '\\'))
192 return StripModuleName(bslash_pos
+ 1);
194 if (const char *slash_pos
= internal_strrchr(module
, '/')) {
195 return slash_pos
+ 1;
200 void ReportErrorSummary(const char *error_message
) {
201 if (!common_flags()->print_summary
)
203 InternalScopedString
buff(kMaxSummaryLength
);
204 buff
.append("SUMMARY: %s: %s", SanitizerToolName
, error_message
);
205 __sanitizer_report_error_summary(buff
.data());
209 void ReportErrorSummary(const char *error_type
, const AddressInfo
&info
) {
210 if (!common_flags()->print_summary
)
212 InternalScopedString
buff(kMaxSummaryLength
);
213 buff
.append("%s ", error_type
);
214 RenderFrame(&buff
, "%L %F", 0, info
, common_flags()->symbolize_vs_style
,
215 common_flags()->strip_path_prefix
);
216 ReportErrorSummary(buff
.data());
220 // Removes the ANSI escape sequences from the input string (in-place).
221 void RemoveANSIEscapeSequencesFromString(char *str
) {
225 // We are going to remove the escape sequences in place.
230 // Skip over ANSI escape sequences with pointer 's'.
231 if (*s
== '\033' && *(s
+ 1) == '[') {
232 s
= internal_strchrnul(s
, 'm');
239 // 's' now points at a character we want to keep. Copy over the buffer
240 // content if the escape sequence has been perviously skipped andadvance
245 // If we have not seen an escape sequence, just advance both pointers.
250 // Null terminate the string.
254 void LoadedModule::set(const char *module_name
, uptr base_address
) {
256 full_name_
= internal_strdup(module_name
);
257 base_address_
= base_address
;
260 void LoadedModule::clear() {
261 InternalFree(full_name_
);
262 full_name_
= nullptr;
263 while (!ranges_
.empty()) {
264 AddressRange
*r
= ranges_
.front();
270 void LoadedModule::addAddressRange(uptr beg
, uptr end
, bool executable
) {
271 void *mem
= InternalAlloc(sizeof(AddressRange
));
272 AddressRange
*r
= new(mem
) AddressRange(beg
, end
, executable
);
273 ranges_
.push_back(r
);
276 bool LoadedModule::containsAddress(uptr address
) const {
277 for (const AddressRange
&r
: ranges()) {
278 if (r
.beg
<= address
&& address
< r
.end
)
284 static atomic_uintptr_t g_total_mmaped
;
286 void IncreaseTotalMmap(uptr size
) {
287 if (!common_flags()->mmap_limit_mb
) return;
289 atomic_fetch_add(&g_total_mmaped
, size
, memory_order_relaxed
) + size
;
290 // Since for now mmap_limit_mb is not a user-facing flag, just kill
291 // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
292 RAW_CHECK((total_mmaped
>> 20) < common_flags()->mmap_limit_mb
);
295 void DecreaseTotalMmap(uptr size
) {
296 if (!common_flags()->mmap_limit_mb
) return;
297 atomic_fetch_sub(&g_total_mmaped
, size
, memory_order_relaxed
);
300 bool TemplateMatch(const char *templ
, const char *str
) {
301 if ((!str
) || str
[0] == 0)
304 if (templ
&& templ
[0] == '^') {
308 bool asterisk
= false;
309 while (templ
&& templ
[0]) {
310 if (templ
[0] == '*') {
317 return str
[0] == 0 || asterisk
;
320 char *tpos
= (char*)internal_strchr(templ
, '*');
321 char *tpos1
= (char*)internal_strchr(templ
, '$');
322 if ((!tpos
) || (tpos1
&& tpos1
< tpos
))
326 const char *str0
= str
;
327 const char *spos
= internal_strstr(str
, templ
);
328 str
= spos
+ internal_strlen(templ
);
331 tpos
[0] = tpos
== tpos1
? '$' : '*';
334 if (start
&& spos
!= str0
)
342 static const char kPathSeparator
= SANITIZER_WINDOWS
? ';' : ':';
344 char *FindPathToBinary(const char *name
) {
345 if (FileExists(name
)) {
346 return internal_strdup(name
);
349 const char *path
= GetEnv("PATH");
352 uptr name_len
= internal_strlen(name
);
353 InternalScopedBuffer
<char> buffer(kMaxPathLength
);
354 const char *beg
= path
;
356 const char *end
= internal_strchrnul(beg
, kPathSeparator
);
357 uptr prefix_len
= end
- beg
;
358 if (prefix_len
+ name_len
+ 2 <= kMaxPathLength
) {
359 internal_memcpy(buffer
.data(), beg
, prefix_len
);
360 buffer
[prefix_len
] = '/';
361 internal_memcpy(&buffer
[prefix_len
+ 1], name
, name_len
);
362 buffer
[prefix_len
+ 1 + name_len
] = '\0';
363 if (FileExists(buffer
.data()))
364 return internal_strdup(buffer
.data());
366 if (*end
== '\0') break;
372 static char binary_name_cache_str
[kMaxPathLength
];
373 static char process_name_cache_str
[kMaxPathLength
];
375 const char *GetProcessName() {
376 return process_name_cache_str
;
379 static uptr
ReadProcessName(/*out*/ char *buf
, uptr buf_len
) {
380 ReadLongProcessName(buf
, buf_len
);
381 char *s
= const_cast<char *>(StripModuleName(buf
));
382 uptr len
= internal_strlen(s
);
384 internal_memmove(buf
, s
, len
);
390 void UpdateProcessName() {
391 ReadProcessName(process_name_cache_str
, sizeof(process_name_cache_str
));
394 // Call once to make sure that binary_name_cache_str is initialized
395 void CacheBinaryName() {
396 if (binary_name_cache_str
[0] != '\0')
398 ReadBinaryName(binary_name_cache_str
, sizeof(binary_name_cache_str
));
399 ReadProcessName(process_name_cache_str
, sizeof(process_name_cache_str
));
402 uptr
ReadBinaryNameCached(/*out*/char *buf
, uptr buf_len
) {
404 uptr name_len
= internal_strlen(binary_name_cache_str
);
405 name_len
= (name_len
< buf_len
- 1) ? name_len
: buf_len
- 1;
408 internal_memcpy(buf
, binary_name_cache_str
, name_len
);
409 buf
[name_len
] = '\0';
413 void PrintCmdline() {
414 char **argv
= GetArgv();
416 Printf("\nCommand: ");
417 for (uptr i
= 0; argv
[i
]; ++i
)
418 Printf("%s ", argv
[i
]);
423 static const int kMaxMallocFreeHooks
= 5;
424 struct MallocFreeHook
{
425 void (*malloc_hook
)(const void *, uptr
);
426 void (*free_hook
)(const void *);
429 static MallocFreeHook MFHooks
[kMaxMallocFreeHooks
];
431 void RunMallocHooks(const void *ptr
, uptr size
) {
432 for (int i
= 0; i
< kMaxMallocFreeHooks
; i
++) {
433 auto hook
= MFHooks
[i
].malloc_hook
;
439 void RunFreeHooks(const void *ptr
) {
440 for (int i
= 0; i
< kMaxMallocFreeHooks
; i
++) {
441 auto hook
= MFHooks
[i
].free_hook
;
447 static int InstallMallocFreeHooks(void (*malloc_hook
)(const void *, uptr
),
448 void (*free_hook
)(const void *)) {
449 if (!malloc_hook
|| !free_hook
) return 0;
450 for (int i
= 0; i
< kMaxMallocFreeHooks
; i
++) {
451 if (MFHooks
[i
].malloc_hook
== nullptr) {
452 MFHooks
[i
].malloc_hook
= malloc_hook
;
453 MFHooks
[i
].free_hook
= free_hook
;
460 } // namespace __sanitizer
462 using namespace __sanitizer
; // NOLINT
465 void __sanitizer_set_report_path(const char *path
) {
466 report_file
.SetReportPath(path
);
469 void __sanitizer_set_report_fd(void *fd
) {
470 report_file
.fd
= (fd_t
)reinterpret_cast<uptr
>(fd
);
471 report_file
.fd_pid
= internal_getpid();
474 void __sanitizer_report_error_summary(const char *error_summary
) {
475 Printf("%s\n", error_summary
);
478 SANITIZER_INTERFACE_ATTRIBUTE
479 void __sanitizer_set_death_callback(void (*callback
)(void)) {
480 SetUserDieCallback(callback
);
483 SANITIZER_INTERFACE_ATTRIBUTE
484 int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook
)(const void *,
486 void (*free_hook
)(const void *)) {
487 return InstallMallocFreeHooks(malloc_hook
, free_hook
);
490 #if !SANITIZER_GO && !SANITIZER_SUPPORTS_WEAK_HOOKS
491 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
492 void __sanitizer_print_memory_profile(int top_percent
) {