sanitizer_common.cc revision 47fcd76474fc6b6c963ae4eeeeea15d465bd6a3c
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_flags.h" 16#include "sanitizer_libc.h" 17 18namespace __sanitizer { 19 20const char *SanitizerToolName = "SanitizerTool"; 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 139const char *StripPathPrefix(const char *filepath, 140 const char *strip_path_prefix) { 141 if (filepath == 0) return 0; 142 if (strip_path_prefix == 0) return filepath; 143 const char *pos = internal_strstr(filepath, strip_path_prefix); 144 if (pos == 0) return filepath; 145 pos += internal_strlen(strip_path_prefix); 146 if (pos[0] == '.' && pos[1] == '/') 147 pos += 2; 148 return pos; 149} 150 151void PrintSourceLocation(const char *file, int line, int column) { 152 CHECK(file); 153 Printf("%s", StripPathPrefix(file, common_flags()->strip_path_prefix)); 154 if (line > 0) { 155 Printf(":%d", line); 156 if (column > 0) 157 Printf(":%d", column); 158 } 159} 160 161void PrintModuleAndOffset(const char *module, uptr offset) { 162 Printf("(%s+0x%zx)", 163 StripPathPrefix(module, common_flags()->strip_path_prefix), offset); 164} 165 166void ReportErrorSummary(const char *error_type, const char *file, 167 int line, const char *function) { 168 const int kMaxSize = 1024; // We don't want a summary too long. 169 InternalScopedBuffer<char> buff(kMaxSize); 170 internal_snprintf( 171 buff.data(), kMaxSize, "SUMMARY: %s: %s %s:%d %s", SanitizerToolName, 172 error_type, 173 file ? StripPathPrefix(file, common_flags()->strip_path_prefix) : "??", 174 line, function ? function : "??"); 175 __sanitizer_report_error_summary(buff.data()); 176} 177 178LoadedModule::LoadedModule(const char *module_name, uptr base_address) { 179 full_name_ = internal_strdup(module_name); 180 base_address_ = base_address; 181 n_ranges_ = 0; 182} 183 184void LoadedModule::addAddressRange(uptr beg, uptr end) { 185 CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges); 186 ranges_[n_ranges_].beg = beg; 187 ranges_[n_ranges_].end = end; 188 n_ranges_++; 189} 190 191bool LoadedModule::containsAddress(uptr address) const { 192 for (uptr i = 0; i < n_ranges_; i++) { 193 if (ranges_[i].beg <= address && address < ranges_[i].end) 194 return true; 195 } 196 return false; 197} 198 199} // namespace __sanitizer 200 201using namespace __sanitizer; // NOLINT 202 203extern "C" { 204void __sanitizer_set_report_path(const char *path) { 205 if (!path) 206 return; 207 uptr len = internal_strlen(path); 208 if (len > sizeof(report_path_prefix) - 100) { 209 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", 210 path[0], path[1], path[2], path[3], 211 path[4], path[5], path[6], path[7]); 212 Die(); 213 } 214 if (report_fd != kStdoutFd && 215 report_fd != kStderrFd && 216 report_fd != kInvalidFd) 217 internal_close(report_fd); 218 report_fd = kInvalidFd; 219 log_to_file = false; 220 if (internal_strcmp(path, "stdout") == 0) { 221 report_fd = kStdoutFd; 222 } else if (internal_strcmp(path, "stderr") == 0) { 223 report_fd = kStderrFd; 224 } else { 225 internal_strncpy(report_path_prefix, path, sizeof(report_path_prefix)); 226 report_path_prefix[len] = '\0'; 227 log_to_file = true; 228 } 229} 230 231void NOINLINE __sanitizer_sandbox_on_notify(void *reserved) { 232 (void)reserved; 233 PrepareForSandboxing(); 234} 235 236void __sanitizer_report_error_summary(const char *error_summary) { 237 Printf("%s\n", error_summary); 238} 239} // extern "C" 240