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