Home | History | Annotate | Download | only in sanitizer_common
      1 //===-- sanitizer_common.cc -----------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file is shared between AddressSanitizer and ThreadSanitizer
     11 // run-time libraries.
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "sanitizer_common.h"
     15 #include "sanitizer_allocator_internal.h"
     16 #include "sanitizer_flags.h"
     17 #include "sanitizer_libc.h"
     18 #include "sanitizer_placement_new.h"
     19 #include "sanitizer_stacktrace_printer.h"
     20 #include "sanitizer_symbolizer.h"
     21 
     22 namespace __sanitizer {
     23 
     24 const char *SanitizerToolName = "SanitizerTool";
     25 
     26 atomic_uint32_t current_verbosity;
     27 
     28 uptr GetPageSizeCached() {
     29   static uptr PageSize;
     30   if (!PageSize)
     31     PageSize = GetPageSize();
     32   return PageSize;
     33 }
     34 
     35 StaticSpinMutex report_file_mu;
     36 ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
     37 
     38 void RawWrite(const char *buffer) {
     39   report_file.Write(buffer, internal_strlen(buffer));
     40 }
     41 
     42 void ReportFile::ReopenIfNecessary() {
     43   mu->CheckLocked();
     44   if (fd == kStdoutFd || fd == kStderrFd) return;
     45 
     46   uptr pid = internal_getpid();
     47   // If in tracer, use the parent's file.
     48   if (pid == stoptheworld_tracer_pid)
     49     pid = stoptheworld_tracer_ppid;
     50   if (fd != kInvalidFd) {
     51     // If the report file is already opened by the current process,
     52     // do nothing. Otherwise the report file was opened by the parent
     53     // process, close it now.
     54     if (fd_pid == pid)
     55       return;
     56     else
     57       CloseFile(fd);
     58   }
     59 
     60   const char *exe_name = GetProcessName();
     61   if (common_flags()->log_exe_name && exe_name) {
     62     internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix,
     63                       exe_name, pid);
     64   } else {
     65     internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
     66   }
     67   fd = OpenFile(full_path, WrOnly);
     68   if (fd == kInvalidFd) {
     69     const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
     70     WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
     71     WriteToFile(kStderrFd, full_path, internal_strlen(full_path));
     72     Die();
     73   }
     74   fd_pid = pid;
     75 }
     76 
     77 void ReportFile::SetReportPath(const char *path) {
     78   if (!path)
     79     return;
     80   uptr len = internal_strlen(path);
     81   if (len > sizeof(path_prefix) - 100) {
     82     Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
     83            path[0], path[1], path[2], path[3],
     84            path[4], path[5], path[6], path[7]);
     85     Die();
     86   }
     87 
     88   SpinMutexLock l(mu);
     89   if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
     90     CloseFile(fd);
     91   fd = kInvalidFd;
     92   if (internal_strcmp(path, "stdout") == 0) {
     93     fd = kStdoutFd;
     94   } else if (internal_strcmp(path, "stderr") == 0) {
     95     fd = kStderrFd;
     96   } else {
     97     internal_snprintf(path_prefix, kMaxPathLength, "%s", path);
     98   }
     99 }
    100 
    101 // PID of the tracer task in StopTheWorld. It shares the address space with the
    102 // main process, but has a different PID and thus requires special handling.
    103 uptr stoptheworld_tracer_pid = 0;
    104 // Cached pid of parent process - if the parent process dies, we want to keep
    105 // writing to the same log file.
    106 uptr stoptheworld_tracer_ppid = 0;
    107 
    108 static const int kMaxNumOfInternalDieCallbacks = 5;
    109 static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks];
    110 
    111 bool AddDieCallback(DieCallbackType callback) {
    112   for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
    113     if (InternalDieCallbacks[i] == nullptr) {
    114       InternalDieCallbacks[i] = callback;
    115       return true;
    116     }
    117   }
    118   return false;
    119 }
    120 
    121 bool RemoveDieCallback(DieCallbackType callback) {
    122   for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) {
    123     if (InternalDieCallbacks[i] == callback) {
    124       internal_memmove(&InternalDieCallbacks[i], &InternalDieCallbacks[i + 1],
    125                        sizeof(InternalDieCallbacks[0]) *
    126                            (kMaxNumOfInternalDieCallbacks - i - 1));
    127       InternalDieCallbacks[kMaxNumOfInternalDieCallbacks - 1] = nullptr;
    128       return true;
    129     }
    130   }
    131   return false;
    132 }
    133 
    134 static DieCallbackType UserDieCallback;
    135 void SetUserDieCallback(DieCallbackType callback) {
    136   UserDieCallback = callback;
    137 }
    138 
    139 void NORETURN Die() {
    140   if (UserDieCallback)
    141     UserDieCallback();
    142   for (int i = kMaxNumOfInternalDieCallbacks - 1; i >= 0; i--) {
    143     if (InternalDieCallbacks[i])
    144       InternalDieCallbacks[i]();
    145   }
    146   if (common_flags()->abort_on_error)
    147     Abort();
    148   internal__exit(common_flags()->exitcode);
    149 }
    150 
    151 static CheckFailedCallbackType CheckFailedCallback;
    152 void SetCheckFailedCallback(CheckFailedCallbackType callback) {
    153   CheckFailedCallback = callback;
    154 }
    155 
    156 void NORETURN CheckFailed(const char *file, int line, const char *cond,
    157                           u64 v1, u64 v2) {
    158   if (CheckFailedCallback) {
    159     CheckFailedCallback(file, line, cond, v1, v2);
    160   }
    161   Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
    162                                                             v1, v2);
    163   Die();
    164 }
    165 
    166 void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
    167                                       const char *mmap_type, error_t err,
    168                                       bool raw_report) {
    169   static int recursion_count;
    170   if (raw_report || recursion_count) {
    171     // If raw report is requested or we went into recursion, just die.
    172     // The Report() and CHECK calls below may call mmap recursively and fail.
    173     RawWrite("ERROR: Failed to mmap\n");
    174     Die();
    175   }
    176   recursion_count++;
    177   Report("ERROR: %s failed to "
    178          "%s 0x%zx (%zd) bytes of %s (error code: %d)\n",
    179          SanitizerToolName, mmap_type, size, size, mem_type, err);
    180 #ifndef SANITIZER_GO
    181   DumpProcessMap();
    182 #endif
    183   UNREACHABLE("unable to mmap");
    184 }
    185 
    186 bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
    187                       uptr *read_len, uptr max_len, error_t *errno_p) {
    188   uptr PageSize = GetPageSizeCached();
    189   uptr kMinFileLen = PageSize;
    190   *buff = nullptr;
    191   *buff_size = 0;
    192   *read_len = 0;
    193   // The files we usually open are not seekable, so try different buffer sizes.
    194   for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
    195     fd_t fd = OpenFile(file_name, RdOnly, errno_p);
    196     if (fd == kInvalidFd) return false;
    197     UnmapOrDie(*buff, *buff_size);
    198     *buff = (char*)MmapOrDie(size, __func__);
    199     *buff_size = size;
    200     *read_len = 0;
    201     // Read up to one page at a time.
    202     bool reached_eof = false;
    203     while (*read_len + PageSize <= size) {
    204       uptr just_read;
    205       if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) {
    206         UnmapOrDie(*buff, *buff_size);
    207         return false;
    208       }
    209       if (just_read == 0) {
    210         reached_eof = true;
    211         break;
    212       }
    213       *read_len += just_read;
    214     }
    215     CloseFile(fd);
    216     if (reached_eof)  // We've read the whole file.
    217       break;
    218   }
    219   return true;
    220 }
    221 
    222 typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
    223 
    224 template<class T>
    225 static inline bool CompareLess(const T &a, const T &b) {
    226   return a < b;
    227 }
    228 
    229 void SortArray(uptr *array, uptr size) {
    230   InternalSort<uptr*, UptrComparisonFunction>(&array, size, CompareLess);
    231 }
    232 
    233 // We want to map a chunk of address space aligned to 'alignment'.
    234 // We do it by maping a bit more and then unmaping redundant pieces.
    235 // We probably can do it with fewer syscalls in some OS-dependent way.
    236 void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
    237 // uptr PageSize = GetPageSizeCached();
    238   CHECK(IsPowerOfTwo(size));
    239   CHECK(IsPowerOfTwo(alignment));
    240   uptr map_size = size + alignment;
    241   uptr map_res = (uptr)MmapOrDie(map_size, mem_type);
    242   uptr map_end = map_res + map_size;
    243   uptr res = map_res;
    244   if (res & (alignment - 1))  // Not aligned.
    245     res = (map_res + alignment) & ~(alignment - 1);
    246   uptr end = res + size;
    247   if (res != map_res)
    248     UnmapOrDie((void*)map_res, res - map_res);
    249   if (end != map_end)
    250     UnmapOrDie((void*)end, map_end - end);
    251   return (void*)res;
    252 }
    253 
    254 const char *StripPathPrefix(const char *filepath,
    255                             const char *strip_path_prefix) {
    256   if (!filepath) return nullptr;
    257   if (!strip_path_prefix) return filepath;
    258   const char *res = filepath;
    259   if (const char *pos = internal_strstr(filepath, strip_path_prefix))
    260     res = pos + internal_strlen(strip_path_prefix);
    261   if (res[0] == '.' && res[1] == '/')
    262     res += 2;
    263   return res;
    264 }
    265 
    266 const char *StripModuleName(const char *module) {
    267   if (!module)
    268     return nullptr;
    269   if (SANITIZER_WINDOWS) {
    270     // On Windows, both slash and backslash are possible.
    271     // Pick the one that goes last.
    272     if (const char *bslash_pos = internal_strrchr(module, '\\'))
    273       return StripModuleName(bslash_pos + 1);
    274   }
    275   if (const char *slash_pos = internal_strrchr(module, '/')) {
    276     return slash_pos + 1;
    277   }
    278   return module;
    279 }
    280 
    281 void ReportErrorSummary(const char *error_message) {
    282   if (!common_flags()->print_summary)
    283     return;
    284   InternalScopedString buff(kMaxSummaryLength);
    285   buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message);
    286   __sanitizer_report_error_summary(buff.data());
    287 }
    288 
    289 #ifndef SANITIZER_GO
    290 void ReportErrorSummary(const char *error_type, const AddressInfo &info) {
    291   if (!common_flags()->print_summary)
    292     return;
    293   InternalScopedString buff(kMaxSummaryLength);
    294   buff.append("%s ", error_type);
    295   RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style,
    296               common_flags()->strip_path_prefix);
    297   ReportErrorSummary(buff.data());
    298 }
    299 #endif
    300 
    301 // Removes the ANSI escape sequences from the input string (in-place).
    302 void RemoveANSIEscapeSequencesFromString(char *str) {
    303   if (!str)
    304     return;
    305 
    306   // We are going to remove the escape sequences in place.
    307   char *s = str;
    308   char *z = str;
    309   while (*s != '\0') {
    310     CHECK_GE(s, z);
    311     // Skip over ANSI escape sequences with pointer 's'.
    312     if (*s == '\033' && *(s + 1) == '[') {
    313       s = internal_strchrnul(s, 'm');
    314       if (*s == '\0') {
    315         break;
    316       }
    317       s++;
    318       continue;
    319     }
    320     // 's' now points at a character we want to keep. Copy over the buffer
    321     // content if the escape sequence has been perviously skipped andadvance
    322     // both pointers.
    323     if (s != z)
    324       *z = *s;
    325 
    326     // If we have not seen an escape sequence, just advance both pointers.
    327     z++;
    328     s++;
    329   }
    330 
    331   // Null terminate the string.
    332   *z = '\0';
    333 }
    334 
    335 void LoadedModule::set(const char *module_name, uptr base_address) {
    336   clear();
    337   full_name_ = internal_strdup(module_name);
    338   base_address_ = base_address;
    339 }
    340 
    341 void LoadedModule::clear() {
    342   InternalFree(full_name_);
    343   full_name_ = nullptr;
    344   while (!ranges_.empty()) {
    345     AddressRange *r = ranges_.front();
    346     ranges_.pop_front();
    347     InternalFree(r);
    348   }
    349 }
    350 
    351 void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) {
    352   void *mem = InternalAlloc(sizeof(AddressRange));
    353   AddressRange *r = new(mem) AddressRange(beg, end, executable);
    354   ranges_.push_back(r);
    355 }
    356 
    357 bool LoadedModule::containsAddress(uptr address) const {
    358   for (Iterator iter = ranges(); iter.hasNext();) {
    359     const AddressRange *r = iter.next();
    360     if (r->beg <= address && address < r->end)
    361       return true;
    362   }
    363   return false;
    364 }
    365 
    366 static atomic_uintptr_t g_total_mmaped;
    367 
    368 void IncreaseTotalMmap(uptr size) {
    369   if (!common_flags()->mmap_limit_mb) return;
    370   uptr total_mmaped =
    371       atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;
    372   // Since for now mmap_limit_mb is not a user-facing flag, just kill
    373   // a program. Use RAW_CHECK to avoid extra mmaps in reporting.
    374   RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);
    375 }
    376 
    377 void DecreaseTotalMmap(uptr size) {
    378   if (!common_flags()->mmap_limit_mb) return;
    379   atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
    380 }
    381 
    382 bool TemplateMatch(const char *templ, const char *str) {
    383   if ((!str) || str[0] == 0)
    384     return false;
    385   bool start = false;
    386   if (templ && templ[0] == '^') {
    387     start = true;
    388     templ++;
    389   }
    390   bool asterisk = false;
    391   while (templ && templ[0]) {
    392     if (templ[0] == '*') {
    393       templ++;
    394       start = false;
    395       asterisk = true;
    396       continue;
    397     }
    398     if (templ[0] == '$')
    399       return str[0] == 0 || asterisk;
    400     if (str[0] == 0)
    401       return false;
    402     char *tpos = (char*)internal_strchr(templ, '*');
    403     char *tpos1 = (char*)internal_strchr(templ, '$');
    404     if ((!tpos) || (tpos1 && tpos1 < tpos))
    405       tpos = tpos1;
    406     if (tpos)
    407       tpos[0] = 0;
    408     const char *str0 = str;
    409     const char *spos = internal_strstr(str, templ);
    410     str = spos + internal_strlen(templ);
    411     templ = tpos;
    412     if (tpos)
    413       tpos[0] = tpos == tpos1 ? '$' : '*';
    414     if (!spos)
    415       return false;
    416     if (start && spos != str0)
    417       return false;
    418     start = false;
    419     asterisk = false;
    420   }
    421   return true;
    422 }
    423 
    424 static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':';
    425 
    426 char *FindPathToBinary(const char *name) {
    427   const char *path = GetEnv("PATH");
    428   if (!path)
    429     return nullptr;
    430   uptr name_len = internal_strlen(name);
    431   InternalScopedBuffer<char> buffer(kMaxPathLength);
    432   const char *beg = path;
    433   while (true) {
    434     const char *end = internal_strchrnul(beg, kPathSeparator);
    435     uptr prefix_len = end - beg;
    436     if (prefix_len + name_len + 2 <= kMaxPathLength) {
    437       internal_memcpy(buffer.data(), beg, prefix_len);
    438       buffer[prefix_len] = '/';
    439       internal_memcpy(&buffer[prefix_len + 1], name, name_len);
    440       buffer[prefix_len + 1 + name_len] = '\0';
    441       if (FileExists(buffer.data()))
    442         return internal_strdup(buffer.data());
    443     }
    444     if (*end == '\0') break;
    445     beg = end + 1;
    446   }
    447   return nullptr;
    448 }
    449 
    450 static char binary_name_cache_str[kMaxPathLength];
    451 static char process_name_cache_str[kMaxPathLength];
    452 
    453 const char *GetProcessName() {
    454   return process_name_cache_str;
    455 }
    456 
    457 static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) {
    458   ReadLongProcessName(buf, buf_len);
    459   char *s = const_cast<char *>(StripModuleName(buf));
    460   uptr len = internal_strlen(s);
    461   if (s != buf) {
    462     internal_memmove(buf, s, len);
    463     buf[len] = '\0';
    464   }
    465   return len;
    466 }
    467 
    468 void UpdateProcessName() {
    469   ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
    470 }
    471 
    472 // Call once to make sure that binary_name_cache_str is initialized
    473 void CacheBinaryName() {
    474   if (binary_name_cache_str[0] != '\0')
    475     return;
    476   ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str));
    477   ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));
    478 }
    479 
    480 uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
    481   CacheBinaryName();
    482   uptr name_len = internal_strlen(binary_name_cache_str);
    483   name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1;
    484   if (buf_len == 0)
    485     return 0;
    486   internal_memcpy(buf, binary_name_cache_str, name_len);
    487   buf[name_len] = '\0';
    488   return name_len;
    489 }
    490 
    491 } // namespace __sanitizer
    492 
    493 using namespace __sanitizer;  // NOLINT
    494 
    495 extern "C" {
    496 void __sanitizer_set_report_path(const char *path) {
    497   report_file.SetReportPath(path);
    498 }
    499 
    500 void __sanitizer_report_error_summary(const char *error_summary) {
    501   Printf("%s\n", error_summary);
    502 }
    503 
    504 SANITIZER_INTERFACE_ATTRIBUTE
    505 void __sanitizer_set_death_callback(void (*callback)(void)) {
    506   SetUserDieCallback(callback);
    507 }
    508 } // extern "C"
    509