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