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_internal.h"
14 #include "sanitizer_flags.h"
15 #include "sanitizer_libc.h"
16 #include "sanitizer_placement_new.h"
17 #include "sanitizer_stacktrace_printer.h"
18 #include "sanitizer_symbolizer.h"
20 namespace __sanitizer
{
22 const char *SanitizerToolName
= "SanitizerTool";
24 atomic_uint32_t current_verbosity
;
26 uptr
GetPageSizeCached() {
29 PageSize
= GetPageSize();
33 StaticSpinMutex report_file_mu
;
34 ReportFile report_file
= {&report_file_mu
, kStderrFd
, "", "", 0};
36 void RawWrite(const char *buffer
) {
37 report_file
.Write(buffer
, internal_strlen(buffer
));
40 void ReportFile::ReopenIfNecessary() {
42 if (fd
== kStdoutFd
|| fd
== kStderrFd
) return;
44 uptr pid
= internal_getpid();
45 // If in tracer, use the parent's file.
46 if (pid
== stoptheworld_tracer_pid
)
47 pid
= stoptheworld_tracer_ppid
;
48 if (fd
!= kInvalidFd
) {
49 // If the report file is already opened by the current process,
50 // do nothing. Otherwise the report file was opened by the parent
51 // process, close it now.
58 const char *exe_name
= GetProcessName();
59 if (common_flags()->log_exe_name
&& exe_name
) {
60 internal_snprintf(full_path
, kMaxPathLength
, "%s.%s.%zu", path_prefix
,
63 internal_snprintf(full_path
, kMaxPathLength
, "%s.%zu", path_prefix
, pid
);
65 fd
= OpenFile(full_path
, WrOnly
);
66 if (fd
== kInvalidFd
) {
67 const char *ErrorMsgPrefix
= "ERROR: Can't open file: ";
68 WriteToFile(kStderrFd
, ErrorMsgPrefix
, internal_strlen(ErrorMsgPrefix
));
69 WriteToFile(kStderrFd
, full_path
, internal_strlen(full_path
));
75 void ReportFile::SetReportPath(const char *path
) {
78 uptr len
= internal_strlen(path
);
79 if (len
> sizeof(path_prefix
) - 100) {
80 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
81 path
[0], path
[1], path
[2], path
[3],
82 path
[4], path
[5], path
[6], path
[7]);
87 if (fd
!= kStdoutFd
&& fd
!= kStderrFd
&& fd
!= kInvalidFd
)
90 if (internal_strcmp(path
, "stdout") == 0) {
92 } else if (internal_strcmp(path
, "stderr") == 0) {
95 internal_snprintf(path_prefix
, kMaxPathLength
, "%s", path
);
99 // PID of the tracer task in StopTheWorld. It shares the address space with the
100 // main process, but has a different PID and thus requires special handling.
101 uptr stoptheworld_tracer_pid
= 0;
102 // Cached pid of parent process - if the parent process dies, we want to keep
103 // writing to the same log file.
104 uptr stoptheworld_tracer_ppid
= 0;
106 static const int kMaxNumOfInternalDieCallbacks
= 5;
107 static DieCallbackType InternalDieCallbacks
[kMaxNumOfInternalDieCallbacks
];
109 bool AddDieCallback(DieCallbackType callback
) {
110 for (int i
= 0; i
< kMaxNumOfInternalDieCallbacks
; i
++) {
111 if (InternalDieCallbacks
[i
] == nullptr) {
112 InternalDieCallbacks
[i
] = callback
;
119 bool RemoveDieCallback(DieCallbackType callback
) {
120 for (int i
= 0; i
< kMaxNumOfInternalDieCallbacks
; i
++) {
121 if (InternalDieCallbacks
[i
] == callback
) {
122 internal_memmove(&InternalDieCallbacks
[i
], &InternalDieCallbacks
[i
+ 1],
123 sizeof(InternalDieCallbacks
[0]) *
124 (kMaxNumOfInternalDieCallbacks
- i
- 1));
125 InternalDieCallbacks
[kMaxNumOfInternalDieCallbacks
- 1] = nullptr;
132 static DieCallbackType UserDieCallback
;
133 void SetUserDieCallback(DieCallbackType callback
) {
134 UserDieCallback
= callback
;
137 void NORETURN
Die() {
140 for (int i
= kMaxNumOfInternalDieCallbacks
- 1; i
>= 0; i
--) {
141 if (InternalDieCallbacks
[i
])
142 InternalDieCallbacks
[i
]();
144 if (common_flags()->abort_on_error
)
146 internal__exit(common_flags()->exitcode
);
149 static CheckFailedCallbackType CheckFailedCallback
;
150 void SetCheckFailedCallback(CheckFailedCallbackType callback
) {
151 CheckFailedCallback
= callback
;
154 void NORETURN
CheckFailed(const char *file
, int line
, const char *cond
,
156 if (CheckFailedCallback
) {
157 CheckFailedCallback(file
, line
, cond
, v1
, v2
);
159 Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file
, line
, cond
,
164 void NORETURN
ReportMmapFailureAndDie(uptr size
, const char *mem_type
,
165 const char *mmap_type
, error_t err
) {
166 static int recursion_count
;
167 if (recursion_count
) {
168 // The Report() and CHECK calls below may call mmap recursively and fail.
169 // If we went into recursion, just die.
170 RawWrite("ERROR: Failed to mmap\n");
174 Report("ERROR: %s failed to "
175 "%s 0x%zx (%zd) bytes of %s (error code: %d)\n",
176 SanitizerToolName
, mmap_type
, size
, size
, mem_type
, err
);
180 UNREACHABLE("unable to mmap");
183 bool ReadFileToBuffer(const char *file_name
, char **buff
, uptr
*buff_size
,
184 uptr
*read_len
, uptr max_len
, error_t
*errno_p
) {
185 uptr PageSize
= GetPageSizeCached();
186 uptr kMinFileLen
= PageSize
;
190 // The files we usually open are not seekable, so try different buffer sizes.
191 for (uptr size
= kMinFileLen
; size
<= max_len
; size
*= 2) {
192 fd_t fd
= OpenFile(file_name
, RdOnly
, errno_p
);
193 if (fd
== kInvalidFd
) return false;
194 UnmapOrDie(*buff
, *buff_size
);
195 *buff
= (char*)MmapOrDie(size
, __func__
);
198 // Read up to one page at a time.
199 bool reached_eof
= false;
200 while (*read_len
+ PageSize
<= size
) {
202 if (!ReadFromFile(fd
, *buff
+ *read_len
, PageSize
, &just_read
, errno_p
)) {
203 UnmapOrDie(*buff
, *buff_size
);
206 if (just_read
== 0) {
210 *read_len
+= just_read
;
213 if (reached_eof
) // We've read the whole file.
219 typedef bool UptrComparisonFunction(const uptr
&a
, const uptr
&b
);
222 static inline bool CompareLess(const T
&a
, const T
&b
) {
226 void SortArray(uptr
*array
, uptr size
) {
227 InternalSort
<uptr
*, UptrComparisonFunction
>(&array
, size
, CompareLess
);
230 // We want to map a chunk of address space aligned to 'alignment'.
231 // We do it by maping a bit more and then unmaping redundant pieces.
232 // We probably can do it with fewer syscalls in some OS-dependent way.
233 void *MmapAlignedOrDie(uptr size
, uptr alignment
, const char *mem_type
) {
234 // uptr PageSize = GetPageSizeCached();
235 CHECK(IsPowerOfTwo(size
));
236 CHECK(IsPowerOfTwo(alignment
));
237 uptr map_size
= size
+ alignment
;
238 uptr map_res
= (uptr
)MmapOrDie(map_size
, mem_type
);
239 uptr map_end
= map_res
+ map_size
;
241 if (res
& (alignment
- 1)) // Not aligned.
242 res
= (map_res
+ alignment
) & ~(alignment
- 1);
243 uptr end
= res
+ size
;
245 UnmapOrDie((void*)map_res
, res
- map_res
);
247 UnmapOrDie((void*)end
, map_end
- end
);
251 const char *StripPathPrefix(const char *filepath
,
252 const char *strip_path_prefix
) {
253 if (!filepath
) return nullptr;
254 if (!strip_path_prefix
) return filepath
;
255 const char *res
= filepath
;
256 if (const char *pos
= internal_strstr(filepath
, strip_path_prefix
))
257 res
= pos
+ internal_strlen(strip_path_prefix
);
258 if (res
[0] == '.' && res
[1] == '/')
263 const char *StripModuleName(const char *module
) {
266 if (SANITIZER_WINDOWS
) {
267 // On Windows, both slash and backslash are possible.
268 // Pick the one that goes last.
269 if (const char *bslash_pos
= internal_strrchr(module
, '\\'))
270 return StripModuleName(bslash_pos
+ 1);
272 if (const char *slash_pos
= internal_strrchr(module
, '/')) {
273 return slash_pos
+ 1;
278 void ReportErrorSummary(const char *error_message
) {
279 if (!common_flags()->print_summary
)
281 InternalScopedString
buff(kMaxSummaryLength
);
282 buff
.append("SUMMARY: %s: %s", SanitizerToolName
, error_message
);
283 __sanitizer_report_error_summary(buff
.data());
287 void ReportErrorSummary(const char *error_type
, const AddressInfo
&info
) {
288 if (!common_flags()->print_summary
)
290 InternalScopedString
buff(kMaxSummaryLength
);
291 buff
.append("%s ", error_type
);
292 RenderFrame(&buff
, "%L %F", 0, info
, common_flags()->symbolize_vs_style
,
293 common_flags()->strip_path_prefix
);
294 ReportErrorSummary(buff
.data());
298 void LoadedModule::set(const char *module_name
, uptr base_address
) {
300 full_name_
= internal_strdup(module_name
);
301 base_address_
= base_address
;
304 void LoadedModule::clear() {
305 InternalFree(full_name_
);
306 full_name_
= nullptr;
307 while (!ranges_
.empty()) {
308 AddressRange
*r
= ranges_
.front();
314 void LoadedModule::addAddressRange(uptr beg
, uptr end
, bool executable
) {
315 void *mem
= InternalAlloc(sizeof(AddressRange
));
316 AddressRange
*r
= new(mem
) AddressRange(beg
, end
, executable
);
317 ranges_
.push_back(r
);
320 bool LoadedModule::containsAddress(uptr address
) const {
321 for (Iterator iter
= ranges(); iter
.hasNext();) {
322 const AddressRange
*r
= iter
.next();
323 if (r
->beg
<= address
&& address
< r
->end
)
329 static atomic_uintptr_t g_total_mmaped
;
331 void IncreaseTotalMmap(uptr size
) {
332 if (!common_flags()->mmap_limit_mb
) return;
334 atomic_fetch_add(&g_total_mmaped
, size
, memory_order_relaxed
) + size
;
335 // Since for now mmap_limit_mb is not a user-facing flag, just kill
336 // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
337 RAW_CHECK((total_mmaped
>> 20) < common_flags()->mmap_limit_mb
);
340 void DecreaseTotalMmap(uptr size
) {
341 if (!common_flags()->mmap_limit_mb
) return;
342 atomic_fetch_sub(&g_total_mmaped
, size
, memory_order_relaxed
);
345 bool TemplateMatch(const char *templ
, const char *str
) {
346 if ((!str
) || str
[0] == 0)
349 if (templ
&& templ
[0] == '^') {
353 bool asterisk
= false;
354 while (templ
&& templ
[0]) {
355 if (templ
[0] == '*') {
362 return str
[0] == 0 || asterisk
;
365 char *tpos
= (char*)internal_strchr(templ
, '*');
366 char *tpos1
= (char*)internal_strchr(templ
, '$');
367 if ((!tpos
) || (tpos1
&& tpos1
< tpos
))
371 const char *str0
= str
;
372 const char *spos
= internal_strstr(str
, templ
);
373 str
= spos
+ internal_strlen(templ
);
376 tpos
[0] = tpos
== tpos1
? '$' : '*';
379 if (start
&& spos
!= str0
)
387 static const char kPathSeparator
= SANITIZER_WINDOWS
? ';' : ':';
389 char *FindPathToBinary(const char *name
) {
390 const char *path
= GetEnv("PATH");
393 uptr name_len
= internal_strlen(name
);
394 InternalScopedBuffer
<char> buffer(kMaxPathLength
);
395 const char *beg
= path
;
397 const char *end
= internal_strchrnul(beg
, kPathSeparator
);
398 uptr prefix_len
= end
- beg
;
399 if (prefix_len
+ name_len
+ 2 <= kMaxPathLength
) {
400 internal_memcpy(buffer
.data(), beg
, prefix_len
);
401 buffer
[prefix_len
] = '/';
402 internal_memcpy(&buffer
[prefix_len
+ 1], name
, name_len
);
403 buffer
[prefix_len
+ 1 + name_len
] = '\0';
404 if (FileExists(buffer
.data()))
405 return internal_strdup(buffer
.data());
407 if (*end
== '\0') break;
413 static char binary_name_cache_str
[kMaxPathLength
];
414 static char process_name_cache_str
[kMaxPathLength
];
416 const char *GetProcessName() {
417 return process_name_cache_str
;
420 static uptr
ReadProcessName(/*out*/ char *buf
, uptr buf_len
) {
421 ReadLongProcessName(buf
, buf_len
);
422 char *s
= const_cast<char *>(StripModuleName(buf
));
423 uptr len
= internal_strlen(s
);
425 internal_memmove(buf
, s
, len
);
431 void UpdateProcessName() {
432 ReadProcessName(process_name_cache_str
, sizeof(process_name_cache_str
));
435 // Call once to make sure that binary_name_cache_str is initialized
436 void CacheBinaryName() {
437 if (binary_name_cache_str
[0] != '\0')
439 ReadBinaryName(binary_name_cache_str
, sizeof(binary_name_cache_str
));
440 ReadProcessName(process_name_cache_str
, sizeof(process_name_cache_str
));
443 uptr
ReadBinaryNameCached(/*out*/char *buf
, uptr buf_len
) {
445 uptr name_len
= internal_strlen(binary_name_cache_str
);
446 name_len
= (name_len
< buf_len
- 1) ? name_len
: buf_len
- 1;
449 internal_memcpy(buf
, binary_name_cache_str
, name_len
);
450 buf
[name_len
] = '\0';
454 } // namespace __sanitizer
456 using namespace __sanitizer
; // NOLINT
459 void __sanitizer_set_report_path(const char *path
) {
460 report_file
.SetReportPath(path
);
463 void __sanitizer_report_error_summary(const char *error_summary
) {
464 Printf("%s\n", error_summary
);
467 SANITIZER_INTERFACE_ATTRIBUTE
468 void __sanitizer_set_death_callback(void (*callback
)(void)) {
469 SetUserDieCallback(callback
);