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_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" 21 22 namespace __sanitizer { 23 24 const char *SanitizerToolName = "SanitizerTool"; 25 26 atomic_uint32_t current_verbosity; 27 28 uptr GetPageSizeCached() { 29 static uptr PageSize; 30 if (!PageSize) 31 PageSize = GetPageSize(); 32 return PageSize; 33 } 34 35 StaticSpinMutex report_file_mu; 36 ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; 37 38 void RawWrite(const char *buffer) { 39 report_file.Write(buffer, internal_strlen(buffer)); 40 } 41 42 void ReportFile::ReopenIfNecessary() { 43 mu->CheckLocked(); 44 if (fd == kStdoutFd || fd == kStderrFd) return; 45 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. 54 if (fd_pid == pid) 55 return; 56 else 57 CloseFile(fd); 58 } 59 60 internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); 61 fd = OpenFile(full_path, WrOnly); 62 if (fd == kInvalidFd) { 63 const char *ErrorMsgPrefix = "ERROR: Can't open file: "; 64 WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); 65 WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); 66 Die(); 67 } 68 fd_pid = pid; 69 } 70 71 void ReportFile::SetReportPath(const char *path) { 72 if (!path) 73 return; 74 uptr len = internal_strlen(path); 75 if (len > sizeof(path_prefix) - 100) { 76 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", 77 path[0], path[1], path[2], path[3], 78 path[4], path[5], path[6], path[7]); 79 Die(); 80 } 81 82 SpinMutexLock l(mu); 83 if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) 84 CloseFile(fd); 85 fd = kInvalidFd; 86 if (internal_strcmp(path, "stdout") == 0) { 87 fd = kStdoutFd; 88 } else if (internal_strcmp(path, "stderr") == 0) { 89 fd = kStderrFd; 90 } else { 91 internal_snprintf(path_prefix, kMaxPathLength, "%s", path); 92 } 93 } 94 95 // PID of the tracer task in StopTheWorld. It shares the address space with the 96 // main process, but has a different PID and thus requires special handling. 97 uptr stoptheworld_tracer_pid = 0; 98 // Cached pid of parent process - if the parent process dies, we want to keep 99 // writing to the same log file. 100 uptr stoptheworld_tracer_ppid = 0; 101 102 static DieCallbackType InternalDieCallback, UserDieCallback; 103 void SetDieCallback(DieCallbackType callback) { 104 InternalDieCallback = callback; 105 } 106 void SetUserDieCallback(DieCallbackType callback) { 107 UserDieCallback = callback; 108 } 109 110 DieCallbackType GetDieCallback() { 111 return InternalDieCallback; 112 } 113 114 void NORETURN Die() { 115 if (UserDieCallback) 116 UserDieCallback(); 117 if (InternalDieCallback) 118 InternalDieCallback(); 119 internal__exit(1); 120 } 121 122 static CheckFailedCallbackType CheckFailedCallback; 123 void SetCheckFailedCallback(CheckFailedCallbackType callback) { 124 CheckFailedCallback = callback; 125 } 126 127 void NORETURN CheckFailed(const char *file, int line, const char *cond, 128 u64 v1, u64 v2) { 129 if (CheckFailedCallback) { 130 CheckFailedCallback(file, line, cond, v1, v2); 131 } 132 Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond, 133 v1, v2); 134 Die(); 135 } 136 137 uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, 138 uptr max_len, error_t *errno_p) { 139 uptr PageSize = GetPageSizeCached(); 140 uptr kMinFileLen = PageSize; 141 uptr read_len = 0; 142 *buff = 0; 143 *buff_size = 0; 144 // The files we usually open are not seekable, so try different buffer sizes. 145 for (uptr size = kMinFileLen; size <= max_len; size *= 2) { 146 fd_t fd = OpenFile(file_name, RdOnly, errno_p); 147 if (fd == kInvalidFd) return 0; 148 UnmapOrDie(*buff, *buff_size); 149 *buff = (char*)MmapOrDie(size, __func__); 150 *buff_size = size; 151 // Read up to one page at a time. 152 read_len = 0; 153 bool reached_eof = false; 154 while (read_len + PageSize <= size) { 155 uptr just_read; 156 if (!ReadFromFile(fd, *buff + read_len, PageSize, &just_read, errno_p)) { 157 UnmapOrDie(*buff, *buff_size); 158 return 0; 159 } 160 if (just_read == 0) { 161 reached_eof = true; 162 break; 163 } 164 read_len += just_read; 165 } 166 CloseFile(fd); 167 if (reached_eof) // We've read the whole file. 168 break; 169 } 170 return read_len; 171 } 172 173 typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); 174 175 template<class T> 176 static inline bool CompareLess(const T &a, const T &b) { 177 return a < b; 178 } 179 180 void SortArray(uptr *array, uptr size) { 181 InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess); 182 } 183 184 // We want to map a chunk of address space aligned to 'alignment'. 185 // We do it by maping a bit more and then unmaping redundant pieces. 186 // We probably can do it with fewer syscalls in some OS-dependent way. 187 void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { 188 // uptr PageSize = GetPageSizeCached(); 189 CHECK(IsPowerOfTwo(size)); 190 CHECK(IsPowerOfTwo(alignment)); 191 uptr map_size = size + alignment; 192 uptr map_res = (uptr)MmapOrDie(map_size, mem_type); 193 uptr map_end = map_res + map_size; 194 uptr res = map_res; 195 if (res & (alignment - 1)) // Not aligned. 196 res = (map_res + alignment) & ~(alignment - 1); 197 uptr end = res + size; 198 if (res != map_res) 199 UnmapOrDie((void*)map_res, res - map_res); 200 if (end != map_end) 201 UnmapOrDie((void*)end, map_end - end); 202 return (void*)res; 203 } 204 205 const char *StripPathPrefix(const char *filepath, 206 const char *strip_path_prefix) { 207 if (filepath == 0) return 0; 208 if (strip_path_prefix == 0) return filepath; 209 const char *res = filepath; 210 if (const char *pos = internal_strstr(filepath, strip_path_prefix)) 211 res = pos + internal_strlen(strip_path_prefix); 212 if (res[0] == '.' && res[1] == '/') 213 res += 2; 214 return res; 215 } 216 217 const char *StripModuleName(const char *module) { 218 if (module == 0) 219 return 0; 220 if (SANITIZER_WINDOWS) { 221 // On Windows, both slash and backslash are possible. 222 // Pick the one that goes last. 223 if (const char *bslash_pos = internal_strrchr(module, '\\')) 224 return StripModuleName(bslash_pos + 1); 225 } 226 if (const char *slash_pos = internal_strrchr(module, '/')) { 227 return slash_pos + 1; 228 } 229 return module; 230 } 231 232 void ReportErrorSummary(const char *error_message) { 233 if (!common_flags()->print_summary) 234 return; 235 InternalScopedString buff(kMaxSummaryLength); 236 buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message); 237 __sanitizer_report_error_summary(buff.data()); 238 } 239 240 #ifndef SANITIZER_GO 241 void ReportErrorSummary(const char *error_type, const AddressInfo &info) { 242 if (!common_flags()->print_summary) 243 return; 244 InternalScopedString buff(kMaxSummaryLength); 245 buff.append("%s ", error_type); 246 RenderFrame(&buff, "%L %F", 0, info, common_flags()->strip_path_prefix); 247 ReportErrorSummary(buff.data()); 248 } 249 #endif 250 251 void LoadedModule::set(const char *module_name, uptr base_address) { 252 clear(); 253 full_name_ = internal_strdup(module_name); 254 base_address_ = base_address; 255 } 256 257 void LoadedModule::clear() { 258 InternalFree(full_name_); 259 full_name_ = nullptr; 260 while (!ranges_.empty()) { 261 AddressRange *r = ranges_.front(); 262 ranges_.pop_front(); 263 InternalFree(r); 264 } 265 } 266 267 void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) { 268 void *mem = InternalAlloc(sizeof(AddressRange)); 269 AddressRange *r = new(mem) AddressRange(beg, end, executable); 270 ranges_.push_back(r); 271 } 272 273 bool LoadedModule::containsAddress(uptr address) const { 274 for (Iterator iter = ranges(); iter.hasNext();) { 275 const AddressRange *r = iter.next(); 276 if (r->beg <= address && address < r->end) 277 return true; 278 } 279 return false; 280 } 281 282 static atomic_uintptr_t g_total_mmaped; 283 284 void IncreaseTotalMmap(uptr size) { 285 if (!common_flags()->mmap_limit_mb) return; 286 uptr total_mmaped = 287 atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size; 288 // Since for now mmap_limit_mb is not a user-facing flag, just kill 289 // a program. Use RAW_CHECK to avoid extra mmaps in reporting. 290 RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb); 291 } 292 293 void DecreaseTotalMmap(uptr size) { 294 if (!common_flags()->mmap_limit_mb) return; 295 atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed); 296 } 297 298 bool TemplateMatch(const char *templ, const char *str) { 299 if (str == 0 || str[0] == 0) 300 return false; 301 bool start = false; 302 if (templ && templ[0] == '^') { 303 start = true; 304 templ++; 305 } 306 bool asterisk = false; 307 while (templ && templ[0]) { 308 if (templ[0] == '*') { 309 templ++; 310 start = false; 311 asterisk = true; 312 continue; 313 } 314 if (templ[0] == '$') 315 return str[0] == 0 || asterisk; 316 if (str[0] == 0) 317 return false; 318 char *tpos = (char*)internal_strchr(templ, '*'); 319 char *tpos1 = (char*)internal_strchr(templ, '$'); 320 if (tpos == 0 || (tpos1 && tpos1 < tpos)) 321 tpos = tpos1; 322 if (tpos != 0) 323 tpos[0] = 0; 324 const char *str0 = str; 325 const char *spos = internal_strstr(str, templ); 326 str = spos + internal_strlen(templ); 327 templ = tpos; 328 if (tpos) 329 tpos[0] = tpos == tpos1 ? '$' : '*'; 330 if (spos == 0) 331 return false; 332 if (start && spos != str0) 333 return false; 334 start = false; 335 asterisk = false; 336 } 337 return true; 338 } 339 340 } // namespace __sanitizer 341 342 using namespace __sanitizer; // NOLINT 343 344 extern "C" { 345 void __sanitizer_set_report_path(const char *path) { 346 report_file.SetReportPath(path); 347 } 348 349 void __sanitizer_report_error_summary(const char *error_summary) { 350 Printf("%s\n", error_summary); 351 } 352 353 SANITIZER_INTERFACE_ATTRIBUTE 354 void __sanitizer_set_death_callback(void (*callback)(void)) { 355 SetUserDieCallback(callback); 356 } 357 } // extern "C" 358