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 // PID of the tracer task in StopTheWorld. It shares the address space with the
29 // main process, but has a different PID and thus requires special handling.
30 uptr stoptheworld_tracer_pid
= 0;
31 // Cached pid of parent process - if the parent process dies, we want to keep
32 // writing to the same log file.
33 uptr stoptheworld_tracer_ppid
= 0;
35 StaticSpinMutex CommonSanitizerReportMutex
;
37 void NORETURN
ReportMmapFailureAndDie(uptr size
, const char *mem_type
,
38 const char *mmap_type
, error_t err
,
40 static int recursion_count
;
41 if (raw_report
|| recursion_count
) {
42 // If raw report is requested or we went into recursion, just die.
43 // The Report() and CHECK calls below may call mmap recursively and fail.
44 RawWrite("ERROR: Failed to mmap\n");
48 Report("ERROR: %s failed to "
49 "%s 0x%zx (%zd) bytes of %s (error code: %d)\n",
50 SanitizerToolName
, mmap_type
, size
, size
, mem_type
, err
);
54 UNREACHABLE("unable to mmap");
57 typedef bool UptrComparisonFunction(const uptr
&a
, const uptr
&b
);
58 typedef bool U32ComparisonFunction(const u32
&a
, const u32
&b
);
61 static inline bool CompareLess(const T
&a
, const T
&b
) {
65 void SortArray(uptr
*array
, uptr size
) {
66 InternalSort
<uptr
*, UptrComparisonFunction
>(&array
, size
, CompareLess
);
69 void SortArray(u32
*array
, uptr size
) {
70 InternalSort
<u32
*, U32ComparisonFunction
>(&array
, size
, CompareLess
);
73 const char *StripPathPrefix(const char *filepath
,
74 const char *strip_path_prefix
) {
75 if (!filepath
) return nullptr;
76 if (!strip_path_prefix
) return filepath
;
77 const char *res
= filepath
;
78 if (const char *pos
= internal_strstr(filepath
, strip_path_prefix
))
79 res
= pos
+ internal_strlen(strip_path_prefix
);
80 if (res
[0] == '.' && res
[1] == '/')
85 const char *StripModuleName(const char *module
) {
88 if (SANITIZER_WINDOWS
) {
89 // On Windows, both slash and backslash are possible.
90 // Pick the one that goes last.
91 if (const char *bslash_pos
= internal_strrchr(module
, '\\'))
92 return StripModuleName(bslash_pos
+ 1);
94 if (const char *slash_pos
= internal_strrchr(module
, '/')) {
100 void ReportErrorSummary(const char *error_message
, const char *alt_tool_name
) {
101 if (!common_flags()->print_summary
)
103 InternalScopedString
buff(kMaxSummaryLength
);
104 buff
.append("SUMMARY: %s: %s",
105 alt_tool_name
? alt_tool_name
: SanitizerToolName
, error_message
);
106 __sanitizer_report_error_summary(buff
.data());
110 void ReportErrorSummary(const char *error_type
, const AddressInfo
&info
,
111 const char *alt_tool_name
) {
112 if (!common_flags()->print_summary
) return;
113 InternalScopedString
buff(kMaxSummaryLength
);
114 buff
.append("%s ", error_type
);
115 RenderFrame(&buff
, "%L %F", 0, info
, common_flags()->symbolize_vs_style
,
116 common_flags()->strip_path_prefix
);
117 ReportErrorSummary(buff
.data(), alt_tool_name
);
121 // Removes the ANSI escape sequences from the input string (in-place).
122 void RemoveANSIEscapeSequencesFromString(char *str
) {
126 // We are going to remove the escape sequences in place.
131 // Skip over ANSI escape sequences with pointer 's'.
132 if (*s
== '\033' && *(s
+ 1) == '[') {
133 s
= internal_strchrnul(s
, 'm');
140 // 's' now points at a character we want to keep. Copy over the buffer
141 // content if the escape sequence has been perviously skipped andadvance
146 // If we have not seen an escape sequence, just advance both pointers.
151 // Null terminate the string.
155 void LoadedModule::set(const char *module_name
, uptr base_address
) {
157 full_name_
= internal_strdup(module_name
);
158 base_address_
= base_address
;
161 void LoadedModule::set(const char *module_name
, uptr base_address
,
162 ModuleArch arch
, u8 uuid
[kModuleUUIDSize
],
164 set(module_name
, base_address
);
166 internal_memcpy(uuid_
, uuid
, sizeof(uuid_
));
167 instrumented_
= instrumented
;
170 void LoadedModule::clear() {
171 InternalFree(full_name_
);
173 max_executable_address_
= 0;
174 full_name_
= nullptr;
175 arch_
= kModuleArchUnknown
;
176 internal_memset(uuid_
, 0, kModuleUUIDSize
);
177 instrumented_
= false;
178 while (!ranges_
.empty()) {
179 AddressRange
*r
= ranges_
.front();
185 void LoadedModule::addAddressRange(uptr beg
, uptr end
, bool executable
,
186 bool writable
, const char *name
) {
187 void *mem
= InternalAlloc(sizeof(AddressRange
));
189 new(mem
) AddressRange(beg
, end
, executable
, writable
, name
);
190 ranges_
.push_back(r
);
191 if (executable
&& end
> max_executable_address_
)
192 max_executable_address_
= end
;
195 bool LoadedModule::containsAddress(uptr address
) const {
196 for (const AddressRange
&r
: ranges()) {
197 if (r
.beg
<= address
&& address
< r
.end
)
203 static atomic_uintptr_t g_total_mmaped
;
205 void IncreaseTotalMmap(uptr size
) {
206 if (!common_flags()->mmap_limit_mb
) return;
208 atomic_fetch_add(&g_total_mmaped
, size
, memory_order_relaxed
) + size
;
209 // Since for now mmap_limit_mb is not a user-facing flag, just kill
210 // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
211 RAW_CHECK((total_mmaped
>> 20) < common_flags()->mmap_limit_mb
);
214 void DecreaseTotalMmap(uptr size
) {
215 if (!common_flags()->mmap_limit_mb
) return;
216 atomic_fetch_sub(&g_total_mmaped
, size
, memory_order_relaxed
);
219 bool TemplateMatch(const char *templ
, const char *str
) {
220 if ((!str
) || str
[0] == 0)
223 if (templ
&& templ
[0] == '^') {
227 bool asterisk
= false;
228 while (templ
&& templ
[0]) {
229 if (templ
[0] == '*') {
236 return str
[0] == 0 || asterisk
;
239 char *tpos
= (char*)internal_strchr(templ
, '*');
240 char *tpos1
= (char*)internal_strchr(templ
, '$');
241 if ((!tpos
) || (tpos1
&& tpos1
< tpos
))
245 const char *str0
= str
;
246 const char *spos
= internal_strstr(str
, templ
);
247 str
= spos
+ internal_strlen(templ
);
250 tpos
[0] = tpos
== tpos1
? '$' : '*';
253 if (start
&& spos
!= str0
)
261 static char binary_name_cache_str
[kMaxPathLength
];
262 static char process_name_cache_str
[kMaxPathLength
];
264 const char *GetProcessName() {
265 return process_name_cache_str
;
268 static uptr
ReadProcessName(/*out*/ char *buf
, uptr buf_len
) {
269 ReadLongProcessName(buf
, buf_len
);
270 char *s
= const_cast<char *>(StripModuleName(buf
));
271 uptr len
= internal_strlen(s
);
273 internal_memmove(buf
, s
, len
);
279 void UpdateProcessName() {
280 ReadProcessName(process_name_cache_str
, sizeof(process_name_cache_str
));
283 // Call once to make sure that binary_name_cache_str is initialized
284 void CacheBinaryName() {
285 if (binary_name_cache_str
[0] != '\0')
287 ReadBinaryName(binary_name_cache_str
, sizeof(binary_name_cache_str
));
288 ReadProcessName(process_name_cache_str
, sizeof(process_name_cache_str
));
291 uptr
ReadBinaryNameCached(/*out*/char *buf
, uptr buf_len
) {
293 uptr name_len
= internal_strlen(binary_name_cache_str
);
294 name_len
= (name_len
< buf_len
- 1) ? name_len
: buf_len
- 1;
297 internal_memcpy(buf
, binary_name_cache_str
, name_len
);
298 buf
[name_len
] = '\0';
302 void PrintCmdline() {
303 char **argv
= GetArgv();
305 Printf("\nCommand: ");
306 for (uptr i
= 0; argv
[i
]; ++i
)
307 Printf("%s ", argv
[i
]);
312 static const int kMaxMallocFreeHooks
= 5;
313 struct MallocFreeHook
{
314 void (*malloc_hook
)(const void *, uptr
);
315 void (*free_hook
)(const void *);
318 static MallocFreeHook MFHooks
[kMaxMallocFreeHooks
];
320 void RunMallocHooks(const void *ptr
, uptr size
) {
321 for (int i
= 0; i
< kMaxMallocFreeHooks
; i
++) {
322 auto hook
= MFHooks
[i
].malloc_hook
;
328 void RunFreeHooks(const void *ptr
) {
329 for (int i
= 0; i
< kMaxMallocFreeHooks
; i
++) {
330 auto hook
= MFHooks
[i
].free_hook
;
336 static int InstallMallocFreeHooks(void (*malloc_hook
)(const void *, uptr
),
337 void (*free_hook
)(const void *)) {
338 if (!malloc_hook
|| !free_hook
) return 0;
339 for (int i
= 0; i
< kMaxMallocFreeHooks
; i
++) {
340 if (MFHooks
[i
].malloc_hook
== nullptr) {
341 MFHooks
[i
].malloc_hook
= malloc_hook
;
342 MFHooks
[i
].free_hook
= free_hook
;
349 } // namespace __sanitizer
351 using namespace __sanitizer
; // NOLINT
354 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary
,
355 const char *error_summary
) {
356 Printf("%s\n", error_summary
);
359 SANITIZER_INTERFACE_ATTRIBUTE
360 void __sanitizer_set_death_callback(void (*callback
)(void)) {
361 SetUserDieCallback(callback
);
364 SANITIZER_INTERFACE_ATTRIBUTE
365 int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook
)(const void *,
367 void (*free_hook
)(const void *)) {
368 return InstallMallocFreeHooks(malloc_hook
, free_hook
);