1 //===-- sanitizer_common.cpp ----------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is shared between AddressSanitizer and ThreadSanitizer 10 // run-time libraries. 11 //===----------------------------------------------------------------------===// 12 13 #include "sanitizer_common.h" 14 15 #include "sanitizer_allocator_interface.h" 16 #include "sanitizer_allocator_internal.h" 17 #include "sanitizer_atomic.h" 18 #include "sanitizer_flags.h" 19 #include "sanitizer_interface_internal.h" 20 #include "sanitizer_libc.h" 21 #include "sanitizer_placement_new.h" 22 23 namespace __sanitizer { 24 25 const char *SanitizerToolName = "SanitizerTool"; 26 27 atomic_uint32_t current_verbosity; 28 uptr PageSizeCached; 29 u32 NumberOfCPUsCached; 30 31 // PID of the tracer task in StopTheWorld. It shares the address space with the 32 // main process, but has a different PID and thus requires special handling. 33 uptr stoptheworld_tracer_pid = 0; 34 // Cached pid of parent process - if the parent process dies, we want to keep 35 // writing to the same log file. 36 uptr stoptheworld_tracer_ppid = 0; 37 38 void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type, 39 const char *mmap_type, error_t err, 40 bool raw_report) { 41 static int recursion_count; 42 if (raw_report || recursion_count) { 43 // If raw report is requested or we went into recursion just die. The 44 // Report() and CHECK calls below may call mmap recursively and fail. 45 RawWrite("ERROR: Failed to mmap\n"); 46 Die(); 47 } 48 recursion_count++; 49 if (ErrorIsOOM(err)) { 50 ERROR_OOM("failed to %s 0x%zx (%zd) bytes of %s (error code: %d)\n", 51 mmap_type, size, size, mem_type, err); 52 } else { 53 Report( 54 "ERROR: %s failed to " 55 "%s 0x%zx (%zd) bytes of %s (error code: %d)\n", 56 SanitizerToolName, mmap_type, size, size, mem_type, err); 57 } 58 #if !SANITIZER_GO 59 DumpProcessMap(); 60 #endif 61 UNREACHABLE("unable to mmap"); 62 } 63 64 void NORETURN ReportMunmapFailureAndDie(void *addr, uptr size, error_t err, 65 bool raw_report) { 66 static int recursion_count; 67 if (raw_report || recursion_count) { 68 // If raw report is requested or we went into recursion just die. The 69 // Report() and CHECK calls below may call munmap recursively and fail. 70 RawWrite("ERROR: Failed to munmap\n"); 71 Die(); 72 } 73 recursion_count++; 74 Report( 75 "ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p (error " 76 "code: %d)\n", 77 SanitizerToolName, size, size, addr, err); 78 #if !SANITIZER_GO 79 DumpProcessMap(); 80 #endif 81 UNREACHABLE("unable to unmmap"); 82 } 83 84 typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); 85 typedef bool U32ComparisonFunction(const u32 &a, const u32 &b); 86 87 const char *StripPathPrefix(const char *filepath, 88 const char *strip_path_prefix) { 89 if (!filepath) return nullptr; 90 if (!strip_path_prefix) return filepath; 91 const char *res = filepath; 92 if (const char *pos = internal_strstr(filepath, strip_path_prefix)) 93 res = pos + internal_strlen(strip_path_prefix); 94 if (res[0] == '.' && res[1] == '/') 95 res += 2; 96 return res; 97 } 98 99 const char *StripModuleName(const char *module) { 100 if (!module) 101 return nullptr; 102 if (SANITIZER_WINDOWS) { 103 // On Windows, both slash and backslash are possible. 104 // Pick the one that goes last. 105 if (const char *bslash_pos = internal_strrchr(module, '\\')) 106 return StripModuleName(bslash_pos + 1); 107 } 108 if (const char *slash_pos = internal_strrchr(module, '/')) { 109 return slash_pos + 1; 110 } 111 return module; 112 } 113 114 void ReportErrorSummary(const char *error_message, const char *alt_tool_name) { 115 if (!common_flags()->print_summary) 116 return; 117 InternalScopedString buff; 118 buff.AppendF("SUMMARY: %s: %s", 119 alt_tool_name ? alt_tool_name : SanitizerToolName, 120 error_message); 121 __sanitizer_report_error_summary(buff.data()); 122 } 123 124 // Removes the ANSI escape sequences from the input string (in-place). 125 void RemoveANSIEscapeSequencesFromString(char *str) { 126 if (!str) 127 return; 128 129 // We are going to remove the escape sequences in place. 130 char *s = str; 131 char *z = str; 132 while (*s != '\0') { 133 CHECK_GE(s, z); 134 // Skip over ANSI escape sequences with pointer 's'. 135 if (*s == '\033' && *(s + 1) == '[') { 136 s = internal_strchrnul(s, 'm'); 137 if (*s == '\0') { 138 break; 139 } 140 s++; 141 continue; 142 } 143 // 's' now points at a character we want to keep. Copy over the buffer 144 // content if the escape sequence has been perviously skipped andadvance 145 // both pointers. 146 if (s != z) 147 *z = *s; 148 149 // If we have not seen an escape sequence, just advance both pointers. 150 z++; 151 s++; 152 } 153 154 // Null terminate the string. 155 *z = '\0'; 156 } 157 158 void LoadedModule::set(const char *module_name, uptr base_address) { 159 clear(); 160 full_name_ = internal_strdup(module_name); 161 base_address_ = base_address; 162 } 163 164 void LoadedModule::set(const char *module_name, uptr base_address, 165 ModuleArch arch, u8 uuid[kModuleUUIDSize], 166 bool instrumented) { 167 set(module_name, base_address); 168 arch_ = arch; 169 internal_memcpy(uuid_, uuid, sizeof(uuid_)); 170 uuid_size_ = kModuleUUIDSize; 171 instrumented_ = instrumented; 172 } 173 174 void LoadedModule::setUuid(const char *uuid, uptr size) { 175 if (size > kModuleUUIDSize) 176 size = kModuleUUIDSize; 177 internal_memcpy(uuid_, uuid, size); 178 uuid_size_ = size; 179 } 180 181 void LoadedModule::clear() { 182 InternalFree(full_name_); 183 base_address_ = 0; 184 max_address_ = 0; 185 full_name_ = nullptr; 186 arch_ = kModuleArchUnknown; 187 internal_memset(uuid_, 0, kModuleUUIDSize); 188 instrumented_ = false; 189 while (!ranges_.empty()) { 190 AddressRange *r = ranges_.front(); 191 ranges_.pop_front(); 192 InternalFree(r); 193 } 194 } 195 196 void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable, 197 bool writable, const char *name) { 198 void *mem = InternalAlloc(sizeof(AddressRange)); 199 AddressRange *r = 200 new(mem) AddressRange(beg, end, executable, writable, name); 201 ranges_.push_back(r); 202 max_address_ = Max(max_address_, end); 203 } 204 205 bool LoadedModule::containsAddress(uptr address) const { 206 for (const AddressRange &r : ranges()) { 207 if (r.beg <= address && address < r.end) 208 return true; 209 } 210 return false; 211 } 212 213 static atomic_uintptr_t g_total_mmaped; 214 215 void IncreaseTotalMmap(uptr size) { 216 if (!common_flags()->mmap_limit_mb) return; 217 uptr total_mmaped = 218 atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size; 219 // Since for now mmap_limit_mb is not a user-facing flag, just kill 220 // a program. Use RAW_CHECK to avoid extra mmaps in reporting. 221 RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb); 222 } 223 224 void DecreaseTotalMmap(uptr size) { 225 if (!common_flags()->mmap_limit_mb) return; 226 atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed); 227 } 228 229 bool TemplateMatch(const char *templ, const char *str) { 230 if ((!str) || str[0] == 0) 231 return false; 232 bool start = false; 233 if (templ && templ[0] == '^') { 234 start = true; 235 templ++; 236 } 237 bool asterisk = false; 238 while (templ && templ[0]) { 239 if (templ[0] == '*') { 240 templ++; 241 start = false; 242 asterisk = true; 243 continue; 244 } 245 if (templ[0] == '$') 246 return str[0] == 0 || asterisk; 247 if (str[0] == 0) 248 return false; 249 char *tpos = (char*)internal_strchr(templ, '*'); 250 char *tpos1 = (char*)internal_strchr(templ, '$'); 251 if ((!tpos) || (tpos1 && tpos1 < tpos)) 252 tpos = tpos1; 253 if (tpos) 254 tpos[0] = 0; 255 const char *str0 = str; 256 const char *spos = internal_strstr(str, templ); 257 str = spos + internal_strlen(templ); 258 templ = tpos; 259 if (tpos) 260 tpos[0] = tpos == tpos1 ? '$' : '*'; 261 if (!spos) 262 return false; 263 if (start && spos != str0) 264 return false; 265 start = false; 266 asterisk = false; 267 } 268 return true; 269 } 270 271 static char binary_name_cache_str[kMaxPathLength]; 272 static char process_name_cache_str[kMaxPathLength]; 273 274 const char *GetProcessName() { 275 return process_name_cache_str; 276 } 277 278 static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) { 279 ReadLongProcessName(buf, buf_len); 280 char *s = const_cast<char *>(StripModuleName(buf)); 281 uptr len = internal_strlen(s); 282 if (s != buf) { 283 internal_memmove(buf, s, len); 284 buf[len] = '\0'; 285 } 286 return len; 287 } 288 289 void UpdateProcessName() { 290 ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); 291 } 292 293 // Call once to make sure that binary_name_cache_str is initialized 294 void CacheBinaryName() { 295 if (binary_name_cache_str[0] != '\0') 296 return; 297 ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str)); 298 ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); 299 } 300 301 uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) { 302 CacheBinaryName(); 303 uptr name_len = internal_strlen(binary_name_cache_str); 304 name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1; 305 if (buf_len == 0) 306 return 0; 307 internal_memcpy(buf, binary_name_cache_str, name_len); 308 buf[name_len] = '\0'; 309 return name_len; 310 } 311 312 uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len) { 313 ReadBinaryNameCached(buf, buf_len); 314 const char *exec_name_pos = StripModuleName(buf); 315 uptr name_len = exec_name_pos - buf; 316 buf[name_len] = '\0'; 317 return name_len; 318 } 319 320 #if !SANITIZER_GO 321 void PrintCmdline() { 322 char **argv = GetArgv(); 323 if (!argv) return; 324 Printf("\nCommand: "); 325 for (uptr i = 0; argv[i]; ++i) 326 Printf("%s ", argv[i]); 327 Printf("\n\n"); 328 } 329 #endif 330 331 // Malloc hooks. 332 static const int kMaxMallocFreeHooks = 5; 333 struct MallocFreeHook { 334 void (*malloc_hook)(const void *, uptr); 335 void (*free_hook)(const void *); 336 }; 337 338 static MallocFreeHook MFHooks[kMaxMallocFreeHooks]; 339 340 void RunMallocHooks(void *ptr, uptr size) { 341 __sanitizer_malloc_hook(ptr, size); 342 for (int i = 0; i < kMaxMallocFreeHooks; i++) { 343 auto hook = MFHooks[i].malloc_hook; 344 if (!hook) 345 break; 346 hook(ptr, size); 347 } 348 } 349 350 // Returns '1' if the call to free() should be ignored (based on 351 // __sanitizer_ignore_free_hook), or '0' otherwise. 352 int RunFreeHooks(void *ptr) { 353 if (__sanitizer_ignore_free_hook(ptr)) { 354 return 1; 355 } 356 357 __sanitizer_free_hook(ptr); 358 for (int i = 0; i < kMaxMallocFreeHooks; i++) { 359 auto hook = MFHooks[i].free_hook; 360 if (!hook) 361 break; 362 hook(ptr); 363 } 364 365 return 0; 366 } 367 368 static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr), 369 void (*free_hook)(const void *)) { 370 if (!malloc_hook || !free_hook) return 0; 371 for (int i = 0; i < kMaxMallocFreeHooks; i++) { 372 if (MFHooks[i].malloc_hook == nullptr) { 373 MFHooks[i].malloc_hook = malloc_hook; 374 MFHooks[i].free_hook = free_hook; 375 return i + 1; 376 } 377 } 378 return 0; 379 } 380 381 void internal_sleep(unsigned seconds) { 382 internal_usleep((u64)seconds * 1000 * 1000); 383 } 384 void SleepForSeconds(unsigned seconds) { 385 internal_usleep((u64)seconds * 1000 * 1000); 386 } 387 void SleepForMillis(unsigned millis) { internal_usleep((u64)millis * 1000); } 388 389 void WaitForDebugger(unsigned seconds, const char *label) { 390 if (seconds) { 391 Report("Sleeping for %u second(s) %s\n", seconds, label); 392 SleepForSeconds(seconds); 393 } 394 } 395 396 } // namespace __sanitizer 397 398 using namespace __sanitizer; 399 400 extern "C" { 401 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary, 402 const char *error_summary) { 403 Printf("%s\n", error_summary); 404 } 405 406 SANITIZER_INTERFACE_ATTRIBUTE 407 int __sanitizer_acquire_crash_state() { 408 static atomic_uint8_t in_crash_state = {}; 409 return !atomic_exchange(&in_crash_state, 1, memory_order_relaxed); 410 } 411 412 SANITIZER_INTERFACE_ATTRIBUTE 413 int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *, 414 uptr), 415 void (*free_hook)(const void *)) { 416 return InstallMallocFreeHooks(malloc_hook, free_hook); 417 } 418 419 // Provide default (no-op) implementation of malloc hooks. 420 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook, void *ptr, 421 uptr size) { 422 (void)ptr; 423 (void)size; 424 } 425 426 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook, void *ptr) { 427 (void)ptr; 428 } 429 430 SANITIZER_INTERFACE_WEAK_DEF(int, __sanitizer_ignore_free_hook, void *ptr) { 431 (void)ptr; 432 return 0; 433 } 434 435 } // extern "C" 436