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