1 //===-- sanitizer_common.cc -----------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is shared between AddressSanitizer and ThreadSanitizer
11 // run-time libraries.
12 //===----------------------------------------------------------------------===//
14 #include "sanitizer_common.h"
15 #include "sanitizer_allocator_internal.h"
16 #include "sanitizer_flags.h"
17 #include "sanitizer_libc.h"
18 #include "sanitizer_placement_new.h"
19 #include "sanitizer_stacktrace_printer.h"
20 #include "sanitizer_symbolizer.h"
22 namespace __sanitizer {
24 const char *SanitizerToolName = "SanitizerTool";
26 atomic_uint32_t current_verbosity;
28 uptr GetPageSizeCached() {
31 PageSize = GetPageSize();
35 StaticSpinMutex report_file_mu;
36 ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
38 void RawWrite(const char *buffer) {
39 report_file.Write(buffer, internal_strlen(buffer));
42 void ReportFile::ReopenIfNecessary() {
44 if (fd == kStdoutFd || fd == kStderrFd) return;
46 uptr pid = internal_getpid();
47 // If in tracer, use the parent's file.
48 if (pid == stoptheworld_tracer_pid)
49 pid = stoptheworld_tracer_ppid;
50 if (fd != kInvalidFd) {
51 // If the report file is already opened by the current process,
52 // do nothing. Otherwise the report file was opened by the parent
53 // process, close it now.
60 const char *exe_name = GetBinaryBasename();
61 if (common_flags()->log_exe_name && exe_name) {
62 internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix,
65 internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
67 fd = OpenFile(full_path, WrOnly);
68 if (fd == kInvalidFd) {
69 const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
70 WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
71 WriteToFile(kStderrFd, full_path, internal_strlen(full_path));
77 void ReportFile::SetReportPath(const char *path) {
80 uptr len = internal_strlen(path);
81 if (len > sizeof(path_prefix) - 100) {
82 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
83 path[0], path[1], path[2], path[3],
84 path[4], path[5], path[6], path[7]);
89 if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
92 if (internal_strcmp(path, "stdout") == 0) {
94 } else if (internal_strcmp(path, "stderr") == 0) {
97 internal_snprintf(path_prefix, kMaxPathLength, "%s", path);
101 // PID of the tracer task in StopTheWorld. It shares the address space with the
102 // main process, but has a different PID and thus requires special handling.
103 uptr stoptheworld_tracer_pid = 0;
104 // Cached pid of parent process - if the parent process dies, we want to keep
105 // writing to the same log file.
106 uptr stoptheworld_tracer_ppid = 0;
108 static DieCallbackType InternalDieCallback, UserDieCallback;
109 void SetDieCallback(DieCallbackType callback) {
110 InternalDieCallback = callback;
112 void SetUserDieCallback(DieCallbackType callback) {
113 UserDieCallback = callback;
116 DieCallbackType GetDieCallback() {
117 return InternalDieCallback;
120 void NORETURN Die() {
123 if (InternalDieCallback)
124 InternalDieCallback();
128 static CheckFailedCallbackType CheckFailedCallback;
129 void SetCheckFailedCallback(CheckFailedCallbackType callback) {
130 CheckFailedCallback = callback;
133 void NORETURN CheckFailed(const char *file, int line, const char *cond,
135 if (CheckFailedCallback) {
136 CheckFailedCallback(file, line, cond, v1, v2);
138 Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
143 uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
144 uptr max_len, error_t *errno_p) {
145 uptr PageSize = GetPageSizeCached();
146 uptr kMinFileLen = PageSize;
150 // The files we usually open are not seekable, so try different buffer sizes.
151 for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
152 fd_t fd = OpenFile(file_name, RdOnly, errno_p);
153 if (fd == kInvalidFd) return 0;
154 UnmapOrDie(*buff, *buff_size);
155 *buff = (char*)MmapOrDie(size, __func__);
157 // Read up to one page at a time.
159 bool reached_eof = false;
160 while (read_len + PageSize <= size) {
162 if (!ReadFromFile(fd, *buff + read_len, PageSize, &just_read, errno_p)) {
163 UnmapOrDie(*buff, *buff_size);
166 if (just_read == 0) {
170 read_len += just_read;
173 if (reached_eof) // We've read the whole file.
179 typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
182 static inline bool CompareLess(const T &a, const T &b) {
186 void SortArray(uptr *array, uptr size) {
187 InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
190 // We want to map a chunk of address space aligned to 'alignment'.
191 // We do it by maping a bit more and then unmaping redundant pieces.
192 // We probably can do it with fewer syscalls in some OS-dependent way.
193 void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
194 // uptr PageSize = GetPageSizeCached();
195 CHECK(IsPowerOfTwo(size));
196 CHECK(IsPowerOfTwo(alignment));
197 uptr map_size = size + alignment;
198 uptr map_res = (uptr)MmapOrDie(map_size, mem_type);
199 uptr map_end = map_res + map_size;
201 if (res & (alignment - 1)) // Not aligned.
202 res = (map_res + alignment) & ~(alignment - 1);
203 uptr end = res + size;
205 UnmapOrDie((void*)map_res, res - map_res);
207 UnmapOrDie((void*)end, map_end - end);
211 const char *StripPathPrefix(const char *filepath,
212 const char *strip_path_prefix) {
213 if (filepath == 0) return 0;
214 if (strip_path_prefix == 0) return filepath;
215 const char *res = filepath;
216 if (const char *pos = internal_strstr(filepath, strip_path_prefix))
217 res = pos + internal_strlen(strip_path_prefix);
218 if (res[0] == '.' && res[1] == '/')
223 const char *StripModuleName(const char *module) {
226 if (SANITIZER_WINDOWS) {
227 // On Windows, both slash and backslash are possible.
228 // Pick the one that goes last.
229 if (const char *bslash_pos = internal_strrchr(module, '\\'))
230 return StripModuleName(bslash_pos + 1);
232 if (const char *slash_pos = internal_strrchr(module, '/')) {
233 return slash_pos + 1;
238 void ReportErrorSummary(const char *error_message) {
239 if (!common_flags()->print_summary)
241 InternalScopedString buff(kMaxSummaryLength);
242 buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message);
243 __sanitizer_report_error_summary(buff.data());
247 void ReportErrorSummary(const char *error_type, const AddressInfo &info) {
248 if (!common_flags()->print_summary)
250 InternalScopedString buff(kMaxSummaryLength);
251 buff.append("%s ", error_type);
252 RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style,
253 common_flags()->strip_path_prefix);
254 ReportErrorSummary(buff.data());
258 void LoadedModule::set(const char *module_name, uptr base_address) {
260 full_name_ = internal_strdup(module_name);
261 base_address_ = base_address;
264 void LoadedModule::clear() {
265 InternalFree(full_name_);
266 full_name_ = nullptr;
267 while (!ranges_.empty()) {
268 AddressRange *r = ranges_.front();
274 void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) {
275 void *mem = InternalAlloc(sizeof(AddressRange));
276 AddressRange *r = new(mem) AddressRange(beg, end, executable);
277 ranges_.push_back(r);
280 bool LoadedModule::containsAddress(uptr address) const {
281 for (Iterator iter = ranges(); iter.hasNext();) {
282 const AddressRange *r = iter.next();
283 if (r->beg <= address && address < r->end)
289 static atomic_uintptr_t g_total_mmaped;
291 void IncreaseTotalMmap(uptr size) {
292 if (!common_flags()->mmap_limit_mb) return;
294 atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
295 // Since for now mmap_limit_mb is not a user-facing flag, just kill
296 // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
297 RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);
300 void DecreaseTotalMmap(uptr size) {
301 if (!common_flags()->mmap_limit_mb) return;
302 atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
305 bool TemplateMatch(const char *templ, const char *str) {
306 if (str == 0 || str[0] == 0)
309 if (templ && templ[0] == '^') {
313 bool asterisk = false;
314 while (templ && templ[0]) {
315 if (templ[0] == '*') {
322 return str[0] == 0 || asterisk;
325 char *tpos = (char*)internal_strchr(templ, '*');
326 char *tpos1 = (char*)internal_strchr(templ, '$');
327 if (tpos == 0 || (tpos1 && tpos1 < tpos))
331 const char *str0 = str;
332 const char *spos = internal_strstr(str, templ);
333 str = spos + internal_strlen(templ);
336 tpos[0] = tpos == tpos1 ? '$' : '*';
339 if (start && spos != str0)
347 static char binary_name_cache_str[kMaxPathLength];
348 static const char *binary_basename_cache_str;
350 const char *GetBinaryBasename() {
351 return binary_basename_cache_str;
354 // Call once to make sure that binary_name_cache_str is initialized
355 void CacheBinaryName() {
356 if (binary_name_cache_str[0] != '\0')
358 ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str));
359 binary_basename_cache_str = StripModuleName(binary_name_cache_str);
362 uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
364 uptr name_len = internal_strlen(binary_name_cache_str);
365 name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1;
368 internal_memcpy(buf, binary_name_cache_str, name_len);
369 buf[name_len] = '\0';
373 } // namespace __sanitizer
375 using namespace __sanitizer; // NOLINT
378 void __sanitizer_set_report_path(const char *path) {
379 report_file.SetReportPath(path);
382 void __sanitizer_report_error_summary(const char *error_summary) {
383 Printf("%s\n", error_summary);
386 SANITIZER_INTERFACE_ATTRIBUTE
387 void __sanitizer_set_death_callback(void (*callback)(void)) {
388 SetUserDieCallback(callback);