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 22namespace __sanitizer { 23 24const char *SanitizerToolName = "SanitizerTool"; 25 26atomic_uint32_t current_verbosity; 27 28uptr GetPageSizeCached() { 29 static uptr PageSize; 30 if (!PageSize) 31 PageSize = GetPageSize(); 32 return PageSize; 33} 34 35StaticSpinMutex report_file_mu; 36ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; 37 38void RawWrite(const char *buffer) { 39 report_file.Write(buffer, internal_strlen(buffer)); 40} 41 42void 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 const char *exe_name = GetProcessName(); 61 if (common_flags()->log_exe_name && exe_name) { 62 internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, 63 exe_name, pid); 64 } else { 65 internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); 66 } 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)); 72 Die(); 73 } 74 fd_pid = pid; 75} 76 77void ReportFile::SetReportPath(const char *path) { 78 if (!path) 79 return; 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]); 85 Die(); 86 } 87 88 SpinMutexLock l(mu); 89 if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) 90 CloseFile(fd); 91 fd = kInvalidFd; 92 if (internal_strcmp(path, "stdout") == 0) { 93 fd = kStdoutFd; 94 } else if (internal_strcmp(path, "stderr") == 0) { 95 fd = kStderrFd; 96 } else { 97 internal_snprintf(path_prefix, kMaxPathLength, "%s", path); 98 } 99} 100 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. 103uptr 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. 106uptr stoptheworld_tracer_ppid = 0; 107 108static const int kMaxNumOfInternalDieCallbacks = 5; 109static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks]; 110 111bool AddDieCallback(DieCallbackType callback) { 112 for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) { 113 if (InternalDieCallbacks[i] == nullptr) { 114 InternalDieCallbacks[i] = callback; 115 return true; 116 } 117 } 118 return false; 119} 120 121bool RemoveDieCallback(DieCallbackType callback) { 122 for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) { 123 if (InternalDieCallbacks[i] == callback) { 124 internal_memmove(&InternalDieCallbacks[i], &InternalDieCallbacks[i + 1], 125 sizeof(InternalDieCallbacks[0]) * 126 (kMaxNumOfInternalDieCallbacks - i - 1)); 127 InternalDieCallbacks[kMaxNumOfInternalDieCallbacks - 1] = nullptr; 128 return true; 129 } 130 } 131 return false; 132} 133 134static DieCallbackType UserDieCallback; 135void SetUserDieCallback(DieCallbackType callback) { 136 UserDieCallback = callback; 137} 138 139void NORETURN Die() { 140 if (UserDieCallback) 141 UserDieCallback(); 142 for (int i = kMaxNumOfInternalDieCallbacks - 1; i >= 0; i--) { 143 if (InternalDieCallbacks[i]) 144 InternalDieCallbacks[i](); 145 } 146 if (common_flags()->abort_on_error) 147 Abort(); 148 internal__exit(common_flags()->exitcode); 149} 150 151static CheckFailedCallbackType CheckFailedCallback; 152void SetCheckFailedCallback(CheckFailedCallbackType callback) { 153 CheckFailedCallback = callback; 154} 155 156void NORETURN CheckFailed(const char *file, int line, const char *cond, 157 u64 v1, u64 v2) { 158 if (CheckFailedCallback) { 159 CheckFailedCallback(file, line, cond, v1, v2); 160 } 161 Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond, 162 v1, v2); 163 Die(); 164} 165 166void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type, 167 const char *mmap_type, error_t err, 168 bool raw_report) { 169 static int recursion_count; 170 if (raw_report || recursion_count) { 171 // If raw report is requested or we went into recursion, just die. 172 // The Report() and CHECK calls below may call mmap recursively and fail. 173 RawWrite("ERROR: Failed to mmap\n"); 174 Die(); 175 } 176 recursion_count++; 177 Report("ERROR: %s failed to " 178 "%s 0x%zx (%zd) bytes of %s (error code: %d)\n", 179 SanitizerToolName, mmap_type, size, size, mem_type, err); 180#ifndef SANITIZER_GO 181 DumpProcessMap(); 182#endif 183 UNREACHABLE("unable to mmap"); 184} 185 186bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, 187 uptr *read_len, uptr max_len, error_t *errno_p) { 188 uptr PageSize = GetPageSizeCached(); 189 uptr kMinFileLen = PageSize; 190 *buff = nullptr; 191 *buff_size = 0; 192 *read_len = 0; 193 // The files we usually open are not seekable, so try different buffer sizes. 194 for (uptr size = kMinFileLen; size <= max_len; size *= 2) { 195 fd_t fd = OpenFile(file_name, RdOnly, errno_p); 196 if (fd == kInvalidFd) return false; 197 UnmapOrDie(*buff, *buff_size); 198 *buff = (char*)MmapOrDie(size, __func__); 199 *buff_size = size; 200 *read_len = 0; 201 // Read up to one page at a time. 202 bool reached_eof = false; 203 while (*read_len + PageSize <= size) { 204 uptr just_read; 205 if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) { 206 UnmapOrDie(*buff, *buff_size); 207 return false; 208 } 209 if (just_read == 0) { 210 reached_eof = true; 211 break; 212 } 213 *read_len += just_read; 214 } 215 CloseFile(fd); 216 if (reached_eof) // We've read the whole file. 217 break; 218 } 219 return true; 220} 221 222typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); 223 224template<class T> 225static inline bool CompareLess(const T &a, const T &b) { 226 return a < b; 227} 228 229void SortArray(uptr *array, uptr size) { 230 InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess); 231} 232 233// We want to map a chunk of address space aligned to 'alignment'. 234// We do it by maping a bit more and then unmaping redundant pieces. 235// We probably can do it with fewer syscalls in some OS-dependent way. 236void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { 237// uptr PageSize = GetPageSizeCached(); 238 CHECK(IsPowerOfTwo(size)); 239 CHECK(IsPowerOfTwo(alignment)); 240 uptr map_size = size + alignment; 241 uptr map_res = (uptr)MmapOrDie(map_size, mem_type); 242 uptr map_end = map_res + map_size; 243 uptr res = map_res; 244 if (res & (alignment - 1)) // Not aligned. 245 res = (map_res + alignment) & ~(alignment - 1); 246 uptr end = res + size; 247 if (res != map_res) 248 UnmapOrDie((void*)map_res, res - map_res); 249 if (end != map_end) 250 UnmapOrDie((void*)end, map_end - end); 251 return (void*)res; 252} 253 254const char *StripPathPrefix(const char *filepath, 255 const char *strip_path_prefix) { 256 if (!filepath) return nullptr; 257 if (!strip_path_prefix) return filepath; 258 const char *res = filepath; 259 if (const char *pos = internal_strstr(filepath, strip_path_prefix)) 260 res = pos + internal_strlen(strip_path_prefix); 261 if (res[0] == '.' && res[1] == '/') 262 res += 2; 263 return res; 264} 265 266const char *StripModuleName(const char *module) { 267 if (!module) 268 return nullptr; 269 if (SANITIZER_WINDOWS) { 270 // On Windows, both slash and backslash are possible. 271 // Pick the one that goes last. 272 if (const char *bslash_pos = internal_strrchr(module, '\\')) 273 return StripModuleName(bslash_pos + 1); 274 } 275 if (const char *slash_pos = internal_strrchr(module, '/')) { 276 return slash_pos + 1; 277 } 278 return module; 279} 280 281void ReportErrorSummary(const char *error_message) { 282 if (!common_flags()->print_summary) 283 return; 284 InternalScopedString buff(kMaxSummaryLength); 285 buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message); 286 __sanitizer_report_error_summary(buff.data()); 287} 288 289#ifndef SANITIZER_GO 290void ReportErrorSummary(const char *error_type, const AddressInfo &info) { 291 if (!common_flags()->print_summary) 292 return; 293 InternalScopedString buff(kMaxSummaryLength); 294 buff.append("%s ", error_type); 295 RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style, 296 common_flags()->strip_path_prefix); 297 ReportErrorSummary(buff.data()); 298} 299#endif 300 301// Removes the ANSI escape sequences from the input string (in-place). 302void RemoveANSIEscapeSequencesFromString(char *str) { 303 if (!str) 304 return; 305 306 // We are going to remove the escape sequences in place. 307 char *s = str; 308 char *z = str; 309 while (*s != '\0') { 310 CHECK_GE(s, z); 311 // Skip over ANSI escape sequences with pointer 's'. 312 if (*s == '\033' && *(s + 1) == '[') { 313 s = internal_strchrnul(s, 'm'); 314 if (*s == '\0') { 315 break; 316 } 317 s++; 318 continue; 319 } 320 // 's' now points at a character we want to keep. Copy over the buffer 321 // content if the escape sequence has been perviously skipped andadvance 322 // both pointers. 323 if (s != z) 324 *z = *s; 325 326 // If we have not seen an escape sequence, just advance both pointers. 327 z++; 328 s++; 329 } 330 331 // Null terminate the string. 332 *z = '\0'; 333} 334 335void LoadedModule::set(const char *module_name, uptr base_address) { 336 clear(); 337 full_name_ = internal_strdup(module_name); 338 base_address_ = base_address; 339} 340 341void LoadedModule::clear() { 342 InternalFree(full_name_); 343 full_name_ = nullptr; 344 while (!ranges_.empty()) { 345 AddressRange *r = ranges_.front(); 346 ranges_.pop_front(); 347 InternalFree(r); 348 } 349} 350 351void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) { 352 void *mem = InternalAlloc(sizeof(AddressRange)); 353 AddressRange *r = new(mem) AddressRange(beg, end, executable); 354 ranges_.push_back(r); 355} 356 357bool LoadedModule::containsAddress(uptr address) const { 358 for (Iterator iter = ranges(); iter.hasNext();) { 359 const AddressRange *r = iter.next(); 360 if (r->beg <= address && address < r->end) 361 return true; 362 } 363 return false; 364} 365 366static atomic_uintptr_t g_total_mmaped; 367 368void IncreaseTotalMmap(uptr size) { 369 if (!common_flags()->mmap_limit_mb) return; 370 uptr total_mmaped = 371 atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size; 372 // Since for now mmap_limit_mb is not a user-facing flag, just kill 373 // a program. Use RAW_CHECK to avoid extra mmaps in reporting. 374 RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb); 375} 376 377void DecreaseTotalMmap(uptr size) { 378 if (!common_flags()->mmap_limit_mb) return; 379 atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed); 380} 381 382bool TemplateMatch(const char *templ, const char *str) { 383 if ((!str) || str[0] == 0) 384 return false; 385 bool start = false; 386 if (templ && templ[0] == '^') { 387 start = true; 388 templ++; 389 } 390 bool asterisk = false; 391 while (templ && templ[0]) { 392 if (templ[0] == '*') { 393 templ++; 394 start = false; 395 asterisk = true; 396 continue; 397 } 398 if (templ[0] == '$') 399 return str[0] == 0 || asterisk; 400 if (str[0] == 0) 401 return false; 402 char *tpos = (char*)internal_strchr(templ, '*'); 403 char *tpos1 = (char*)internal_strchr(templ, '$'); 404 if ((!tpos) || (tpos1 && tpos1 < tpos)) 405 tpos = tpos1; 406 if (tpos) 407 tpos[0] = 0; 408 const char *str0 = str; 409 const char *spos = internal_strstr(str, templ); 410 str = spos + internal_strlen(templ); 411 templ = tpos; 412 if (tpos) 413 tpos[0] = tpos == tpos1 ? '$' : '*'; 414 if (!spos) 415 return false; 416 if (start && spos != str0) 417 return false; 418 start = false; 419 asterisk = false; 420 } 421 return true; 422} 423 424static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; 425 426char *FindPathToBinary(const char *name) { 427 const char *path = GetEnv("PATH"); 428 if (!path) 429 return nullptr; 430 uptr name_len = internal_strlen(name); 431 InternalScopedBuffer<char> buffer(kMaxPathLength); 432 const char *beg = path; 433 while (true) { 434 const char *end = internal_strchrnul(beg, kPathSeparator); 435 uptr prefix_len = end - beg; 436 if (prefix_len + name_len + 2 <= kMaxPathLength) { 437 internal_memcpy(buffer.data(), beg, prefix_len); 438 buffer[prefix_len] = '/'; 439 internal_memcpy(&buffer[prefix_len + 1], name, name_len); 440 buffer[prefix_len + 1 + name_len] = '\0'; 441 if (FileExists(buffer.data())) 442 return internal_strdup(buffer.data()); 443 } 444 if (*end == '\0') break; 445 beg = end + 1; 446 } 447 return nullptr; 448} 449 450static char binary_name_cache_str[kMaxPathLength]; 451static char process_name_cache_str[kMaxPathLength]; 452 453const char *GetProcessName() { 454 return process_name_cache_str; 455} 456 457static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) { 458 ReadLongProcessName(buf, buf_len); 459 char *s = const_cast<char *>(StripModuleName(buf)); 460 uptr len = internal_strlen(s); 461 if (s != buf) { 462 internal_memmove(buf, s, len); 463 buf[len] = '\0'; 464 } 465 return len; 466} 467 468void UpdateProcessName() { 469 ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); 470} 471 472// Call once to make sure that binary_name_cache_str is initialized 473void CacheBinaryName() { 474 if (binary_name_cache_str[0] != '\0') 475 return; 476 ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str)); 477 ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); 478} 479 480uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) { 481 CacheBinaryName(); 482 uptr name_len = internal_strlen(binary_name_cache_str); 483 name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1; 484 if (buf_len == 0) 485 return 0; 486 internal_memcpy(buf, binary_name_cache_str, name_len); 487 buf[name_len] = '\0'; 488 return name_len; 489} 490 491} // namespace __sanitizer 492 493using namespace __sanitizer; // NOLINT 494 495extern "C" { 496void __sanitizer_set_report_path(const char *path) { 497 report_file.SetReportPath(path); 498} 499 500void __sanitizer_report_error_summary(const char *error_summary) { 501 Printf("%s\n", error_summary); 502} 503 504SANITIZER_INTERFACE_ATTRIBUTE 505void __sanitizer_set_death_callback(void (*callback)(void)) { 506 SetUserDieCallback(callback); 507} 508} // extern "C" 509