sanitizer_common.cc revision 923bac7a85d8bd37219b440a6b4c0800ea4bcd21
1//===-- sanitizer_common.cc -----------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file is shared between AddressSanitizer and ThreadSanitizer 11// run-time libraries. 12//===----------------------------------------------------------------------===// 13 14#include "sanitizer_common.h" 15#include "sanitizer_libc.h" 16 17namespace __sanitizer { 18 19const char *SanitizerToolName = "SanitizerTool"; 20uptr SanitizerVerbosity = 0; 21 22uptr GetPageSizeCached() { 23 static uptr PageSize; 24 if (!PageSize) 25 PageSize = GetPageSize(); 26 return PageSize; 27} 28 29 30// By default, dump to stderr. If |log_to_file| is true and |report_fd_pid| 31// isn't equal to the current PID, try to obtain file descriptor by opening 32// file "report_path_prefix.<PID>". 33fd_t report_fd = kStderrFd; 34 35// Set via __sanitizer_set_report_path. 36bool log_to_file = false; 37char report_path_prefix[sizeof(report_path_prefix)]; 38 39// PID of process that opened |report_fd|. If a fork() occurs, the PID of the 40// child thread will be different from |report_fd_pid|. 41uptr report_fd_pid = 0; 42 43static DieCallbackType DieCallback; 44void SetDieCallback(DieCallbackType callback) { 45 DieCallback = callback; 46} 47 48DieCallbackType GetDieCallback() { 49 return DieCallback; 50} 51 52void NORETURN Die() { 53 if (DieCallback) { 54 DieCallback(); 55 } 56 internal__exit(1); 57} 58 59static CheckFailedCallbackType CheckFailedCallback; 60void SetCheckFailedCallback(CheckFailedCallbackType callback) { 61 CheckFailedCallback = callback; 62} 63 64void NORETURN CheckFailed(const char *file, int line, const char *cond, 65 u64 v1, u64 v2) { 66 if (CheckFailedCallback) { 67 CheckFailedCallback(file, line, cond, v1, v2); 68 } 69 Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond, 70 v1, v2); 71 Die(); 72} 73 74uptr ReadFileToBuffer(const char *file_name, char **buff, 75 uptr *buff_size, uptr max_len) { 76 uptr PageSize = GetPageSizeCached(); 77 uptr kMinFileLen = PageSize; 78 uptr read_len = 0; 79 *buff = 0; 80 *buff_size = 0; 81 // The files we usually open are not seekable, so try different buffer sizes. 82 for (uptr size = kMinFileLen; size <= max_len; size *= 2) { 83 uptr openrv = OpenFile(file_name, /*write*/ false); 84 if (internal_iserror(openrv)) return 0; 85 fd_t fd = openrv; 86 UnmapOrDie(*buff, *buff_size); 87 *buff = (char*)MmapOrDie(size, __FUNCTION__); 88 *buff_size = size; 89 // Read up to one page at a time. 90 read_len = 0; 91 bool reached_eof = false; 92 while (read_len + PageSize <= size) { 93 uptr just_read = internal_read(fd, *buff + read_len, PageSize); 94 if (just_read == 0) { 95 reached_eof = true; 96 break; 97 } 98 read_len += just_read; 99 } 100 internal_close(fd); 101 if (reached_eof) // We've read the whole file. 102 break; 103 } 104 return read_len; 105} 106 107typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); 108 109template<class T> 110static inline bool CompareLess(const T &a, const T &b) { 111 return a < b; 112} 113 114void SortArray(uptr *array, uptr size) { 115 InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess); 116} 117 118// We want to map a chunk of address space aligned to 'alignment'. 119// We do it by maping a bit more and then unmaping redundant pieces. 120// We probably can do it with fewer syscalls in some OS-dependent way. 121void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { 122// uptr PageSize = GetPageSizeCached(); 123 CHECK(IsPowerOfTwo(size)); 124 CHECK(IsPowerOfTwo(alignment)); 125 uptr map_size = size + alignment; 126 uptr map_res = (uptr)MmapOrDie(map_size, mem_type); 127 uptr map_end = map_res + map_size; 128 uptr res = map_res; 129 if (res & (alignment - 1)) // Not aligned. 130 res = (map_res + alignment) & ~(alignment - 1); 131 uptr end = res + size; 132 if (res != map_res) 133 UnmapOrDie((void*)map_res, res - map_res); 134 if (end != map_end) 135 UnmapOrDie((void*)end, map_end - end); 136 return (void*)res; 137} 138 139void ReportErrorSummary(const char *error_type, const char *file, 140 int line, const char *function) { 141 const int kMaxSize = 1024; // We don't want a summary too long. 142 InternalScopedBuffer<char> buff(kMaxSize); 143 internal_snprintf(buff.data(), kMaxSize, "%s: %s %s:%d %s", 144 SanitizerToolName, error_type, 145 file ? file : "??", line, function ? function : "??"); 146 __sanitizer_report_error_summary(buff.data()); 147} 148 149} // namespace __sanitizer 150 151using namespace __sanitizer; // NOLINT 152 153extern "C" { 154void __sanitizer_set_report_path(const char *path) { 155 if (!path) return; 156 uptr len = internal_strlen(path); 157 if (len > sizeof(report_path_prefix) - 100) { 158 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", 159 path[0], path[1], path[2], path[3], 160 path[4], path[5], path[6], path[7]); 161 Die(); 162 } 163 internal_strncpy(report_path_prefix, path, sizeof(report_path_prefix)); 164 report_path_prefix[len] = '\0'; 165 report_fd = kInvalidFd; 166 log_to_file = true; 167} 168 169void __sanitizer_set_report_fd(int fd) { 170 if (report_fd != kStdoutFd && 171 report_fd != kStderrFd && 172 report_fd != kInvalidFd) 173 internal_close(report_fd); 174 report_fd = fd; 175} 176 177void NOINLINE __sanitizer_sandbox_on_notify(void *reserved) { 178 (void)reserved; 179 PrepareForSandboxing(); 180} 181 182void __sanitizer_report_error_summary(const char *error_summary) { 183 Printf("SUMMARY: %s\n", error_summary); 184} 185} // extern "C" 186