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_interface.h" 16 #include "sanitizer_allocator_internal.h" 17 #include "sanitizer_flags.h" 18 #include "sanitizer_libc.h" 19 #include "sanitizer_placement_new.h" 20 #include "sanitizer_stacktrace_printer.h" 21 #include "sanitizer_symbolizer.h" 22 23 namespace __sanitizer { 24 25 const char *SanitizerToolName = "SanitizerTool"; 26 27 atomic_uint32_t current_verbosity; 28 uptr PageSizeCached; 29 30 StaticSpinMutex report_file_mu; 31 ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0}; 32 33 void RawWrite(const char *buffer) { 34 report_file.Write(buffer, internal_strlen(buffer)); 35 } 36 37 void ReportFile::ReopenIfNecessary() { 38 mu->CheckLocked(); 39 if (fd == kStdoutFd || fd == kStderrFd) return; 40 41 uptr pid = internal_getpid(); 42 // If in tracer, use the parent's file. 43 if (pid == stoptheworld_tracer_pid) 44 pid = stoptheworld_tracer_ppid; 45 if (fd != kInvalidFd) { 46 // If the report file is already opened by the current process, 47 // do nothing. Otherwise the report file was opened by the parent 48 // process, close it now. 49 if (fd_pid == pid) 50 return; 51 else 52 CloseFile(fd); 53 } 54 55 const char *exe_name = GetProcessName(); 56 if (common_flags()->log_exe_name && exe_name) { 57 internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, 58 exe_name, pid); 59 } else { 60 internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid); 61 } 62 fd = OpenFile(full_path, WrOnly); 63 if (fd == kInvalidFd) { 64 const char *ErrorMsgPrefix = "ERROR: Can't open file: "; 65 WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix)); 66 WriteToFile(kStderrFd, full_path, internal_strlen(full_path)); 67 Die(); 68 } 69 fd_pid = pid; 70 } 71 72 void ReportFile::SetReportPath(const char *path) { 73 if (!path) 74 return; 75 uptr len = internal_strlen(path); 76 if (len > sizeof(path_prefix) - 100) { 77 Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n", 78 path[0], path[1], path[2], path[3], 79 path[4], path[5], path[6], path[7]); 80 Die(); 81 } 82 83 SpinMutexLock l(mu); 84 if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd) 85 CloseFile(fd); 86 fd = kInvalidFd; 87 if (internal_strcmp(path, "stdout") == 0) { 88 fd = kStdoutFd; 89 } else if (internal_strcmp(path, "stderr") == 0) { 90 fd = kStderrFd; 91 } else { 92 internal_snprintf(path_prefix, kMaxPathLength, "%s", path); 93 } 94 } 95 96 // PID of the tracer task in StopTheWorld. It shares the address space with the 97 // main process, but has a different PID and thus requires special handling. 98 uptr stoptheworld_tracer_pid = 0; 99 // Cached pid of parent process - if the parent process dies, we want to keep 100 // writing to the same log file. 101 uptr stoptheworld_tracer_ppid = 0; 102 103 void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type, 104 const char *mmap_type, error_t err, 105 bool raw_report) { 106 static int recursion_count; 107 if (raw_report || recursion_count) { 108 // If raw report is requested or we went into recursion, just die. 109 // The Report() and CHECK calls below may call mmap recursively and fail. 110 RawWrite("ERROR: Failed to mmap\n"); 111 Die(); 112 } 113 recursion_count++; 114 Report("ERROR: %s failed to " 115 "%s 0x%zx (%zd) bytes of %s (error code: %d)\n", 116 SanitizerToolName, mmap_type, size, size, mem_type, err); 117 #ifndef SANITIZER_GO 118 DumpProcessMap(); 119 #endif 120 UNREACHABLE("unable to mmap"); 121 } 122 123 bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, 124 uptr *read_len, uptr max_len, error_t *errno_p) { 125 uptr PageSize = GetPageSizeCached(); 126 uptr kMinFileLen = PageSize; 127 *buff = nullptr; 128 *buff_size = 0; 129 *read_len = 0; 130 // The files we usually open are not seekable, so try different buffer sizes. 131 for (uptr size = kMinFileLen; size <= max_len; size *= 2) { 132 fd_t fd = OpenFile(file_name, RdOnly, errno_p); 133 if (fd == kInvalidFd) return false; 134 UnmapOrDie(*buff, *buff_size); 135 *buff = (char*)MmapOrDie(size, __func__); 136 *buff_size = size; 137 *read_len = 0; 138 // Read up to one page at a time. 139 bool reached_eof = false; 140 while (*read_len + PageSize <= size) { 141 uptr just_read; 142 if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) { 143 UnmapOrDie(*buff, *buff_size); 144 return false; 145 } 146 if (just_read == 0) { 147 reached_eof = true; 148 break; 149 } 150 *read_len += just_read; 151 } 152 CloseFile(fd); 153 if (reached_eof) // We've read the whole file. 154 break; 155 } 156 return true; 157 } 158 159 typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); 160 161 template<class T> 162 static inline bool CompareLess(const T &a, const T &b) { 163 return a < b; 164 } 165 166 void SortArray(uptr *array, uptr size) { 167 InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess); 168 } 169 170 const char *StripPathPrefix(const char *filepath, 171 const char *strip_path_prefix) { 172 if (!filepath) return nullptr; 173 if (!strip_path_prefix) return filepath; 174 const char *res = filepath; 175 if (const char *pos = internal_strstr(filepath, strip_path_prefix)) 176 res = pos + internal_strlen(strip_path_prefix); 177 if (res[0] == '.' && res[1] == '/') 178 res += 2; 179 return res; 180 } 181 182 const char *StripModuleName(const char *module) { 183 if (!module) 184 return nullptr; 185 if (SANITIZER_WINDOWS) { 186 // On Windows, both slash and backslash are possible. 187 // Pick the one that goes last. 188 if (const char *bslash_pos = internal_strrchr(module, '\\')) 189 return StripModuleName(bslash_pos + 1); 190 } 191 if (const char *slash_pos = internal_strrchr(module, '/')) { 192 return slash_pos + 1; 193 } 194 return module; 195 } 196 197 void ReportErrorSummary(const char *error_message) { 198 if (!common_flags()->print_summary) 199 return; 200 InternalScopedString buff(kMaxSummaryLength); 201 buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message); 202 __sanitizer_report_error_summary(buff.data()); 203 } 204 205 #ifndef SANITIZER_GO 206 void ReportErrorSummary(const char *error_type, const AddressInfo &info) { 207 if (!common_flags()->print_summary) 208 return; 209 InternalScopedString buff(kMaxSummaryLength); 210 buff.append("%s ", error_type); 211 RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style, 212 common_flags()->strip_path_prefix); 213 ReportErrorSummary(buff.data()); 214 } 215 #endif 216 217 // Removes the ANSI escape sequences from the input string (in-place). 218 void RemoveANSIEscapeSequencesFromString(char *str) { 219 if (!str) 220 return; 221 222 // We are going to remove the escape sequences in place. 223 char *s = str; 224 char *z = str; 225 while (*s != '\0') { 226 CHECK_GE(s, z); 227 // Skip over ANSI escape sequences with pointer 's'. 228 if (*s == '\033' && *(s + 1) == '[') { 229 s = internal_strchrnul(s, 'm'); 230 if (*s == '\0') { 231 break; 232 } 233 s++; 234 continue; 235 } 236 // 's' now points at a character we want to keep. Copy over the buffer 237 // content if the escape sequence has been perviously skipped andadvance 238 // both pointers. 239 if (s != z) 240 *z = *s; 241 242 // If we have not seen an escape sequence, just advance both pointers. 243 z++; 244 s++; 245 } 246 247 // Null terminate the string. 248 *z = '\0'; 249 } 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 (const AddressRange &r : ranges()) { 275 if (r.beg <= address && address < r.end) 276 return true; 277 } 278 return false; 279 } 280 281 static atomic_uintptr_t g_total_mmaped; 282 283 void IncreaseTotalMmap(uptr size) { 284 if (!common_flags()->mmap_limit_mb) return; 285 uptr total_mmaped = 286 atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size; 287 // Since for now mmap_limit_mb is not a user-facing flag, just kill 288 // a program. Use RAW_CHECK to avoid extra mmaps in reporting. 289 RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb); 290 } 291 292 void DecreaseTotalMmap(uptr size) { 293 if (!common_flags()->mmap_limit_mb) return; 294 atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed); 295 } 296 297 bool TemplateMatch(const char *templ, const char *str) { 298 if ((!str) || str[0] == 0) 299 return false; 300 bool start = false; 301 if (templ && templ[0] == '^') { 302 start = true; 303 templ++; 304 } 305 bool asterisk = false; 306 while (templ && templ[0]) { 307 if (templ[0] == '*') { 308 templ++; 309 start = false; 310 asterisk = true; 311 continue; 312 } 313 if (templ[0] == '$') 314 return str[0] == 0 || asterisk; 315 if (str[0] == 0) 316 return false; 317 char *tpos = (char*)internal_strchr(templ, '*'); 318 char *tpos1 = (char*)internal_strchr(templ, '$'); 319 if ((!tpos) || (tpos1 && tpos1 < tpos)) 320 tpos = tpos1; 321 if (tpos) 322 tpos[0] = 0; 323 const char *str0 = str; 324 const char *spos = internal_strstr(str, templ); 325 str = spos + internal_strlen(templ); 326 templ = tpos; 327 if (tpos) 328 tpos[0] = tpos == tpos1 ? '$' : '*'; 329 if (!spos) 330 return false; 331 if (start && spos != str0) 332 return false; 333 start = false; 334 asterisk = false; 335 } 336 return true; 337 } 338 339 static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; 340 341 char *FindPathToBinary(const char *name) { 342 if (FileExists(name)) { 343 return internal_strdup(name); 344 } 345 346 const char *path = GetEnv("PATH"); 347 if (!path) 348 return nullptr; 349 uptr name_len = internal_strlen(name); 350 InternalScopedBuffer<char> buffer(kMaxPathLength); 351 const char *beg = path; 352 while (true) { 353 const char *end = internal_strchrnul(beg, kPathSeparator); 354 uptr prefix_len = end - beg; 355 if (prefix_len + name_len + 2 <= kMaxPathLength) { 356 internal_memcpy(buffer.data(), beg, prefix_len); 357 buffer[prefix_len] = '/'; 358 internal_memcpy(&buffer[prefix_len + 1], name, name_len); 359 buffer[prefix_len + 1 + name_len] = '\0'; 360 if (FileExists(buffer.data())) 361 return internal_strdup(buffer.data()); 362 } 363 if (*end == '\0') break; 364 beg = end + 1; 365 } 366 return nullptr; 367 } 368 369 static char binary_name_cache_str[kMaxPathLength]; 370 static char process_name_cache_str[kMaxPathLength]; 371 372 const char *GetProcessName() { 373 return process_name_cache_str; 374 } 375 376 static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) { 377 ReadLongProcessName(buf, buf_len); 378 char *s = const_cast<char *>(StripModuleName(buf)); 379 uptr len = internal_strlen(s); 380 if (s != buf) { 381 internal_memmove(buf, s, len); 382 buf[len] = '\0'; 383 } 384 return len; 385 } 386 387 void UpdateProcessName() { 388 ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); 389 } 390 391 // Call once to make sure that binary_name_cache_str is initialized 392 void CacheBinaryName() { 393 if (binary_name_cache_str[0] != '\0') 394 return; 395 ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str)); 396 ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); 397 } 398 399 uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) { 400 CacheBinaryName(); 401 uptr name_len = internal_strlen(binary_name_cache_str); 402 name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1; 403 if (buf_len == 0) 404 return 0; 405 internal_memcpy(buf, binary_name_cache_str, name_len); 406 buf[name_len] = '\0'; 407 return name_len; 408 } 409 410 void PrintCmdline() { 411 char **argv = GetArgv(); 412 if (!argv) return; 413 Printf("\nCommand: "); 414 for (uptr i = 0; argv[i]; ++i) 415 Printf("%s ", argv[i]); 416 Printf("\n\n"); 417 } 418 419 // Malloc hooks. 420 static const int kMaxMallocFreeHooks = 5; 421 struct MallocFreeHook { 422 void (*malloc_hook)(const void *, uptr); 423 void (*free_hook)(const void *); 424 }; 425 426 static MallocFreeHook MFHooks[kMaxMallocFreeHooks]; 427 428 void RunMallocHooks(const void *ptr, uptr size) { 429 for (int i = 0; i < kMaxMallocFreeHooks; i++) { 430 auto hook = MFHooks[i].malloc_hook; 431 if (!hook) return; 432 hook(ptr, size); 433 } 434 } 435 436 void RunFreeHooks(const void *ptr) { 437 for (int i = 0; i < kMaxMallocFreeHooks; i++) { 438 auto hook = MFHooks[i].free_hook; 439 if (!hook) return; 440 hook(ptr); 441 } 442 } 443 444 static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr), 445 void (*free_hook)(const void *)) { 446 if (!malloc_hook || !free_hook) return 0; 447 for (int i = 0; i < kMaxMallocFreeHooks; i++) { 448 if (MFHooks[i].malloc_hook == nullptr) { 449 MFHooks[i].malloc_hook = malloc_hook; 450 MFHooks[i].free_hook = free_hook; 451 return i + 1; 452 } 453 } 454 return 0; 455 } 456 457 } // namespace __sanitizer 458 459 using namespace __sanitizer; // NOLINT 460 461 extern "C" { 462 void __sanitizer_set_report_path(const char *path) { 463 report_file.SetReportPath(path); 464 } 465 466 void __sanitizer_set_report_fd(void *fd) { 467 report_file.fd = (fd_t)reinterpret_cast<uptr>(fd); 468 report_file.fd_pid = internal_getpid(); 469 } 470 471 void __sanitizer_report_error_summary(const char *error_summary) { 472 Printf("%s\n", error_summary); 473 } 474 475 SANITIZER_INTERFACE_ATTRIBUTE 476 void __sanitizer_set_death_callback(void (*callback)(void)) { 477 SetUserDieCallback(callback); 478 } 479 480 SANITIZER_INTERFACE_ATTRIBUTE 481 int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *, 482 uptr), 483 void (*free_hook)(const void *)) { 484 return InstallMallocFreeHooks(malloc_hook, free_hook); 485 } 486 } // extern "C" 487