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