Path: blob/main/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp
35233 views
//===-- sanitizer_common.cpp ----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file is shared between AddressSanitizer and ThreadSanitizer9// run-time libraries.10//===----------------------------------------------------------------------===//1112#include "sanitizer_common.h"1314#include "sanitizer_allocator_interface.h"15#include "sanitizer_allocator_internal.h"16#include "sanitizer_atomic.h"17#include "sanitizer_flags.h"18#include "sanitizer_interface_internal.h"19#include "sanitizer_libc.h"20#include "sanitizer_placement_new.h"2122namespace __sanitizer {2324const char *SanitizerToolName = "SanitizerTool";2526atomic_uint32_t current_verbosity;27uptr PageSizeCached;28u32 NumberOfCPUsCached;2930// PID of the tracer task in StopTheWorld. It shares the address space with the31// main process, but has a different PID and thus requires special handling.32uptr stoptheworld_tracer_pid = 0;33// Cached pid of parent process - if the parent process dies, we want to keep34// writing to the same log file.35uptr stoptheworld_tracer_ppid = 0;3637void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,38const char *mmap_type, error_t err,39bool raw_report) {40static int recursion_count;41if (raw_report || recursion_count) {42// If raw report is requested or we went into recursion just die. The43// Report() and CHECK calls below may call mmap recursively and fail.44RawWrite("ERROR: Failed to mmap\n");45Die();46}47recursion_count++;48if (ErrorIsOOM(err)) {49ERROR_OOM("failed to %s 0x%zx (%zd) bytes of %s (error code: %d)\n",50mmap_type, size, size, mem_type, err);51} else {52Report(53"ERROR: %s failed to "54"%s 0x%zx (%zd) bytes of %s (error code: %d)\n",55SanitizerToolName, mmap_type, size, size, mem_type, err);56}57#if !SANITIZER_GO58DumpProcessMap();59#endif60UNREACHABLE("unable to mmap");61}6263void NORETURN ReportMunmapFailureAndDie(void *addr, uptr size, error_t err,64bool raw_report) {65static int recursion_count;66if (raw_report || recursion_count) {67// If raw report is requested or we went into recursion just die. The68// Report() and CHECK calls below may call munmap recursively and fail.69RawWrite("ERROR: Failed to munmap\n");70Die();71}72recursion_count++;73Report(74"ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p (error "75"code: %d)\n",76SanitizerToolName, size, size, addr, err);77#if !SANITIZER_GO78DumpProcessMap();79#endif80UNREACHABLE("unable to unmmap");81}8283typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);84typedef bool U32ComparisonFunction(const u32 &a, const u32 &b);8586const char *StripPathPrefix(const char *filepath,87const char *strip_path_prefix) {88if (!filepath) return nullptr;89if (!strip_path_prefix) return filepath;90const char *res = filepath;91if (const char *pos = internal_strstr(filepath, strip_path_prefix))92res = pos + internal_strlen(strip_path_prefix);93if (res[0] == '.' && res[1] == '/')94res += 2;95return res;96}9798const char *StripModuleName(const char *module) {99if (!module)100return nullptr;101if (SANITIZER_WINDOWS) {102// On Windows, both slash and backslash are possible.103// Pick the one that goes last.104if (const char *bslash_pos = internal_strrchr(module, '\\'))105return StripModuleName(bslash_pos + 1);106}107if (const char *slash_pos = internal_strrchr(module, '/')) {108return slash_pos + 1;109}110return module;111}112113void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {114if (!common_flags()->print_summary)115return;116InternalScopedString buff;117buff.AppendF("SUMMARY: %s: %s",118alt_tool_name ? alt_tool_name : SanitizerToolName,119error_message);120__sanitizer_report_error_summary(buff.data());121}122123// Removes the ANSI escape sequences from the input string (in-place).124void RemoveANSIEscapeSequencesFromString(char *str) {125if (!str)126return;127128// We are going to remove the escape sequences in place.129char *s = str;130char *z = str;131while (*s != '\0') {132CHECK_GE(s, z);133// Skip over ANSI escape sequences with pointer 's'.134if (*s == '\033' && *(s + 1) == '[') {135s = internal_strchrnul(s, 'm');136if (*s == '\0') {137break;138}139s++;140continue;141}142// 's' now points at a character we want to keep. Copy over the buffer143// content if the escape sequence has been perviously skipped andadvance144// both pointers.145if (s != z)146*z = *s;147148// If we have not seen an escape sequence, just advance both pointers.149z++;150s++;151}152153// Null terminate the string.154*z = '\0';155}156157void LoadedModule::set(const char *module_name, uptr base_address) {158clear();159full_name_ = internal_strdup(module_name);160base_address_ = base_address;161}162163void LoadedModule::set(const char *module_name, uptr base_address,164ModuleArch arch, u8 uuid[kModuleUUIDSize],165bool instrumented) {166set(module_name, base_address);167arch_ = arch;168internal_memcpy(uuid_, uuid, sizeof(uuid_));169uuid_size_ = kModuleUUIDSize;170instrumented_ = instrumented;171}172173void LoadedModule::setUuid(const char *uuid, uptr size) {174if (size > kModuleUUIDSize)175size = kModuleUUIDSize;176internal_memcpy(uuid_, uuid, size);177uuid_size_ = size;178}179180void LoadedModule::clear() {181InternalFree(full_name_);182base_address_ = 0;183max_address_ = 0;184full_name_ = nullptr;185arch_ = kModuleArchUnknown;186internal_memset(uuid_, 0, kModuleUUIDSize);187instrumented_ = false;188while (!ranges_.empty()) {189AddressRange *r = ranges_.front();190ranges_.pop_front();191InternalFree(r);192}193}194195void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable,196bool writable, const char *name) {197void *mem = InternalAlloc(sizeof(AddressRange));198AddressRange *r =199new(mem) AddressRange(beg, end, executable, writable, name);200ranges_.push_back(r);201max_address_ = Max(max_address_, end);202}203204bool LoadedModule::containsAddress(uptr address) const {205for (const AddressRange &r : ranges()) {206if (r.beg <= address && address < r.end)207return true;208}209return false;210}211212static atomic_uintptr_t g_total_mmaped;213214void IncreaseTotalMmap(uptr size) {215if (!common_flags()->mmap_limit_mb) return;216uptr total_mmaped =217atomic_fetch_add(&g_total_mmaped, size, memory_order_relaxed) + size;218// Since for now mmap_limit_mb is not a user-facing flag, just kill219// a program. Use RAW_CHECK to avoid extra mmaps in reporting.220RAW_CHECK((total_mmaped >> 20) < common_flags()->mmap_limit_mb);221}222223void DecreaseTotalMmap(uptr size) {224if (!common_flags()->mmap_limit_mb) return;225atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);226}227228bool TemplateMatch(const char *templ, const char *str) {229if ((!str) || str[0] == 0)230return false;231bool start = false;232if (templ && templ[0] == '^') {233start = true;234templ++;235}236bool asterisk = false;237while (templ && templ[0]) {238if (templ[0] == '*') {239templ++;240start = false;241asterisk = true;242continue;243}244if (templ[0] == '$')245return str[0] == 0 || asterisk;246if (str[0] == 0)247return false;248char *tpos = (char*)internal_strchr(templ, '*');249char *tpos1 = (char*)internal_strchr(templ, '$');250if ((!tpos) || (tpos1 && tpos1 < tpos))251tpos = tpos1;252if (tpos)253tpos[0] = 0;254const char *str0 = str;255const char *spos = internal_strstr(str, templ);256str = spos + internal_strlen(templ);257templ = tpos;258if (tpos)259tpos[0] = tpos == tpos1 ? '$' : '*';260if (!spos)261return false;262if (start && spos != str0)263return false;264start = false;265asterisk = false;266}267return true;268}269270static char binary_name_cache_str[kMaxPathLength];271static char process_name_cache_str[kMaxPathLength];272273const char *GetProcessName() {274return process_name_cache_str;275}276277static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) {278ReadLongProcessName(buf, buf_len);279char *s = const_cast<char *>(StripModuleName(buf));280uptr len = internal_strlen(s);281if (s != buf) {282internal_memmove(buf, s, len);283buf[len] = '\0';284}285return len;286}287288void UpdateProcessName() {289ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));290}291292// Call once to make sure that binary_name_cache_str is initialized293void CacheBinaryName() {294if (binary_name_cache_str[0] != '\0')295return;296ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str));297ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str));298}299300uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {301CacheBinaryName();302uptr name_len = internal_strlen(binary_name_cache_str);303name_len = (name_len < buf_len - 1) ? name_len : buf_len - 1;304if (buf_len == 0)305return 0;306internal_memcpy(buf, binary_name_cache_str, name_len);307buf[name_len] = '\0';308return name_len;309}310311uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len) {312ReadBinaryNameCached(buf, buf_len);313const char *exec_name_pos = StripModuleName(buf);314uptr name_len = exec_name_pos - buf;315buf[name_len] = '\0';316return name_len;317}318319#if !SANITIZER_GO320void PrintCmdline() {321char **argv = GetArgv();322if (!argv) return;323Printf("\nCommand: ");324for (uptr i = 0; argv[i]; ++i)325Printf("%s ", argv[i]);326Printf("\n\n");327}328#endif329330// Malloc hooks.331static const int kMaxMallocFreeHooks = 5;332struct MallocFreeHook {333void (*malloc_hook)(const void *, uptr);334void (*free_hook)(const void *);335};336337static MallocFreeHook MFHooks[kMaxMallocFreeHooks];338339void RunMallocHooks(void *ptr, uptr size) {340__sanitizer_malloc_hook(ptr, size);341for (int i = 0; i < kMaxMallocFreeHooks; i++) {342auto hook = MFHooks[i].malloc_hook;343if (!hook)344break;345hook(ptr, size);346}347}348349// Returns '1' if the call to free() should be ignored (based on350// __sanitizer_ignore_free_hook), or '0' otherwise.351int RunFreeHooks(void *ptr) {352if (__sanitizer_ignore_free_hook(ptr)) {353return 1;354}355356__sanitizer_free_hook(ptr);357for (int i = 0; i < kMaxMallocFreeHooks; i++) {358auto hook = MFHooks[i].free_hook;359if (!hook)360break;361hook(ptr);362}363364return 0;365}366367static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr),368void (*free_hook)(const void *)) {369if (!malloc_hook || !free_hook) return 0;370for (int i = 0; i < kMaxMallocFreeHooks; i++) {371if (MFHooks[i].malloc_hook == nullptr) {372MFHooks[i].malloc_hook = malloc_hook;373MFHooks[i].free_hook = free_hook;374return i + 1;375}376}377return 0;378}379380void internal_sleep(unsigned seconds) {381internal_usleep((u64)seconds * 1000 * 1000);382}383void SleepForSeconds(unsigned seconds) {384internal_usleep((u64)seconds * 1000 * 1000);385}386void SleepForMillis(unsigned millis) { internal_usleep((u64)millis * 1000); }387388void WaitForDebugger(unsigned seconds, const char *label) {389if (seconds) {390Report("Sleeping for %u second(s) %s\n", seconds, label);391SleepForSeconds(seconds);392}393}394395} // namespace __sanitizer396397using namespace __sanitizer;398399extern "C" {400SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary,401const char *error_summary) {402Printf("%s\n", error_summary);403}404405SANITIZER_INTERFACE_ATTRIBUTE406int __sanitizer_acquire_crash_state() {407static atomic_uint8_t in_crash_state = {};408return !atomic_exchange(&in_crash_state, 1, memory_order_relaxed);409}410411SANITIZER_INTERFACE_ATTRIBUTE412int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *,413uptr),414void (*free_hook)(const void *)) {415return InstallMallocFreeHooks(malloc_hook, free_hook);416}417418// Provide default (no-op) implementation of malloc hooks.419SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook, void *ptr,420uptr size) {421(void)ptr;422(void)size;423}424425SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook, void *ptr) {426(void)ptr;427}428429SANITIZER_INTERFACE_WEAK_DEF(int, __sanitizer_ignore_free_hook, void *ptr) {430(void)ptr;431return 0;432}433434} // extern "C"435436437