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 typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); 65 typedef bool U32ComparisonFunction(const u32 &a, const u32 &b); 66 67 const char *StripPathPrefix(const char *filepath, 68 const char *strip_path_prefix) { 69 if (!filepath) return nullptr; 70 if (!strip_path_prefix) return filepath; 71 const char *res = filepath; 72 if (const char *pos = internal_strstr(filepath, strip_path_prefix)) 73 res = pos + internal_strlen(strip_path_prefix); 74 if (res[0] == '.' && res[1] == '/') 75 res += 2; 76 return res; 77 } 78 79 const char *StripModuleName(const char *module) { 80 if (!module) 81 return nullptr; 82 if (SANITIZER_WINDOWS) { 83 // On Windows, both slash and backslash are possible. 84 // Pick the one that goes last. 85 if (const char *bslash_pos = internal_strrchr(module, '\\')) 86 return StripModuleName(bslash_pos + 1); 87 } 88 if (const char *slash_pos = internal_strrchr(module, '/')) { 89 return slash_pos + 1; 90 } 91 return module; 92 } 93 94 void ReportErrorSummary(const char *error_message, const char *alt_tool_name) { 95 if (!common_flags()->print_summary) 96 return; 97 InternalScopedString buff; 98 buff.append("SUMMARY: %s: %s", 99 alt_tool_name ? alt_tool_name : SanitizerToolName, error_message); 100 __sanitizer_report_error_summary(buff.data()); 101 } 102 103 // Removes the ANSI escape sequences from the input string (in-place). 104 void RemoveANSIEscapeSequencesFromString(char *str) { 105 if (!str) 106 return; 107 108 // We are going to remove the escape sequences in place. 109 char *s = str; 110 char *z = str; 111 while (*s != '\0') { 112 CHECK_GE(s, z); 113 // Skip over ANSI escape sequences with pointer 's'. 114 if (*s == '\033' && *(s + 1) == '[') { 115 s = internal_strchrnul(s, 'm'); 116 if (*s == '\0') { 117 break; 118 } 119 s++; 120 continue; 121 } 122 // 's' now points at a character we want to keep. Copy over the buffer 123 // content if the escape sequence has been perviously skipped andadvance 124 // both pointers. 125 if (s != z) 126 *z = *s; 127 128 // If we have not seen an escape sequence, just advance both pointers. 129 z++; 130 s++; 131 } 132 133 // Null terminate the string. 134 *z = '\0'; 135 } 136 137 void LoadedModule::set(const char *module_name, uptr base_address) { 138 clear(); 139 full_name_ = internal_strdup(module_name); 140 base_address_ = base_address; 141 } 142 143 void LoadedModule::set(const char *module_name, uptr base_address, 144 ModuleArch arch, u8 uuid[kModuleUUIDSize], 145 bool instrumented) { 146 set(module_name, base_address); 147 arch_ = arch; 148 internal_memcpy(uuid_, uuid, sizeof(uuid_)); 149 uuid_size_ = kModuleUUIDSize; 150 instrumented_ = instrumented; 151 } 152 153 void LoadedModule::setUuid(const char *uuid, uptr size) { 154 if (size > kModuleUUIDSize) 155 size = kModuleUUIDSize; 156 internal_memcpy(uuid_, uuid, size); 157 uuid_size_ = size; 158 } 159 160 void LoadedModule::clear() { 161 InternalFree(full_name_); 162 base_address_ = 0; 163 max_address_ = 0; 164 full_name_ = nullptr; 165 arch_ = kModuleArchUnknown; 166 internal_memset(uuid_, 0, kModuleUUIDSize); 167 instrumented_ = false; 168 while (!ranges_.empty()) { 169 AddressRange *r = ranges_.front(); 170 ranges_.pop_front(); 171 InternalFree(r); 172 } 173 } 174 175 void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable, 176 bool writable, const char *name) { 177 void *mem = InternalAlloc(sizeof(AddressRange)); 178 AddressRange *r = 179 new(mem) AddressRange(beg, end, executable, writable, name); 180 ranges_.push_back(r); 181 max_address_ = Max(max_address_, end); 182 } 183 184 bool LoadedModule::containsAddress(uptr address) const { 185 for (const AddressRange &r : ranges()) { 186 if (r.beg <= address && address < r.end) 187 return true; 188 } 189 return false; 190 } 191 192 static atomic_uintptr_t g_total_mmaped; 193 194 void IncreaseTotalMmap(uptr size) { 195 if (!common_flags()->mmap_limit_mb) return; 196 uptr total_mmaped = 197 atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size; 198 // Since for now mmap_limit_mb is not a user-facing flag, just kill 199 // a program. Use RAW_CHECK to avoid extra mmaps in reporting. 200 RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb); 201 } 202 203 void DecreaseTotalMmap(uptr size) { 204 if (!common_flags()->mmap_limit_mb) return; 205 atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed); 206 } 207 208 bool TemplateMatch(const char *templ, const char *str) { 209 if ((!str) || str[0] == 0) 210 return false; 211 bool start = false; 212 if (templ && templ[0] == '^') { 213 start = true; 214 templ++; 215 } 216 bool asterisk = false; 217 while (templ && templ[0]) { 218 if (templ[0] == '*') { 219 templ++; 220 start = false; 221 asterisk = true; 222 continue; 223 } 224 if (templ[0] == '$') 225 return str[0] == 0 || asterisk; 226 if (str[0] == 0) 227 return false; 228 char *tpos = (char*)internal_strchr(templ, '*'); 229 char *tpos1 = (char*)internal_strchr(templ, '$'); 230 if ((!tpos) || (tpos1 && tpos1 < tpos)) 231 tpos = tpos1; 232 if (tpos) 233 tpos[0] = 0; 234 const char *str0 = str; 235 const char *spos = internal_strstr(str, templ); 236 str = spos + internal_strlen(templ); 237 templ = tpos; 238 if (tpos) 239 tpos[0] = tpos == tpos1 ? '$' : '*'; 240 if (!spos) 241 return false; 242 if (start && spos != str0) 243 return false; 244 start = false; 245 asterisk = false; 246 } 247 return true; 248 } 249 250 static char binary_name_cache_str[kMaxPathLength]; 251 static char process_name_cache_str[kMaxPathLength]; 252 253 const char *GetProcessName() { 254 return process_name_cache_str; 255 } 256 257 static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) { 258 ReadLongProcessName(buf, buf_len); 259 char *s = const_cast<char *>(StripModuleName(buf)); 260 uptr len = internal_strlen(s); 261 if (s != buf) { 262 internal_memmove(buf, s, len); 263 buf[len] = '\0'; 264 } 265 return len; 266 } 267 268 void UpdateProcessName() { 269 ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); 270 } 271 272 // Call once to make sure that binary_name_cache_str is initialized 273 void CacheBinaryName() { 274 if (binary_name_cache_str[0] != '\0') 275 return; 276 ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str)); 277 ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); 278 } 279 280 uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) { 281 CacheBinaryName(); 282 uptr name_len = internal_strlen(binary_name_cache_str); 283 name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1; 284 if (buf_len == 0) 285 return 0; 286 internal_memcpy(buf, binary_name_cache_str, name_len); 287 buf[name_len] = '\0'; 288 return name_len; 289 } 290 291 uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len) { 292 ReadBinaryNameCached(buf, buf_len); 293 const char *exec_name_pos = StripModuleName(buf); 294 uptr name_len = exec_name_pos - buf; 295 buf[name_len] = '\0'; 296 return name_len; 297 } 298 299 #if !SANITIZER_GO 300 void PrintCmdline() { 301 char **argv = GetArgv(); 302 if (!argv) return; 303 Printf("\nCommand: "); 304 for (uptr i = 0; argv[i]; ++i) 305 Printf("%s ", argv[i]); 306 Printf("\n\n"); 307 } 308 #endif 309 310 // Malloc hooks. 311 static const int kMaxMallocFreeHooks = 5; 312 struct MallocFreeHook { 313 void (*malloc_hook)(const void *, uptr); 314 void (*free_hook)(const void *); 315 }; 316 317 static MallocFreeHook MFHooks[kMaxMallocFreeHooks]; 318 319 void RunMallocHooks(void *ptr, uptr size) { 320 __sanitizer_malloc_hook(ptr, size); 321 for (int i = 0; i < kMaxMallocFreeHooks; i++) { 322 auto hook = MFHooks[i].malloc_hook; 323 if (!hook) 324 break; 325 hook(ptr, size); 326 } 327 } 328 329 void RunFreeHooks(void *ptr) { 330 __sanitizer_free_hook(ptr); 331 for (int i = 0; i < kMaxMallocFreeHooks; i++) { 332 auto hook = MFHooks[i].free_hook; 333 if (!hook) 334 break; 335 hook(ptr); 336 } 337 } 338 339 static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr), 340 void (*free_hook)(const void *)) { 341 if (!malloc_hook || !free_hook) return 0; 342 for (int i = 0; i < kMaxMallocFreeHooks; i++) { 343 if (MFHooks[i].malloc_hook == nullptr) { 344 MFHooks[i].malloc_hook = malloc_hook; 345 MFHooks[i].free_hook = free_hook; 346 return i + 1; 347 } 348 } 349 return 0; 350 } 351 352 void internal_sleep(unsigned seconds) { 353 internal_usleep((u64)seconds * 1000 * 1000); 354 } 355 void SleepForSeconds(unsigned seconds) { 356 internal_usleep((u64)seconds * 1000 * 1000); 357 } 358 void SleepForMillis(unsigned millis) { internal_usleep((u64)millis * 1000); } 359 360 void WaitForDebugger(unsigned seconds, const char *label) { 361 if (seconds) { 362 Report("Sleeping for %u second(s) %s\n", seconds, label); 363 SleepForSeconds(seconds); 364 } 365 } 366 367 } // namespace __sanitizer 368 369 using namespace __sanitizer; 370 371 extern "C" { 372 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary, 373 const char *error_summary) { 374 Printf("%s\n", error_summary); 375 } 376 377 SANITIZER_INTERFACE_ATTRIBUTE 378 int __sanitizer_acquire_crash_state() { 379 static atomic_uint8_t in_crash_state = {}; 380 return !atomic_exchange(&in_crash_state, 1, memory_order_relaxed); 381 } 382 383 SANITIZER_INTERFACE_ATTRIBUTE 384 int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *, 385 uptr), 386 void (*free_hook)(const void *)) { 387 return InstallMallocFreeHooks(malloc_hook, free_hook); 388 } 389 390 // Provide default (no-op) implementation of malloc hooks. 391 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook, void *ptr, 392 uptr size) { 393 (void)ptr; 394 (void)size; 395 } 396 397 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook, void *ptr) { 398 (void)ptr; 399 } 400 401 } // extern "C" 402