diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-06-03 15:21:00 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-06-03 15:21:00 +0000 |
commit | 25091d6bd042c6bf2709eaab2bd1a88f3f2d9fda (patch) | |
tree | 55100adfb3ecde3bca3a6aea64f3899b6d46a1c8 | |
parent | 06eabdc027f984611832945782f7c36800d0d397 (diff) |
Vendor import of compiler-rt trunk r304659:vendor/compiler-rt/compiler-rt-trunk-r304659
Notes
Notes:
svn path=/vendor/compiler-rt/dist/; revision=319527
svn path=/vendor/compiler-rt/compiler-rt-trunk-r304659/; revision=319528; tag=vendor/compiler-rt/compiler-rt-trunk-r304659
29 files changed, 186 insertions, 1009 deletions
diff --git a/include/sanitizer/coverage_interface.h b/include/sanitizer/coverage_interface.h index bdb113728b95..637379d47c41 100644 --- a/include/sanitizer/coverage_interface.h +++ b/include/sanitizer/coverage_interface.h @@ -19,8 +19,6 @@ extern "C" { #endif - // Initialize coverage. - void __sanitizer_cov_init(); // Record and dump coverage info. void __sanitizer_cov_dump(); @@ -28,10 +26,6 @@ extern "C" { // .sancov files. void __sanitizer_dump_coverage(const uintptr_t *pcs, uintptr_t len); - // Open <name>.sancov.packed in the coverage directory and return the file - // descriptor. Returns -1 on failure, or if coverage dumping is disabled. - // This is intended for use by sandboxing code. - intptr_t __sanitizer_maybe_open_cov_file(const char *name); #ifdef __cplusplus } // extern "C" #endif diff --git a/lib/asan/asan_activation.cc b/lib/asan/asan_activation.cc index 7e4e604dc218..66eba9ce2748 100644 --- a/lib/asan/asan_activation.cc +++ b/lib/asan/asan_activation.cc @@ -106,7 +106,6 @@ void AsanDeactivate() { // Deactivate the runtime. SetCanPoisonMemory(false); SetMallocContextSize(1); - ReInitializeCoverage(false, nullptr); AllocatorOptions disabled = asan_deactivated_flags.allocator_options; disabled.quarantine_size_mb = 0; @@ -130,8 +129,6 @@ void AsanActivate() { SetCanPoisonMemory(asan_deactivated_flags.poison_heap); SetMallocContextSize(asan_deactivated_flags.malloc_context_size); - ReInitializeCoverage(asan_deactivated_flags.coverage, - asan_deactivated_flags.coverage_dir); ReInitializeAllocator(asan_deactivated_flags.allocator_options); asan_is_deactivated = false; diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index e82a5a4a7e96..4682fba3392c 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -242,9 +242,8 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *) CheckNoDeepBind(filename, flag); \ } while (false) #define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit() -#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \ - CoverageUpdateMapping() -#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CoverageUpdateMapping() +#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) +#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited) #define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \ if (AsanThread *t = GetCurrentThread()) { \ @@ -723,9 +722,7 @@ static void AfterFork() { INTERCEPTOR(int, fork, void) { ENSURE_ASAN_INITED(); BeforeFork(); - if (common_flags()->coverage) CovBeforeFork(); int pid = REAL(fork)(); - if (common_flags()->coverage) CovAfterFork(pid); AfterFork(); return pid; } diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc index f41ee2df2d96..714496d5c606 100644 --- a/lib/asan/asan_thread.cc +++ b/lib/asan/asan_thread.cc @@ -166,16 +166,19 @@ void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save, } inline AsanThread::StackBounds AsanThread::GetStackBounds() const { - if (!atomic_load(&stack_switching_, memory_order_acquire)) - return StackBounds{stack_bottom_, stack_top_}; // NOLINT + if (!atomic_load(&stack_switching_, memory_order_acquire)) { + // Make sure the stack bounds are fully initialized. + if (stack_bottom_ >= stack_top_) return {0, 0}; + return {stack_bottom_, stack_top_}; + } char local; const uptr cur_stack = (uptr)&local; // Note: need to check next stack first, because FinishSwitchFiber // may be in process of overwriting stack_top_/bottom_. But in such case // we are already on the next stack. if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_) - return StackBounds{next_stack_bottom_, next_stack_top_}; // NOLINT - return StackBounds{stack_bottom_, stack_top_}; // NOLINT + return {next_stack_bottom_, next_stack_top_}; + return {stack_bottom_, stack_top_}; } uptr AsanThread::stack_top() { @@ -197,6 +200,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() { uptr stack_size = this->stack_size(); if (stack_size == 0) // stack_size is not yet available, don't use FakeStack. return nullptr; + CHECK_LE(stack_size, 0x10000000); uptr old_val = 0; // fake_stack_ has 3 states: // 0 -- not initialized diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc index a5ffc6835f5f..d4f670681fa5 100644 --- a/lib/lsan/lsan_common.cc +++ b/lib/lsan/lsan_common.cc @@ -408,6 +408,9 @@ static void MarkInvalidPCCb(uptr chunk, void *arg) { // On Linux, handles dynamically allocated TLS blocks by treating all chunks // allocated from ld-linux.so as reachable. +// On Linux, treats all chunks allocated from ld-linux.so as reachable, which +// covers dynamically allocated TLS blocks, internal dynamic loader's loaded +// modules accounting etc. // Dynamic TLS blocks contain the TLS variables of dynamically loaded modules. // They are allocated with a __libc_memalign() call in allocate_and_init() // (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc index c903be42d1e7..2e4095b495fe 100644 --- a/lib/lsan/lsan_common_linux.cc +++ b/lib/lsan/lsan_common_linux.cc @@ -23,6 +23,10 @@ #include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_stackdepot.h" +#if SANITIZER_USE_GETAUXVAL +#include <sys/auxv.h> +#endif // SANITIZER_USE_GETAUXVAL + namespace __lsan { static const char kLinkerName[] = "ld"; @@ -30,8 +34,12 @@ static const char kLinkerName[] = "ld"; static char linker_placeholder[sizeof(LoadedModule)] ALIGNED(64); static LoadedModule *linker = nullptr; -static bool IsLinker(const char* full_name) { - return LibraryNameIs(full_name, kLinkerName); +static bool IsLinker(const LoadedModule& module) { +#if SANITIZER_USE_GETAUXVAL + return module.base_address() == getauxval(AT_BASE); +#else + return LibraryNameIs(module.full_name(), kLinkerName); +#endif // SANITIZER_USE_GETAUXVAL } __attribute__((tls_model("initial-exec"))) @@ -49,22 +57,25 @@ void InitializePlatformSpecificModules() { ListOfModules modules; modules.init(); for (LoadedModule &module : modules) { - if (!IsLinker(module.full_name())) continue; + if (!IsLinker(module)) + continue; if (linker == nullptr) { linker = reinterpret_cast<LoadedModule *>(linker_placeholder); *linker = module; module = LoadedModule(); } else { VReport(1, "LeakSanitizer: Multiple modules match \"%s\". " - "TLS will not be handled correctly.\n", kLinkerName); + "TLS and other allocations originating from linker might be " + "falsely reported as leaks.\n", kLinkerName); linker->clear(); linker = nullptr; return; } } if (linker == nullptr) { - VReport(1, "LeakSanitizer: Dynamic linker not found. " - "TLS will not be handled correctly.\n"); + VReport(1, "LeakSanitizer: Dynamic linker not found. TLS and other " + "allocations originating from linker might be falsely reported " + "as leaks.\n"); } } diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index 6cdc91897cd8..bf8459ef5e91 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -54,9 +54,7 @@ set(SANITIZER_NOLIBC_SOURCES set(SANITIZER_LIBCDEP_SOURCES sanitizer_common_libcdep.cc sancov_flags.cc - sanitizer_coverage_libcdep.cc sanitizer_coverage_libcdep_new.cc - sanitizer_coverage_mapping_libcdep.cc sanitizer_coverage_win_sections.cc sanitizer_linux_libcdep.cc sanitizer_posix_libcdep.cc diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index a1c9c5a57a84..79ee6873bcc4 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -317,15 +317,9 @@ bool AddressSpaceIsUnlimited(); void SetAddressSpaceUnlimited(); void AdjustStackSize(void *attr); void PrepareForSandboxing(__sanitizer_sandbox_arguments *args); -void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args); void SetSandboxingCallback(void (*f)()); -void CoverageUpdateMapping(); -void CovBeforeFork(); -void CovAfterFork(int child_pid); - void InitializeCoverage(bool enabled, const char *coverage_dir); -void ReInitializeCoverage(bool enabled, const char *coverage_dir); void InitTlsSize(); uptr GetTlsSize(); diff --git a/lib/sanitizer_common/sanitizer_coverage_interface.inc b/lib/sanitizer_common/sanitizer_coverage_interface.inc index 70c10e04b653..d4749000d80a 100644 --- a/lib/sanitizer_common/sanitizer_coverage_interface.inc +++ b/lib/sanitizer_common/sanitizer_coverage_interface.inc @@ -11,7 +11,6 @@ INTERFACE_FUNCTION(__sanitizer_cov_dump) INTERFACE_FUNCTION(__sanitizer_dump_coverage) INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage) -INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file) INTERFACE_WEAK_FUNCTION(__sancov_default_options) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp1) diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc deleted file mode 100644 index abfdf3d02088..000000000000 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ /dev/null @@ -1,627 +0,0 @@ -//===-- sanitizer_coverage.cc ---------------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Sanitizer Coverage. -// This file implements run-time support for a poor man's coverage tool. -// -// Compiler instrumentation: -// For every interesting basic block the compiler injects the following code: -// if (Guard < 0) { -// __sanitizer_cov(&Guard); -// } -// At the module start up time __sanitizer_cov_module_init sets the guards -// to consecutive negative numbers (-1, -2, -3, ...). -// It's fine to call __sanitizer_cov more than once for a given block. -// -// Run-time: -// - __sanitizer_cov(): record that we've executed the PC (GET_CALLER_PC). -// and atomically set Guard to -Guard. -// - __sanitizer_cov_dump: dump the coverage data to disk. -// For every module of the current process that has coverage data -// this will create a file module_name.PID.sancov. -// -// The file format is simple: the first 8 bytes is the magic, -// one of 0xC0BFFFFFFFFFFF64 and 0xC0BFFFFFFFFFFF32. The last byte of the -// magic defines the size of the following offsets. -// The rest of the data is the offsets in the module. -// -// Eventually, this coverage implementation should be obsoleted by a more -// powerful general purpose Clang/LLVM coverage instrumentation. -// Consider this implementation as prototype. -// -// FIXME: support (or at least test with) dlclose. -//===----------------------------------------------------------------------===// - -#include "sanitizer_allocator_internal.h" -#include "sanitizer_common.h" -#include "sanitizer_libc.h" -#include "sanitizer_mutex.h" -#include "sanitizer_procmaps.h" -#include "sanitizer_stacktrace.h" -#include "sanitizer_symbolizer.h" -#include "sanitizer_flags.h" - -using namespace __sanitizer; - -static const u64 kMagic64 = 0xC0BFFFFFFFFFFF64ULL; -static const u64 kMagic32 = 0xC0BFFFFFFFFFFF32ULL; -static const uptr kNumWordsForMagic = SANITIZER_WORDSIZE == 64 ? 1 : 2; -static const u64 kMagic = SANITIZER_WORDSIZE == 64 ? kMagic64 : kMagic32; - -static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once. - -static atomic_uintptr_t coverage_counter; - -// pc_array is the array containing the covered PCs. -// To make the pc_array thread- and async-signal-safe it has to be large enough. -// 128M counters "ought to be enough for anybody" (4M on 32-bit). - -// With coverage_direct=1 in ASAN_OPTIONS, pc_array memory is mapped to a file. -// In this mode, __sanitizer_cov_dump does nothing, and CovUpdateMapping() -// dump current memory layout to another file. - -static bool cov_sandboxed = false; -static fd_t cov_fd = kInvalidFd; -static unsigned int cov_max_block_size = 0; -static bool coverage_enabled = false; -static const char *coverage_dir; - -namespace __sanitizer { - -class CoverageData { - public: - void Init(); - void Enable(); - void Disable(); - void ReInit(); - void BeforeFork(); - void AfterFork(int child_pid); - void Extend(uptr npcs); - void Add(uptr pc, u32 *guard); - void DumpOffsets(); - void DumpAll(); - - void InitializeGuardArray(s32 *guards); - void InitializeGuards(s32 *guards, uptr n, const char *module_name, - uptr caller_pc); - void ReinitializeGuards(); - - uptr *data(); - uptr size() const; - - private: - struct NamedPcRange { - const char *copied_module_name; - uptr beg, end; // elements [beg,end) in pc_array. - }; - - void DirectOpen(); - void UpdateModuleNameVec(uptr caller_pc, uptr range_beg, uptr range_end); - void GetRangeOffsets(const NamedPcRange& r, Symbolizer* s, - InternalMmapVector<uptr>* offsets) const; - - // Maximal size pc array may ever grow. - // We MmapNoReserve this space to ensure that the array is contiguous. - static const uptr kPcArrayMaxSize = - FIRST_32_SECOND_64(1 << (SANITIZER_ANDROID ? 24 : 26), 1 << 27); - // The amount file mapping for the pc array is grown by. - static const uptr kPcArrayMmapSize = 64 * 1024; - - // pc_array is allocated with MmapNoReserveOrDie and so it uses only as - // much RAM as it really needs. - uptr *pc_array; - // Index of the first available pc_array slot. - atomic_uintptr_t pc_array_index; - // Array size. - atomic_uintptr_t pc_array_size; - // Current file mapped size of the pc array. - uptr pc_array_mapped_size; - // Descriptor of the file mapped pc array. - fd_t pc_fd; - - // Vector of coverage guard arrays, protected by mu. - InternalMmapVectorNoCtor<s32*> guard_array_vec; - - // Vector of module and compilation unit pc ranges. - InternalMmapVectorNoCtor<NamedPcRange> comp_unit_name_vec; - InternalMmapVectorNoCtor<NamedPcRange> module_name_vec; - - StaticSpinMutex mu; -}; - -static CoverageData coverage_data; - -void CovUpdateMapping(const char *path, uptr caller_pc = 0); - -void CoverageData::DirectOpen() { - InternalScopedString path(kMaxPathLength); - internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.raw", - coverage_dir, internal_getpid()); - pc_fd = OpenFile(path.data(), RdWr); - if (pc_fd == kInvalidFd) { - Report("Coverage: failed to open %s for reading/writing\n", path.data()); - Die(); - } - - pc_array_mapped_size = 0; - CovUpdateMapping(coverage_dir); -} - -void CoverageData::Init() { - pc_fd = kInvalidFd; -} - -void CoverageData::Enable() { - if (pc_array) - return; - pc_array = reinterpret_cast<uptr *>( - MmapNoReserveOrDie(sizeof(uptr) * kPcArrayMaxSize, "CovInit")); - atomic_store(&pc_array_index, 0, memory_order_relaxed); - if (common_flags()->coverage_direct) { - Report("coverage_direct=1 is deprecated, don't use it.\n"); - Die(); - atomic_store(&pc_array_size, 0, memory_order_relaxed); - } else { - atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed); - } -} - -void CoverageData::InitializeGuardArray(s32 *guards) { - Enable(); // Make sure coverage is enabled at this point. - s32 n = guards[0]; - for (s32 j = 1; j <= n; j++) { - uptr idx = atomic_load_relaxed(&pc_array_index); - atomic_store_relaxed(&pc_array_index, idx + 1); - guards[j] = -static_cast<s32>(idx + 1); - } -} - -void CoverageData::Disable() { - if (pc_array) { - UnmapOrDie(pc_array, sizeof(uptr) * kPcArrayMaxSize); - pc_array = nullptr; - } - if (pc_fd != kInvalidFd) { - CloseFile(pc_fd); - pc_fd = kInvalidFd; - } -} - -void CoverageData::ReinitializeGuards() { - // Assuming single thread. - atomic_store(&pc_array_index, 0, memory_order_relaxed); - for (uptr i = 0; i < guard_array_vec.size(); i++) - InitializeGuardArray(guard_array_vec[i]); -} - -void CoverageData::ReInit() { - Disable(); - if (coverage_enabled) { - if (common_flags()->coverage_direct) { - // In memory-mapped mode we must extend the new file to the known array - // size. - uptr size = atomic_load(&pc_array_size, memory_order_relaxed); - uptr npcs = size / sizeof(uptr); - Enable(); - if (size) Extend(npcs); - if (coverage_enabled) CovUpdateMapping(coverage_dir); - } else { - Enable(); - } - } - // Re-initialize the guards. - // We are single-threaded now, no need to grab any lock. - CHECK_EQ(atomic_load(&pc_array_index, memory_order_relaxed), 0); - ReinitializeGuards(); -} - -void CoverageData::BeforeFork() { - mu.Lock(); -} - -void CoverageData::AfterFork(int child_pid) { - // We are single-threaded so it's OK to release the lock early. - mu.Unlock(); - if (child_pid == 0) ReInit(); -} - -// Extend coverage PC array to fit additional npcs elements. -void CoverageData::Extend(uptr npcs) { - if (!common_flags()->coverage_direct) return; - SpinMutexLock l(&mu); - - uptr size = atomic_load(&pc_array_size, memory_order_relaxed); - size += npcs * sizeof(uptr); - - if (coverage_enabled && size > pc_array_mapped_size) { - if (pc_fd == kInvalidFd) DirectOpen(); - CHECK_NE(pc_fd, kInvalidFd); - - uptr new_mapped_size = pc_array_mapped_size; - while (size > new_mapped_size) new_mapped_size += kPcArrayMmapSize; - CHECK_LE(new_mapped_size, sizeof(uptr) * kPcArrayMaxSize); - - // Extend the file and map the new space at the end of pc_array. - uptr res = internal_ftruncate(pc_fd, new_mapped_size); - int err; - if (internal_iserror(res, &err)) { - Printf("failed to extend raw coverage file: %d\n", err); - Die(); - } - - uptr next_map_base = ((uptr)pc_array) + pc_array_mapped_size; - void *p = MapWritableFileToMemory((void *)next_map_base, - new_mapped_size - pc_array_mapped_size, - pc_fd, pc_array_mapped_size); - CHECK_EQ((uptr)p, next_map_base); - pc_array_mapped_size = new_mapped_size; - } - - atomic_store(&pc_array_size, size, memory_order_release); -} - -void CoverageData::UpdateModuleNameVec(uptr caller_pc, uptr range_beg, - uptr range_end) { - auto sym = Symbolizer::GetOrInit(); - if (!sym) - return; - const char *module_name = sym->GetModuleNameForPc(caller_pc); - if (!module_name) return; - if (module_name_vec.empty() || - module_name_vec.back().copied_module_name != module_name) - module_name_vec.push_back({module_name, range_beg, range_end}); - else - module_name_vec.back().end = range_end; -} - -void CoverageData::InitializeGuards(s32 *guards, uptr n, - const char *comp_unit_name, - uptr caller_pc) { - // The array 'guards' has n+1 elements, we use the element zero - // to store 'n'. - CHECK_LT(n, 1 << 30); - guards[0] = static_cast<s32>(n); - InitializeGuardArray(guards); - SpinMutexLock l(&mu); - uptr range_end = atomic_load(&pc_array_index, memory_order_relaxed); - uptr range_beg = range_end - n; - comp_unit_name_vec.push_back({comp_unit_name, range_beg, range_end}); - guard_array_vec.push_back(guards); - UpdateModuleNameVec(caller_pc, range_beg, range_end); -} - -static const uptr kBundleCounterBits = 16; - -// When coverage_order_pcs==true and SANITIZER_WORDSIZE==64 -// we insert the global counter into the first 16 bits of the PC. -uptr BundlePcAndCounter(uptr pc, uptr counter) { - if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs) - return pc; - static const uptr kMaxCounter = (1 << kBundleCounterBits) - 1; - if (counter > kMaxCounter) - counter = kMaxCounter; - CHECK_EQ(0, pc >> (SANITIZER_WORDSIZE - kBundleCounterBits)); - return pc | (counter << (SANITIZER_WORDSIZE - kBundleCounterBits)); -} - -uptr UnbundlePc(uptr bundle) { - if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs) - return bundle; - return (bundle << kBundleCounterBits) >> kBundleCounterBits; -} - -uptr UnbundleCounter(uptr bundle) { - if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs) - return 0; - return bundle >> (SANITIZER_WORDSIZE - kBundleCounterBits); -} - -// If guard is negative, atomically set it to -guard and store the PC in -// pc_array. -void CoverageData::Add(uptr pc, u32 *guard) { - atomic_uint32_t *atomic_guard = reinterpret_cast<atomic_uint32_t*>(guard); - s32 guard_value = atomic_load(atomic_guard, memory_order_relaxed); - if (guard_value >= 0) return; - - atomic_store(atomic_guard, -guard_value, memory_order_relaxed); - if (!pc_array) return; - - uptr idx = -guard_value - 1; - if (idx >= atomic_load(&pc_array_index, memory_order_acquire)) - return; // May happen after fork when pc_array_index becomes 0. - CHECK_LT(idx, atomic_load(&pc_array_size, memory_order_acquire)); - uptr counter = atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed); - pc_array[idx] = BundlePcAndCounter(pc, counter); -} - -uptr *CoverageData::data() { - return pc_array; -} - -uptr CoverageData::size() const { - return atomic_load(&pc_array_index, memory_order_relaxed); -} - -// Block layout for packed file format: header, followed by module name (no -// trailing zero), followed by data blob. -struct CovHeader { - int pid; - unsigned int module_name_length; - unsigned int data_length; -}; - -static void CovWritePacked(int pid, const char *module, const void *blob, - unsigned int blob_size) { - if (cov_fd == kInvalidFd) return; - unsigned module_name_length = internal_strlen(module); - CovHeader header = {pid, module_name_length, blob_size}; - - if (cov_max_block_size == 0) { - // Writing to a file. Just go ahead. - WriteToFile(cov_fd, &header, sizeof(header)); - WriteToFile(cov_fd, module, module_name_length); - WriteToFile(cov_fd, blob, blob_size); - } else { - // Writing to a socket. We want to split the data into appropriately sized - // blocks. - InternalScopedBuffer<char> block(cov_max_block_size); - CHECK_EQ((uptr)block.data(), (uptr)(CovHeader *)block.data()); - uptr header_size_with_module = sizeof(header) + module_name_length; - CHECK_LT(header_size_with_module, cov_max_block_size); - unsigned int max_payload_size = - cov_max_block_size - header_size_with_module; - char *block_pos = block.data(); - internal_memcpy(block_pos, &header, sizeof(header)); - block_pos += sizeof(header); - internal_memcpy(block_pos, module, module_name_length); - block_pos += module_name_length; - char *block_data_begin = block_pos; - const char *blob_pos = (const char *)blob; - while (blob_size > 0) { - unsigned int payload_size = Min(blob_size, max_payload_size); - blob_size -= payload_size; - internal_memcpy(block_data_begin, blob_pos, payload_size); - blob_pos += payload_size; - ((CovHeader *)block.data())->data_length = payload_size; - WriteToFile(cov_fd, block.data(), header_size_with_module + payload_size); - } - } -} - -// If packed = false: <name>.<pid>.<sancov> (name = module name). -// If packed = true and name == 0: <pid>.<sancov>.<packed>. -// If packed = true and name != 0: <name>.<sancov>.<packed> (name is -// user-supplied). -static fd_t CovOpenFile(InternalScopedString *path, bool packed, - const char *name, const char *extension = "sancov") { - path->clear(); - if (!packed) { - CHECK(name); - path->append("%s/%s.%zd.%s", coverage_dir, name, internal_getpid(), - extension); - } else { - if (!name) - path->append("%s/%zd.%s.packed", coverage_dir, internal_getpid(), - extension); - else - path->append("%s/%s.%s.packed", coverage_dir, name, extension); - } - error_t err; - fd_t fd = OpenFile(path->data(), WrOnly, &err); - if (fd == kInvalidFd) - Report("SanitizerCoverage: failed to open %s for writing (reason: %d)\n", - path->data(), err); - return fd; -} - -void CoverageData::GetRangeOffsets(const NamedPcRange& r, Symbolizer* sym, - InternalMmapVector<uptr>* offsets) const { - offsets->clear(); - for (uptr i = 0; i < kNumWordsForMagic; i++) - offsets->push_back(0); - CHECK(r.copied_module_name); - CHECK_LE(r.beg, r.end); - CHECK_LE(r.end, size()); - for (uptr i = r.beg; i < r.end; i++) { - uptr pc = UnbundlePc(pc_array[i]); - uptr counter = UnbundleCounter(pc_array[i]); - if (!pc) continue; // Not visited. - uptr offset = 0; - sym->GetModuleNameAndOffsetForPC(pc, nullptr, &offset); - offsets->push_back(BundlePcAndCounter(offset, counter)); - } - - CHECK_GE(offsets->size(), kNumWordsForMagic); - SortArray(offsets->data(), offsets->size()); - for (uptr i = 0; i < offsets->size(); i++) - (*offsets)[i] = UnbundlePc((*offsets)[i]); -} - -static void GenerateHtmlReport(const InternalMmapVector<char *> &cov_files) { - if (!common_flags()->html_cov_report) { - return; - } - char *sancov_path = FindPathToBinary(common_flags()->sancov_path); - if (sancov_path == nullptr) { - return; - } - - InternalMmapVector<char *> sancov_argv(cov_files.size() * 2 + 3); - sancov_argv.push_back(sancov_path); - sancov_argv.push_back(internal_strdup("-html-report")); - auto argv_deleter = at_scope_exit([&] { - for (uptr i = 0; i < sancov_argv.size(); ++i) { - InternalFree(sancov_argv[i]); - } - }); - - for (const auto &cov_file : cov_files) { - sancov_argv.push_back(internal_strdup(cov_file)); - } - - { - ListOfModules modules; - modules.init(); - for (const LoadedModule &module : modules) { - sancov_argv.push_back(internal_strdup(module.full_name())); - } - } - - InternalScopedString report_path(kMaxPathLength); - fd_t report_fd = - CovOpenFile(&report_path, false /* packed */, GetProcessName(), "html"); - int pid = StartSubprocess(sancov_argv[0], sancov_argv.data(), - kInvalidFd /* stdin */, report_fd /* std_out */); - if (pid > 0) { - int result = WaitForProcess(pid); - if (result == 0) - Printf("coverage report generated to %s\n", report_path.data()); - } -} - -void CoverageData::DumpOffsets() { - auto sym = Symbolizer::GetOrInit(); - if (!common_flags()->coverage_pcs) return; - Printf("**\n***\n***\n"); - Printf("**WARNING: this implementation of SanitizerCoverage is deprecated\n"); - Printf("**WARNING: and will be removed in future versions\n"); - Printf("**WARNING: See https://clang.llvm.org/docs/SanitizerCoverage.html\n"); - Printf("**\n***\n***\n"); - - CHECK_NE(sym, nullptr); - InternalMmapVector<uptr> offsets(0); - InternalScopedString path(kMaxPathLength); - - InternalMmapVector<char *> cov_files(module_name_vec.size()); - auto cov_files_deleter = at_scope_exit([&] { - for (uptr i = 0; i < cov_files.size(); ++i) { - InternalFree(cov_files[i]); - } - }); - - for (uptr m = 0; m < module_name_vec.size(); m++) { - auto r = module_name_vec[m]; - GetRangeOffsets(r, sym, &offsets); - - uptr num_offsets = offsets.size() - kNumWordsForMagic; - u64 *magic_p = reinterpret_cast<u64*>(offsets.data()); - CHECK_EQ(*magic_p, 0ULL); - // FIXME: we may want to write 32-bit offsets even in 64-mode - // if all the offsets are small enough. - *magic_p = kMagic; - - const char *module_name = StripModuleName(r.copied_module_name); - if (cov_sandboxed) { - if (cov_fd != kInvalidFd) { - CovWritePacked(internal_getpid(), module_name, offsets.data(), - offsets.size() * sizeof(offsets[0])); - VReport(1, " CovDump: %zd PCs written to packed file\n", num_offsets); - } - } else { - // One file per module per process. - fd_t fd = CovOpenFile(&path, false /* packed */, module_name); - if (fd == kInvalidFd) continue; - WriteToFile(fd, offsets.data(), offsets.size() * sizeof(offsets[0])); - CloseFile(fd); - cov_files.push_back(internal_strdup(path.data())); - VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), num_offsets); - } - } - if (cov_fd != kInvalidFd) - CloseFile(cov_fd); - - GenerateHtmlReport(cov_files); -} - -void CoverageData::DumpAll() { - if (!coverage_enabled || common_flags()->coverage_direct) return; - if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed)) - return; - DumpOffsets(); -} - -void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { - if (!args) return; - if (!coverage_enabled) return; - cov_sandboxed = args->coverage_sandboxed; - if (!cov_sandboxed) return; - cov_max_block_size = args->coverage_max_block_size; - if (args->coverage_fd >= 0) { - cov_fd = (fd_t)args->coverage_fd; - } else { - InternalScopedString path(kMaxPathLength); - // Pre-open the file now. The sandbox won't allow us to do it later. - cov_fd = CovOpenFile(&path, true /* packed */, nullptr); - } -} - -fd_t MaybeOpenCovFile(const char *name) { - CHECK(name); - if (!coverage_enabled) return kInvalidFd; - InternalScopedString path(kMaxPathLength); - return CovOpenFile(&path, true /* packed */, name); -} - -void CovBeforeFork() { - coverage_data.BeforeFork(); -} - -void CovAfterFork(int child_pid) { - coverage_data.AfterFork(child_pid); -} - -static void MaybeDumpCoverage() { - if (common_flags()->coverage) - __sanitizer_cov_dump(); -} - -void InitializeCoverage(bool enabled, const char *dir) { - if (coverage_enabled) - return; // May happen if two sanitizer enable coverage in the same process. - coverage_enabled = enabled; - coverage_dir = dir; - coverage_data.Init(); - if (enabled) coverage_data.Enable(); - if (!common_flags()->coverage_direct) Atexit(__sanitizer_cov_dump); - AddDieCallback(MaybeDumpCoverage); -} - -void ReInitializeCoverage(bool enabled, const char *dir) { - coverage_enabled = enabled; - coverage_dir = dir; - coverage_data.ReInit(); -} - -void CoverageUpdateMapping() { - if (coverage_enabled) - CovUpdateMapping(coverage_dir); -} - -} // namespace __sanitizer - -extern "C" { -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { - __sanitizer_dump_trace_pc_guard_coverage(); -} -SANITIZER_INTERFACE_ATTRIBUTE -sptr __sanitizer_maybe_open_cov_file(const char *name) { - return (sptr)MaybeOpenCovFile(name); -} -// Default empty implementations (weak). Users should redefine them. -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} -SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} -} // extern "C" diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc index a98dde76e22a..24433356c63d 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cc @@ -146,6 +146,17 @@ static TracePcGuardController pc_guard_controller; } // namespace } // namespace __sancov +namespace __sanitizer { +void InitializeCoverage(bool enabled, const char *dir) { + static bool coverage_enabled = false; + if (coverage_enabled) + return; // May happen if two sanitizer enable coverage in the same process. + coverage_enabled = enabled; + Atexit(__sanitizer_cov_dump); + AddDieCallback(__sanitizer_cov_dump); +} +} // namespace __sanitizer + extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( // NOLINT const uptr* pcs, uptr len) { @@ -166,4 +177,18 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() { __sancov::pc_guard_controller.Dump(); } +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { + __sanitizer_dump_trace_pc_guard_coverage(); +} +// Default empty implementations (weak). Users should redefine them. +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} } // extern "C" diff --git a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc deleted file mode 100644 index 3477b065b06a..000000000000 --- a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc +++ /dev/null @@ -1,122 +0,0 @@ -//===-- sanitizer_coverage_mapping.cc -------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Mmap-based implementation of sanitizer coverage. -// -// This is part of the implementation of code coverage that does not require -// __sanitizer_cov_dump() call. Data is stored in 2 files per process. -// -// $pid.sancov.map describes process memory layout in the following text-based -// format: -// <pointer size in bits> // 1 line, 32 or 64 -// <mapping start> <mapping end> <base address> <dso name> // repeated -// ... -// Mapping lines are NOT sorted. This file is updated every time memory layout -// is changed (i.e. in dlopen() and dlclose() interceptors). -// -// $pid.sancov.raw is a binary dump of PC values, sizeof(uptr) each. Again, not -// sorted. This file is extended by 64Kb at a time and mapped into memory. It -// contains one or more 0 words at the end, up to the next 64Kb aligned offset. -// -// To convert these 2 files to the usual .sancov format, run sancov.py rawunpack -// $pid.sancov.raw. -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_allocator_internal.h" -#include "sanitizer_libc.h" -#include "sanitizer_procmaps.h" - -namespace __sanitizer { - -static const uptr kMaxTextSize = 64 * 1024; - -struct CachedMapping { - public: - bool NeedsUpdate(uptr pc) { - int new_pid = internal_getpid(); - if (last_pid == new_pid && pc && pc >= last_range_start && - pc < last_range_end) - return false; - last_pid = new_pid; - return true; - } - - void SetModuleRange(uptr start, uptr end) { - last_range_start = start; - last_range_end = end; - } - - private: - uptr last_range_start, last_range_end; - int last_pid; -}; - -static CachedMapping cached_mapping; -static StaticSpinMutex mapping_mu; - -void CovUpdateMapping(const char *coverage_dir, uptr caller_pc) { - if (!common_flags()->coverage_direct) return; - - SpinMutexLock l(&mapping_mu); - - if (!cached_mapping.NeedsUpdate(caller_pc)) - return; - - InternalScopedString text(kMaxTextSize); - - { - text.append("%d\n", sizeof(uptr) * 8); - ListOfModules modules; - modules.init(); - for (const LoadedModule &module : modules) { - const char *module_name = StripModuleName(module.full_name()); - uptr base = module.base_address(); - for (const auto &range : module.ranges()) { - if (range.executable) { - uptr start = range.beg; - uptr end = range.end; - text.append("%zx %zx %zx %s\n", start, end, base, module_name); - if (caller_pc && caller_pc >= start && caller_pc < end) - cached_mapping.SetModuleRange(start, end); - } - } - } - } - - error_t err; - InternalScopedString tmp_path(64 + internal_strlen(coverage_dir)); - uptr res = internal_snprintf((char *)tmp_path.data(), tmp_path.size(), - "%s/%zd.sancov.map.tmp", coverage_dir, - internal_getpid()); - CHECK_LE(res, tmp_path.size()); - fd_t map_fd = OpenFile(tmp_path.data(), WrOnly, &err); - if (map_fd == kInvalidFd) { - Report("Coverage: failed to open %s for writing: %d\n", tmp_path.data(), - err); - Die(); - } - - if (!WriteToFile(map_fd, text.data(), text.length(), nullptr, &err)) { - Printf("sancov.map write failed: %d\n", err); - Die(); - } - CloseFile(map_fd); - - InternalScopedString path(64 + internal_strlen(coverage_dir)); - res = internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.map", - coverage_dir, internal_getpid()); - CHECK_LE(res, path.size()); - if (!RenameFile(tmp_path.data(), path.data(), &err)) { - Printf("sancov.map rename failed: %d\n", err); - Die(); - } -} - -} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index f87d8b6433ac..8c486b5b1b4d 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -138,16 +138,6 @@ COMMON_FLAG( bool, coverage, false, "If set, coverage information will be dumped at program shutdown (if the " "coverage instrumentation was enabled at compile time).") -COMMON_FLAG(bool, coverage_pcs, true, - "If set (and if 'coverage' is set too), the coverage information " - "will be dumped as a set of PC offsets for every module.") -COMMON_FLAG(bool, coverage_order_pcs, false, - "If true, the PCs will be dumped in the order they've" - " appeared during the execution.") -COMMON_FLAG(bool, coverage_direct, SANITIZER_ANDROID, - "If set, coverage information will be dumped directly to a memory " - "mapped file. This way data is not lost even if the process is " - "suddenly killed.") COMMON_FLAG(const char *, coverage_dir, ".", "Target directory for coverage dumps. Defaults to the current " "directory.") diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 3bda35655d9e..7bc7682dd962 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -62,8 +62,6 @@ #if SANITIZER_FREEBSD #include <sys/exec.h> #include <sys/sysctl.h> -#include <vm/vm_param.h> -#include <vm/pmap.h> #include <machine/atomic.h> extern "C" { // <sys/umtx.h> must be included after <errno.h> and <sys/types.h> on @@ -77,16 +75,6 @@ extern char **environ; // provided by crt1 #include <sys/signal.h> #endif -#ifndef __GLIBC_PREREQ -#define __GLIBC_PREREQ(x, y) 0 -#endif - -#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 16) -# define SANITIZER_USE_GETAUXVAL 1 -#else -# define SANITIZER_USE_GETAUXVAL 0 -#endif - #if SANITIZER_USE_GETAUXVAL #include <sys/auxv.h> #endif @@ -237,7 +225,8 @@ static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { uptr internal_stat(const char *path, void *buf) { #if SANITIZER_FREEBSD - return internal_syscall(SYSCALL(stat), path, buf); + return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, + (uptr)buf, 0); #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0); @@ -261,7 +250,8 @@ uptr internal_stat(const char *path, void *buf) { uptr internal_lstat(const char *path, void *buf) { #if SANITIZER_FREEBSD - return internal_syscall(SYSCALL(lstat), path, buf); + return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, + (uptr)buf, AT_SYMLINK_NOFOLLOW); #elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, AT_SYMLINK_NOFOLLOW); @@ -604,7 +594,9 @@ uptr internal_getppid() { } uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS +#if SANITIZER_FREEBSD + return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL); +#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count); #else return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count); diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h index 49732aa32323..8fa3f7ab66fc 100644 --- a/lib/sanitizer_common/sanitizer_platform.h +++ b/lib/sanitizer_common/sanitizer_platform.h @@ -269,5 +269,14 @@ # define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 0 #endif +#ifndef __GLIBC_PREREQ +#define __GLIBC_PREREQ(x, y) 0 +#endif + +#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 16) +# define SANITIZER_USE_GETAUXVAL 1 +#else +# define SANITIZER_USE_GETAUXVAL 0 +#endif #endif // SANITIZER_PLATFORM_H diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h index c6f6a211573c..24ffcd7d94f4 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -23,6 +23,9 @@ // incorporates the map structure. # define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ ((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 544))) +// Get sys/_types.h, because that tells us whether 64-bit inodes are +// used in struct dirent below. +#include <sys/_types.h> #else # define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) ((link_map*)(handle)) #endif // !SANITIZER_FREEBSD @@ -485,7 +488,12 @@ namespace __sanitizer { }; #elif SANITIZER_FREEBSD struct __sanitizer_dirent { +#if defined(__INO64) + unsigned long long d_fileno; + unsigned long long d_off; +#else unsigned int d_fileno; +#endif unsigned short d_reclen; // more fields that we don't care about }; diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index 791ff4481ca8..5b1d53698707 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -264,7 +264,6 @@ void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { // Same for /proc/self/exe in the symbolizer. #if !SANITIZER_GO Symbolizer::GetOrInit()->PrepareForSandboxing(); - CovPrepareForSandboxing(args); #endif } diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index c912e8fa2aa3..afc3bb0ac678 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -400,9 +400,6 @@ void ReExec() { } void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { -#if !SANITIZER_GO - CovPrepareForSandboxing(args); -#endif } bool StackSizeIsUnlimited() { diff --git a/lib/sanitizer_common/scripts/check_lint.sh b/lib/sanitizer_common/scripts/check_lint.sh index 9108a81e26c8..82e4bc84d594 100755 --- a/lib/sanitizer_common/scripts/check_lint.sh +++ b/lib/sanitizer_common/scripts/check_lint.sh @@ -18,7 +18,7 @@ fi # Filters # TODO: remove some of these filters COMMON_LINT_FILTER=-build/include,-build/header_guard,-legal/copyright,-whitespace/comments,-readability/casting,\ --build/namespaces +-build/namespaces,-readability/braces ASAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int ASAN_TEST_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/sizeof,-runtime/int,-runtime/printf,-runtime/threadsafe_fn ASAN_LIT_TEST_LINT_FILTER=${ASAN_TEST_LINT_FILTER},-whitespace/line_length diff --git a/lib/sanitizer_common/tests/sanitizer_flags_test.cc b/lib/sanitizer_common/tests/sanitizer_flags_test.cc index 0af84a20b7f5..f3fe139e6ee8 100644 --- a/lib/sanitizer_common/tests/sanitizer_flags_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_flags_test.cc @@ -167,13 +167,13 @@ TEST(SanitizerCommon, CommonFlags) { cf.symbolize = false; cf.coverage = true; - cf.coverage_direct = true; + cf.heap_profile = true; cf.log_path = "path/one"; - parser.ParseString("symbolize=1:coverage_direct=false log_path='path/two'"); + parser.ParseString("symbolize=1:heap_profile=false log_path='path/two'"); EXPECT_TRUE(cf.symbolize); EXPECT_TRUE(cf.coverage); - EXPECT_FALSE(cf.coverage_direct); + EXPECT_FALSE(cf.heap_profile); EXPECT_STREQ("path/two", cf.log_path); } diff --git a/lib/ubsan/ubsan_checks.inc b/lib/ubsan/ubsan_checks.inc index 6e086414051e..0a87e6e8e3a4 100644 --- a/lib/ubsan/ubsan_checks.inc +++ b/lib/ubsan/ubsan_checks.inc @@ -19,6 +19,7 @@ UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined") UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null") +UBSAN_CHECK(PointerOverflow, "pointer-overflow", "pointer-overflow") UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use", "alignment") UBSAN_CHECK(InsufficientObjectSize, "insufficient-object-size", "object-size") UBSAN_CHECK(SignedIntegerOverflow, "signed-integer-overflow", diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index d6a8f52a27b4..80cc8ad25790 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -554,6 +554,37 @@ void __ubsan::__ubsan_handle_nullability_arg_abort(NonNullArgData *Data) { Die(); } +static void handlePointerOverflowImpl(PointerOverflowData *Data, + ValueHandle Base, + ValueHandle Result, + ReportOptions Opts) { + SourceLocation Loc = Data->Loc.acquire(); + ErrorType ET = ErrorType::PointerOverflow; + + if (ignoreReport(Loc, Opts, ET)) + return; + + ScopedReport R(Opts, Loc, ET); + + Diag(Loc, DL_Error, "pointer index expression with base %0 overflowed to %1") + << (void *)Base << (void*)Result; +} + +void __ubsan::__ubsan_handle_pointer_overflow(PointerOverflowData *Data, + ValueHandle Base, + ValueHandle Result) { + GET_REPORT_OPTIONS(false); + handlePointerOverflowImpl(Data, Base, Result, Opts); +} + +void __ubsan::__ubsan_handle_pointer_overflow_abort(PointerOverflowData *Data, + ValueHandle Base, + ValueHandle Result) { + GET_REPORT_OPTIONS(true); + handlePointerOverflowImpl(Data, Base, Result, Opts); + Die(); +} + static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function, ReportOptions Opts) { if (Data->CheckKind != CFITCK_ICall) diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h index 5857bc2495f5..483c18ced579 100644 --- a/lib/ubsan/ubsan_handlers.h +++ b/lib/ubsan/ubsan_handlers.h @@ -152,6 +152,13 @@ struct NonNullArgData { RECOVERABLE(nonnull_arg, NonNullArgData *Data) RECOVERABLE(nullability_arg, NonNullArgData *Data) +struct PointerOverflowData { + SourceLocation Loc; +}; + +RECOVERABLE(pointer_overflow, PointerOverflowData *Data, ValueHandle Base, + ValueHandle Result) + /// \brief Known CFI check kinds. /// Keep in sync with the enum of the same name in CodeGenFunction.h enum CFITypeCheckKind : unsigned char { diff --git a/lib/ubsan/ubsan_interface.inc b/lib/ubsan/ubsan_interface.inc index 0e43ebc68299..681476b3c91d 100644 --- a/lib/ubsan/ubsan_interface.inc +++ b/lib/ubsan/ubsan_interface.inc @@ -36,6 +36,8 @@ INTERFACE_FUNCTION(__ubsan_handle_nullability_return) INTERFACE_FUNCTION(__ubsan_handle_nullability_return_abort) INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds) INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds_abort) +INTERFACE_FUNCTION(__ubsan_handle_pointer_overflow) +INTERFACE_FUNCTION(__ubsan_handle_pointer_overflow_abort) INTERFACE_FUNCTION(__ubsan_handle_shift_out_of_bounds) INTERFACE_FUNCTION(__ubsan_handle_shift_out_of_bounds_abort) INTERFACE_FUNCTION(__ubsan_handle_sub_overflow) diff --git a/test/asan/TestCases/Android/coverage-android.cc b/test/asan/TestCases/Android/coverage-android.cc deleted file mode 100644 index cf4f33ebdb44..000000000000 --- a/test/asan/TestCases/Android/coverage-android.cc +++ /dev/null @@ -1,147 +0,0 @@ -// Test for direct coverage writing with dlopen. - -// Test normal exit, coverage level 1. -// RUN: %clangxx_asan -fsanitize-coverage=func -DSHARED %s -shared -o %T/libcoverage_android_test_1.so -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=func -DSO_DIR=\"%device\" %s -o %t - -// RUN: adb shell rm -rf %device/coverage-android -// RUN: rm -rf %T/coverage-android - -// RUN: adb shell mkdir -p %device/coverage-android/direct -// RUN: mkdir -p %T/coverage-android/direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android/direct:verbosity=1 %run %t -// RUN: adb pull %device/coverage-android/direct %T/coverage-android/direct -// RUN: ls; pwd -// RUN: cd %T/coverage-android/direct -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK1 %s - - -// Test sudden death, coverage level 1. -// RUN: %clangxx_asan -fsanitize-coverage=func -DSHARED -DKILL %s -shared -o %T/libcoverage_android_test_1.so -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=func -DSO_DIR=\"%device\" %s -o %t - -// RUN: adb shell rm -rf %device/coverage-android-kill -// RUN: rm -rf %T/coverage-android-kill - -// RUN: adb shell mkdir -p %device/coverage-android-kill/direct -// RUN: mkdir -p %T/coverage-android-kill/direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android-kill/direct:verbosity=1 not %run %t -// RUN: adb pull %device/coverage-android-kill/direct %T/coverage-android-kill/direct -// RUN: ls; pwd -// RUN: cd %T/coverage-android-kill/direct -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK1 %s - - -// Test normal exit, coverage level 2. -// RUN: %clangxx_asan -fsanitize-coverage=bb -DSHARED %s -shared -o %T/libcoverage_android_test_1.so -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=bb -DSO_DIR=\"%device\" %s -o %t - -// RUN: adb shell rm -rf %device/coverage-android -// RUN: rm -rf %T/coverage-android - -// RUN: adb shell mkdir -p %device/coverage-android/direct -// RUN: mkdir -p %T/coverage-android/direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android/direct:verbosity=1 %run %t -// RUN: adb pull %device/coverage-android/direct %T/coverage-android/direct -// RUN: ls; pwd -// RUN: cd %T/coverage-android/direct -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK2 %s - - -// Test sudden death, coverage level 2. -// RUN: %clangxx_asan -fsanitize-coverage=bb -DSHARED -DKILL %s -shared -o %T/libcoverage_android_test_1.so -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=bb -DSO_DIR=\"%device\" %s -o %t - -// RUN: adb shell rm -rf %device/coverage-android-kill -// RUN: rm -rf %T/coverage-android-kill - -// RUN: adb shell mkdir -p %device/coverage-android-kill/direct -// RUN: mkdir -p %T/coverage-android-kill/direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android-kill/direct:verbosity=1 not %run %t -// RUN: adb pull %device/coverage-android-kill/direct %T/coverage-android-kill/direct -// RUN: ls; pwd -// RUN: cd %T/coverage-android-kill/direct -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK2 %s - - -// Test normal exit, coverage level 3. -// RUN: %clangxx_asan -fsanitize-coverage=edge -DSHARED %s -shared -o %T/libcoverage_android_test_1.so -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=edge -DSO_DIR=\"%device\" %s -o %t - -// RUN: adb shell rm -rf %device/coverage-android -// RUN: rm -rf %T/coverage-android - -// RUN: adb shell mkdir -p %device/coverage-android/direct -// RUN: mkdir -p %T/coverage-android/direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android/direct:verbosity=1 %run %t -// RUN: adb pull %device/coverage-android/direct %T/coverage-android/direct -// RUN: ls; pwd -// RUN: cd %T/coverage-android/direct -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK3 %s - - -// Test sudden death, coverage level 3. -// RUN: %clangxx_asan -fsanitize-coverage=edge -DSHARED -DKILL %s -shared -o %T/libcoverage_android_test_1.so -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=edge -DSO_DIR=\"%device\" %s -o %t - -// RUN: adb shell rm -rf %device/coverage-android-kill -// RUN: rm -rf %T/coverage-android-kill - -// RUN: adb shell mkdir -p %device/coverage-android-kill/direct -// RUN: mkdir -p %T/coverage-android-kill/direct -// RUN: %env_asan_opts=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android-kill/direct:verbosity=1 not %run %t -// RUN: adb pull %device/coverage-android-kill/direct %T/coverage-android-kill/direct -// RUN: ls; pwd -// RUN: cd %T/coverage-android-kill/direct -// RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK3 %s - -// PC counts in CHECK lines are platform dependent and match arm32 at the moment. -// sancov tool does not support Android well enough to match function names -// REQUIRES: arm - -#include <assert.h> -#include <dlfcn.h> -#include <stdio.h> -#include <unistd.h> -#include <sys/types.h> -#include <signal.h> - -#ifdef SHARED -extern "C" { -void bar() { - printf("bar\n"); -#ifdef KILL - kill(getpid(), SIGKILL); -#endif -} -} -#else - -volatile int sink; - -int main(int argc, char **argv) { - fprintf(stderr, "PID: %d\n", getpid()); - void *handle1 = - dlopen(SO_DIR "/libcoverage_android_test_1.so", RTLD_LAZY); - assert(handle1); - - if (argc == 0) - sink = 0; - - void (*bar1)() = (void (*)())dlsym(handle1, "bar"); - assert(bar1); - bar1(); - - return 0; -} -#endif - -// CHECK1: 2 PCs total -// CHECK2: 4 PCs total -// CHECK3: 5 PCs total diff --git a/test/asan/TestCases/Linux/uar_signals.cc b/test/asan/TestCases/Linux/uar_signals.cc index f42c3f666554..f96a2fecb367 100644 --- a/test/asan/TestCases/Linux/uar_signals.cc +++ b/test/asan/TestCases/Linux/uar_signals.cc @@ -1,12 +1,13 @@ // This test checks that the implementation of use-after-return // is async-signal-safe. -// RUN: %clangxx_asan -O1 %s -o %t -pthread && %run %t +// RUN: %clangxx_asan -std=c++11 -O1 %s -o %t -pthread && %run %t // REQUIRES: stable-runtime #include <signal.h> #include <stdlib.h> #include <stdio.h> #include <sys/time.h> #include <pthread.h> +#include <initializer_list> int *g; int n_signals; @@ -17,7 +18,6 @@ void SignalHandler(int, siginfo_t*, void*) { int local; g = &local; n_signals++; - // printf("s: %p\n", &local); } static void EnableSigprof(Sigaction SignalHandler) { @@ -49,22 +49,29 @@ void RecursiveFunction(int depth) { RecursiveFunction(depth - 1); } -void *Thread(void *) { - RecursiveFunction(18); +void *FastThread(void *) { + RecursiveFunction(1); + return NULL; +} + +void *SlowThread(void *) { + RecursiveFunction(1); return NULL; } int main(int argc, char **argv) { EnableSigprof(SignalHandler); - for (int i = 0; i < 4; i++) { - fprintf(stderr, "."); - const int kNumThread = sizeof(void*) == 8 ? 16 : 8; - pthread_t t[kNumThread]; - for (int i = 0; i < kNumThread; i++) - pthread_create(&t[i], 0, Thread, 0); - for (int i = 0; i < kNumThread; i++) - pthread_join(t[i], 0); + for (auto Thread : {&FastThread, &SlowThread}) { + for (int i = 0; i < 1000; i++) { + fprintf(stderr, "."); + const int kNumThread = sizeof(void*) == 8 ? 32 : 8; + pthread_t t[kNumThread]; + for (int i = 0; i < kNumThread; i++) + pthread_create(&t[i], 0, Thread, 0); + for (int i = 0; i < kNumThread; i++) + pthread_join(t[i], 0); + } + fprintf(stderr, "\n"); } - fprintf(stderr, "\n"); } diff --git a/test/asan/TestCases/Posix/coverage-maybe-open-file.cc b/test/asan/TestCases/Posix/coverage-maybe-open-file.cc deleted file mode 100644 index ee2977af11c4..000000000000 --- a/test/asan/TestCases/Posix/coverage-maybe-open-file.cc +++ /dev/null @@ -1,34 +0,0 @@ -// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 -// XFAIL: android -// UNSUPPORTED: ios -// -// RUN: %clangxx_asan -fsanitize-coverage=func %s -o %t -// RUN: rm -rf %T/coverage-maybe-open-file -// RUN: mkdir -p %T/coverage-maybe-open-file && cd %T/coverage-maybe-open-file -// RUN: %env_asan_opts=coverage=1 %run %t | FileCheck %s --check-prefix=CHECK-success -// RUN: %env_asan_opts=coverage=0 %run %t | FileCheck %s --check-prefix=CHECK-fail -// RUN: FileCheck %s < test.sancov.packed -implicit-check-not={{.}} --check-prefix=CHECK-test -// RUN: cd .. && rm -rf %T/coverage-maybe-open-file - -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -#include <sanitizer/coverage_interface.h> - -// FIXME: the code below might not work on Windows. -int main(int argc, char **argv) { - int fd = __sanitizer_maybe_open_cov_file("test"); - if (fd > 0) { - printf("SUCCESS\n"); - const char s[] = "test\n"; - write(fd, s, strlen(s)); - close(fd); - } else { - printf("FAIL\n"); - } -} - -// CHECK-success: SUCCESS -// CHECK-fail: FAIL -// CHECK-test: {{^}}test{{$}} diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc new file mode 100644 index 000000000000..b7246ebf2751 --- /dev/null +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc @@ -0,0 +1,23 @@ +// Tests -fsanitize-coverage=inline-8bit-counters +// +// REQUIRES: has_sancovcc,stable-runtime +// UNSUPPORTED: i386-darwin +// +// RUN: %clangxx -O0 %s -fsanitize-coverage=inline-8bit-counters 2>&1 + +#include <stdio.h> +#include <assert.h> + +const char *first_counter; + +extern "C" +void __sanitizer_cov_8bit_counters_init(const char *start, const char *end) { + printf("INIT: %p %p\n", start, end); + assert(end - start > 1); + first_counter = start; +} + +int main() { + assert(first_counter); + assert(*first_counter == 1); +} diff --git a/test/ubsan/TestCases/Pointer/index-overflow.cpp b/test/ubsan/TestCases/Pointer/index-overflow.cpp new file mode 100644 index 000000000000..eb7f95e85c2c --- /dev/null +++ b/test/ubsan/TestCases/Pointer/index-overflow.cpp @@ -0,0 +1,19 @@ +// RUN: %clangxx -fsanitize=pointer-overflow %s -o %t +// RUN: %t 1 2>&1 | FileCheck %s --check-prefix=ERR +// RUN: %t 0 2>&1 | FileCheck %s --check-prefix=SAFE +// RUN: %t -1 2>&1 | FileCheck %s --check-prefix=SAFE + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> + +int main(int argc, char *argv[]) { + // SAFE-NOT: runtime error + // ERR: runtime error: pointer index expression with base {{.*}} overflowed to + + char *p = (char *)(UINTPTR_MAX); + + printf("%p\n", p + atoi(argv[1])); + + return 0; +} |