brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.4 KiB · 6cd69a5 Raw
436 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file is shared between AddressSanitizer and ThreadSanitizer10// 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 23namespace __sanitizer {24 25const char *SanitizerToolName = "SanitizerTool";26 27atomic_uint32_t current_verbosity;28uptr PageSizeCached;29u32 NumberOfCPUsCached;30 31// PID of the tracer task in StopTheWorld. It shares the address space with the32// main process, but has a different PID and thus requires special handling.33uptr stoptheworld_tracer_pid = 0;34// Cached pid of parent process - if the parent process dies, we want to keep35// writing to the same log file.36uptr stoptheworld_tracer_ppid = 0;37 38void 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.  The44    // 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_GO59  DumpProcessMap();60#endif61  UNREACHABLE("unable to mmap");62}63 64void 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.  The69    // 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_GO79  DumpProcessMap();80#endif81  UNREACHABLE("unable to unmmap");82}83 84typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);85typedef bool U32ComparisonFunction(const u32 &a, const u32 &b);86 87const 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 99const 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 114void 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).125void 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 buffer144    // content if the escape sequence has been perviously skipped andadvance145    // 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 158void 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 164void 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 174void 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 181void 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 196void 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 205bool 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 213static atomic_uintptr_t g_total_mmaped;214 215void 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 kill220  // a program. Use RAW_CHECK to avoid extra mmaps in reporting.221  RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);222}223 224void DecreaseTotalMmap(uptr size) {225  if (!common_flags()->mmap_limit_mb) return;226  atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);227}228 229bool 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 271static char binary_name_cache_str[kMaxPathLength];272static char process_name_cache_str[kMaxPathLength];273 274const char *GetProcessName() {275  return process_name_cache_str;276}277 278static 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 289void 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 initialized294void 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 301uptr 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 312uptr 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_GO321void 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#endif330 331// Malloc hooks.332static const int kMaxMallocFreeHooks = 5;333struct MallocFreeHook {334  void (*malloc_hook)(const void *, uptr);335  void (*free_hook)(const void *);336};337 338static MallocFreeHook MFHooks[kMaxMallocFreeHooks];339 340void 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// Returns '1' if the call to free() should be ignored (based on351// __sanitizer_ignore_free_hook), or '0' otherwise.352int RunFreeHooks(void *ptr) {353  if (__sanitizer_ignore_free_hook(ptr)) {354    return 1;355  }356 357  __sanitizer_free_hook(ptr);358  for (int i = 0; i < kMaxMallocFreeHooks; i++) {359    auto hook = MFHooks[i].free_hook;360    if (!hook)361      break;362    hook(ptr);363  }364 365  return 0;366}367 368static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr),369                                  void (*free_hook)(const void *)) {370  if (!malloc_hook || !free_hook) return 0;371  for (int i = 0; i < kMaxMallocFreeHooks; i++) {372    if (MFHooks[i].malloc_hook == nullptr) {373      MFHooks[i].malloc_hook = malloc_hook;374      MFHooks[i].free_hook = free_hook;375      return i + 1;376    }377  }378  return 0;379}380 381void internal_sleep(unsigned seconds) {382  internal_usleep((u64)seconds * 1000 * 1000);383}384void SleepForSeconds(unsigned seconds) {385  internal_usleep((u64)seconds * 1000 * 1000);386}387void SleepForMillis(unsigned millis) { internal_usleep((u64)millis * 1000); }388 389void WaitForDebugger(unsigned seconds, const char *label) {390  if (seconds) {391    Report("Sleeping for %u second(s) %s\n", seconds, label);392    SleepForSeconds(seconds);393  }394}395 396} // namespace __sanitizer397 398using namespace __sanitizer;399 400extern "C" {401SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary,402                             const char *error_summary) {403  Printf("%s\n", error_summary);404}405 406SANITIZER_INTERFACE_ATTRIBUTE407int __sanitizer_acquire_crash_state() {408  static atomic_uint8_t in_crash_state = {};409  return !atomic_exchange(&in_crash_state, 1, memory_order_relaxed);410}411 412SANITIZER_INTERFACE_ATTRIBUTE413int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *,414                                                                  uptr),415                                              void (*free_hook)(const void *)) {416  return InstallMallocFreeHooks(malloc_hook, free_hook);417}418 419// Provide default (no-op) implementation of malloc hooks.420SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook, void *ptr,421                             uptr size) {422  (void)ptr;423  (void)size;424}425 426SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook, void *ptr) {427  (void)ptr;428}429 430SANITIZER_INTERFACE_WEAK_DEF(int, __sanitizer_ignore_free_hook, void *ptr) {431  (void)ptr;432  return 0;433}434 435} // extern "C"436