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