diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:52:19 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:52:19 +0000 |
commit | 5c909fa013fc285f010a95e8d387e0ef3412da9c (patch) | |
tree | 1059d068ad281f4776ff44cd414574f99a460023 /lib/sanitizer_common | |
parent | f31bcc68c72371a2bf63aead9f3373a1ff2053b6 (diff) | |
download | src-5c909fa013fc285f010a95e8d387e0ef3412da9c.tar.gz src-5c909fa013fc285f010a95e8d387e0ef3412da9c.zip |
Vendor import of compiler-rt trunk r256633:vendor/compiler-rt/compiler-rt-trunk-r256633
Notes
Notes:
svn path=/vendor/compiler-rt/dist/; revision=292925
svn path=/vendor/compiler-rt/compiler-rt-trunk-r256633/; revision=292926; tag=vendor/compiler-rt/compiler-rt-trunk-r256633
Diffstat (limited to 'lib/sanitizer_common')
82 files changed, 3426 insertions, 1239 deletions
diff --git a/lib/sanitizer_common/.clang-format b/lib/sanitizer_common/.clang-format new file mode 100644 index 000000000000..f6cb8ad931f5 --- /dev/null +++ b/lib/sanitizer_common/.clang-format @@ -0,0 +1 @@ +BasedOnStyle: Google diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt index f604c9f201d4..6a20f025507a 100644 --- a/lib/sanitizer_common/CMakeLists.txt +++ b/lib/sanitizer_common/CMakeLists.txt @@ -33,6 +33,12 @@ set(SANITIZER_SOURCES sanitizer_thread_registry.cc sanitizer_win.cc) +# Libc functions stubs. These sources should be linked instead of +# SANITIZER_LIBCDEP_SOURCES when sanitizer_common library must not depend on +# libc. +set(SANITIZER_NOLIBC_SOURCES + sanitizer_common_nolibc.cc) + set(SANITIZER_LIBCDEP_SOURCES sanitizer_common_libcdep.cc sanitizer_coverage_libcdep.cc @@ -43,7 +49,6 @@ set(SANITIZER_LIBCDEP_SOURCES sanitizer_stoptheworld_linux_libcdep.cc sanitizer_symbolizer_libcdep.cc sanitizer_symbolizer_posix_libcdep.cc - sanitizer_symbolizer_process_libcdep.cc sanitizer_unwind_linux_libcdep.cc) # Explicitly list all sanitizer_common headers. Not all of these are @@ -97,9 +102,9 @@ set(SANITIZER_HEADERS sanitizer_symbolizer_internal.h sanitizer_symbolizer_libbacktrace.h sanitizer_symbolizer_mac.h - sanitizer_symbolizer_win.h sanitizer_syscall_generic.inc sanitizer_syscall_linux_x86_64.inc + sanitizer_syscall_linux_aarch64.inc sanitizer_thread_registry.h) set(SANITIZER_COMMON_DEFINITIONS) @@ -124,38 +129,28 @@ append_list_if(SANITIZER_LIMIT_FRAME_SIZE -Wframe-larger-than=570 append_list_if(COMPILER_RT_HAS_WGLOBAL_CONSTRUCTORS_FLAG -Wglobal-constructors SANITIZER_CFLAGS) -add_custom_target(sanitizer_common) -set(SANITIZER_RUNTIME_LIBRARIES) if(APPLE) - # Build universal binary on APPLE. - - add_compiler_rt_object_libraries(RTSanitizerCommon - OS ${SANITIZER_COMMON_SUPPORTED_OS} - ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} - SOURCES ${SANITIZER_SOURCES} ${SANITIZER_LIBCDEP_SOURCES} - CFLAGS ${SANITIZER_CFLAGS} - DEFS ${SANITIZER_COMMON_DEFINITIONS}) - foreach(os ${SANITIZER_COMMON_SUPPORTED_OS}) - list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.${os}) - endforeach() -else() - # Otherwise, build separate libraries for each target. - - add_compiler_rt_object_libraries(RTSanitizerCommon - ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} - SOURCES ${SANITIZER_SOURCES} CFLAGS ${SANITIZER_CFLAGS} - DEFS ${SANITIZER_COMMON_DEFINITIONS}) - add_compiler_rt_object_libraries(RTSanitizerCommonLibc - ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} - SOURCES ${SANITIZER_LIBCDEP_SOURCES} CFLAGS ${SANITIZER_CFLAGS} - DEFS ${SANITIZER_COMMON_DEFINITIONS}) - foreach(arch ${SANITIZER_COMMON_SUPPORTED_ARCH}) - list(APPEND SANITIZER_RUNTIME_LIBRARIES RTSanitizerCommon.${arch} - RTSanitizerCommonLibc.${arch}) - endforeach() + set(OS_OPTION OS ${SANITIZER_COMMON_SUPPORTED_OS}) endif() -add_dependencies(compiler-rt sanitizer_common) +add_compiler_rt_object_libraries(RTSanitizerCommon + ${OS_OPTION} + ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} + SOURCES ${SANITIZER_SOURCES} + CFLAGS ${SANITIZER_CFLAGS} + DEFS ${SANITIZER_COMMON_DEFINITIONS}) +add_compiler_rt_object_libraries(RTSanitizerCommonNoLibc + ${OS_OPTION} + ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} + SOURCES ${SANITIZER_NOLIBC_SOURCES} + CFLAGS ${SANITIZER_CFLAGS} + DEFS ${SANITIZER_COMMON_DEFINITIONS}) +add_compiler_rt_object_libraries(RTSanitizerCommonLibc + ${OS_OPTION} + ARCHS ${SANITIZER_COMMON_SUPPORTED_ARCH} + SOURCES ${SANITIZER_LIBCDEP_SOURCES} + CFLAGS ${SANITIZER_CFLAGS} + DEFS ${SANITIZER_COMMON_DEFINITIONS}) # Unit tests for common sanitizer runtime. if(COMPILER_RT_INCLUDE_TESTS) diff --git a/lib/sanitizer_common/Makefile.mk b/lib/sanitizer_common/Makefile.mk index da83c2d6b3b7..5bb20d076e81 100644 --- a/lib/sanitizer_common/Makefile.mk +++ b/lib/sanitizer_common/Makefile.mk @@ -11,6 +11,8 @@ ModuleName := sanitizer_common SubDirs := Sources := $(foreach file,$(wildcard $(Dir)/*.cc),$(notdir $(file))) +NolibcSources := $(foreach file,$(wildcard $(Dir)/*_nolibc.cc),$(notdir $(file))) +Sources := $(filter-out $(NolibcSources),$(Sources)) ObjNames := $(Sources:%.cc=%.o) Implementation := Generic diff --git a/lib/sanitizer_common/sanitizer_addrhashmap.h b/lib/sanitizer_common/sanitizer_addrhashmap.h index acf4ff020939..e55fc4f95a9a 100644 --- a/lib/sanitizer_common/sanitizer_addrhashmap.h +++ b/lib/sanitizer_common/sanitizer_addrhashmap.h @@ -143,7 +143,7 @@ bool AddrHashMap<T, kSize>::Handle::created() const { template<typename T, uptr kSize> bool AddrHashMap<T, kSize>::Handle::exists() const { - return cell_ != 0; + return cell_ != nullptr; } template<typename T, uptr kSize> @@ -160,7 +160,7 @@ void AddrHashMap<T, kSize>::acquire(Handle *h) { h->created_ = false; h->addidx_ = -1U; h->bucket_ = b; - h->cell_ = 0; + h->cell_ = nullptr; // If we want to remove the element, we need exclusive access to the bucket, // so skip the lock-free phase. @@ -250,7 +250,7 @@ void AddrHashMap<T, kSize>::acquire(Handle *h) { } // Store in the add cells. - if (add == 0) { + if (!add) { // Allocate a new add array. const uptr kInitSize = 64; add = (AddBucket*)InternalAlloc(kInitSize); @@ -282,7 +282,7 @@ void AddrHashMap<T, kSize>::acquire(Handle *h) { template<typename T, uptr kSize> void AddrHashMap<T, kSize>::release(Handle *h) { - if (h->cell_ == 0) + if (!h->cell_) return; Bucket *b = h->bucket_; Cell *c = h->cell_; diff --git a/lib/sanitizer_common/sanitizer_allocator.cc b/lib/sanitizer_common/sanitizer_allocator.cc index 03b3e83153de..538e2db95d4e 100644 --- a/lib/sanitizer_common/sanitizer_allocator.cc +++ b/lib/sanitizer_common/sanitizer_allocator.cc @@ -11,6 +11,7 @@ // run-time libraries. // This allocator is used inside run-times. //===----------------------------------------------------------------------===// + #include "sanitizer_allocator.h" #include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" @@ -44,7 +45,7 @@ InternalAllocator *internal_allocator() { return 0; } -#else // SANITIZER_GO +#else // SANITIZER_GO static ALIGNED(64) char internal_alloc_placeholder[sizeof(InternalAllocator)]; static atomic_uint8_t internal_allocator_initialized; @@ -77,29 +78,29 @@ static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache) { } static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) { - if (cache == 0) { + if (!cache) { SpinMutexLock l(&internal_allocator_cache_mu); return internal_allocator()->Deallocate(&internal_allocator_cache, ptr); } internal_allocator()->Deallocate(cache, ptr); } -#endif // SANITIZER_GO +#endif // SANITIZER_GO const u64 kBlockMagic = 0x6A6CB03ABCEBC041ull; void *InternalAlloc(uptr size, InternalAllocatorCache *cache) { if (size + sizeof(u64) < size) - return 0; + return nullptr; void *p = RawInternalAlloc(size + sizeof(u64), cache); - if (p == 0) - return 0; + if (!p) + return nullptr; ((u64*)p)[0] = kBlockMagic; return (char*)p + sizeof(u64); } void InternalFree(void *addr, InternalAllocatorCache *cache) { - if (addr == 0) + if (!addr) return; addr = (char*)addr - sizeof(u64); CHECK_EQ(kBlockMagic, ((u64*)addr)[0]); @@ -147,4 +148,4 @@ void NORETURN ReportAllocatorCannotReturnNull() { Die(); } -} // namespace __sanitizer +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h index deaffef7150d..44d6fce3b291 100644 --- a/lib/sanitizer_common/sanitizer_allocator.h +++ b/lib/sanitizer_common/sanitizer_allocator.h @@ -347,7 +347,7 @@ class SizeClassAllocator64 { CHECK_LT(class_id, kNumClasses); RegionInfo *region = GetRegionInfo(class_id); Batch *b = region->free_list.Pop(); - if (b == 0) + if (!b) b = PopulateFreeList(stat, c, class_id, region); region->n_allocated += b->count; return b; @@ -371,16 +371,16 @@ class SizeClassAllocator64 { void *GetBlockBegin(const void *p) { uptr class_id = GetSizeClass(p); uptr size = SizeClassMap::Size(class_id); - if (!size) return 0; + if (!size) return nullptr; uptr chunk_idx = GetChunkIdx((uptr)p, size); uptr reg_beg = (uptr)p & ~(kRegionSize - 1); uptr beg = chunk_idx * size; uptr next_beg = beg + size; - if (class_id >= kNumClasses) return 0; + if (class_id >= kNumClasses) return nullptr; RegionInfo *region = GetRegionInfo(class_id); if (region->mapped_user >= next_beg) return reinterpret_cast<void*>(reg_beg + beg); - return 0; + return nullptr; } static uptr GetActuallyAllocatedSize(void *p) { @@ -609,6 +609,7 @@ class TwoLevelByteMap { internal_memset(map1_, 0, sizeof(map1_)); mu_.Init(); } + void TestOnlyUnmap() { for (uptr i = 0; i < kSize1; i++) { u8 *p = Get(i); @@ -822,6 +823,10 @@ class SizeClassAllocator32 { void PrintStats() { } + static uptr AdditionalSize() { + return 0; + } + typedef SizeClassMap SizeClassMapT; static const uptr kNumClasses = SizeClassMap::kNumClasses; @@ -868,9 +873,9 @@ class SizeClassAllocator32 { uptr reg = AllocateRegion(stat, class_id); uptr n_chunks = kRegionSize / (size + kMetadataSize); uptr max_count = SizeClassMap::MaxCached(class_id); - Batch *b = 0; + Batch *b = nullptr; for (uptr i = reg; i < reg + n_chunks * size; i += size) { - if (b == 0) { + if (!b) { if (SizeClassMap::SizeClassRequiresSeparateTransferBatch(class_id)) b = (Batch*)c->Allocate(this, SizeClassMap::ClassID(sizeof(Batch))); else @@ -881,7 +886,7 @@ class SizeClassAllocator32 { if (b->count == max_count) { CHECK_GT(b->count, 0); sci->free_list.push_back(b); - b = 0; + b = nullptr; } } if (b) { @@ -1061,7 +1066,7 @@ class LargeMmapAllocator { void *ReturnNullOrDie() { if (atomic_load(&may_return_null_, memory_order_acquire)) - return 0; + return nullptr; ReportAllocatorCannotReturnNull(); } @@ -1101,7 +1106,7 @@ class LargeMmapAllocator { } bool PointerIsMine(const void *p) { - return GetBlockBegin(p) != 0; + return GetBlockBegin(p) != nullptr; } uptr GetActuallyAllocatedSize(void *p) { @@ -1130,13 +1135,13 @@ class LargeMmapAllocator { nearest_chunk = ch; } if (!nearest_chunk) - return 0; + return nullptr; Header *h = reinterpret_cast<Header *>(nearest_chunk); CHECK_GE(nearest_chunk, h->map_beg); CHECK_LT(nearest_chunk, h->map_beg + h->map_size); CHECK_LE(nearest_chunk, p); if (h->map_beg + h->map_size <= p) - return 0; + return nullptr; return GetUser(h); } @@ -1146,7 +1151,7 @@ class LargeMmapAllocator { mutex_.CheckLocked(); uptr p = reinterpret_cast<uptr>(ptr); uptr n = n_chunks_; - if (!n) return 0; + if (!n) return nullptr; if (!chunks_sorted_) { // Do one-time sort. chunks_sorted_ is reset in Allocate/Deallocate. SortArray(reinterpret_cast<uptr*>(chunks_), n); @@ -1158,7 +1163,7 @@ class LargeMmapAllocator { chunks_[n - 1]->map_size; } if (p < min_mmap_ || p >= max_mmap_) - return 0; + return nullptr; uptr beg = 0, end = n - 1; // This loop is a log(n) lower_bound. It does not check for the exact match // to avoid expensive cache-thrashing loads. @@ -1179,7 +1184,7 @@ class LargeMmapAllocator { Header *h = chunks_[beg]; if (h->map_beg + h->map_size <= p || p < h->map_beg) - return 0; + return nullptr; return GetUser(h); } @@ -1308,7 +1313,7 @@ class CombinedAllocator { void *ReturnNullOrDie() { if (MayReturnNull()) - return 0; + return nullptr; ReportAllocatorCannotReturnNull(); } @@ -1340,7 +1345,7 @@ class CombinedAllocator { return Allocate(cache, new_size, alignment); if (!new_size) { Deallocate(cache, p); - return 0; + return nullptr; } CHECK(PointerIsMine(p)); uptr old_size = GetActuallyAllocatedSize(p); @@ -1445,7 +1450,6 @@ class CombinedAllocator { // Returns true if calloc(size, n) should return 0 due to overflow in size*n. bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n); -} // namespace __sanitizer - -#endif // SANITIZER_ALLOCATOR_H +} // namespace __sanitizer +#endif // SANITIZER_ALLOCATOR_H diff --git a/lib/sanitizer_common/sanitizer_allocator_internal.h b/lib/sanitizer_common/sanitizer_allocator_internal.h index 9b9cfd0b5931..3dcfccd7cba3 100644 --- a/lib/sanitizer_common/sanitizer_allocator_internal.h +++ b/lib/sanitizer_common/sanitizer_allocator_internal.h @@ -1,4 +1,4 @@ -//===-- sanitizer_allocator_internal.h -------------------------- C++ -----===// +//===-- sanitizer_allocator_internal.h --------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -45,19 +45,19 @@ typedef SizeClassAllocatorLocalCache<PrimaryInternalAllocator> typedef CombinedAllocator<PrimaryInternalAllocator, InternalAllocatorCache, LargeMmapAllocator<> > InternalAllocator; -void *InternalAlloc(uptr size, InternalAllocatorCache *cache = 0); -void InternalFree(void *p, InternalAllocatorCache *cache = 0); +void *InternalAlloc(uptr size, InternalAllocatorCache *cache = nullptr); +void InternalFree(void *p, InternalAllocatorCache *cache = nullptr); InternalAllocator *internal_allocator(); enum InternalAllocEnum { INTERNAL_ALLOC }; -} // namespace __sanitizer +} // namespace __sanitizer inline void *operator new(__sanitizer::operator_new_size_type size, InternalAllocEnum) { return InternalAlloc(size); } -#endif // SANITIZER_ALLOCATOR_INTERNAL_H +#endif // SANITIZER_ALLOCATOR_INTERNAL_H diff --git a/lib/sanitizer_common/sanitizer_asm.h b/lib/sanitizer_common/sanitizer_asm.h index 906012a96f11..47c2b12a2049 100644 --- a/lib/sanitizer_common/sanitizer_asm.h +++ b/lib/sanitizer_common/sanitizer_asm.h @@ -23,8 +23,11 @@ # define CFI_STARTPROC .cfi_startproc # define CFI_ENDPROC .cfi_endproc # define CFI_ADJUST_CFA_OFFSET(n) .cfi_adjust_cfa_offset n +# define CFI_DEF_CFA_OFFSET(n) .cfi_def_cfa_offset n # define CFI_REL_OFFSET(reg, n) .cfi_rel_offset reg, n +# define CFI_OFFSET(reg, n) .cfi_offset reg, n # define CFI_DEF_CFA_REGISTER(reg) .cfi_def_cfa_register reg +# define CFI_DEF_CFA(reg, n) .cfi_def_cfa reg, n # define CFI_RESTORE(reg) .cfi_restore reg #else // No CFI @@ -32,9 +35,24 @@ # define CFI_STARTPROC # define CFI_ENDPROC # define CFI_ADJUST_CFA_OFFSET(n) +# define CFI_DEF_CFA_OFFSET(n) # define CFI_REL_OFFSET(reg, n) +# define CFI_OFFSET(reg, n) # define CFI_DEF_CFA_REGISTER(reg) +# define CFI_DEF_CFA(reg, n) # define CFI_RESTORE(reg) #endif - +#if !defined(__APPLE__) +# define ASM_HIDDEN(symbol) .hidden symbol +# define ASM_TYPE_FUNCTION(symbol) .type symbol, @function +# define ASM_SIZE(symbol) .size symbol, .-symbol +# define ASM_TSAN_SYMBOL(symbol) symbol +# define ASM_TSAN_SYMBOL_INTERCEPTOR(symbol) symbol +#else +# define ASM_HIDDEN(symbol) +# define ASM_TYPE_FUNCTION(symbol) +# define ASM_SIZE(symbol) +# define ASM_TSAN_SYMBOL(symbol) _##symbol +# define ASM_TSAN_SYMBOL_INTERCEPTOR(symbol) _wrap_##symbol +#endif diff --git a/lib/sanitizer_common/sanitizer_atomic.h b/lib/sanitizer_common/sanitizer_atomic.h index 7e3374aadd0c..b26693e24f8d 100644 --- a/lib/sanitizer_common/sanitizer_atomic.h +++ b/lib/sanitizer_common/sanitizer_atomic.h @@ -63,4 +63,20 @@ struct atomic_uintptr_t { # error "Unsupported compiler" #endif +namespace __sanitizer { + +// Clutter-reducing helpers. + +template<typename T> +INLINE typename T::Type atomic_load_relaxed(const volatile T *a) { + return atomic_load(a, memory_order_relaxed); +} + +template<typename T> +INLINE void atomic_store_relaxed(volatile T *a, typename T::Type v) { + atomic_store(a, v, memory_order_relaxed); +} + +} // namespace __sanitizer + #endif // SANITIZER_ATOMIC_H diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc index d14e98824d99..9b41a3aa0af9 100644 --- a/lib/sanitizer_common/sanitizer_common.cc +++ b/lib/sanitizer_common/sanitizer_common.cc @@ -57,7 +57,7 @@ void ReportFile::ReopenIfNecessary() { CloseFile(fd); } - const char *exe_name = GetBinaryBasename(); + const char *exe_name = GetProcessName(); if (common_flags()->log_exe_name && exe_name) { internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix, exe_name, pid); @@ -105,24 +105,47 @@ uptr stoptheworld_tracer_pid = 0; // writing to the same log file. uptr stoptheworld_tracer_ppid = 0; -static DieCallbackType InternalDieCallback, UserDieCallback; -void SetDieCallback(DieCallbackType callback) { - InternalDieCallback = callback; +static const int kMaxNumOfInternalDieCallbacks = 5; +static DieCallbackType InternalDieCallbacks[kMaxNumOfInternalDieCallbacks]; + +bool AddDieCallback(DieCallbackType callback) { + for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) { + if (InternalDieCallbacks[i] == nullptr) { + InternalDieCallbacks[i] = callback; + return true; + } + } + return false; } -void SetUserDieCallback(DieCallbackType callback) { - UserDieCallback = callback; + +bool RemoveDieCallback(DieCallbackType callback) { + for (int i = 0; i < kMaxNumOfInternalDieCallbacks; i++) { + if (InternalDieCallbacks[i] == callback) { + internal_memmove(&InternalDieCallbacks[i], &InternalDieCallbacks[i + 1], + sizeof(InternalDieCallbacks[0]) * + (kMaxNumOfInternalDieCallbacks - i - 1)); + InternalDieCallbacks[kMaxNumOfInternalDieCallbacks - 1] = nullptr; + return true; + } + } + return false; } -DieCallbackType GetDieCallback() { - return InternalDieCallback; +static DieCallbackType UserDieCallback; +void SetUserDieCallback(DieCallbackType callback) { + UserDieCallback = callback; } void NORETURN Die() { if (UserDieCallback) UserDieCallback(); - if (InternalDieCallback) - InternalDieCallback(); - internal__exit(1); + for (int i = kMaxNumOfInternalDieCallbacks - 1; i >= 0; i--) { + if (InternalDieCallbacks[i]) + InternalDieCallbacks[i](); + } + if (common_flags()->abort_on_error) + Abort(); + internal__exit(common_flags()->exitcode); } static CheckFailedCallbackType CheckFailedCallback; @@ -140,40 +163,60 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond, Die(); } -uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, - uptr max_len, error_t *errno_p) { +void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type, + const char *mmap_type, error_t err, + bool raw_report) { + static int recursion_count; + if (raw_report || recursion_count) { + // If raw report is requested or we went into recursion, just die. + // The Report() and CHECK calls below may call mmap recursively and fail. + RawWrite("ERROR: Failed to mmap\n"); + Die(); + } + recursion_count++; + Report("ERROR: %s failed to " + "%s 0x%zx (%zd) bytes of %s (error code: %d)\n", + SanitizerToolName, mmap_type, size, size, mem_type, err); +#ifndef SANITIZER_GO + DumpProcessMap(); +#endif + UNREACHABLE("unable to mmap"); +} + +bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, + uptr *read_len, uptr max_len, error_t *errno_p) { uptr PageSize = GetPageSizeCached(); uptr kMinFileLen = PageSize; - uptr read_len = 0; - *buff = 0; + *buff = nullptr; *buff_size = 0; + *read_len = 0; // The files we usually open are not seekable, so try different buffer sizes. for (uptr size = kMinFileLen; size <= max_len; size *= 2) { fd_t fd = OpenFile(file_name, RdOnly, errno_p); - if (fd == kInvalidFd) return 0; + if (fd == kInvalidFd) return false; UnmapOrDie(*buff, *buff_size); *buff = (char*)MmapOrDie(size, __func__); *buff_size = size; + *read_len = 0; // Read up to one page at a time. - read_len = 0; bool reached_eof = false; - while (read_len + PageSize <= size) { + while (*read_len + PageSize <= size) { uptr just_read; - if (!ReadFromFile(fd, *buff + read_len, PageSize, &just_read, errno_p)) { + if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) { UnmapOrDie(*buff, *buff_size); - return 0; + return false; } if (just_read == 0) { reached_eof = true; break; } - read_len += just_read; + *read_len += just_read; } CloseFile(fd); if (reached_eof) // We've read the whole file. break; } - return read_len; + return true; } typedef bool UptrComparisonFunction(const uptr &a, const uptr &b); @@ -210,8 +253,8 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) { const char *StripPathPrefix(const char *filepath, const char *strip_path_prefix) { - if (filepath == 0) return 0; - if (strip_path_prefix == 0) return filepath; + if (!filepath) return nullptr; + if (!strip_path_prefix) return filepath; const char *res = filepath; if (const char *pos = internal_strstr(filepath, strip_path_prefix)) res = pos + internal_strlen(strip_path_prefix); @@ -221,8 +264,8 @@ const char *StripPathPrefix(const char *filepath, } const char *StripModuleName(const char *module) { - if (module == 0) - return 0; + if (!module) + return nullptr; if (SANITIZER_WINDOWS) { // On Windows, both slash and backslash are possible. // Pick the one that goes last. @@ -255,6 +298,40 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info) { } #endif +// Removes the ANSI escape sequences from the input string (in-place). +void RemoveANSIEscapeSequencesFromString(char *str) { + if (!str) + return; + + // We are going to remove the escape sequences in place. + char *s = str; + char *z = str; + while (*s != '\0') { + CHECK_GE(s, z); + // Skip over ANSI escape sequences with pointer 's'. + if (*s == '\033' && *(s + 1) == '[') { + s = internal_strchrnul(s, 'm'); + if (*s == '\0') { + break; + } + s++; + continue; + } + // 's' now points at a character we want to keep. Copy over the buffer + // content if the escape sequence has been perviously skipped andadvance + // both pointers. + if (s != z) + *z = *s; + + // If we have not seen an escape sequence, just advance both pointers. + z++; + s++; + } + + // Null terminate the string. + *z = '\0'; +} + void LoadedModule::set(const char *module_name, uptr base_address) { clear(); full_name_ = internal_strdup(module_name); @@ -303,7 +380,7 @@ void DecreaseTotalMmap(uptr size) { } bool TemplateMatch(const char *templ, const char *str) { - if (str == 0 || str[0] == 0) + if ((!str) || str[0] == 0) return false; bool start = false; if (templ && templ[0] == '^') { @@ -324,9 +401,9 @@ bool TemplateMatch(const char *templ, const char *str) { return false; char *tpos = (char*)internal_strchr(templ, '*'); char *tpos1 = (char*)internal_strchr(templ, '$'); - if (tpos == 0 || (tpos1 && tpos1 < tpos)) + if ((!tpos) || (tpos1 && tpos1 < tpos)) tpos = tpos1; - if (tpos != 0) + if (tpos) tpos[0] = 0; const char *str0 = str; const char *spos = internal_strstr(str, templ); @@ -334,7 +411,7 @@ bool TemplateMatch(const char *templ, const char *str) { templ = tpos; if (tpos) tpos[0] = tpos == tpos1 ? '$' : '*'; - if (spos == 0) + if (!spos) return false; if (start && spos != str0) return false; @@ -344,11 +421,52 @@ bool TemplateMatch(const char *templ, const char *str) { return true; } +static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':'; + +char *FindPathToBinary(const char *name) { + const char *path = GetEnv("PATH"); + if (!path) + return nullptr; + uptr name_len = internal_strlen(name); + InternalScopedBuffer<char> buffer(kMaxPathLength); + const char *beg = path; + while (true) { + const char *end = internal_strchrnul(beg, kPathSeparator); + uptr prefix_len = end - beg; + if (prefix_len + name_len + 2 <= kMaxPathLength) { + internal_memcpy(buffer.data(), beg, prefix_len); + buffer[prefix_len] = '/'; + internal_memcpy(&buffer[prefix_len + 1], name, name_len); + buffer[prefix_len + 1 + name_len] = '\0'; + if (FileExists(buffer.data())) + return internal_strdup(buffer.data()); + } + if (*end == '\0') break; + beg = end + 1; + } + return nullptr; +} + static char binary_name_cache_str[kMaxPathLength]; -static const char *binary_basename_cache_str; +static char process_name_cache_str[kMaxPathLength]; + +const char *GetProcessName() { + return process_name_cache_str; +} + +static uptr ReadProcessName(/*out*/ char *buf, uptr buf_len) { + ReadLongProcessName(buf, buf_len); + char *s = const_cast<char *>(StripModuleName(buf)); + uptr len = internal_strlen(s); + if (s != buf) { + internal_memmove(buf, s, len); + buf[len] = '\0'; + } + return len; +} -const char *GetBinaryBasename() { - return binary_basename_cache_str; +void UpdateProcessName() { + ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); } // Call once to make sure that binary_name_cache_str is initialized @@ -356,7 +474,7 @@ void CacheBinaryName() { if (binary_name_cache_str[0] != '\0') return; ReadBinaryName(binary_name_cache_str, sizeof(binary_name_cache_str)); - binary_basename_cache_str = StripModuleName(binary_name_cache_str); + ReadProcessName(process_name_cache_str, sizeof(process_name_cache_str)); } uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) { @@ -370,7 +488,7 @@ uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) { return name_len; } -} // namespace __sanitizer +} // namespace __sanitizer using namespace __sanitizer; // NOLINT @@ -387,4 +505,4 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_set_death_callback(void (*callback)(void)) { SetUserDieCallback(callback); } -} // extern "C" +} // extern "C" diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h index 2c5a8dbe1238..0585f6b15b87 100644 --- a/lib/sanitizer_common/sanitizer_common.h +++ b/lib/sanitizer_common/sanitizer_common.h @@ -49,6 +49,8 @@ static const uptr kMaxNumberOfModules = 1 << 14; const uptr kMaxThreadStackSize = 1 << 30; // 1Gb +static const uptr kErrorMessageBufferSize = 1 << 16; + // Denotes fake PC values that come from JIT/JAVA/etc. // For such PC values __tsan_symbolize_external() will be called. const u64 kExternalPCBit = 1ULL << 60; @@ -76,7 +78,10 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, uptr *tls_addr, uptr *tls_size); // Memory management -void *MmapOrDie(uptr size, const char *mem_type); +void *MmapOrDie(uptr size, const char *mem_type, bool raw_report = false); +INLINE void *MmapOrDieQuietly(uptr size, const char *mem_type) { + return MmapOrDie(size, mem_type, /*raw_report*/ true); +} void UnmapOrDie(void *addr, uptr size); void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name = nullptr); @@ -97,6 +102,8 @@ void DecreaseTotalMmap(uptr size); uptr GetRSS(); void NoHugePagesInRegion(uptr addr, uptr length); void DontDumpShadowMemory(uptr addr, uptr length); +// Check if the built VMA size matches the runtime one. +void CheckVMASize(); // InternalScopedBuffer can be used instead of large stack arrays to // keep frame size low. @@ -160,6 +167,7 @@ void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback); // IO void RawWrite(const char *buffer); bool ColorizeReports(); +void RemoveANSIEscapeSequencesFromString(char *buffer); void Printf(const char *format, ...); void Report(const char *format, ...); void SetPrintfAndReportCallback(void (*callback)(const char *)); @@ -224,14 +232,23 @@ bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p = nullptr); +// Scoped file handle closer. +struct FileCloser { + explicit FileCloser(fd_t fd) : fd(fd) {} + ~FileCloser() { CloseFile(fd); } + fd_t fd; +}; + bool SupportsColoredOutput(fd_t fd); // Opens the file 'file_name" and reads up to 'max_len' bytes. // The resulting buffer is mmaped and stored in '*buff'. -// The size of the mmaped region is stored in '*buff_size', -// Returns the number of read bytes or 0 if file can not be opened. -uptr ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, - uptr max_len, error_t *errno_p = nullptr); +// The size of the mmaped region is stored in '*buff_size'. +// The total number of read bytes is stored in '*read_len'. +// Returns true if file was successfully opened and read. +bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size, + uptr *read_len, uptr max_len = 1 << 26, + error_t *errno_p = nullptr); // Maps given file to virtual memory, and returns pointer to it // (or NULL if mapping fails). Stores the size of mmaped region // in '*buff_size'. @@ -249,7 +266,9 @@ const char *StripModuleName(const char *module); // OS uptr ReadBinaryName(/*out*/char *buf, uptr buf_len); uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len); -const char *GetBinaryBasename(); +uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len); +const char *GetProcessName(); +void UpdateProcessName(); void CacheBinaryName(); void DisableCoreDumperIfNecessary(); void DumpProcessMap(); @@ -295,6 +314,9 @@ void NORETURN Abort(); void NORETURN Die(); void NORETURN CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2); +void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type, + const char *mmap_type, error_t err, + bool raw_report = false); // Set the name of the current thread to 'name', return true on succees. // The name may be truncated to a system-dependent limit. @@ -306,9 +328,16 @@ bool SanitizerGetThreadName(char *name, int max_len); // Specific tools may override behavior of "Die" and "CheckFailed" functions // to do tool-specific job. typedef void (*DieCallbackType)(void); -void SetDieCallback(DieCallbackType); -void SetUserDieCallback(DieCallbackType); -DieCallbackType GetDieCallback(); + +// It's possible to add several callbacks that would be run when "Die" is +// called. The callbacks will be run in the opposite order. The tools are +// strongly recommended to setup all callbacks during initialization, when there +// is only a single thread. +bool AddDieCallback(DieCallbackType callback); +bool RemoveDieCallback(DieCallbackType callback); + +void SetUserDieCallback(DieCallbackType callback); + typedef void (*CheckFailedCallbackType)(const char *, int, const char *, u64, u64); void SetCheckFailedCallback(CheckFailedCallbackType callback); @@ -400,7 +429,7 @@ INLINE uptr RoundUpToPowerOfTwo(uptr size) { } INLINE uptr RoundUpTo(uptr size, uptr boundary) { - CHECK(IsPowerOfTwo(boundary)); + RAW_CHECK(IsPowerOfTwo(boundary)); return (size + boundary - 1) & ~(boundary - 1); } @@ -626,17 +655,34 @@ enum AndroidApiLevel { ANDROID_POST_LOLLIPOP = 23 }; -#if SANITIZER_ANDROID +void WriteToSyslog(const char *buffer); + +#if SANITIZER_MAC +void LogFullErrorReport(const char *buffer); +#else +INLINE void LogFullErrorReport(const char *buffer) {} +#endif + +#if SANITIZER_LINUX || SANITIZER_MAC +void WriteOneLineToSyslog(const char *s); +#else +INLINE void WriteOneLineToSyslog(const char *s) {} +#endif + +#if SANITIZER_LINUX // Initialize Android logging. Any writes before this are silently lost. void AndroidLogInit(); -void AndroidLogWrite(const char *buffer); -void GetExtraActivationFlags(char *buf, uptr size); +bool ShouldLogAfterPrintf(); +#else +INLINE void AndroidLogInit() {} +INLINE bool ShouldLogAfterPrintf() { return false; } +#endif + +#if SANITIZER_ANDROID void SanitizerInitializeUnwinder(); AndroidApiLevel AndroidGetApiLevel(); #else -INLINE void AndroidLogInit() {} INLINE void AndroidLogWrite(const char *buffer_unused) {} -INLINE void GetExtraActivationFlags(char *buf, uptr size) { *buf = '\0'; } INLINE void SanitizerInitializeUnwinder() {} INLINE AndroidApiLevel AndroidGetApiLevel() { return ANDROID_NOT_ANDROID; } #endif @@ -685,6 +731,9 @@ struct SignalContext { void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp); +void DisableReexec(); +void MaybeReexec(); + } // namespace __sanitizer inline void *operator new(__sanitizer::operator_new_size_type size, diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc index a7772b7394a5..4639ddc92c6c 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -31,6 +31,7 @@ // COMMON_INTERCEPTOR_HANDLE_RECVMSG // COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED //===----------------------------------------------------------------------===// + #include "interception/interception.h" #include "sanitizer_addrhashmap.h" #include "sanitizer_placement_new.h" @@ -39,6 +40,22 @@ #include <stdarg.h> +#if SANITIZER_INTERCEPTOR_HOOKS +#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) \ + do { \ + if (f) \ + f(__VA_ARGS__); \ + } while (false); +#define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \ + extern "C" { \ + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void f(__VA_ARGS__); \ + } // extern "C" +#else +#define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) +#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) + +#endif // SANITIZER_INTERCEPTOR_HOOKS + #if SANITIZER_WINDOWS && !defined(va_copy) #define va_copy(dst, src) ((dst) = (src)) #endif // _WIN32 @@ -118,6 +135,14 @@ #define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) *begin = *end = 0; #endif +#ifndef COMMON_INTERCEPTOR_ACQUIRE +#define COMMON_INTERCEPTOR_ACQUIRE(ctx, u) {} +#endif + +#ifndef COMMON_INTERCEPTOR_RELEASE +#define COMMON_INTERCEPTOR_RELEASE(ctx, u) {} +#endif + struct FileMetadata { // For open_memstream(). char **addr; @@ -188,9 +213,14 @@ static inline int CharCmpX(unsigned char c1, unsigned char c2) { return (c1 == c2) ? 0 : (c1 < c2) ? -1 : 1; } +DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, uptr called_pc, + const char *s1, const char *s2) + INTERCEPTOR(int, strcmp, const char *s1, const char *s2) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, strcmp, s1, s2); + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strcmp, GET_CALLER_PC(), s1, + s2); unsigned char c1, c2; uptr i; for (i = 0;; i++) { @@ -203,11 +233,16 @@ INTERCEPTOR(int, strcmp, const char *s1, const char *s2) { return CharCmpX(c1, c2); } +DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, uptr called_pc, + const char *s1, const char *s2, uptr n) + INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) { if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) return internal_strncmp(s1, s2, size); void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, strncmp, s1, s2, size); + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, GET_CALLER_PC(), s1, + s2, size); unsigned char c1 = 0, c2 = 0; uptr i; for (i = 0; i < size; i++) { @@ -362,8 +397,52 @@ INTERCEPTOR(char *, strpbrk, const char *s1, const char *s2) { #define INIT_STRPBRK #endif +#if SANITIZER_INTERCEPT_MEMCMP + +DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, uptr called_pc, + const void *s1, const void *s2, uptr n) + +INTERCEPTOR(int, memcmp, const void *a1, const void *a2, uptr size) { + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_memcmp(a1, a2, size); + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, memcmp, a1, a2, size); + CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memcmp, GET_CALLER_PC(), a1, + a2, size); + if (common_flags()->intercept_memcmp) { + if (common_flags()->strict_memcmp) { + // Check the entire regions even if the first bytes of the buffers are + // different. + COMMON_INTERCEPTOR_READ_RANGE(ctx, a1, size); + COMMON_INTERCEPTOR_READ_RANGE(ctx, a2, size); + // Fallthrough to REAL(memcmp) below. + } else { + unsigned char c1 = 0, c2 = 0; + const unsigned char *s1 = (const unsigned char*)a1; + const unsigned char *s2 = (const unsigned char*)a2; + uptr i; + for (i = 0; i < size; i++) { + c1 = s1[i]; + c2 = s2[i]; + if (c1 != c2) break; + } + COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, size)); + COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, size)); + return CharCmpX(c1, c2); + } + } + return REAL(memcmp(a1, a2, size)); +} + +#define INIT_MEMCMP COMMON_INTERCEPT_FUNCTION(memcmp) +#else +#define INIT_MEMCMP +#endif + #if SANITIZER_INTERCEPT_MEMCHR INTERCEPTOR(void*, memchr, const void *s, int c, SIZE_T n) { + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_memchr(s, c, n); void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, memchr, s, c, n); void *res = REAL(memchr)(s, c, n); @@ -411,7 +490,7 @@ INTERCEPTOR(float, frexpf, float x, int *exp) { COMMON_INTERCEPTOR_ENTER(ctx, frexpf, x, exp); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. float res = REAL(frexpf)(x, exp); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp)); return res; @@ -422,7 +501,7 @@ INTERCEPTOR(long double, frexpl, long double x, int *exp) { COMMON_INTERCEPTOR_ENTER(ctx, frexpl, x, exp); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. long double res = REAL(frexpl)(x, exp); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp)); return res; @@ -463,7 +542,7 @@ INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) { COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SSIZE_T res = REAL(read)(fd, ptr, count); if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res); if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); @@ -481,7 +560,7 @@ INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) { COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SSIZE_T res = REAL(pread)(fd, ptr, count, offset); if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res); if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); @@ -499,7 +578,7 @@ INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) { COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SSIZE_T res = REAL(pread64)(fd, ptr, count, offset); if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res); if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); @@ -746,7 +825,7 @@ INTERCEPTOR(char *, ctime, unsigned long *timep) { COMMON_INTERCEPTOR_ENTER(ctx, ctime, timep); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. char *res = REAL(ctime)(timep); if (res) { COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); @@ -759,7 +838,7 @@ INTERCEPTOR(char *, ctime_r, unsigned long *timep, char *result) { COMMON_INTERCEPTOR_ENTER(ctx, ctime_r, timep, result); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. char *res = REAL(ctime_r)(timep, result); if (res) { COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); @@ -772,7 +851,7 @@ INTERCEPTOR(char *, asctime, __sanitizer_tm *tm) { COMMON_INTERCEPTOR_ENTER(ctx, asctime, tm); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. char *res = REAL(asctime)(tm); if (res) { COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm)); @@ -785,7 +864,7 @@ INTERCEPTOR(char *, asctime_r, __sanitizer_tm *tm, char *result) { COMMON_INTERCEPTOR_ENTER(ctx, asctime_r, tm, result); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. char *res = REAL(asctime_r)(tm, result); if (res) { COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm)); @@ -829,7 +908,7 @@ INTERCEPTOR(char *, strptime, char *s, char *format, __sanitizer_tm *tm) { COMMON_INTERCEPTOR_READ_RANGE(ctx, format, REAL(strlen)(format) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. char *res = REAL(strptime)(s, format, tm); COMMON_INTERCEPTOR_READ_STRING(ctx, s, res ? res - s : 0); if (res && tm) { @@ -966,7 +1045,7 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format) // FIXME: under ASan the REAL() call below may write to freed memory and // corrupt its metadata. See -// https://code.google.com/p/address-sanitizer/issues/detail?id=321. +// https://github.com/google/sanitizers/issues/321. #define VSPRINTF_INTERCEPTOR_IMPL(vname, str, ...) \ { \ VPRINTF_INTERCEPTOR_ENTER(vname, str, __VA_ARGS__) \ @@ -983,7 +1062,7 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format) // FIXME: under ASan the REAL() call below may write to freed memory and // corrupt its metadata. See -// https://code.google.com/p/address-sanitizer/issues/detail?id=321. +// https://github.com/google/sanitizers/issues/321. #define VSNPRINTF_INTERCEPTOR_IMPL(vname, str, size, ...) \ { \ VPRINTF_INTERCEPTOR_ENTER(vname, str, size, __VA_ARGS__) \ @@ -1000,7 +1079,7 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format) // FIXME: under ASan the REAL() call below may write to freed memory and // corrupt its metadata. See -// https://code.google.com/p/address-sanitizer/issues/detail?id=321. +// https://github.com/google/sanitizers/issues/321. #define VASPRINTF_INTERCEPTOR_IMPL(vname, strp, ...) \ { \ VPRINTF_INTERCEPTOR_ENTER(vname, strp, __VA_ARGS__) \ @@ -1243,14 +1322,14 @@ INTERCEPTOR(__sanitizer_passwd *, getpwnam, const char *name) { COMMON_INTERCEPTOR_ENTER(ctx, getpwnam, name); COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); __sanitizer_passwd *res = REAL(getpwnam)(name); - if (res != 0) unpoison_passwd(ctx, res); + if (res) unpoison_passwd(ctx, res); return res; } INTERCEPTOR(__sanitizer_passwd *, getpwuid, u32 uid) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getpwuid, uid); __sanitizer_passwd *res = REAL(getpwuid)(uid); - if (res != 0) unpoison_passwd(ctx, res); + if (res) unpoison_passwd(ctx, res); return res; } INTERCEPTOR(__sanitizer_group *, getgrnam, const char *name) { @@ -1258,14 +1337,14 @@ INTERCEPTOR(__sanitizer_group *, getgrnam, const char *name) { COMMON_INTERCEPTOR_ENTER(ctx, getgrnam, name); COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); __sanitizer_group *res = REAL(getgrnam)(name); - if (res != 0) unpoison_group(ctx, res); + if (res) unpoison_group(ctx, res); return res; } INTERCEPTOR(__sanitizer_group *, getgrgid, u32 gid) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getgrgid, gid); __sanitizer_group *res = REAL(getgrgid)(gid); - if (res != 0) unpoison_group(ctx, res); + if (res) unpoison_group(ctx, res); return res; } #define INIT_GETPWNAM_AND_FRIENDS \ @@ -1285,7 +1364,7 @@ INTERCEPTOR(int, getpwnam_r, const char *name, __sanitizer_passwd *pwd, COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(getpwnam_r)(name, pwd, buf, buflen, result); if (!res) { if (result && *result) unpoison_passwd(ctx, *result); @@ -1300,7 +1379,7 @@ INTERCEPTOR(int, getpwuid_r, u32 uid, __sanitizer_passwd *pwd, char *buf, COMMON_INTERCEPTOR_ENTER(ctx, getpwuid_r, uid, pwd, buf, buflen, result); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result); if (!res) { if (result && *result) unpoison_passwd(ctx, *result); @@ -1316,7 +1395,7 @@ INTERCEPTOR(int, getgrnam_r, const char *name, __sanitizer_group *grp, COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(getgrnam_r)(name, grp, buf, buflen, result); if (!res) { if (result && *result) unpoison_group(ctx, *result); @@ -1331,7 +1410,7 @@ INTERCEPTOR(int, getgrgid_r, u32 gid, __sanitizer_group *grp, char *buf, COMMON_INTERCEPTOR_ENTER(ctx, getgrgid_r, gid, grp, buf, buflen, result); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(getgrgid_r)(gid, grp, buf, buflen, result); if (!res) { if (result && *result) unpoison_group(ctx, *result); @@ -1354,14 +1433,14 @@ INTERCEPTOR(__sanitizer_passwd *, getpwent, int dummy) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getpwent, dummy); __sanitizer_passwd *res = REAL(getpwent)(dummy); - if (res != 0) unpoison_passwd(ctx, res); + if (res) unpoison_passwd(ctx, res); return res; } INTERCEPTOR(__sanitizer_group *, getgrent, int dummy) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getgrent, dummy); __sanitizer_group *res = REAL(getgrent)(dummy); - if (res != 0) unpoison_group(ctx, res);; + if (res) unpoison_group(ctx, res);; return res; } #define INIT_GETPWENT \ @@ -1376,14 +1455,14 @@ INTERCEPTOR(__sanitizer_passwd *, fgetpwent, void *fp) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent, fp); __sanitizer_passwd *res = REAL(fgetpwent)(fp); - if (res != 0) unpoison_passwd(ctx, res); + if (res) unpoison_passwd(ctx, res); return res; } INTERCEPTOR(__sanitizer_group *, fgetgrent, void *fp) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent, fp); __sanitizer_group *res = REAL(fgetgrent)(fp); - if (res != 0) unpoison_group(ctx, res); + if (res) unpoison_group(ctx, res); return res; } #define INIT_FGETPWENT \ @@ -1400,7 +1479,7 @@ INTERCEPTOR(int, getpwent_r, __sanitizer_passwd *pwbuf, char *buf, COMMON_INTERCEPTOR_ENTER(ctx, getpwent_r, pwbuf, buf, buflen, pwbufp); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(getpwent_r)(pwbuf, buf, buflen, pwbufp); if (!res) { if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp); @@ -1415,7 +1494,7 @@ INTERCEPTOR(int, fgetpwent_r, void *fp, __sanitizer_passwd *pwbuf, char *buf, COMMON_INTERCEPTOR_ENTER(ctx, fgetpwent_r, fp, pwbuf, buf, buflen, pwbufp); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(fgetpwent_r)(fp, pwbuf, buf, buflen, pwbufp); if (!res) { if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp); @@ -1430,7 +1509,7 @@ INTERCEPTOR(int, getgrent_r, __sanitizer_group *pwbuf, char *buf, SIZE_T buflen, COMMON_INTERCEPTOR_ENTER(ctx, getgrent_r, pwbuf, buf, buflen, pwbufp); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(getgrent_r)(pwbuf, buf, buflen, pwbufp); if (!res) { if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp); @@ -1445,7 +1524,7 @@ INTERCEPTOR(int, fgetgrent_r, void *fp, __sanitizer_group *pwbuf, char *buf, COMMON_INTERCEPTOR_ENTER(ctx, fgetgrent_r, fp, pwbuf, buf, buflen, pwbufp); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(fgetgrent_r)(fp, pwbuf, buf, buflen, pwbufp); if (!res) { if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp); @@ -1502,7 +1581,7 @@ INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) { COMMON_INTERCEPTOR_ENTER(ctx, clock_getres, clk_id, tp); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(clock_getres)(clk_id, tp); if (!res && tp) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz); @@ -1514,7 +1593,7 @@ INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) { COMMON_INTERCEPTOR_ENTER(ctx, clock_gettime, clk_id, tp); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(clock_gettime)(clk_id, tp); if (!res) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz); @@ -1541,7 +1620,7 @@ INTERCEPTOR(int, getitimer, int which, void *curr_value) { COMMON_INTERCEPTOR_ENTER(ctx, getitimer, which, curr_value); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(getitimer)(which, curr_value); if (!res && curr_value) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerval_sz); @@ -1555,7 +1634,7 @@ INTERCEPTOR(int, setitimer, int which, const void *new_value, void *old_value) { COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerval_sz); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(setitimer)(which, new_value, old_value); if (!res && old_value) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerval_sz); @@ -1612,16 +1691,19 @@ static int wrapped_gl_stat(const char *s, void *st) { return pglob_copy->gl_stat(s, st); } +static const __sanitizer_glob_t kGlobCopy = { + 0, 0, 0, + 0, wrapped_gl_closedir, wrapped_gl_readdir, + wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat}; + INTERCEPTOR(int, glob, const char *pattern, int flags, int (*errfunc)(const char *epath, int eerrno), __sanitizer_glob_t *pglob) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob); COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0); - __sanitizer_glob_t glob_copy = { - 0, 0, 0, - 0, wrapped_gl_closedir, wrapped_gl_readdir, - wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat}; + __sanitizer_glob_t glob_copy; + internal_memcpy(&glob_copy, &kGlobCopy, sizeof(glob_copy)); if (flags & glob_altdirfunc) { Swap(pglob->gl_closedir, glob_copy.gl_closedir); Swap(pglob->gl_readdir, glob_copy.gl_readdir); @@ -1649,10 +1731,8 @@ INTERCEPTOR(int, glob64, const char *pattern, int flags, void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, glob64, pattern, flags, errfunc, pglob); COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0); - __sanitizer_glob_t glob_copy = { - 0, 0, 0, - 0, wrapped_gl_closedir, wrapped_gl_readdir, - wrapped_gl_opendir, wrapped_gl_lstat, wrapped_gl_stat}; + __sanitizer_glob_t glob_copy; + internal_memcpy(&glob_copy, &kGlobCopy, sizeof(glob_copy)); if (flags & glob_altdirfunc) { Swap(pglob->gl_closedir, glob_copy.gl_closedir); Swap(pglob->gl_readdir, glob_copy.gl_readdir); @@ -1689,7 +1769,7 @@ INTERCEPTOR_WITH_SUFFIX(int, wait, int *status) { COMMON_INTERCEPTOR_ENTER(ctx, wait, status); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(wait)(status); if (res != -1 && status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); @@ -1707,7 +1787,7 @@ INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop, COMMON_INTERCEPTOR_ENTER(ctx, waitid, idtype, id, infop, options); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(waitid)(idtype, id, infop, options); if (res != -1 && infop) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, infop, siginfo_t_sz); @@ -1718,7 +1798,7 @@ INTERCEPTOR_WITH_SUFFIX(int, waitpid, int pid, int *status, int options) { COMMON_INTERCEPTOR_ENTER(ctx, waitpid, pid, status, options); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(waitpid)(pid, status, options); if (res != -1 && status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); @@ -1729,7 +1809,7 @@ INTERCEPTOR(int, wait3, int *status, int options, void *rusage) { COMMON_INTERCEPTOR_ENTER(ctx, wait3, status, options, rusage); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(wait3)(status, options, rusage); if (res != -1) { if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); @@ -1743,7 +1823,7 @@ INTERCEPTOR(int, __wait4, int pid, int *status, int options, void *rusage) { COMMON_INTERCEPTOR_ENTER(ctx, __wait4, pid, status, options, rusage); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(__wait4)(pid, status, options, rusage); if (res != -1) { if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); @@ -1758,7 +1838,7 @@ INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) { COMMON_INTERCEPTOR_ENTER(ctx, wait4, pid, status, options, rusage); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(wait4)(pid, status, options, rusage); if (res != -1) { if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); @@ -1787,7 +1867,7 @@ INTERCEPTOR(char *, inet_ntop, int af, const void *src, char *dst, u32 size) { // FIXME: figure out read size based on the address family. // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. char *res = REAL(inet_ntop)(af, src, dst, size); if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); return res; @@ -1799,7 +1879,7 @@ INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) { // FIXME: figure out read size based on the address family. // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(inet_pton)(af, src, dst); if (res == 1) { uptr sz = __sanitizer_in_addr_sz(af); @@ -1821,7 +1901,7 @@ INTERCEPTOR(int, inet_aton, const char *cp, void *dst) { if (cp) COMMON_INTERCEPTOR_READ_RANGE(ctx, cp, REAL(strlen)(cp) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(inet_aton)(cp, dst); if (res != 0) { uptr sz = __sanitizer_in_addr_sz(af_inet); @@ -1840,7 +1920,7 @@ INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) { COMMON_INTERCEPTOR_ENTER(ctx, pthread_getschedparam, thread, policy, param); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(pthread_getschedparam)(thread, policy, param); if (res == 0) { if (policy) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, policy, sizeof(*policy)); @@ -1867,7 +1947,7 @@ INTERCEPTOR(int, getaddrinfo, char *node, char *service, COMMON_INTERCEPTOR_READ_RANGE(ctx, hints, sizeof(__sanitizer_addrinfo)); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(getaddrinfo)(node, service, hints, out); if (res == 0 && out) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, out, sizeof(*out)); @@ -1899,7 +1979,7 @@ INTERCEPTOR(int, getnameinfo, void *sockaddr, unsigned salen, char *host, // There is padding in in_addr that may make this too noisy // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(getnameinfo)(sockaddr, salen, host, hostlen, serv, servlen, flags); if (res == 0) { @@ -1923,7 +2003,7 @@ INTERCEPTOR(int, getsockname, int sock_fd, void *addr, int *addrlen) { int addrlen_in = *addrlen; // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(getsockname)(sock_fd, addr, addrlen); if (res == 0) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addrlen_in, *addrlen)); @@ -2009,7 +2089,7 @@ INTERCEPTOR(int, gethostbyname_r, char *name, struct __sanitizer_hostent *ret, h_errnop); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(gethostbyname_r)(name, ret, buf, buflen, result, h_errnop); if (result) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); @@ -2032,7 +2112,7 @@ INTERCEPTOR(int, gethostent_r, struct __sanitizer_hostent *ret, char *buf, h_errnop); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(gethostent_r)(ret, buf, buflen, result, h_errnop); if (result) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); @@ -2058,7 +2138,7 @@ INTERCEPTOR(int, gethostbyaddr_r, void *addr, int len, int type, COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, len); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(gethostbyaddr_r)(addr, len, type, ret, buf, buflen, result, h_errnop); if (result) { @@ -2084,7 +2164,7 @@ INTERCEPTOR(int, gethostbyname2_r, char *name, int af, result, h_errnop); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(gethostbyname2_r)(name, af, ret, buf, buflen, result, h_errnop); if (result) { @@ -2110,7 +2190,7 @@ INTERCEPTOR(int, getsockopt, int sockfd, int level, int optname, void *optval, if (optlen) COMMON_INTERCEPTOR_READ_RANGE(ctx, optlen, sizeof(*optlen)); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(getsockopt)(sockfd, level, optname, optval, optlen); if (res == 0) if (optval && optlen) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, optval, *optlen); @@ -2154,7 +2234,7 @@ INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) { } // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int fd2 = REAL(accept4)(fd, addr, addrlen, f); if (fd2 >= 0) { if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2); @@ -2174,7 +2254,7 @@ INTERCEPTOR(double, modf, double x, double *iptr) { COMMON_INTERCEPTOR_ENTER(ctx, modf, x, iptr); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. double res = REAL(modf)(x, iptr); if (iptr) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr)); @@ -2186,7 +2266,7 @@ INTERCEPTOR(float, modff, float x, float *iptr) { COMMON_INTERCEPTOR_ENTER(ctx, modff, x, iptr); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. float res = REAL(modff)(x, iptr); if (iptr) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr)); @@ -2198,7 +2278,7 @@ INTERCEPTOR(long double, modfl, long double x, long double *iptr) { COMMON_INTERCEPTOR_ENTER(ctx, modfl, x, iptr); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. long double res = REAL(modfl)(x, iptr); if (iptr) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr)); @@ -2233,7 +2313,7 @@ INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg, COMMON_INTERCEPTOR_ENTER(ctx, recvmsg, fd, msg, flags); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SSIZE_T res = REAL(recvmsg)(fd, msg, flags); if (res >= 0) { if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); @@ -2257,7 +2337,7 @@ INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) { if (addrlen) addr_sz = *addrlen; // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(getpeername)(sockfd, addr, addrlen); if (!res && addr && addrlen) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addr_sz, *addrlen)); @@ -2273,7 +2353,7 @@ INTERCEPTOR(int, sysinfo, void *info) { void *ctx; // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. COMMON_INTERCEPTOR_ENTER(ctx, sysinfo, info); int res = REAL(sysinfo)(info); if (!res && info) @@ -2291,7 +2371,7 @@ INTERCEPTOR(__sanitizer_dirent *, opendir, const char *path) { COMMON_INTERCEPTOR_ENTER(ctx, opendir, path); COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); __sanitizer_dirent *res = REAL(opendir)(path); - if (res != 0) + if (res) COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path); return res; } @@ -2301,7 +2381,7 @@ INTERCEPTOR(__sanitizer_dirent *, readdir, void *dirp) { COMMON_INTERCEPTOR_ENTER(ctx, readdir, dirp); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. __sanitizer_dirent *res = REAL(readdir)(dirp); if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen); return res; @@ -2313,7 +2393,7 @@ INTERCEPTOR(int, readdir_r, void *dirp, __sanitizer_dirent *entry, COMMON_INTERCEPTOR_ENTER(ctx, readdir_r, dirp, entry, result); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(readdir_r)(dirp, entry, result); if (!res) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); @@ -2337,7 +2417,7 @@ INTERCEPTOR(__sanitizer_dirent64 *, readdir64, void *dirp) { COMMON_INTERCEPTOR_ENTER(ctx, readdir64, dirp); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. __sanitizer_dirent64 *res = REAL(readdir64)(dirp); if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen); return res; @@ -2349,7 +2429,7 @@ INTERCEPTOR(int, readdir64_r, void *dirp, __sanitizer_dirent64 *entry, COMMON_INTERCEPTOR_ENTER(ctx, readdir64_r, dirp, entry, result); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(readdir64_r)(dirp, entry, result); if (!res) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); @@ -2369,6 +2449,7 @@ INTERCEPTOR(int, readdir64_r, void *dirp, __sanitizer_dirent64 *entry, INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, ptrace, request, pid, addr, data); + __sanitizer_iovec local_iovec; if (data) { if (request == ptrace_setregs) @@ -2377,17 +2458,25 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) { COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpregs_struct_sz); else if (request == ptrace_setfpxregs) COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpxregs_struct_sz); + else if (request == ptrace_setvfpregs) + COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_vfpregs_struct_sz); else if (request == ptrace_setsiginfo) COMMON_INTERCEPTOR_READ_RANGE(ctx, data, siginfo_t_sz); - else if (request == ptrace_setregset) { - __sanitizer_iovec *iov = (__sanitizer_iovec *)data; - COMMON_INTERCEPTOR_READ_RANGE(ctx, iov->iov_base, iov->iov_len); + // Some kernel might zero the iovec::iov_base in case of invalid + // write access. In this case copy the invalid address for further + // inspection. + else if (request == ptrace_setregset || request == ptrace_getregset) { + __sanitizer_iovec *iovec = (__sanitizer_iovec*)data; + COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec)); + local_iovec = *iovec; + if (request == ptrace_setregset) + COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec->iov_base, iovec->iov_len); } } // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. uptr res = REAL(ptrace)(request, pid, addr, data); if (!res && data) { @@ -2399,13 +2488,17 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpregs_struct_sz); else if (request == ptrace_getfpxregs) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_struct_sz); + else if (request == ptrace_getvfpregs) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_vfpregs_struct_sz); else if (request == ptrace_getsiginfo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, siginfo_t_sz); else if (request == ptrace_geteventmsg) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(unsigned long)); else if (request == ptrace_getregset) { - __sanitizer_iovec *iov = (__sanitizer_iovec *)data; - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iov->iov_base, iov->iov_len); + __sanitizer_iovec *iovec = (__sanitizer_iovec*)data; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec, sizeof(*iovec)); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, local_iovec.iov_base, + local_iovec.iov_len); } } return res; @@ -2438,7 +2531,7 @@ INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) { COMMON_INTERCEPTOR_ENTER(ctx, getcwd, buf, size); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. char *res = REAL(getcwd)(buf, size); if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); return res; @@ -2454,7 +2547,7 @@ INTERCEPTOR(char *, get_current_dir_name, int fake) { COMMON_INTERCEPTOR_ENTER(ctx, get_current_dir_name, fake); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. char *res = REAL(get_current_dir_name)(fake); if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); return res; @@ -2481,7 +2574,7 @@ UNUSED static inline void FixRealStrtolEndptr(const char *nptr, char **endptr) { UNUSED static inline void StrtolFixAndCheck(void *ctx, const char *nptr, char **endptr, char *real_endptr, int base) { - if (endptr != 0) { + if (endptr) { *endptr = real_endptr; COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr)); } @@ -2503,7 +2596,7 @@ INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) { COMMON_INTERCEPTOR_ENTER(ctx, strtoimax, nptr, endptr, base); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. char *real_endptr; INTMAX_T res = REAL(strtoimax)(nptr, &real_endptr, base); StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); @@ -2515,7 +2608,7 @@ INTERCEPTOR(INTMAX_T, strtoumax, const char *nptr, char **endptr, int base) { COMMON_INTERCEPTOR_ENTER(ctx, strtoumax, nptr, endptr, base); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. char *real_endptr; INTMAX_T res = REAL(strtoumax)(nptr, &real_endptr, base); StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base); @@ -2535,7 +2628,7 @@ INTERCEPTOR(SIZE_T, mbstowcs, wchar_t *dest, const char *src, SIZE_T len) { COMMON_INTERCEPTOR_ENTER(ctx, mbstowcs, dest, src, len); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SIZE_T res = REAL(mbstowcs)(dest, src, len); if (res != (SIZE_T) - 1 && dest) { SIZE_T write_cnt = res + (res < len); @@ -2552,7 +2645,7 @@ INTERCEPTOR(SIZE_T, mbsrtowcs, wchar_t *dest, const char **src, SIZE_T len, if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SIZE_T res = REAL(mbsrtowcs)(dest, src, len, ps); if (res != (SIZE_T)(-1) && dest && src) { // This function, and several others, may or may not write the terminating @@ -2582,7 +2675,7 @@ INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms, if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SIZE_T res = REAL(mbsnrtowcs)(dest, src, nms, len, ps); if (res != (SIZE_T)(-1) && dest && src) { SIZE_T write_cnt = res + !*src; @@ -2602,7 +2695,7 @@ INTERCEPTOR(SIZE_T, wcstombs, char *dest, const wchar_t *src, SIZE_T len) { COMMON_INTERCEPTOR_ENTER(ctx, wcstombs, dest, src, len); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SIZE_T res = REAL(wcstombs)(dest, src, len); if (res != (SIZE_T) - 1 && dest) { SIZE_T write_cnt = res + (res < len); @@ -2619,7 +2712,7 @@ INTERCEPTOR(SIZE_T, wcsrtombs, char *dest, const wchar_t **src, SIZE_T len, if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SIZE_T res = REAL(wcsrtombs)(dest, src, len, ps); if (res != (SIZE_T) - 1 && dest && src) { SIZE_T write_cnt = res + !*src; @@ -2647,9 +2740,9 @@ INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms, if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SIZE_T res = REAL(wcsnrtombs)(dest, src, nms, len, ps); - if (res != (SIZE_T) - 1 && dest && src) { + if (res != ((SIZE_T)-1) && dest && src) { SIZE_T write_cnt = res + !*src; COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt); } @@ -2661,13 +2754,35 @@ INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms, #define INIT_WCSNRTOMBS #endif + +#if SANITIZER_INTERCEPT_WCRTOMB +INTERCEPTOR(SIZE_T, wcrtomb, char *dest, wchar_t src, void *ps) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, wcrtomb, dest, src, ps); + if (ps) COMMON_INTERCEPTOR_READ_RANGE(ctx, ps, mbstate_t_sz); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + SIZE_T res = REAL(wcrtomb)(dest, src, ps); + if (res != ((SIZE_T)-1) && dest) { + SIZE_T write_cnt = res; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dest, write_cnt); + } + return res; +} + +#define INIT_WCRTOMB COMMON_INTERCEPT_FUNCTION(wcrtomb); +#else +#define INIT_WCRTOMB +#endif + #if SANITIZER_INTERCEPT_TCGETATTR INTERCEPTOR(int, tcgetattr, int fd, void *termios_p) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, tcgetattr, fd, termios_p); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(tcgetattr)(fd, termios_p); if (!res && termios_p) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, termios_p, struct_termios_sz); @@ -2689,7 +2804,7 @@ INTERCEPTOR(char *, realpath, const char *path, char *resolved_path) { // version of a versioned symbol. For realpath(), this gives us something // (called __old_realpath) that does not handle NULL in the second argument. // Handle it as part of the interceptor. - char *allocated_path = 0; + char *allocated_path = nullptr; if (!resolved_path) allocated_path = resolved_path = (char *)WRAP(malloc)(path_max + 1); @@ -2724,7 +2839,7 @@ INTERCEPTOR(SIZE_T, confstr, int name, char *buf, SIZE_T len) { COMMON_INTERCEPTOR_ENTER(ctx, confstr, name, buf, len); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SIZE_T res = REAL(confstr)(name, buf, len); if (buf && res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res < len ? res : len); @@ -2741,7 +2856,7 @@ INTERCEPTOR(int, sched_getaffinity, int pid, SIZE_T cpusetsize, void *mask) { COMMON_INTERCEPTOR_ENTER(ctx, sched_getaffinity, pid, cpusetsize, mask); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(sched_getaffinity)(pid, cpusetsize, mask); if (mask && !res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mask, cpusetsize); return res; @@ -2783,7 +2898,7 @@ INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) { COMMON_INTERCEPTOR_ENTER(ctx, strerror_r, errnum, buf, buflen); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. char *res = REAL(strerror_r)(errnum, buf, buflen); // There are 2 versions of strerror_r: // * POSIX version returns 0 on success, negative error code on failure, @@ -2814,7 +2929,7 @@ INTERCEPTOR(int, __xpg_strerror_r, int errnum, char *buf, SIZE_T buflen) { COMMON_INTERCEPTOR_ENTER(ctx, __xpg_strerror_r, errnum, buf, buflen); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(__xpg_strerror_r)(errnum, buf, buflen); // This version always returns a null-terminated string. if (buf && buflen) @@ -2859,11 +2974,12 @@ INTERCEPTOR(int, scandir, char *dirp, __sanitizer_dirent ***namelist, scandir_compar = compar; // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. - int res = REAL(scandir)(dirp, namelist, filter ? wrapped_scandir_filter : 0, - compar ? wrapped_scandir_compar : 0); - scandir_filter = 0; - scandir_compar = 0; + // https://github.com/google/sanitizers/issues/321. + int res = REAL(scandir)(dirp, namelist, + filter ? wrapped_scandir_filter : nullptr, + compar ? wrapped_scandir_compar : nullptr); + scandir_filter = nullptr; + scandir_compar = nullptr; if (namelist && res > 0) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist)); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res); @@ -2911,12 +3027,13 @@ INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist, scandir64_compar = compar; // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = - REAL(scandir64)(dirp, namelist, filter ? wrapped_scandir64_filter : 0, - compar ? wrapped_scandir64_compar : 0); - scandir64_filter = 0; - scandir64_compar = 0; + REAL(scandir64)(dirp, namelist, + filter ? wrapped_scandir64_filter : nullptr, + compar ? wrapped_scandir64_compar : nullptr); + scandir64_filter = nullptr; + scandir64_compar = nullptr; if (namelist && res > 0) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelist, sizeof(*namelist)); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *namelist, sizeof(**namelist) * res); @@ -2937,7 +3054,7 @@ INTERCEPTOR(int, getgroups, int size, u32 *lst) { COMMON_INTERCEPTOR_ENTER(ctx, getgroups, size, lst); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(getgroups)(size, lst); if (res && lst) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst)); return res; @@ -3003,7 +3120,7 @@ INTERCEPTOR(int, wordexp, char *s, __sanitizer_wordexp_t *p, int flags) { if (s) COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(wordexp)(s, p, flags); if (!res && p) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); @@ -3029,7 +3146,7 @@ INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) { // FIXME: read sigset_t when all of sigemptyset, etc are intercepted // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(sigwait)(set, sig); if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig)); return res; @@ -3046,7 +3163,7 @@ INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) { // FIXME: read sigset_t when all of sigemptyset, etc are intercepted // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(sigwaitinfo)(set, info); if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz); return res; @@ -3065,7 +3182,7 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info, // FIXME: read sigset_t when all of sigemptyset, etc are intercepted // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(sigtimedwait)(set, info, timeout); if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz); return res; @@ -3081,7 +3198,7 @@ INTERCEPTOR(int, sigemptyset, __sanitizer_sigset_t *set) { COMMON_INTERCEPTOR_ENTER(ctx, sigemptyset, set); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(sigemptyset)(set); if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set)); return res; @@ -3092,7 +3209,7 @@ INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) { COMMON_INTERCEPTOR_ENTER(ctx, sigfillset, set); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(sigfillset)(set); if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set)); return res; @@ -3110,7 +3227,7 @@ INTERCEPTOR(int, sigpending, __sanitizer_sigset_t *set) { COMMON_INTERCEPTOR_ENTER(ctx, sigpending, set); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(sigpending)(set); if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set)); return res; @@ -3128,7 +3245,7 @@ INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set, // FIXME: read sigset_t when all of sigemptyset, etc are intercepted // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(sigprocmask)(how, set, oldset); if (!res && oldset) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); @@ -3145,7 +3262,7 @@ INTERCEPTOR(int, backtrace, void **buffer, int size) { COMMON_INTERCEPTOR_ENTER(ctx, backtrace, buffer, size); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(backtrace)(buffer, size); if (res && buffer) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buffer, res * sizeof(*buffer)); @@ -3159,7 +3276,7 @@ INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) { COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, size * sizeof(*buffer)); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. char **res = REAL(backtrace_symbols)(buffer, size); if (res && size) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, size * sizeof(*res)); @@ -3267,7 +3384,7 @@ INTERCEPTOR(int, statfs, char *path, void *buf) { if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(statfs)(path, buf); if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz); return res; @@ -3277,7 +3394,7 @@ INTERCEPTOR(int, fstatfs, int fd, void *buf) { COMMON_INTERCEPTOR_ENTER(ctx, fstatfs, fd, buf); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(fstatfs)(fd, buf); if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz); return res; @@ -3296,7 +3413,7 @@ INTERCEPTOR(int, statfs64, char *path, void *buf) { if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(statfs64)(path, buf); if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz); return res; @@ -3306,7 +3423,7 @@ INTERCEPTOR(int, fstatfs64, int fd, void *buf) { COMMON_INTERCEPTOR_ENTER(ctx, fstatfs64, fd, buf); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(fstatfs64)(fd, buf); if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz); return res; @@ -3325,7 +3442,7 @@ INTERCEPTOR(int, statvfs, char *path, void *buf) { if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(statvfs)(path, buf); if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz); return res; @@ -3335,7 +3452,7 @@ INTERCEPTOR(int, fstatvfs, int fd, void *buf) { COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(fstatvfs)(fd, buf); if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz); return res; @@ -3354,7 +3471,7 @@ INTERCEPTOR(int, statvfs64, char *path, void *buf) { if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(statvfs64)(path, buf); if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz); return res; @@ -3364,7 +3481,7 @@ INTERCEPTOR(int, fstatvfs64, int fd, void *buf) { COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs64, fd, buf); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(fstatvfs64)(fd, buf); if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz); return res; @@ -3420,7 +3537,7 @@ INTERCEPTOR(int, ether_ntohost, char *hostname, __sanitizer_ether_addr *addr) { if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr)); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(ether_ntohost)(hostname, addr); if (!res && hostname) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1); @@ -3433,7 +3550,7 @@ INTERCEPTOR(int, ether_hostton, char *hostname, __sanitizer_ether_addr *addr) { COMMON_INTERCEPTOR_READ_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(ether_hostton)(hostname, addr); if (!res && addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr)); return res; @@ -3445,7 +3562,7 @@ INTERCEPTOR(int, ether_line, char *line, __sanitizer_ether_addr *addr, if (line) COMMON_INTERCEPTOR_READ_RANGE(ctx, line, REAL(strlen)(line) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(ether_line)(line, addr, hostname); if (!res) { if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr)); @@ -3469,7 +3586,7 @@ INTERCEPTOR(char *, ether_ntoa_r, __sanitizer_ether_addr *addr, char *buf) { if (addr) COMMON_INTERCEPTOR_READ_RANGE(ctx, addr, sizeof(*addr)); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. char *res = REAL(ether_ntoa_r)(addr, buf); if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); return res; @@ -3481,7 +3598,7 @@ INTERCEPTOR(__sanitizer_ether_addr *, ether_aton_r, char *buf, if (buf) COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, REAL(strlen)(buf) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. __sanitizer_ether_addr *res = REAL(ether_aton_r)(buf, addr); if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(*res)); return res; @@ -3499,7 +3616,7 @@ INTERCEPTOR(int, shmctl, int shmid, int cmd, void *buf) { COMMON_INTERCEPTOR_ENTER(ctx, shmctl, shmid, cmd, buf); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(shmctl)(shmid, cmd, buf); if (res >= 0) { unsigned sz = 0; @@ -3524,7 +3641,7 @@ INTERCEPTOR(int, random_r, void *buf, u32 *result) { COMMON_INTERCEPTOR_ENTER(ctx, random_r, buf, result); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(random_r)(buf, result); if (!res && result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); @@ -3537,7 +3654,7 @@ INTERCEPTOR(int, random_r, void *buf, u32 *result) { // FIXME: under ASan the REAL() call below may write to freed memory and corrupt // its metadata. See -// https://code.google.com/p/address-sanitizer/issues/detail?id=321. +// https://github.com/google/sanitizers/issues/321. #if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET || \ SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSSCHED || \ SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GET || \ @@ -3576,7 +3693,7 @@ INTERCEPTOR(int, pthread_attr_getstack, void *attr, void **addr, SIZE_T *size) { COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getstack, attr, addr, size); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(pthread_attr_getstack)(attr, addr, size); if (!res) { if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr)); @@ -3625,7 +3742,7 @@ INTERCEPTOR(int, pthread_attr_getaffinity_np, void *attr, SIZE_T cpusetsize, cpuset); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(pthread_attr_getaffinity_np)(attr, cpusetsize, cpuset); if (!res && cpusetsize && cpuset) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cpuset, cpusetsize); @@ -3735,7 +3852,7 @@ INTERCEPTOR(char *, tmpnam, char *s) { if (s) // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1); else COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); @@ -3753,7 +3870,7 @@ INTERCEPTOR(char *, tmpnam_r, char *s) { COMMON_INTERCEPTOR_ENTER(ctx, tmpnam_r, s); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. char *res = REAL(tmpnam_r)(s); if (res && s) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1); return res; @@ -3797,7 +3914,7 @@ INTERCEPTOR(void, sincos, double x, double *sin, double *cos) { COMMON_INTERCEPTOR_ENTER(ctx, sincos, x, sin, cos); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. REAL(sincos)(x, sin, cos); if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin)); if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos)); @@ -3807,7 +3924,7 @@ INTERCEPTOR(void, sincosf, float x, float *sin, float *cos) { COMMON_INTERCEPTOR_ENTER(ctx, sincosf, x, sin, cos); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. REAL(sincosf)(x, sin, cos); if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin)); if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos)); @@ -3817,7 +3934,7 @@ INTERCEPTOR(void, sincosl, long double x, long double *sin, long double *cos) { COMMON_INTERCEPTOR_ENTER(ctx, sincosl, x, sin, cos); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. REAL(sincosl)(x, sin, cos); if (sin) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sin, sizeof(*sin)); if (cos) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cos, sizeof(*cos)); @@ -3836,7 +3953,7 @@ INTERCEPTOR(double, remquo, double x, double y, int *quo) { COMMON_INTERCEPTOR_ENTER(ctx, remquo, x, y, quo); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. double res = REAL(remquo)(x, y, quo); if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo)); return res; @@ -3846,7 +3963,7 @@ INTERCEPTOR(float, remquof, float x, float y, int *quo) { COMMON_INTERCEPTOR_ENTER(ctx, remquof, x, y, quo); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. float res = REAL(remquof)(x, y, quo); if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo)); return res; @@ -3856,7 +3973,7 @@ INTERCEPTOR(long double, remquol, long double x, long double y, int *quo) { COMMON_INTERCEPTOR_ENTER(ctx, remquol, x, y, quo); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. long double res = REAL(remquol)(x, y, quo); if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo)); return res; @@ -3906,7 +4023,7 @@ INTERCEPTOR(double, lgamma_r, double x, int *signp) { COMMON_INTERCEPTOR_ENTER(ctx, lgamma_r, x, signp); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. double res = REAL(lgamma_r)(x, signp); if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp)); return res; @@ -3916,7 +4033,7 @@ INTERCEPTOR(float, lgammaf_r, float x, int *signp) { COMMON_INTERCEPTOR_ENTER(ctx, lgammaf_r, x, signp); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. float res = REAL(lgammaf_r)(x, signp); if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp)); return res; @@ -3934,7 +4051,7 @@ INTERCEPTOR(long double, lgammal_r, long double x, int *signp) { COMMON_INTERCEPTOR_ENTER(ctx, lgammal_r, x, signp); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. long double res = REAL(lgammal_r)(x, signp); if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp)); return res; @@ -3950,7 +4067,7 @@ INTERCEPTOR(int, drand48_r, void *buffer, double *result) { COMMON_INTERCEPTOR_ENTER(ctx, drand48_r, buffer, result); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(drand48_r)(buffer, result); if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); return res; @@ -3960,7 +4077,7 @@ INTERCEPTOR(int, lrand48_r, void *buffer, long *result) { COMMON_INTERCEPTOR_ENTER(ctx, lrand48_r, buffer, result); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(lrand48_r)(buffer, result); if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); return res; @@ -3990,7 +4107,7 @@ INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) { COMMON_INTERCEPTOR_ENTER(ctx, getline, lineptr, n, stream); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SSIZE_T res = REAL(getline)(lineptr, n, stream); if (res > 0) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr)); @@ -4002,7 +4119,7 @@ INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) { // FIXME: under ASan the call below may write to freed memory and corrupt its // metadata. See -// https://code.google.com/p/address-sanitizer/issues/detail?id=321. +// https://github.com/google/sanitizers/issues/321. #define GETDELIM_INTERCEPTOR_IMPL(vname) \ { \ void *ctx; \ @@ -4046,10 +4163,10 @@ INTERCEPTOR(SIZE_T, iconv, void *cd, char **inbuf, SIZE_T *inbytesleft, COMMON_INTERCEPTOR_READ_RANGE(ctx, *inbuf, *inbytesleft); if (outbytesleft) COMMON_INTERCEPTOR_READ_RANGE(ctx, outbytesleft, sizeof(*outbytesleft)); - void *outbuf_orig = outbuf ? *outbuf : 0; + void *outbuf_orig = outbuf ? *outbuf : nullptr; // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SIZE_T res = REAL(iconv)(cd, inbuf, inbytesleft, outbuf, outbytesleft); if (res != (SIZE_T) - 1 && outbuf && *outbuf > outbuf_orig) { SIZE_T sz = (char *)*outbuf - (char *)outbuf_orig; @@ -4068,7 +4185,7 @@ INTERCEPTOR(__sanitizer_clock_t, times, void *tms) { COMMON_INTERCEPTOR_ENTER(ctx, times, tms); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. __sanitizer_clock_t res = REAL(times)(tms); if (res != (__sanitizer_clock_t)-1 && tms) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tms, struct_tms_sz); @@ -4111,7 +4228,7 @@ INTERCEPTOR(SSIZE_T, listxattr, const char *path, char *list, SIZE_T size) { if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SSIZE_T res = REAL(listxattr)(path, list, size); // Here and below, size == 0 is a special case where nothing is written to the // buffer, and res contains the desired buffer size. @@ -4124,7 +4241,7 @@ INTERCEPTOR(SSIZE_T, llistxattr, const char *path, char *list, SIZE_T size) { if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SSIZE_T res = REAL(llistxattr)(path, list, size); if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res); return res; @@ -4134,7 +4251,7 @@ INTERCEPTOR(SSIZE_T, flistxattr, int fd, char *list, SIZE_T size) { COMMON_INTERCEPTOR_ENTER(ctx, flistxattr, fd, list, size); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SSIZE_T res = REAL(flistxattr)(fd, list, size); if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res); return res; @@ -4156,7 +4273,7 @@ INTERCEPTOR(SSIZE_T, getxattr, const char *path, const char *name, char *value, if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SSIZE_T res = REAL(getxattr)(path, name, value, size); if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res); return res; @@ -4169,7 +4286,7 @@ INTERCEPTOR(SSIZE_T, lgetxattr, const char *path, const char *name, char *value, if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SSIZE_T res = REAL(lgetxattr)(path, name, value, size); if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res); return res; @@ -4181,7 +4298,7 @@ INTERCEPTOR(SSIZE_T, fgetxattr, int fd, const char *name, char *value, if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. SSIZE_T res = REAL(fgetxattr)(fd, name, value, size); if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res); return res; @@ -4200,7 +4317,7 @@ INTERCEPTOR(int, getresuid, void *ruid, void *euid, void *suid) { COMMON_INTERCEPTOR_ENTER(ctx, getresuid, ruid, euid, suid); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(getresuid)(ruid, euid, suid); if (res >= 0) { if (ruid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ruid, uid_t_sz); @@ -4214,7 +4331,7 @@ INTERCEPTOR(int, getresgid, void *rgid, void *egid, void *sgid) { COMMON_INTERCEPTOR_ENTER(ctx, getresgid, rgid, egid, sgid); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(getresgid)(rgid, egid, sgid); if (res >= 0) { if (rgid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rgid, gid_t_sz); @@ -4239,7 +4356,7 @@ INTERCEPTOR(int, getifaddrs, __sanitizer_ifaddrs **ifap) { COMMON_INTERCEPTOR_ENTER(ctx, getifaddrs, ifap); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(getifaddrs)(ifap); if (res == 0 && ifap) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifap, sizeof(void *)); @@ -4275,7 +4392,7 @@ INTERCEPTOR(char *, if_indextoname, unsigned int ifindex, char* ifname) { COMMON_INTERCEPTOR_ENTER(ctx, if_indextoname, ifindex, ifname); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. char *res = REAL(if_indextoname)(ifindex, ifname); if (res && ifname) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifname, REAL(strlen)(ifname) + 1); @@ -4303,7 +4420,7 @@ INTERCEPTOR(int, capget, void *hdrp, void *datap) { COMMON_INTERCEPTOR_READ_RANGE(ctx, hdrp, __user_cap_header_struct_sz); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(capget)(hdrp, datap); if (res == 0 && datap) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datap, __user_cap_data_struct_sz); @@ -4329,9 +4446,9 @@ INTERCEPTOR(int, capset, void *hdrp, const void *datap) { #endif #if SANITIZER_INTERCEPT_AEABI_MEM -DECLARE_REAL_AND_INTERCEPTOR(void *, memmove, void *, const void *, uptr); -DECLARE_REAL_AND_INTERCEPTOR(void *, memcpy, void *, const void *, uptr); -DECLARE_REAL_AND_INTERCEPTOR(void *, memset, void *, int, uptr); +DECLARE_REAL_AND_INTERCEPTOR(void *, memmove, void *, const void *, uptr) +DECLARE_REAL_AND_INTERCEPTOR(void *, memcpy, void *, const void *, uptr) +DECLARE_REAL_AND_INTERCEPTOR(void *, memset, void *, int, uptr) INTERCEPTOR(void *, __aeabi_memmove, void *to, const void *from, uptr size) { return WRAP(memmove)(to, from, size); @@ -4404,7 +4521,7 @@ INTERCEPTOR(int, ftime, __sanitizer_timeb *tp) { COMMON_INTERCEPTOR_ENTER(ctx, ftime, tp); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(ftime)(tp); if (tp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, sizeof(*tp)); @@ -4422,7 +4539,7 @@ INTERCEPTOR(void, xdrmem_create, __sanitizer_XDR *xdrs, uptr addr, COMMON_INTERCEPTOR_ENTER(ctx, xdrmem_create, xdrs, addr, size, op); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. REAL(xdrmem_create)(xdrs, addr, size, op); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs)); if (op == __sanitizer_XDR_ENCODE) { @@ -4437,14 +4554,14 @@ INTERCEPTOR(void, xdrstdio_create, __sanitizer_XDR *xdrs, void *file, int op) { COMMON_INTERCEPTOR_ENTER(ctx, xdrstdio_create, xdrs, file, op); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. REAL(xdrstdio_create)(xdrs, file, op); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs)); } // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See -// https://code.google.com/p/address-sanitizer/issues/detail?id=321. +// https://github.com/google/sanitizers/issues/321. #define XDR_INTERCEPTOR(F, T) \ INTERCEPTOR(int, F, __sanitizer_XDR *xdrs, T *p) { \ void *ctx; \ @@ -4498,7 +4615,7 @@ INTERCEPTOR(int, xdr_bytes, __sanitizer_XDR *xdrs, char **p, unsigned *sizep, } // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(xdr_bytes)(xdrs, p, sizep, maxsize); if (p && sizep && xdrs->x_op == __sanitizer_XDR_DECODE) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); @@ -4518,7 +4635,7 @@ INTERCEPTOR(int, xdr_string, __sanitizer_XDR *xdrs, char **p, } // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. int res = REAL(xdr_string)(xdrs, p, maxsize); if (p && xdrs->x_op == __sanitizer_XDR_DECODE) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); @@ -4570,7 +4687,7 @@ INTERCEPTOR(void *, tsearch, void *key, void **rootp, COMMON_INTERCEPTOR_ENTER(ctx, tsearch, key, rootp, compar); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. void *res = REAL(tsearch)(key, rootp, compar); if (res && *(void **)res == key) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(void *)); @@ -4652,7 +4769,7 @@ INTERCEPTOR(int, __woverflow, __sanitizer_FILE *fp, int ch) { INTERCEPTOR(__sanitizer_FILE *, fopen, const char *path, const char *mode) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, fopen, path, mode); - COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1); __sanitizer_FILE *res = REAL(fopen)(path, mode); COMMON_INTERCEPTOR_FILE_OPEN(ctx, res, path); @@ -4671,7 +4788,7 @@ INTERCEPTOR(__sanitizer_FILE *, freopen, const char *path, const char *mode, __sanitizer_FILE *fp) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, freopen, path, mode, fp); - COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1); COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp); __sanitizer_FILE *res = REAL(freopen)(path, mode, fp); @@ -4702,7 +4819,7 @@ INTERCEPTOR(__sanitizer_FILE *, freopen64, const char *path, const char *mode, __sanitizer_FILE *fp) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, freopen64, path, mode, fp); - COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); COMMON_INTERCEPTOR_READ_RANGE(ctx, mode, REAL(strlen)(mode) + 1); COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp); __sanitizer_FILE *res = REAL(freopen64)(path, mode, fp); @@ -4723,7 +4840,7 @@ INTERCEPTOR(__sanitizer_FILE *, open_memstream, char **ptr, SIZE_T *sizeloc) { COMMON_INTERCEPTOR_ENTER(ctx, open_memstream, ptr, sizeloc); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. __sanitizer_FILE *res = REAL(open_memstream)(ptr, sizeloc); if (res) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr)); @@ -4754,7 +4871,7 @@ INTERCEPTOR(__sanitizer_FILE *, fmemopen, void *buf, SIZE_T size, COMMON_INTERCEPTOR_ENTER(ctx, fmemopen, buf, size, mode); // FIXME: under ASan the call below may write to freed memory and corrupt // its metadata. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=321. + // https://github.com/google/sanitizers/issues/321. __sanitizer_FILE *res = REAL(fmemopen)(buf, size, mode); if (res) unpoison_file(res); return res; @@ -4831,15 +4948,14 @@ INTERCEPTOR(int, fflush, __sanitizer_FILE *fp) { INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, fclose, fp); - if (fp) { - COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp); - const FileMetadata *m = GetInterceptorMetadata(fp); - if (m) { - COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size); - DeleteInterceptorMetadata(fp); - } + COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp); + const FileMetadata *m = GetInterceptorMetadata(fp); + int res = REAL(fclose)(fp); + if (m) { + COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size); + DeleteInterceptorMetadata(fp); } - return REAL(fclose)(fp); + return res; } #define INIT_FCLOSE COMMON_INTERCEPT_FUNCTION(fclose); #else @@ -4922,7 +5038,7 @@ static void MlockIsUnsupported() { static atomic_uint8_t printed; if (atomic_exchange(&printed, 1, memory_order_relaxed)) return; - VPrintf(1, "INFO: %s ignores mlock/mlockall/munlock/munlockall\n", + VPrintf(1, "%s ignores mlock/mlockall/munlock/munlockall\n", SanitizerToolName); } @@ -5013,6 +5129,192 @@ INTERCEPTOR(__sanitizer_FILE *, fopencookie, void *cookie, const char *mode, #define INIT_FOPENCOOKIE #endif // SANITIZER_INTERCEPT_FOPENCOOKIE +#if SANITIZER_INTERCEPT_SEM +INTERCEPTOR(int, sem_init, __sanitizer_sem_t *s, int pshared, unsigned value) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sem_init, s, pshared, value); + // Workaround a bug in glibc's "old" semaphore implementation by + // zero-initializing the sem_t contents. This has to be done here because + // interceptors bind to the lowest symbols version by default, hitting the + // buggy code path while the non-sanitized build of the same code works fine. + REAL(memset)(s, 0, sizeof(*s)); + int res = REAL(sem_init)(s, pshared, value); + return res; +} + +INTERCEPTOR(int, sem_destroy, __sanitizer_sem_t *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sem_destroy, s); + int res = REAL(sem_destroy)(s); + return res; +} + +INTERCEPTOR(int, sem_wait, __sanitizer_sem_t *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sem_wait, s); + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sem_wait)(s); + if (res == 0) { + COMMON_INTERCEPTOR_ACQUIRE(ctx, (uptr)s); + } + return res; +} + +INTERCEPTOR(int, sem_trywait, __sanitizer_sem_t *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sem_trywait, s); + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sem_trywait)(s); + if (res == 0) { + COMMON_INTERCEPTOR_ACQUIRE(ctx, (uptr)s); + } + return res; +} + +INTERCEPTOR(int, sem_timedwait, __sanitizer_sem_t *s, void *abstime) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sem_timedwait, s, abstime); + COMMON_INTERCEPTOR_READ_RANGE(ctx, abstime, struct_timespec_sz); + int res = COMMON_INTERCEPTOR_BLOCK_REAL(sem_timedwait)(s, abstime); + if (res == 0) { + COMMON_INTERCEPTOR_ACQUIRE(ctx, (uptr)s); + } + return res; +} + +INTERCEPTOR(int, sem_post, __sanitizer_sem_t *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sem_post, s); + COMMON_INTERCEPTOR_RELEASE(ctx, (uptr)s); + int res = REAL(sem_post)(s); + return res; +} + +INTERCEPTOR(int, sem_getvalue, __sanitizer_sem_t *s, int *sval) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sem_getvalue, s, sval); + int res = REAL(sem_getvalue)(s, sval); + if (res == 0) { + COMMON_INTERCEPTOR_ACQUIRE(ctx, (uptr)s); + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sval, sizeof(*sval)); + } + return res; +} +#define INIT_SEM \ + COMMON_INTERCEPT_FUNCTION(sem_init); \ + COMMON_INTERCEPT_FUNCTION(sem_destroy); \ + COMMON_INTERCEPT_FUNCTION(sem_wait); \ + COMMON_INTERCEPT_FUNCTION(sem_trywait); \ + COMMON_INTERCEPT_FUNCTION(sem_timedwait); \ + COMMON_INTERCEPT_FUNCTION(sem_post); \ + COMMON_INTERCEPT_FUNCTION(sem_getvalue); +#else +#define INIT_SEM +#endif // SANITIZER_INTERCEPT_SEM + +#if SANITIZER_INTERCEPT_PTHREAD_SETCANCEL +INTERCEPTOR(int, pthread_setcancelstate, int state, int *oldstate) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_setcancelstate, state, oldstate); + int res = REAL(pthread_setcancelstate)(state, oldstate); + if (res == 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldstate, sizeof(*oldstate)); + return res; +} + +INTERCEPTOR(int, pthread_setcanceltype, int type, int *oldtype) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, pthread_setcanceltype, type, oldtype); + int res = REAL(pthread_setcanceltype)(type, oldtype); + if (res == 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldtype, sizeof(*oldtype)); + return res; +} +#define INIT_PTHREAD_SETCANCEL \ + COMMON_INTERCEPT_FUNCTION(pthread_setcancelstate); \ + COMMON_INTERCEPT_FUNCTION(pthread_setcanceltype); +#else +#define INIT_PTHREAD_SETCANCEL +#endif + +#if SANITIZER_INTERCEPT_MINCORE +INTERCEPTOR(int, mincore, void *addr, uptr length, unsigned char *vec) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, mincore, addr, length, vec); + int res = REAL(mincore)(addr, length, vec); + if (res == 0) { + uptr page_size = GetPageSizeCached(); + uptr vec_size = ((length + page_size - 1) & (~(page_size - 1))) / page_size; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, vec, vec_size); + } + return res; +} +#define INIT_MINCORE COMMON_INTERCEPT_FUNCTION(mincore); +#else +#define INIT_MINCORE +#endif + +#if SANITIZER_INTERCEPT_PROCESS_VM_READV +INTERCEPTOR(SSIZE_T, process_vm_readv, int pid, __sanitizer_iovec *local_iov, + uptr liovcnt, __sanitizer_iovec *remote_iov, uptr riovcnt, + uptr flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, process_vm_readv, pid, local_iov, liovcnt, + remote_iov, riovcnt, flags); + SSIZE_T res = REAL(process_vm_readv)(pid, local_iov, liovcnt, remote_iov, + riovcnt, flags); + if (res > 0) + write_iovec(ctx, local_iov, liovcnt, res); + return res; +} + +INTERCEPTOR(SSIZE_T, process_vm_writev, int pid, __sanitizer_iovec *local_iov, + uptr liovcnt, __sanitizer_iovec *remote_iov, uptr riovcnt, + uptr flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, process_vm_writev, pid, local_iov, liovcnt, + remote_iov, riovcnt, flags); + SSIZE_T res = REAL(process_vm_writev)(pid, local_iov, liovcnt, remote_iov, + riovcnt, flags); + if (res > 0) + read_iovec(ctx, local_iov, liovcnt, res); + return res; +} +#define INIT_PROCESS_VM_READV \ + COMMON_INTERCEPT_FUNCTION(process_vm_readv); \ + COMMON_INTERCEPT_FUNCTION(process_vm_writev); +#else +#define INIT_PROCESS_VM_READV +#endif + +#if SANITIZER_INTERCEPT_CTERMID +INTERCEPTOR(char *, ctermid, char *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ctermid, s); + char *res = REAL(ctermid)(s); + if (res) { + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); + } + return res; +} +#define INIT_CTERMID COMMON_INTERCEPT_FUNCTION(ctermid); +#else +#define INIT_CTERMID +#endif + +#if SANITIZER_INTERCEPT_CTERMID_R +INTERCEPTOR(char *, ctermid_r, char *s) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, ctermid_r, s); + char *res = REAL(ctermid_r)(s); + if (res) { + COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); + } + return res; +} +#define INIT_CTERMID_R COMMON_INTERCEPT_FUNCTION(ctermid_r); +#else +#define INIT_CTERMID_R +#endif + static void InitializeCommonInterceptors() { static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1]; interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap(); @@ -5027,6 +5329,7 @@ static void InitializeCommonInterceptors() { INIT_STRSPN; INIT_STRPBRK; INIT_MEMCHR; + INIT_MEMCMP; INIT_MEMRCHR; INIT_READ; INIT_PREAD; @@ -5092,6 +5395,7 @@ static void InitializeCommonInterceptors() { INIT_MBSNRTOWCS; INIT_WCSTOMBS; INIT_WCSNRTOMBS; + INIT_WCRTOMB; INIT_TCGETATTR; INIT_REALPATH; INIT_CANONICALIZE_FILE_NAME; @@ -5181,4 +5485,10 @@ static void InitializeCommonInterceptors() { INIT_TIMERFD; INIT_MLOCKX; INIT_FOPENCOOKIE; + INIT_SEM; + INIT_PTHREAD_SETCANCEL; + INIT_MINCORE; + INIT_PROCESS_VM_READV; + INIT_CTERMID; + INIT_CTERMID_R; } diff --git a/lib/sanitizer_common/sanitizer_common_interceptors_format.inc b/lib/sanitizer_common/sanitizer_common_interceptors_format.inc index 8f94802aeae8..92318cda35fd 100644 --- a/lib/sanitizer_common/sanitizer_common_interceptors_format.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors_format.inc @@ -13,6 +13,7 @@ // with a few common GNU extensions. // //===----------------------------------------------------------------------===// + #include <stdarg.h> static const char *parse_number(const char *p, int *out) { @@ -191,7 +192,7 @@ static const char *scanf_parse_next(const char *p, bool allowGnuMalloc, continue; } if (*p == '\0') { - return 0; + return nullptr; } // %n$ p = maybe_parse_param_index(p, &dir->argIdx); @@ -206,7 +207,7 @@ static const char *scanf_parse_next(const char *p, bool allowGnuMalloc, p = parse_number(p, &dir->fieldWidth); CHECK(p); if (dir->fieldWidth <= 0) // Width if at all must be non-zero - return 0; + return nullptr; } // m if (*p == 'm') { @@ -226,8 +227,8 @@ static const char *scanf_parse_next(const char *p, bool allowGnuMalloc, while (*p && *p != ']') ++p; if (*p == 0) - return 0; // unexpected end of string - // Consume the closing ']'. + return nullptr; // unexpected end of string + // Consume the closing ']'. ++p; } // This is unfortunately ambiguous between old GNU extension @@ -251,7 +252,7 @@ static const char *scanf_parse_next(const char *p, bool allowGnuMalloc, while (*q && *q != ']' && *q != '%') ++q; if (*q == 0 || *q == '%') - return 0; + return nullptr; p = q + 1; // Consume the closing ']'. dir->maybeGnuMalloc = true; } @@ -395,7 +396,7 @@ static const char *printf_parse_next(const char *p, PrintfDirective *dir) { continue; } if (*p == '\0') { - return 0; + return nullptr; } // %n$ p = maybe_parse_param_index(p, &dir->precisionIdx); @@ -408,7 +409,7 @@ static const char *printf_parse_next(const char *p, PrintfDirective *dir) { p = maybe_parse_number_or_star(p, &dir->fieldWidth, &dir->starredWidth); if (!p) - return 0; + return nullptr; // Precision if (*p == '.') { ++p; @@ -416,7 +417,7 @@ static const char *printf_parse_next(const char *p, PrintfDirective *dir) { p = maybe_parse_number_or_star(p, &dir->fieldPrecision, &dir->starredPrecision); if (!p) - return 0; + return nullptr; // m$ if (dir->starredPrecision) { p = maybe_parse_param_index(p, &dir->precisionIdx); @@ -556,4 +557,4 @@ static void printf_common(void *ctx, const char *format, va_list aq) { } } -#endif // SANITIZER_INTERCEPT_PRINTF +#endif // SANITIZER_INTERCEPT_PRINTF diff --git a/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc index b94c21c96aa0..fcd0a3d70f52 100755 --- a/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc +++ b/lib/sanitizer_common/sanitizer_common_interceptors_ioctl.inc @@ -520,7 +520,7 @@ static const ioctl_desc *ioctl_table_lookup(unsigned req) { if (left == right && ioctl_table[left].req == req) return ioctl_table + left; else - return 0; + return nullptr; } static bool ioctl_decode(unsigned req, ioctl_desc *desc) { @@ -567,7 +567,7 @@ static const ioctl_desc *ioctl_lookup(unsigned req) { (desc->type == ioctl_desc::READWRITE || desc->type == ioctl_desc::WRITE || desc->type == ioctl_desc::READ)) return desc; - return 0; + return nullptr; } static void ioctl_common_pre(void *ctx, const ioctl_desc *desc, int d, diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc index 1b65bced75d5..b5d46f244f66 100644 --- a/lib/sanitizer_common/sanitizer_common_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "sanitizer_common.h" + #include "sanitizer_flags.h" #include "sanitizer_stackdepot.h" #include "sanitizer_stacktrace.h" @@ -46,6 +47,7 @@ void SetSandboxingCallback(void (*f)()) { } void ReportErrorSummary(const char *error_type, StackTrace *stack) { +#if !SANITIZER_GO if (!common_flags()->print_summary) return; if (stack->size == 0) { @@ -58,6 +60,7 @@ void ReportErrorSummary(const char *error_type, StackTrace *stack) { SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc); ReportErrorSummary(error_type, frame->info); frame->ClearAll(); +#endif } static void (*SoftRssLimitExceededCallback)(bool exceeded); @@ -116,8 +119,30 @@ void BackgroundThread(void *arg) { } } +void WriteToSyslog(const char *msg) { + InternalScopedString msg_copy(kErrorMessageBufferSize); + msg_copy.append("%s", msg); + char *p = msg_copy.data(); + char *q; + + // Remove color sequences since syslogs cannot print them. + RemoveANSIEscapeSequencesFromString(p); + + // Print one line at a time. + // syslog, at least on Android, has an implicit message length limit. + do { + q = internal_strchr(p, '\n'); + if (q) + *q = '\0'; + WriteOneLineToSyslog(p); + if (q) + p = q + 1; + } while (q); +} + void MaybeStartBackgroudThread() { -#if SANITIZER_LINUX // Need to implement/test on other platforms. +#if SANITIZER_LINUX && \ + !SANITIZER_GO // Need to implement/test on other platforms. // Start the background thread if one of the rss limits is given. if (!common_flags()->hard_rss_limit_mb && !common_flags()->soft_rss_limit_mb) return; diff --git a/lib/sanitizer_common/sanitizer_common_nolibc.cc b/lib/sanitizer_common/sanitizer_common_nolibc.cc new file mode 100644 index 000000000000..89c17e0797ef --- /dev/null +++ b/lib/sanitizer_common/sanitizer_common_nolibc.cc @@ -0,0 +1,26 @@ +//===-- sanitizer_common_nolibc.cc ----------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains stubs for libc function to facilitate optional use of +// libc in no-libcdep sources. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#include "sanitizer_common.h" +#include "sanitizer_libc.h" + +namespace __sanitizer { + +#if SANITIZER_LINUX +bool ShouldLogAfterPrintf() { return false; } +#endif +void WriteToSyslog(const char *buffer) {} +void Abort() { internal__exit(1); } + +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_common_syscalls.inc b/lib/sanitizer_common/sanitizer_common_syscalls.inc index 5d4840f961ef..008e57745cc5 100644 --- a/lib/sanitizer_common/sanitizer_common_syscalls.inc +++ b/lib/sanitizer_common/sanitizer_common_syscalls.inc @@ -2301,7 +2301,7 @@ POST_SYSCALL(ni_syscall)(long res) {} PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) { #if !SANITIZER_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__)) + defined(__powerpc64__) || defined(__aarch64__)) if (data) { if (request == ptrace_setregs) { PRE_READ((void *)data, struct_user_regs_struct_sz); @@ -2322,7 +2322,7 @@ PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) { POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) { #if !SANITIZER_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__)) + defined(__powerpc64__) || defined(__aarch64__)) if (res >= 0 && data) { // Note that this is different from the interceptor in // sanitizer_common_interceptors.inc. diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index f511c996d8c2..b9833c5a1d97 100644 --- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -53,6 +53,12 @@ static const u64 kMagic32 = 0xC0BFFFFFFFFFFF32ULL; static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once. static atomic_uintptr_t coverage_counter; +static atomic_uintptr_t caller_callee_counter; + +static void ResetGlobalCounters() { + return atomic_store(&coverage_counter, 0, memory_order_relaxed); + return atomic_store(&caller_callee_counter, 0, memory_order_relaxed); +} // 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. @@ -90,7 +96,7 @@ class CoverageData { void DumpAll(); ALWAYS_INLINE - void TraceBasicBlock(s32 *id); + void TraceBasicBlock(u32 *id); void InitializeGuardArray(s32 *guards); void InitializeGuards(s32 *guards, uptr n, const char *module_name, @@ -225,7 +231,8 @@ 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_fetch_add(&pc_array_index, 1, memory_order_relaxed); + uptr idx = atomic_load_relaxed(&pc_array_index); + atomic_store_relaxed(&pc_array_index, idx + 1); guards[j] = -static_cast<s32>(idx + 1); } } @@ -435,7 +442,7 @@ void CoverageData::IndirCall(uptr caller, uptr callee, uptr callee_cache[], uptr was = 0; if (atomic_compare_exchange_strong(&atomic_callee_cache[i], &was, callee, memory_order_seq_cst)) { - atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed); + atomic_fetch_add(&caller_callee_counter, 1, memory_order_relaxed); return; } if (was == callee) // Already have this callee. @@ -675,11 +682,11 @@ void CoverageData::DumpCallerCalleePairs() { // it once and then cache in the provided 'cache' storage. // // This function will eventually be inlined by the compiler. -void CoverageData::TraceBasicBlock(s32 *id) { +void CoverageData::TraceBasicBlock(u32 *id) { // Will trap here if // 1. coverage is not enabled at run-time. // 2. The array tr_event_array is full. - *tr_event_pointer = static_cast<u32>(*id - 1); + *tr_event_pointer = *id - 1; tr_event_pointer++; } @@ -813,7 +820,7 @@ void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { } 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 */, 0); + cov_fd = CovOpenFile(&path, true /* packed */, nullptr); } } @@ -832,6 +839,11 @@ 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. @@ -840,6 +852,7 @@ void InitializeCoverage(bool enabled, const char *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) { @@ -853,7 +866,7 @@ void CoverageUpdateMapping() { CovUpdateMapping(coverage_dir); } -} // namespace __sanitizer +} // namespace __sanitizer extern "C" { SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(u32 *guard) { @@ -902,15 +915,23 @@ uptr __sanitizer_get_total_unique_coverage() { } SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_cov_trace_func_enter(s32 *id) { +uptr __sanitizer_get_total_unique_caller_callee_pairs() { + return atomic_load(&caller_callee_counter, memory_order_relaxed); +} + +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_cov_trace_func_enter(u32 *id) { + __sanitizer_cov_with_check(id); coverage_data.TraceBasicBlock(id); } SANITIZER_INTERFACE_ATTRIBUTE -void __sanitizer_cov_trace_basic_block(s32 *id) { +void __sanitizer_cov_trace_basic_block(u32 *id) { + __sanitizer_cov_with_check(id); coverage_data.TraceBasicBlock(id); } SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_reset_coverage() { + ResetGlobalCounters(); coverage_data.ReinitializeGuards(); internal_bzero_aligned16( coverage_data.data(), @@ -931,7 +952,9 @@ SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_update_counter_bitset_and_clear_counters(u8 *bitset) { return coverage_data.Update8bitCounterBitsetAndClearCounters(bitset); } -// Default empty implementation (weak). Users should redefine it. +// Default empty implementations (weak). Users should redefine them. SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __sanitizer_cov_trace_cmp() {} -} // extern "C" +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE +void __sanitizer_cov_trace_switch() {} +} // extern "C" diff --git a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc index a3d75abc0476..c8b5d9014ede 100644 --- a/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc @@ -75,7 +75,7 @@ void CovUpdateMapping(const char *coverage_dir, uptr caller_pc) { InternalScopedBuffer<LoadedModule> modules(kMaxNumberOfModules); CHECK(modules.data()); int n_modules = GetListOfModules(modules.data(), kMaxNumberOfModules, - /* filter */ 0); + /* filter */ nullptr); text.append("%d\n", sizeof(uptr) * 8); for (int i = 0; i < n_modules; ++i) { @@ -124,4 +124,4 @@ void CovUpdateMapping(const char *coverage_dir, uptr caller_pc) { } } -} // namespace __sanitizer +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector1.cc b/lib/sanitizer_common/sanitizer_deadlock_detector1.cc index 5890b54b933b..bd57a403bdcc 100644 --- a/lib/sanitizer_common/sanitizer_deadlock_detector1.cc +++ b/lib/sanitizer_common/sanitizer_deadlock_detector1.cc @@ -71,7 +71,7 @@ DD::DD(const DDFlags *flags) } DDPhysicalThread* DD::CreatePhysicalThread() { - return 0; + return nullptr; } void DD::DestroyPhysicalThread(DDPhysicalThread *pt) { @@ -181,10 +181,10 @@ void DD::MutexDestroy(DDCallback *cb, DDReport *DD::GetReport(DDCallback *cb) { if (!cb->lt->report_pending) - return 0; + return nullptr; cb->lt->report_pending = false; return &cb->lt->rep; } -} // namespace __sanitizer -#endif // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1 +} // namespace __sanitizer +#endif // #if SANITIZER_DEADLOCK_DETECTOR_VERSION == 1 diff --git a/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h b/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h index 8cf26e0d5528..b6e91a16e257 100644 --- a/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h +++ b/lib/sanitizer_common/sanitizer_deadlock_detector_interface.h @@ -72,10 +72,10 @@ struct DDCallback { struct DDetector { static DDetector *Create(const DDFlags *flags); - virtual DDPhysicalThread* CreatePhysicalThread() { return 0; } + virtual DDPhysicalThread* CreatePhysicalThread() { return nullptr; } virtual void DestroyPhysicalThread(DDPhysicalThread *pt) {} - virtual DDLogicalThread* CreateLogicalThread(u64 ctx) { return 0; } + virtual DDLogicalThread* CreateLogicalThread(u64 ctx) { return nullptr; } virtual void DestroyLogicalThread(DDLogicalThread *lt) {} virtual void MutexInit(DDCallback *cb, DDMutex *m) {} @@ -85,7 +85,7 @@ struct DDetector { virtual void MutexBeforeUnlock(DDCallback *cb, DDMutex *m, bool wlock) {} virtual void MutexDestroy(DDCallback *cb, DDMutex *m) {} - virtual DDReport *GetReport(DDCallback *cb) { return 0; } + virtual DDReport *GetReport(DDCallback *cb) { return nullptr; } }; } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_flag_parser.cc b/lib/sanitizer_common/sanitizer_flag_parser.cc index d125002daf4c..67830b2940bb 100644 --- a/lib/sanitizer_common/sanitizer_flag_parser.cc +++ b/lib/sanitizer_common/sanitizer_flag_parser.cc @@ -127,6 +127,24 @@ void FlagParser::ParseString(const char *s) { pos_ = old_pos_; } +bool FlagParser::ParseFile(const char *path, bool ignore_missing) { + static const uptr kMaxIncludeSize = 1 << 15; + char *data; + uptr data_mapped_size; + error_t err; + uptr len; + if (!ReadFileToBuffer(path, &data, &data_mapped_size, &len, + Max(kMaxIncludeSize, GetPageSizeCached()), &err)) { + if (ignore_missing) + return true; + Printf("Failed to read options from '%s': error %d\n", path, err); + return false; + } + ParseString(data); + UnmapOrDie(data, data_mapped_size); + return true; +} + bool FlagParser::run_handler(const char *name, const char *value) { for (int i = 0; i < n_flags_; ++i) { if (internal_strcmp(name, flags_[i].name) == 0) diff --git a/lib/sanitizer_common/sanitizer_flag_parser.h b/lib/sanitizer_common/sanitizer_flag_parser.h index 0ac7634cb876..2477aeddba5f 100644 --- a/lib/sanitizer_common/sanitizer_flag_parser.h +++ b/lib/sanitizer_common/sanitizer_flag_parser.h @@ -93,6 +93,7 @@ class FlagParser { void RegisterHandler(const char *name, FlagHandlerBase *handler, const char *desc); void ParseString(const char *s); + bool ParseFile(const char *path, bool ignore_missing); void PrintFlagDescriptions(); static LowLevelAllocator Alloc; diff --git a/lib/sanitizer_common/sanitizer_flags.cc b/lib/sanitizer_common/sanitizer_flags.cc index 01098a3d6b87..18b9ea3df9e1 100644 --- a/lib/sanitizer_common/sanitizer_flags.cc +++ b/lib/sanitizer_common/sanitizer_flags.cc @@ -45,34 +45,49 @@ void CommonFlags::CopyFrom(const CommonFlags &other) { internal_memcpy(this, &other, sizeof(*this)); } +// Copy the string from "s" to "out", replacing "%b" with the binary basename. +static void SubstituteBinaryName(const char *s, char *out, uptr out_size) { + char *out_end = out + out_size; + while (*s && out < out_end - 1) { + if (s[0] != '%' || s[1] != 'b') { *out++ = *s++; continue; } + const char *base = GetProcessName(); + CHECK(base); + while (*base && out < out_end - 1) + *out++ = *base++; + s += 2; // skip "%b" + } + *out = '\0'; +} + class FlagHandlerInclude : public FlagHandlerBase { - static const uptr kMaxIncludeSize = 1 << 15; FlagParser *parser_; + bool ignore_missing_; public: - explicit FlagHandlerInclude(FlagParser *parser) : parser_(parser) {} + explicit FlagHandlerInclude(FlagParser *parser, bool ignore_missing) + : parser_(parser), ignore_missing_(ignore_missing) {} bool Parse(const char *value) final { - char *data; - uptr data_mapped_size; - error_t err; - uptr len = - ReadFileToBuffer(value, &data, &data_mapped_size, - Max(kMaxIncludeSize, GetPageSizeCached()), &err); - if (!len) { - Printf("Failed to read options from '%s': error %d\n", value, err); - return false; + if (internal_strchr(value, '%')) { + char *buf = (char *)MmapOrDie(kMaxPathLength, "FlagHandlerInclude"); + SubstituteBinaryName(value, buf, kMaxPathLength); + bool res = parser_->ParseFile(buf, ignore_missing_); + UnmapOrDie(buf, kMaxPathLength); + return res; } - parser_->ParseString(data); - UnmapOrDie(data, data_mapped_size); - return true; + return parser_->ParseFile(value, ignore_missing_); } }; -void RegisterIncludeFlag(FlagParser *parser, CommonFlags *cf) { - FlagHandlerInclude *fh_include = - new (FlagParser::Alloc) FlagHandlerInclude(parser); // NOLINT +void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf) { + FlagHandlerInclude *fh_include = new (FlagParser::Alloc) // NOLINT + FlagHandlerInclude(parser, /*ignore_missing*/ false); parser->RegisterHandler("include", fh_include, "read more options from the given file"); + FlagHandlerInclude *fh_include_if_exists = new (FlagParser::Alloc) // NOLINT + FlagHandlerInclude(parser, /*ignore_missing*/ true); + parser->RegisterHandler( + "include_if_exists", fh_include_if_exists, + "read more options from the given file (if it exists)"); } void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) { @@ -81,7 +96,7 @@ void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf) { #include "sanitizer_flags.inc" #undef COMMON_FLAG - RegisterIncludeFlag(parser, cf); + RegisterIncludeFlags(parser, cf); } } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_flags.h b/lib/sanitizer_common/sanitizer_flags.h index fda6d710757e..33c3c4512725 100644 --- a/lib/sanitizer_common/sanitizer_flags.h +++ b/lib/sanitizer_common/sanitizer_flags.h @@ -49,7 +49,7 @@ inline void OverrideCommonFlags(const CommonFlags &cf) { class FlagParser; void RegisterCommonFlags(FlagParser *parser, CommonFlags *cf = &common_flags_dont_use); -void RegisterIncludeFlag(FlagParser *parser, CommonFlags *cf); +void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf); } // namespace __sanitizer #endif // SANITIZER_FLAGS_H diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc index bbb39c73e2d0..c89273117a5e 100644 --- a/lib/sanitizer_common/sanitizer_flags.inc +++ b/lib/sanitizer_common/sanitizer_flags.inc @@ -10,6 +10,7 @@ // This file describes common flags available in all sanitizers. // //===----------------------------------------------------------------------===// + #ifndef COMMON_FLAG #error "Define COMMON_FLAG prior to including this file!" #endif @@ -24,7 +25,7 @@ COMMON_FLAG( "If set, use the online symbolizer from common sanitizer runtime to turn " "virtual addresses to file/line locations.") COMMON_FLAG( - const char *, external_symbolizer_path, 0, + const char *, external_symbolizer_path, nullptr, "Path to external symbolizer. If empty, the tool will search $PATH for " "the symbolizer.") COMMON_FLAG( @@ -55,6 +56,10 @@ COMMON_FLAG( "Mention name of executable when reporting error and " "append executable name to logs (as in \"log_path.exe_name.pid\").") COMMON_FLAG( + bool, log_to_syslog, SANITIZER_ANDROID || SANITIZER_MAC, + "Write all sanitizer output to syslog in addition to other means of " + "logging.") +COMMON_FLAG( int, verbosity, 0, "Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).") COMMON_FLAG(bool, detect_leaks, true, "Enable memory leak detection.") @@ -74,6 +79,10 @@ COMMON_FLAG(bool, handle_segv, SANITIZER_NEEDS_SEGV, "If set, registers the tool's custom SIGSEGV/SIGBUS handler.") COMMON_FLAG(bool, handle_abort, false, "If set, registers the tool's custom SIGABRT handler.") +COMMON_FLAG(bool, handle_sigill, false, + "If set, registers the tool's custom SIGILL handler.") +COMMON_FLAG(bool, handle_sigfpe, true, + "If set, registers the tool's custom SIGFPE handler.") COMMON_FLAG(bool, allow_user_segv_handler, false, "If set, allows user to register a SEGV handler even if the tool " "registers one.") @@ -170,6 +179,21 @@ COMMON_FLAG(bool, intercept_strspn, true, COMMON_FLAG(bool, intercept_strpbrk, true, "If set, uses custom wrappers for strpbrk function " "to find more errors.") +COMMON_FLAG(bool, intercept_memcmp, true, + "If set, uses custom wrappers for memcmp function " + "to find more errors.") +COMMON_FLAG(bool, strict_memcmp, true, + "If true, assume that memcmp(p1, p2, n) always reads n bytes before " + "comparing p1 and p2.") COMMON_FLAG(bool, decorate_proc_maps, false, "If set, decorate sanitizer " "mappings in /proc/self/maps with " "user-readable names") +COMMON_FLAG(int, exitcode, 1, "Override the program exit status if the tool " + "found an error") +COMMON_FLAG( + bool, abort_on_error, SANITIZER_MAC, + "If set, the tool calls abort() instead of _exit() after printing the " + "error report.") +COMMON_FLAG(bool, suppress_equal_pcs, true, + "Deduplicate multiple reports for single source location in " + "halt_on_error=false mode (asan only).") diff --git a/lib/sanitizer_common/sanitizer_interface_internal.h b/lib/sanitizer_common/sanitizer_interface_internal.h index 94d9f4e9524a..b11ae30106f7 100644 --- a/lib/sanitizer_common/sanitizer_interface_internal.h +++ b/lib/sanitizer_common/sanitizer_interface_internal.h @@ -53,6 +53,9 @@ extern "C" { SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_verify_contiguous_container(const void *beg, const void *mid, const void *end); -} // extern "C" + SANITIZER_INTERFACE_ATTRIBUTE + const void *__sanitizer_contiguous_container_find_bad_address( + const void *beg, const void *mid, const void *end); + } // extern "C" #endif // SANITIZER_INTERFACE_INTERNAL_H diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h index b76c6023aba2..e83eed0830d8 100644 --- a/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/lib/sanitizer_common/sanitizer_internal_defs.h @@ -117,7 +117,10 @@ using namespace __sanitizer; // NOLINT // Common defs. #define INLINE inline #define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE -#define WEAK SANITIZER_WEAK_ATTRIBUTE +#define SANITIZER_WEAK_DEFAULT_IMPL \ + extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE +#define SANITIZER_WEAK_CXX_DEFAULT_IMPL \ + extern "C++" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE // Platform-specific defs. #if defined(_MSC_VER) @@ -129,7 +132,6 @@ using namespace __sanitizer; // NOLINT # define NOINLINE __declspec(noinline) # define NORETURN __declspec(noreturn) # define THREADLOCAL __declspec(thread) -# define NOTHROW # define LIKELY(x) (x) # define UNLIKELY(x) (x) # define PREFETCH(x) /* _mm_prefetch(x, _MM_HINT_NTA) */ @@ -143,7 +145,6 @@ using namespace __sanitizer; // NOLINT # define NOINLINE __attribute__((noinline)) # define NORETURN __attribute__((noreturn)) # define THREADLOCAL __thread -# define NOTHROW throw() # define LIKELY(x) __builtin_expect(!!(x), 1) # define UNLIKELY(x) __builtin_expect(!!(x), 0) # if defined(__i386__) || defined(__x86_64__) @@ -162,6 +163,12 @@ using namespace __sanitizer; // NOLINT # define USED #endif +#if !defined(_MSC_VER) || defined(__clang__) || MSC_PREREQ(1900) +# define NOEXCEPT noexcept +#else +# define NOEXCEPT throw() +#endif + // Unaligned versions of basic types. typedef ALIGNED(1) u16 uu16; typedef ALIGNED(1) u32 uu32; diff --git a/lib/sanitizer_common/sanitizer_lfstack.h b/lib/sanitizer_common/sanitizer_lfstack.h index 088413908087..879cc80921c7 100644 --- a/lib/sanitizer_common/sanitizer_lfstack.h +++ b/lib/sanitizer_common/sanitizer_lfstack.h @@ -49,8 +49,8 @@ struct LFStack { u64 cmp = atomic_load(&head_, memory_order_acquire); for (;;) { T *cur = (T*)(uptr)(cmp & kPtrMask); - if (cur == 0) - return 0; + if (!cur) + return nullptr; T *nxt = cur->next; u64 cnt = (cmp & kCounterMask); u64 xch = (u64)(uptr)nxt | cnt; @@ -68,6 +68,6 @@ struct LFStack { atomic_uint64_t head_; }; -} // namespace __sanitizer +} // namespace __sanitizer -#endif // #ifndef SANITIZER_LFSTACK_H +#endif // SANITIZER_LFSTACK_H diff --git a/lib/sanitizer_common/sanitizer_libc.cc b/lib/sanitizer_common/sanitizer_libc.cc index cb162a4c4984..cf31e689653f 100644 --- a/lib/sanitizer_common/sanitizer_libc.cc +++ b/lib/sanitizer_common/sanitizer_libc.cc @@ -10,6 +10,7 @@ // This file is shared between AddressSanitizer and ThreadSanitizer // run-time libraries. See sanitizer_libc.h for details. //===----------------------------------------------------------------------===// + #include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" #include "sanitizer_libc.h" @@ -17,7 +18,7 @@ namespace __sanitizer { s64 internal_atoll(const char *nptr) { - return internal_simple_strtoll(nptr, (char**)0, 10); + return internal_simple_strtoll(nptr, nullptr, 10); } void *internal_memchr(const void *s, int c, uptr n) { @@ -25,7 +26,7 @@ void *internal_memchr(const void *s, int c, uptr n) { for (uptr i = 0; i < n; ++i, ++t) if (*t == c) return reinterpret_cast<void *>(const_cast<char *>(t)); - return 0; + return nullptr; } void *internal_memrchr(const void *s, int c, uptr n) { @@ -77,7 +78,8 @@ void internal_bzero_aligned16(void *s, uptr n) { CHECK_EQ((reinterpret_cast<uptr>(s) | n) & 15, 0); for (S16 *p = reinterpret_cast<S16*>(s), *end = p + n / 16; p < end; p++) { p->a = p->b = 0; - SanitizerBreakOptimization(0); // Make sure this does not become memset. + // Make sure this does not become memset. + SanitizerBreakOptimization(nullptr); } } @@ -96,7 +98,7 @@ void *internal_memset(void* s, int c, uptr n) { uptr internal_strcspn(const char *s, const char *reject) { uptr i; for (i = 0; s[i]; i++) { - if (internal_strchr(reject, s[i]) != 0) + if (internal_strchr(reject, s[i])) return i; } return i; @@ -147,7 +149,7 @@ char* internal_strchr(const char *s, int c) { if (*s == (char)c) return const_cast<char *>(s); if (*s == 0) - return 0; + return nullptr; s++; } } @@ -160,7 +162,7 @@ char *internal_strchrnul(const char *s, int c) { } char *internal_strrchr(const char *s, int c) { - const char *res = 0; + const char *res = nullptr; for (uptr i = 0; s[i]; i++) { if (s[i] == c) res = s + i; } @@ -173,6 +175,19 @@ uptr internal_strlen(const char *s) { return i; } +uptr internal_strlcat(char *dst, const char *src, uptr maxlen) { + const uptr srclen = internal_strlen(src); + const uptr dstlen = internal_strnlen(dst, maxlen); + if (dstlen == maxlen) return maxlen + srclen; + if (srclen < maxlen - dstlen) { + internal_memmove(dst + dstlen, src, srclen + 1); + } else { + internal_memmove(dst + dstlen, src, maxlen - dstlen - 1); + dst[maxlen - 1] = '\0'; + } + return dstlen + srclen; +} + char *internal_strncat(char *dst, const char *src, uptr n) { uptr len = internal_strlen(dst); uptr i; @@ -182,6 +197,17 @@ char *internal_strncat(char *dst, const char *src, uptr n) { return dst; } +uptr internal_strlcpy(char *dst, const char *src, uptr maxlen) { + const uptr srclen = internal_strlen(src); + if (srclen < maxlen) { + internal_memmove(dst, src, srclen + 1); + } else if (maxlen != 0) { + internal_memmove(dst, src, maxlen - 1); + dst[maxlen - 1] = '\0'; + } + return srclen; +} + char *internal_strncpy(char *dst, const char *src, uptr n) { uptr i; for (i = 0; i < n && src[i]; i++) @@ -200,12 +226,12 @@ char *internal_strstr(const char *haystack, const char *needle) { // This is O(N^2), but we are not using it in hot places. uptr len1 = internal_strlen(haystack); uptr len2 = internal_strlen(needle); - if (len1 < len2) return 0; + if (len1 < len2) return nullptr; for (uptr pos = 0; pos <= len1 - len2; pos++) { if (internal_memcmp(haystack + pos, needle, len2) == 0) return const_cast<char *>(haystack) + pos; } - return 0; + return nullptr; } s64 internal_simple_strtoll(const char *nptr, char **endptr, int base) { @@ -229,7 +255,7 @@ s64 internal_simple_strtoll(const char *nptr, char **endptr, int base) { have_digits = true; nptr++; } - if (endptr != 0) { + if (endptr) { *endptr = (have_digits) ? const_cast<char *>(nptr) : old_nptr; } if (sgn > 0) { @@ -258,4 +284,4 @@ bool mem_is_zero(const char *beg, uptr size) { return all == 0; } -} // namespace __sanitizer +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_libc.h b/lib/sanitizer_common/sanitizer_libc.h index ae4e938f4af9..df28677c6700 100644 --- a/lib/sanitizer_common/sanitizer_libc.h +++ b/lib/sanitizer_common/sanitizer_libc.h @@ -13,6 +13,7 @@ // functions are intercepted. Instead, we implement a tiny subset of libc here. // FIXME: Some of functions declared in this file are in fact POSIX, not libc. //===----------------------------------------------------------------------===// + #ifndef SANITIZER_LIBC_H #define SANITIZER_LIBC_H @@ -42,8 +43,10 @@ uptr internal_strcspn(const char *s, const char *reject); char *internal_strdup(const char *s); char *internal_strndup(const char *s, uptr n); uptr internal_strlen(const char *s); +uptr internal_strlcat(char *dst, const char *src, uptr maxlen); char *internal_strncat(char *dst, const char *src, uptr n); int internal_strncmp(const char *s1, const char *s2, uptr n); +uptr internal_strlcpy(char *dst, const char *src, uptr maxlen); char *internal_strncpy(char *dst, const char *src, uptr n); uptr internal_strnlen(const char *s, uptr maxlen); char *internal_strrchr(const char *s, int c); @@ -75,8 +78,8 @@ uptr internal_getppid(); uptr internal_sched_yield(); // Error handling -bool internal_iserror(uptr retval, int *rverrno = 0); +bool internal_iserror(uptr retval, int *rverrno = nullptr); -} // namespace __sanitizer +} // namespace __sanitizer -#endif // SANITIZER_LIBC_H +#endif // SANITIZER_LIBC_H diff --git a/lib/sanitizer_common/sanitizer_libignore.cc b/lib/sanitizer_common/sanitizer_libignore.cc index 8c4aeffda45e..545393966b38 100644 --- a/lib/sanitizer_common/sanitizer_libignore.cc +++ b/lib/sanitizer_common/sanitizer_libignore.cc @@ -8,7 +8,8 @@ //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX + +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC #include "sanitizer_libignore.h" #include "sanitizer_flags.h" @@ -38,11 +39,11 @@ void LibIgnore::OnLibraryLoaded(const char *name) { BlockingMutexLock lock(&mutex_); // Try to match suppressions with symlink target. InternalScopedString buf(kMaxPathLength); - if (name != 0 && internal_readlink(name, buf.data(), buf.size() - 1) > 0 && + if (name && internal_readlink(name, buf.data(), buf.size() - 1) > 0 && buf[0]) { for (uptr i = 0; i < count_; i++) { Lib *lib = &libs_[i]; - if (!lib->loaded && lib->real_name == 0 && + if (!lib->loaded && (!lib->real_name) && TemplateMatch(lib->templ, name)) lib->real_name = internal_strdup(buf.data()); } @@ -60,7 +61,7 @@ void LibIgnore::OnLibraryLoaded(const char *name) { if ((prot & MemoryMappingLayout::kProtectionExecute) == 0) continue; if (TemplateMatch(lib->templ, module.data()) || - (lib->real_name != 0 && + (lib->real_name && internal_strcmp(lib->real_name, module.data()) == 0)) { if (loaded) { Report("%s: called_from_lib suppression '%s' is matched against" @@ -93,9 +94,9 @@ void LibIgnore::OnLibraryLoaded(const char *name) { } void LibIgnore::OnLibraryUnloaded() { - OnLibraryLoaded(0); + OnLibraryLoaded(nullptr); } -} // namespace __sanitizer +} // namespace __sanitizer -#endif // #if SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // #if SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc index 98e5d122a0f9..cba38c8c3057 100644 --- a/lib/sanitizer_common/sanitizer_linux.cc +++ b/lib/sanitizer_common/sanitizer_linux.cc @@ -13,9 +13,9 @@ //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" + #if SANITIZER_FREEBSD || SANITIZER_LINUX -#include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" #include "sanitizer_flags.h" #include "sanitizer_internal_defs.h" @@ -74,11 +74,6 @@ extern char **environ; // provided by crt1 #include <sys/signal.h> #endif -#if SANITIZER_ANDROID -#include <android/log.h> -#include <sys/system_properties.h> -#endif - #if SANITIZER_LINUX // <linux/time.h> struct kernel_timeval { @@ -94,7 +89,8 @@ const int FUTEX_WAKE = 1; // Are we using 32-bit or 64-bit Linux syscalls? // x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32 // but it still needs to use 64-bit syscalls. -#if SANITIZER_LINUX && (defined(__x86_64__) || SANITIZER_WORDSIZE == 64) +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \ + SANITIZER_WORDSIZE == 64) # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1 #else # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0 @@ -104,6 +100,8 @@ namespace __sanitizer { #if SANITIZER_LINUX && defined(__x86_64__) #include "sanitizer_syscall_linux_x86_64.inc" +#elif SANITIZER_LINUX && defined(__aarch64__) +#include "sanitizer_syscall_linux_aarch64.inc" #else #include "sanitizer_syscall_generic.inc" #endif @@ -375,23 +373,23 @@ const char *GetEnv(const char *name) { if (!inited) { inited = true; uptr environ_size; - len = ReadFileToBuffer("/proc/self/environ", - &environ, &environ_size, 1 << 26); + if (!ReadFileToBuffer("/proc/self/environ", &environ, &environ_size, &len)) + environ = nullptr; } - if (!environ || len == 0) return 0; + if (!environ || len == 0) return nullptr; uptr namelen = internal_strlen(name); const char *p = environ; while (*p != '\0') { // will happen at the \0\0 that terminates the buffer // proc file has the format NAME=value\0NAME=value\0NAME=value\0... const char* endp = (char*)internal_memchr(p, '\0', len - (p - environ)); - if (endp == 0) // this entry isn't NUL terminated - return 0; + if (!endp) // this entry isn't NUL terminated + return nullptr; else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match. return p + namelen + 1; // point after = p = endp + 1; } - return 0; // Not found. + return nullptr; // Not found. #else #error "Unsupported platform" #endif @@ -405,9 +403,13 @@ extern "C" { static void ReadNullSepFileToArray(const char *path, char ***arr, int arr_size) { char *buff; - uptr buff_size = 0; + uptr buff_size; + uptr buff_len; *arr = (char **)MmapOrDie(arr_size * sizeof(char *), "NullSepFileArray"); - ReadFileToBuffer(path, &buff, &buff_size, 1024 * 1024); + if (!ReadFileToBuffer(path, &buff, &buff_size, &buff_len, 1024 * 1024)) { + (*arr)[0] = nullptr; + return; + } (*arr)[0] = buff; int count, i; for (count = 1, i = 1; ; i++) { @@ -418,7 +420,7 @@ static void ReadNullSepFileToArray(const char *path, char ***arr, count++; } } - (*arr)[count] = 0; + (*arr)[count] = nullptr; } #endif @@ -496,7 +498,7 @@ void BlockingMutex::CheckLocked() { // Note that getdents64 uses a different structure format. We only provide the // 32-bit syscall here. struct linux_dirent { -#if SANITIZER_X32 +#if SANITIZER_X32 || defined(__aarch64__) u64 d_ino; u64 d_off; #else @@ -504,6 +506,9 @@ struct linux_dirent { unsigned long d_off; #endif unsigned short d_reclen; +#ifdef __aarch64__ + unsigned char d_type; +#endif char d_name[256]; }; @@ -585,8 +590,8 @@ int internal_sigaction_norestorer(int signum, const void *act, void *oldact) { } uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum, - (uptr)(u_act ? &k_act : NULL), - (uptr)(u_oldact ? &k_oldact : NULL), + (uptr)(u_act ? &k_act : nullptr), + (uptr)(u_oldact ? &k_oldact : nullptr), (uptr)sizeof(__sanitizer_kernel_sigset_t)); if ((result == 0) && u_oldact) { @@ -732,6 +737,21 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { return module_name_len; } +uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) { +#if SANITIZER_LINUX + char *tmpbuf; + uptr tmpsize; + uptr tmplen; + if (ReadFileToBuffer("/proc/self/cmdline", &tmpbuf, &tmpsize, &tmplen, + 1024 * 1024)) { + internal_strncpy(buf, tmpbuf, buf_len); + UnmapOrDie(tmpbuf, tmpsize); + return internal_strlen(buf); + } +#endif + return ReadBinaryName(buf, buf_len); +} + // Match full names of the form /path/to/base_name{-,.}* bool LibraryNameIs(const char *full_name, const char *base_name) { const char *name = full_name; @@ -913,41 +933,142 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, : "memory", "$29" ); return res; } -#endif // defined(__x86_64__) && SANITIZER_LINUX +#elif defined(__aarch64__) +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + long long res; + if (!fn || !child_stack) + return -EINVAL; + CHECK_EQ(0, (uptr)child_stack % 16); + child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); + ((unsigned long long *)child_stack)[0] = (uptr)fn; + ((unsigned long long *)child_stack)[1] = (uptr)arg; -#if SANITIZER_ANDROID -static atomic_uint8_t android_log_initialized; + register int (*__fn)(void *) __asm__("x0") = fn; + register void *__stack __asm__("x1") = child_stack; + register int __flags __asm__("x2") = flags; + register void *__arg __asm__("x3") = arg; + register int *__ptid __asm__("x4") = parent_tidptr; + register void *__tls __asm__("x5") = newtls; + register int *__ctid __asm__("x6") = child_tidptr; -void AndroidLogInit() { - atomic_store(&android_log_initialized, 1, memory_order_release); -} -// This thing is not, strictly speaking, async signal safe, but it does not seem -// to cause any issues. Alternative is writing to log devices directly, but -// their location and message format might change in the future, so we'd really -// like to avoid that. -void AndroidLogWrite(const char *buffer) { - if (!atomic_load(&android_log_initialized, memory_order_acquire)) - return; + __asm__ __volatile__( + "mov x0,x2\n" /* flags */ + "mov x2,x4\n" /* ptid */ + "mov x3,x5\n" /* tls */ + "mov x4,x6\n" /* ctid */ + "mov x8,%9\n" /* clone */ - char *copy = internal_strdup(buffer); - char *p = copy; - char *q; - // __android_log_write has an implicit message length limit. - // Print one line at a time. - do { - q = internal_strchr(p, '\n'); - if (q) *q = '\0'; - __android_log_write(ANDROID_LOG_INFO, NULL, p); - if (q) p = q + 1; - } while (q); - InternalFree(copy); + "svc 0x0\n" + + /* if (%r0 != 0) + * return %r0; + */ + "cmp x0, #0\n" + "bne 1f\n" + + /* In the child, now. Call "fn(arg)". */ + "ldp x1, x0, [sp], #16\n" + "blr x1\n" + + /* Call _exit(%r0). */ + "mov x8, %10\n" + "svc 0x0\n" + "1:\n" + + : "=r" (res) + : "i"(-EINVAL), + "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg), + "r"(__ptid), "r"(__tls), "r"(__ctid), + "i"(__NR_clone), "i"(__NR_exit) + : "x30", "memory"); + return res; } +#elif defined(__powerpc64__) +uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, + int *parent_tidptr, void *newtls, int *child_tidptr) { + long long res; +/* Stack frame offsets. */ +#if _CALL_ELF != 2 +#define FRAME_MIN_SIZE 112 +#define FRAME_TOC_SAVE 40 +#else +#define FRAME_MIN_SIZE 32 +#define FRAME_TOC_SAVE 24 +#endif + if (!fn || !child_stack) + return -EINVAL; + CHECK_EQ(0, (uptr)child_stack % 16); + child_stack = (char *)child_stack - 2 * sizeof(unsigned long long); + ((unsigned long long *)child_stack)[0] = (uptr)fn; + ((unsigned long long *)child_stack)[1] = (uptr)arg; -void GetExtraActivationFlags(char *buf, uptr size) { - CHECK(size > PROP_VALUE_MAX); - __system_property_get("asan.options", buf); + register int (*__fn)(void *) __asm__("r3") = fn; + register void *__cstack __asm__("r4") = child_stack; + register int __flags __asm__("r5") = flags; + register void * __arg __asm__("r6") = arg; + register int * __ptidptr __asm__("r7") = parent_tidptr; + register void * __newtls __asm__("r8") = newtls; + register int * __ctidptr __asm__("r9") = child_tidptr; + + __asm__ __volatile__( + /* fn, arg, child_stack are saved acrVoss the syscall */ + "mr 28, %5\n\t" + "mr 29, %6\n\t" + "mr 27, %8\n\t" + + /* syscall + r3 == flags + r4 == child_stack + r5 == parent_tidptr + r6 == newtls + r7 == child_tidptr */ + "mr 3, %7\n\t" + "mr 5, %9\n\t" + "mr 6, %10\n\t" + "mr 7, %11\n\t" + "li 0, %3\n\t" + "sc\n\t" + + /* Test if syscall was successful */ + "cmpdi cr1, 3, 0\n\t" + "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t" + "bne- cr1, 1f\n\t" + + /* Do the function call */ + "std 2, %13(1)\n\t" +#if _CALL_ELF != 2 + "ld 0, 0(28)\n\t" + "ld 2, 8(28)\n\t" + "mtctr 0\n\t" +#else + "mr 12, 28\n\t" + "mtctr 12\n\t" +#endif + "mr 3, 27\n\t" + "bctrl\n\t" + "ld 2, %13(1)\n\t" + + /* Call _exit(r3) */ + "li 0, %4\n\t" + "sc\n\t" + + /* Return to parent */ + "1:\n\t" + "mr %0, 3\n\t" + : "=r" (res) + : "0" (-1), "i" (EINVAL), + "i" (__NR_clone), "i" (__NR_exit), + "r" (__fn), "r" (__cstack), "r" (__flags), + "r" (__arg), "r" (__ptidptr), "r" (__newtls), + "r" (__ctidptr), "i" (FRAME_MIN_SIZE), "i" (FRAME_TOC_SAVE) + : "cr0", "cr1", "memory", "ctr", + "r0", "r29", "r27", "r28"); + return res; } +#endif // defined(__x86_64__) && SANITIZER_LINUX +#if SANITIZER_ANDROID #if __ANDROID_API__ < 21 extern "C" __attribute__((weak)) int dl_iterate_phdr( int (*)(struct dl_phdr_info *, size_t, void *), void *); @@ -993,6 +1114,10 @@ AndroidApiLevel AndroidGetApiLevel() { bool IsDeadlySignal(int signum) { if (common_flags()->handle_abort && signum == SIGABRT) return true; + if (common_flags()->handle_sigill && signum == SIGILL) + return true; + if (common_flags()->handle_sigfpe && signum == SIGFPE) + return true; return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv; } @@ -1008,13 +1133,13 @@ void *internal_start_thread(void(*func)(void *arg), void *arg) { #endif internal_sigprocmask(SIG_SETMASK, &set, &old); void *th; - real_pthread_create(&th, 0, (void*(*)(void *arg))func, arg); - internal_sigprocmask(SIG_SETMASK, &old, 0); + real_pthread_create(&th, nullptr, (void*(*)(void *arg))func, arg); + internal_sigprocmask(SIG_SETMASK, &old, nullptr); return th; } void internal_join_thread(void *th) { - real_pthread_join(th, 0); + real_pthread_join(th, nullptr); } #else void *internal_start_thread(void (*func)(void *), void *arg) { return 0; } @@ -1094,6 +1219,14 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { #endif } -} // namespace __sanitizer +void DisableReexec() { + // No need to re-exec on Linux. +} + +void MaybeReexec() { + // No need to re-exec on Linux. +} + +} // namespace __sanitizer -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h index e9fc4ad448d8..77bfbd156815 100644 --- a/lib/sanitizer_common/sanitizer_linux.h +++ b/lib/sanitizer_common/sanitizer_linux.h @@ -44,7 +44,8 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5); // internal_sigaction instead. int internal_sigaction_norestorer(int signum, const void *act, void *oldact); void internal_sigdelset(__sanitizer_sigset_t *set, int signum); -#if defined(__x86_64__) || defined(__mips__) +#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) \ + || defined(__powerpc64__) uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr); #endif diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc index 39eb1d216b2e..0bb66c9d634e 100644 --- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc @@ -13,8 +13,10 @@ //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" + #if SANITIZER_FREEBSD || SANITIZER_LINUX +#include "sanitizer_allocator_internal.h" #include "sanitizer_atomic.h" #include "sanitizer_common.h" #include "sanitizer_flags.h" @@ -47,6 +49,12 @@ #include <android/api-level.h> #endif +#if SANITIZER_ANDROID && __ANDROID_API__ < 21 +#include <android/log.h> +#else +#include <syslog.h> +#endif + #if !SANITIZER_ANDROID #include <elf.h> #include <unistd.h> @@ -54,20 +62,6 @@ namespace __sanitizer { -// This function is defined elsewhere if we intercepted pthread_attr_getstack. -extern "C" { -SANITIZER_WEAK_ATTRIBUTE int -real_pthread_attr_getstack(void *attr, void **addr, size_t *size); -} // extern "C" - -static int my_pthread_attr_getstack(void *attr, void **addr, size_t *size) { -#if !SANITIZER_GO - if (&real_pthread_attr_getstack) - return real_pthread_attr_getstack((pthread_attr_t *)attr, addr, size); -#endif - return pthread_attr_getstack((pthread_attr_t *)attr, addr, size); -} - SANITIZER_WEAK_ATTRIBUTE int real_sigaction(int signum, const void *act, void *oldact); @@ -93,7 +87,8 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, MemoryMappingLayout proc_maps(/*cache_enabled*/true); uptr start, end, offset; uptr prev_end = 0; - while (proc_maps.Next(&start, &end, &offset, 0, 0, /* protection */0)) { + while (proc_maps.Next(&start, &end, &offset, nullptr, 0, + /* protection */nullptr)) { if ((uptr)&rl < end) break; prev_end = end; @@ -118,8 +113,8 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, pthread_attr_init(&attr); CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0); uptr stacksize = 0; - void *stackaddr = 0; - my_pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize); + void *stackaddr = nullptr; + my_pthread_attr_getstack(&attr, &stackaddr, &stacksize); pthread_attr_destroy(&attr); CHECK_LE(stacksize, kMaxThreadStackSize); // Sanity check. @@ -130,7 +125,7 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, #if !SANITIZER_GO bool SetEnv(const char *name, const char *value) { void *f = dlsym(RTLD_NEXT, "setenv"); - if (f == 0) + if (!f) return false; typedef int(*setenv_ft)(const char *name, const char *value, int overwrite); setenv_ft setenv_f; @@ -161,7 +156,7 @@ bool SanitizerGetThreadName(char *name, int max_len) { #endif } -#if !SANITIZER_FREEBSD +#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO static uptr g_tls_size; #endif @@ -171,11 +166,15 @@ static uptr g_tls_size; # define DL_INTERNAL_FUNCTION #endif -#if defined(__mips__) +#if defined(__mips__) || defined(__powerpc64__) // TlsPreTcbSize includes size of struct pthread_descr and size of tcb // head structure. It lies before the static tls blocks. static uptr TlsPreTcbSize() { - const uptr kTcbHead = 16; +# if defined(__mips__) + const uptr kTcbHead = 16; // sizeof (tcbhead_t) +# elif defined(__powerpc64__) + const uptr kTcbHead = 88; // sizeof (tcbhead_t) +# endif const uptr kTlsAlign = 16; const uptr kTlsPreTcbSize = (ThreadDescriptorSize() + kTcbHead + kTlsAlign - 1) & ~(kTlsAlign - 1); @@ -187,6 +186,8 @@ static uptr TlsPreTcbSize() { void InitTlsSize() { #if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO +// all current supported platforms have 16 bytes stack alignment + const size_t kStackAlign = 16; typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION; get_tls_func get_tls; void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info"); @@ -197,13 +198,16 @@ void InitTlsSize() { size_t tls_size = 0; size_t tls_align = 0; get_tls(&tls_size, &tls_align); - g_tls_size = tls_size; -#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID + if (tls_align < kStackAlign) + tls_align = kStackAlign; + g_tls_size = RoundUpTo(tls_size, tls_align); +#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO } -#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__)) \ - && SANITIZER_LINUX -// sizeof(struct thread) from glibc. +#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) \ + || defined(__aarch64__) || defined(__powerpc64__)) \ + && SANITIZER_LINUX && !SANITIZER_ANDROID +// sizeof(struct pthread) from glibc. static atomic_uintptr_t kThreadDescriptorSize; uptr ThreadDescriptorSize() { @@ -218,7 +222,7 @@ uptr ThreadDescriptorSize() { char *end; int minor = internal_simple_strtoll(buf + 8, &end, 10); if (end != buf + 8 && (*end == '\0' || *end == '.')) { - /* sizeof(struct thread) values from various glibc versions. */ + /* sizeof(struct pthread) values from various glibc versions. */ if (SANITIZER_X32) val = 1728; // Assume only one particular version for x32. else if (minor <= 3) @@ -249,6 +253,15 @@ uptr ThreadDescriptorSize() { if (val) atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed); return val; +#elif defined(__aarch64__) + // The sizeof (struct pthread) is the same from GLIBC 2.17 to 2.22. + val = 1776; + atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed); + return val; +#elif defined(__powerpc64__) + val = 1776; // from glibc.ppc64le 2.20-8.fc21 + atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed); + return val; #endif return 0; } @@ -278,6 +291,17 @@ uptr ThreadSelf() { rdhwr %0,$29;\ .set pop" : "=r" (thread_pointer)); descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize(); +# elif defined(__aarch64__) + descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()); +# elif defined(__powerpc64__) + // PPC64LE uses TLS variant I. The thread pointer (in GPR 13) + // points to the end of the TCB + 0x7000. The pthread_descr structure is + // immediately in front of the TCB. TlsPreTcbSize() includes the size of the + // TCB and the size of pthread_descr. + const uptr kTlsTcbOffset = 0x7000; + uptr thread_pointer; + asm("addi %0,13,%1" : "=r"(thread_pointer) : "I"(-kTlsTcbOffset)); + descr_addr = thread_pointer - TlsPreTcbSize(); # else # error "unsupported CPU arch" # endif @@ -307,13 +331,13 @@ uptr ThreadSelf() { #if !SANITIZER_GO static void GetTls(uptr *addr, uptr *size) { -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_ANDROID # if defined(__x86_64__) || defined(__i386__) *addr = ThreadSelf(); *size = GetTlsSize(); *addr -= *size; *addr += ThreadDescriptorSize(); -# elif defined(__mips__) +# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) *addr = ThreadSelf(); *size = GetTlsSize(); # else @@ -333,6 +357,9 @@ static void GetTls(uptr *addr, uptr *size) { *addr = (uptr) dtv[2]; *size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]); } +#elif SANITIZER_ANDROID + *addr = 0; + *size = 0; #else # error "Unknown OS" #endif @@ -341,7 +368,7 @@ static void GetTls(uptr *addr, uptr *size) { #if !SANITIZER_GO uptr GetTlsSize() { -#if SANITIZER_FREEBSD +#if SANITIZER_FREEBSD || SANITIZER_ANDROID uptr addr, size; GetTls(&addr, &size); return size; @@ -376,31 +403,6 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, #endif } -void AdjustStackSize(void *attr_) { - pthread_attr_t *attr = (pthread_attr_t *)attr_; - uptr stackaddr = 0; - size_t stacksize = 0; - my_pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize); - // GLibC will return (0 - stacksize) as the stack address in the case when - // stacksize is set, but stackaddr is not. - bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0); - // We place a lot of tool data into TLS, account for that. - const uptr minstacksize = GetTlsSize() + 128*1024; - if (stacksize < minstacksize) { - if (!stack_set) { - if (stacksize != 0) { - VPrintf(1, "Sanitizer: increasing stacksize %zu->%zu\n", stacksize, - minstacksize); - pthread_attr_setstacksize(attr, minstacksize); - } - } else { - Printf("Sanitizer: pre-allocated stack size is insufficient: " - "%zu < %zu\n", stacksize, minstacksize); - Printf("Sanitizer: pthread_create is likely to fail.\n"); - } - } -} - # if !SANITIZER_FREEBSD typedef ElfW(Phdr) Elf_Phdr; # elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2 @@ -455,7 +457,7 @@ extern "C" __attribute__((weak)) int dl_iterate_phdr( uptr GetListOfModules(LoadedModule *modules, uptr max_modules, string_predicate_t filter) { -#if SANITIZER_ANDROID && __ANDROID_API__ < 21 +#if SANITIZER_ANDROID && __ANDROID_API__ <= 22 u32 api_level = AndroidGetApiLevel(); // Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken. // The runtime check allows the same library to work with @@ -510,6 +512,37 @@ uptr GetRSS() { return rss * GetPageSizeCached(); } -} // namespace __sanitizer +// 64-bit Android targets don't provide the deprecated __android_log_write. +// Starting with the L release, syslog() works and is preferable to +// __android_log_write. +#if SANITIZER_LINUX + +#if SANITIZER_ANDROID +static atomic_uint8_t android_log_initialized; + +void AndroidLogInit() { + atomic_store(&android_log_initialized, 1, memory_order_release); +} + +bool ShouldLogAfterPrintf() { + return atomic_load(&android_log_initialized, memory_order_acquire); +} +#else +void AndroidLogInit() {} + +bool ShouldLogAfterPrintf() { return true; } +#endif // SANITIZER_ANDROID + +void WriteOneLineToSyslog(const char *s) { +#if SANITIZER_ANDROID &&__ANDROID_API__ < 21 + __android_log_write(ANDROID_LOG_INFO, NULL, s); +#else + syslog(LOG_INFO, "%s", s); +#endif +} + +#endif // SANITIZER_LINUX + +} // namespace __sanitizer -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/lib/sanitizer_common/sanitizer_list.h b/lib/sanitizer_common/sanitizer_list.h index 6dd9c8f7bca1..adbb97dc70dc 100644 --- a/lib/sanitizer_common/sanitizer_list.h +++ b/lib/sanitizer_common/sanitizer_list.h @@ -11,6 +11,7 @@ // ThreadSanitizer, etc run-times. // //===----------------------------------------------------------------------===// + #ifndef SANITIZER_LIST_H #define SANITIZER_LIST_H @@ -29,7 +30,7 @@ struct IntrusiveList { friend class Iterator; void clear() { - first_ = last_ = 0; + first_ = last_ = nullptr; size_ = 0; } @@ -38,11 +39,11 @@ struct IntrusiveList { void push_back(Item *x) { if (empty()) { - x->next = 0; + x->next = nullptr; first_ = last_ = x; size_ = 1; } else { - x->next = 0; + x->next = nullptr; last_->next = x; last_ = x; size_++; @@ -51,7 +52,7 @@ struct IntrusiveList { void push_front(Item *x) { if (empty()) { - x->next = 0; + x->next = nullptr; first_ = last_ = x; size_ = 1; } else { @@ -64,8 +65,8 @@ struct IntrusiveList { void pop_front() { CHECK(!empty()); first_ = first_->next; - if (first_ == 0) - last_ = 0; + if (!first_) + last_ = nullptr; size_--; } @@ -125,7 +126,7 @@ struct IntrusiveList { if (current_) current_ = current_->next; return ret; } - bool hasNext() const { return current_ != 0; } + bool hasNext() const { return current_ != nullptr; } private: ListTy *list_; ItemTy *current_; @@ -140,6 +141,6 @@ struct IntrusiveList { Item *last_; }; -} // namespace __sanitizer +} // namespace __sanitizer -#endif // SANITIZER_LIST_H +#endif // SANITIZER_LIST_H diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc index dddce1c1583c..1c96a6b95621 100644 --- a/lib/sanitizer_common/sanitizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_mac.cc @@ -13,6 +13,7 @@ #include "sanitizer_platform.h" #if SANITIZER_MAC +#include "sanitizer_mac.h" // Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so // the clients will most certainly use 64-bit ones as well. @@ -25,7 +26,6 @@ #include "sanitizer_flags.h" #include "sanitizer_internal_defs.h" #include "sanitizer_libc.h" -#include "sanitizer_mac.h" #include "sanitizer_placement_new.h" #include "sanitizer_platform_limits_posix.h" #include "sanitizer_procmaps.h" @@ -36,11 +36,29 @@ extern char **environ; #endif +#if defined(__has_include) && __has_include(<os/trace.h>) +#define SANITIZER_OS_TRACE 1 +#include <os/trace.h> +#else +#define SANITIZER_OS_TRACE 0 +#endif + +#if !SANITIZER_IOS +#include <crt_externs.h> // for _NSGetArgv and _NSGetEnviron +#else +extern "C" { + extern char ***_NSGetArgv(void); +} +#endif + +#include <asl.h> +#include <dlfcn.h> // for dladdr() #include <errno.h> #include <fcntl.h> #include <libkern/OSAtomic.h> #include <mach-o/dyld.h> #include <mach/mach.h> +#include <mach/vm_statistics.h> #include <pthread.h> #include <sched.h> #include <signal.h> @@ -51,6 +69,7 @@ extern char **environ; #include <sys/sysctl.h> #include <sys/types.h> #include <unistd.h> +#include <util.h> namespace __sanitizer { @@ -59,6 +78,7 @@ namespace __sanitizer { // ---------------------- sanitizer_libc.h uptr internal_mmap(void *addr, size_t length, int prot, int flags, int fd, u64 offset) { + if (fd == -1) fd = VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL); return (uptr)mmap(addr, length, prot, flags, fd, offset); } @@ -145,9 +165,30 @@ uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, return sigprocmask(how, set, oldset); } +// Doesn't call pthread_atfork() handlers. +extern "C" pid_t __fork(void); + int internal_fork() { - // TODO(glider): this may call user's pthread_atfork() handlers which is bad. - return fork(); + return __fork(); +} + +int internal_forkpty(int *amaster) { + int master, slave; + if (openpty(&master, &slave, nullptr, nullptr, nullptr) == -1) return -1; + int pid = __fork(); + if (pid == -1) { + close(master); + close(slave); + return -1; + } + if (pid == 0) { + close(master); + CHECK_EQ(login_tty(slave), 0); + } else { + *amaster = master; + close(slave); + } + return pid; } uptr internal_rename(const char *oldpath, const char *newpath) { @@ -178,7 +219,7 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, uptr stacksize = pthread_get_stacksize_np(pthread_self()); // pthread_get_stacksize_np() returns an incorrect stack size for the main // thread on Mavericks. See - // https://code.google.com/p/address-sanitizer/issues/detail?id=261 + // https://github.com/google/sanitizers/issues/261 if ((GetMacosVersion() >= MACOS_VERSION_MAVERICKS) && at_initialization && stacksize == (1 << 19)) { struct rlimit rl; @@ -241,6 +282,10 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { return 0; } +uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { + return ReadBinaryName(buf, buf_len); +} + void ReExec() { UNIMPLEMENTED(); } @@ -365,8 +410,63 @@ uptr GetRSS() { return info.resident_size; } -void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; } -void internal_join_thread(void *th) { } +void *internal_start_thread(void(*func)(void *arg), void *arg) { + // Start the thread with signals blocked, otherwise it can steal user signals. + __sanitizer_sigset_t set, old; + internal_sigfillset(&set); + internal_sigprocmask(SIG_SETMASK, &set, &old); + pthread_t th; + pthread_create(&th, 0, (void*(*)(void *arg))func, arg); + internal_sigprocmask(SIG_SETMASK, &old, 0); + return th; +} + +void internal_join_thread(void *th) { pthread_join((pthread_t)th, 0); } + +static BlockingMutex syslog_lock(LINKER_INITIALIZED); + +void WriteOneLineToSyslog(const char *s) { + syslog_lock.CheckLocked(); + asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s); +} + +void LogFullErrorReport(const char *buffer) { + // Log with os_trace. This will make it into the crash log. +#if SANITIZER_OS_TRACE + if (GetMacosVersion() >= MACOS_VERSION_YOSEMITE) { + // os_trace requires the message (format parameter) to be a string literal. + if (internal_strncmp(SanitizerToolName, "AddressSanitizer", + sizeof("AddressSanitizer") - 1) == 0) + os_trace("Address Sanitizer reported a failure."); + else if (internal_strncmp(SanitizerToolName, "UndefinedBehaviorSanitizer", + sizeof("UndefinedBehaviorSanitizer") - 1) == 0) + os_trace("Undefined Behavior Sanitizer reported a failure."); + else if (internal_strncmp(SanitizerToolName, "ThreadSanitizer", + sizeof("ThreadSanitizer") - 1) == 0) + os_trace("Thread Sanitizer reported a failure."); + else + os_trace("Sanitizer tool reported a failure."); + + if (common_flags()->log_to_syslog) + os_trace("Consult syslog for more information."); + } +#endif + + // Log to syslog. + // The logging on OS X may call pthread_create so we need the threading + // environment to be fully initialized. Also, this should never be called when + // holding the thread registry lock since that may result in a deadlock. If + // the reporting thread holds the thread registry mutex, and asl_log waits + // for GCD to dispatch a new thread, the process will deadlock, because the + // pthread_create wrapper needs to acquire the lock as well. + BlockingMutexLock l(&syslog_lock); + if (common_flags()->log_to_syslog) + WriteToSyslog(buffer); + + // Log to CrashLog. + if (common_flags()->abort_on_error) + CRSetCrashLogMessage(buffer); +} void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { ucontext_t *ucontext = (ucontext_t*)context; @@ -395,6 +495,173 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { # endif } +static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES"; +LowLevelAllocator allocator_for_env; + +// Change the value of the env var |name|, leaking the original value. +// If |name_value| is NULL, the variable is deleted from the environment, +// otherwise the corresponding "NAME=value" string is replaced with +// |name_value|. +void LeakyResetEnv(const char *name, const char *name_value) { + char **env = GetEnviron(); + uptr name_len = internal_strlen(name); + while (*env != 0) { + uptr len = internal_strlen(*env); + if (len > name_len) { + const char *p = *env; + if (!internal_memcmp(p, name, name_len) && p[name_len] == '=') { + // Match. + if (name_value) { + // Replace the old value with the new one. + *env = const_cast<char*>(name_value); + } else { + // Shift the subsequent pointers back. + char **del = env; + do { + del[0] = del[1]; + } while (*del++); + } + } + } + env++; + } +} + +static bool reexec_disabled = false; + +void DisableReexec() { + reexec_disabled = true; +} + +extern "C" double dyldVersionNumber; +static const double kMinDyldVersionWithAutoInterposition = 360.0; + +bool DyldNeedsEnvVariable() { + // If running on OS X 10.11+ or iOS 9.0+, dyld will interpose even if + // DYLD_INSERT_LIBRARIES is not set. However, checking OS version via + // GetMacosVersion() doesn't work for the simulator. Let's instead check + // `dyldVersionNumber`, which is exported by dyld, against a known version + // number from the first OS release where this appeared. + return dyldVersionNumber < kMinDyldVersionWithAutoInterposition; +} + +void MaybeReexec() { + if (reexec_disabled) return; + + // Make sure the dynamic runtime library is preloaded so that the + // wrappers work. If it is not, set DYLD_INSERT_LIBRARIES and re-exec + // ourselves. + Dl_info info; + CHECK(dladdr((void*)((uptr)&__sanitizer_report_error_summary), &info)); + char *dyld_insert_libraries = + const_cast<char*>(GetEnv(kDyldInsertLibraries)); + uptr old_env_len = dyld_insert_libraries ? + internal_strlen(dyld_insert_libraries) : 0; + uptr fname_len = internal_strlen(info.dli_fname); + const char *dylib_name = StripModuleName(info.dli_fname); + uptr dylib_name_len = internal_strlen(dylib_name); + + bool lib_is_in_env = dyld_insert_libraries && + internal_strstr(dyld_insert_libraries, dylib_name); + if (DyldNeedsEnvVariable() && !lib_is_in_env) { + // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime + // library. + InternalScopedString program_name(1024); + uint32_t buf_size = program_name.size(); + _NSGetExecutablePath(program_name.data(), &buf_size); + char *new_env = const_cast<char*>(info.dli_fname); + if (dyld_insert_libraries) { + // Append the runtime dylib name to the existing value of + // DYLD_INSERT_LIBRARIES. + new_env = (char*)allocator_for_env.Allocate(old_env_len + fname_len + 2); + internal_strncpy(new_env, dyld_insert_libraries, old_env_len); + new_env[old_env_len] = ':'; + // Copy fname_len and add a trailing zero. + internal_strncpy(new_env + old_env_len + 1, info.dli_fname, + fname_len + 1); + // Ok to use setenv() since the wrappers don't depend on the value of + // asan_inited. + setenv(kDyldInsertLibraries, new_env, /*overwrite*/1); + } else { + // Set DYLD_INSERT_LIBRARIES equal to the runtime dylib name. + setenv(kDyldInsertLibraries, info.dli_fname, /*overwrite*/0); + } + VReport(1, "exec()-ing the program with\n"); + VReport(1, "%s=%s\n", kDyldInsertLibraries, new_env); + VReport(1, "to enable wrappers.\n"); + execv(program_name.data(), *_NSGetArgv()); + + // We get here only if execv() failed. + Report("ERROR: The process is launched without DYLD_INSERT_LIBRARIES, " + "which is required for the sanitizer to work. We tried to set the " + "environment variable and re-execute itself, but execv() failed, " + "possibly because of sandbox restrictions. Make sure to launch the " + "executable with:\n%s=%s\n", kDyldInsertLibraries, new_env); + CHECK("execv failed" && 0); + } + + if (!lib_is_in_env) + return; + + // DYLD_INSERT_LIBRARIES is set and contains the runtime library. Let's remove + // the dylib from the environment variable, because interceptors are installed + // and we don't want our children to inherit the variable. + + uptr env_name_len = internal_strlen(kDyldInsertLibraries); + // Allocate memory to hold the previous env var name, its value, the '=' + // sign and the '\0' char. + char *new_env = (char*)allocator_for_env.Allocate( + old_env_len + 2 + env_name_len); + CHECK(new_env); + internal_memset(new_env, '\0', old_env_len + 2 + env_name_len); + internal_strncpy(new_env, kDyldInsertLibraries, env_name_len); + new_env[env_name_len] = '='; + char *new_env_pos = new_env + env_name_len + 1; + + // Iterate over colon-separated pieces of |dyld_insert_libraries|. + char *piece_start = dyld_insert_libraries; + char *piece_end = NULL; + char *old_env_end = dyld_insert_libraries + old_env_len; + do { + if (piece_start[0] == ':') piece_start++; + piece_end = internal_strchr(piece_start, ':'); + if (!piece_end) piece_end = dyld_insert_libraries + old_env_len; + if ((uptr)(piece_start - dyld_insert_libraries) > old_env_len) break; + uptr piece_len = piece_end - piece_start; + + char *filename_start = + (char *)internal_memrchr(piece_start, '/', piece_len); + uptr filename_len = piece_len; + if (filename_start) { + filename_start += 1; + filename_len = piece_len - (filename_start - piece_start); + } else { + filename_start = piece_start; + } + + // If the current piece isn't the runtime library name, + // append it to new_env. + if ((dylib_name_len != filename_len) || + (internal_memcmp(filename_start, dylib_name, dylib_name_len) != 0)) { + if (new_env_pos != new_env + env_name_len + 1) { + new_env_pos[0] = ':'; + new_env_pos++; + } + internal_strncpy(new_env_pos, piece_start, piece_len); + new_env_pos += piece_len; + } + // Move on to the next piece. + piece_start = piece_end; + } while (piece_start < old_env_end); + + // Can't use setenv() here, because it requires the allocator to be + // initialized. + // FIXME: instead of filtering DYLD_INSERT_LIBRARIES here, do it in + // a separate function called after InitializeAllocator(). + if (new_env_pos == new_env + env_name_len + 1) new_env = NULL; + LeakyResetEnv(kDyldInsertLibraries, new_env); +} + } // namespace __sanitizer #endif // SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_mac.h b/lib/sanitizer_common/sanitizer_mac.h index 50dbe93226c2..86a9956683d0 100644 --- a/lib/sanitizer_common/sanitizer_mac.h +++ b/lib/sanitizer_common/sanitizer_mac.h @@ -13,6 +13,7 @@ #ifndef SANITIZER_MAC_H #define SANITIZER_MAC_H +#include "sanitizer_common.h" #include "sanitizer_platform.h" #if SANITIZER_MAC #include "sanitizer_posix.h" @@ -37,5 +38,16 @@ char **GetEnviron(); } // namespace __sanitizer +extern "C" { +static char __crashreporter_info_buff__[kErrorMessageBufferSize] = {}; +static const char *__crashreporter_info__ __attribute__((__used__)) = + &__crashreporter_info_buff__[0]; +asm(".desc ___crashreporter_info__, 0x10"); +} // extern "C" + +INLINE void CRSetCrashLogMessage(const char *msg) { + internal_strlcpy(__crashreporter_info_buff__, msg, + sizeof(__crashreporter_info_buff__)); } + #endif // SANITIZER_MAC #endif // SANITIZER_MAC_H diff --git a/lib/sanitizer_common/sanitizer_malloc_mac.inc b/lib/sanitizer_common/sanitizer_malloc_mac.inc new file mode 100644 index 000000000000..149857c168c6 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_malloc_mac.inc @@ -0,0 +1,329 @@ +//===-- sanitizer_malloc_mac.inc --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains Mac-specific malloc interceptors and a custom zone +// implementation, which together replace the system allocator. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" +#if !SANITIZER_MAC +#error "This file should only be compiled on Darwin." +#endif + +#include <AvailabilityMacros.h> +#include <CoreFoundation/CFBase.h> +#include <dlfcn.h> +#include <malloc/malloc.h> +#include <sys/mman.h> + +#include "interception/interception.h" +#include "sanitizer_common/sanitizer_mac.h" + +// Similar code is used in Google Perftools, +// https://github.com/gperftools/gperftools. + +static malloc_zone_t sanitizer_zone; + +INTERCEPTOR(malloc_zone_t *, malloc_create_zone, + vm_size_t start_size, unsigned zone_flags) { + COMMON_MALLOC_ENTER(); + uptr page_size = GetPageSizeCached(); + uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size); + COMMON_MALLOC_MEMALIGN(page_size, allocated_size); + malloc_zone_t *new_zone = (malloc_zone_t *)p; + internal_memcpy(new_zone, &sanitizer_zone, sizeof(sanitizer_zone)); + new_zone->zone_name = NULL; // The name will be changed anyway. + if (GetMacosVersion() >= MACOS_VERSION_LION) { + // Prevent the client app from overwriting the zone contents. + // Library functions that need to modify the zone will set PROT_WRITE on it. + // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher. + mprotect(new_zone, allocated_size, PROT_READ); + } + return new_zone; +} + +INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) { + COMMON_MALLOC_ENTER(); + return &sanitizer_zone; +} + +INTERCEPTOR(malloc_zone_t *, malloc_default_purgeable_zone, void) { + // FIXME: ASan should support purgeable allocations. + // https://github.com/google/sanitizers/issues/139 + COMMON_MALLOC_ENTER(); + return &sanitizer_zone; +} + +INTERCEPTOR(void, malloc_make_purgeable, void *ptr) { + // FIXME: ASan should support purgeable allocations. Ignoring them is fine + // for now. + COMMON_MALLOC_ENTER(); +} + +INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) { + // FIXME: ASan should support purgeable allocations. Ignoring them is fine + // for now. + COMMON_MALLOC_ENTER(); + // Must return 0 if the contents were not purged since the last call to + // malloc_make_purgeable(). + return 0; +} + +INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) { + COMMON_MALLOC_ENTER(); + // Allocate |sizeof(COMMON_MALLOC_ZONE_NAME "-") + internal_strlen(name)| + // bytes. + size_t buflen = + sizeof(COMMON_MALLOC_ZONE_NAME "-") + (name ? internal_strlen(name) : 0); + InternalScopedString new_name(buflen); + if (name && zone->introspect == sanitizer_zone.introspect) { + new_name.append(COMMON_MALLOC_ZONE_NAME "-%s", name); + name = new_name.data(); + } + + // Call the system malloc's implementation for both external and our zones, + // since that appropriately changes VM region protections on the zone. + REAL(malloc_set_zone_name)(zone, name); +} + +INTERCEPTOR(void *, malloc, size_t size) { + COMMON_MALLOC_ENTER(); + COMMON_MALLOC_MALLOC(size); + return p; +} + +INTERCEPTOR(void, free, void *ptr) { + COMMON_MALLOC_ENTER(); + if (!ptr) return; + COMMON_MALLOC_FREE(ptr); +} + +INTERCEPTOR(void *, realloc, void *ptr, size_t size) { + COMMON_MALLOC_ENTER(); + COMMON_MALLOC_REALLOC(ptr, size); + return p; +} + +INTERCEPTOR(void *, calloc, size_t nmemb, size_t size) { + COMMON_MALLOC_ENTER(); + COMMON_MALLOC_CALLOC(nmemb, size); + return p; +} + +INTERCEPTOR(void *, valloc, size_t size) { + COMMON_MALLOC_ENTER(); + COMMON_MALLOC_VALLOC(size); + return p; +} + +INTERCEPTOR(size_t, malloc_good_size, size_t size) { + COMMON_MALLOC_ENTER(); + return sanitizer_zone.introspect->good_size(&sanitizer_zone, size); +} + +INTERCEPTOR(int, posix_memalign, void **memptr, size_t alignment, size_t size) { + COMMON_MALLOC_ENTER(); + CHECK(memptr); + COMMON_MALLOC_MEMALIGN(alignment, size); + if (p) { + *memptr = p; + return 0; + } + return -1; +} + +namespace { + +// TODO(glider): the __sanitizer_mz_* functions should be united with the Linux +// wrappers, as they are basically copied from there. +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +size_t __sanitizer_mz_size(malloc_zone_t* zone, const void* ptr) { + COMMON_MALLOC_SIZE(ptr); + return size; +} + +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +void *__sanitizer_mz_malloc(malloc_zone_t *zone, uptr size) { + COMMON_MALLOC_ENTER(); + COMMON_MALLOC_MALLOC(size); + return p; +} + +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +void *__sanitizer_mz_calloc(malloc_zone_t *zone, size_t nmemb, size_t size) { + if (UNLIKELY(!COMMON_MALLOC_SANITIZER_INITIALIZED)) { + // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. + const size_t kCallocPoolSize = 1024; + static uptr calloc_memory_for_dlsym[kCallocPoolSize]; + static size_t allocated; + size_t size_in_words = ((nmemb * size) + kWordSize - 1) / kWordSize; + void *mem = (void*)&calloc_memory_for_dlsym[allocated]; + allocated += size_in_words; + CHECK(allocated < kCallocPoolSize); + return mem; + } + COMMON_MALLOC_CALLOC(nmemb, size); + return p; +} + +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +void *__sanitizer_mz_valloc(malloc_zone_t *zone, size_t size) { + COMMON_MALLOC_ENTER(); + COMMON_MALLOC_VALLOC(size); + return p; +} + +// TODO(glider): the allocation callbacks need to be refactored. +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_mz_free(malloc_zone_t *zone, void *ptr) { + if (!ptr) return; + COMMON_MALLOC_FREE(ptr); +} + +#define GET_ZONE_FOR_PTR(ptr) \ + malloc_zone_t *zone_ptr = malloc_zone_from_ptr(ptr); \ + const char *zone_name = (zone_ptr == 0) ? 0 : zone_ptr->zone_name + +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +void *__sanitizer_mz_realloc(malloc_zone_t *zone, void *ptr, size_t new_size) { + if (!ptr) { + COMMON_MALLOC_MALLOC(new_size); + return p; + } else { + COMMON_MALLOC_SIZE(ptr); + if (size) { + COMMON_MALLOC_REALLOC(ptr, new_size); + return p; + } else { + // We can't recover from reallocating an unknown address, because + // this would require reading at most |new_size| bytes from + // potentially unaccessible memory. + GET_ZONE_FOR_PTR(ptr); + COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name); + return nullptr; + } + } +} + +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +void __sanitizer_mz_destroy(malloc_zone_t* zone) { + // A no-op -- we will not be destroyed! + Report("__sanitizer_mz_destroy() called -- ignoring\n"); +} + +extern "C" +SANITIZER_INTERFACE_ATTRIBUTE +void *__sanitizer_mz_memalign(malloc_zone_t *zone, size_t align, size_t size) { + COMMON_MALLOC_ENTER(); + COMMON_MALLOC_MEMALIGN(align, size); + return p; +} + +// This function is currently unused, and we build with -Werror. +#if 0 +void __sanitizer_mz_free_definite_size( + malloc_zone_t* zone, void *ptr, size_t size) { + // TODO(glider): check that |size| is valid. + UNIMPLEMENTED(); +} +#endif + +kern_return_t mi_enumerator(task_t task, void *, + unsigned type_mask, vm_address_t zone_address, + memory_reader_t reader, + vm_range_recorder_t recorder) { + // Should enumerate all the pointers we have. Seems like a lot of work. + return KERN_FAILURE; +} + +size_t mi_good_size(malloc_zone_t *zone, size_t size) { + // I think it's always safe to return size, but we maybe could do better. + return size; +} + +boolean_t mi_check(malloc_zone_t *zone) { + UNIMPLEMENTED(); +} + +void mi_print(malloc_zone_t *zone, boolean_t verbose) { + UNIMPLEMENTED(); +} + +void mi_log(malloc_zone_t *zone, void *address) { + // I don't think we support anything like this +} + +void mi_force_lock(malloc_zone_t *zone) { + COMMON_MALLOC_FORCE_LOCK(); +} + +void mi_force_unlock(malloc_zone_t *zone) { + COMMON_MALLOC_FORCE_UNLOCK(); +} + +void mi_statistics(malloc_zone_t *zone, malloc_statistics_t *stats) { + COMMON_MALLOC_FILL_STATS(zone, stats); +} + +boolean_t mi_zone_locked(malloc_zone_t *zone) { + // UNIMPLEMENTED(); + return false; +} + +} // unnamed namespace + +namespace COMMON_MALLOC_NAMESPACE { + +void ReplaceSystemMalloc() { + static malloc_introspection_t sanitizer_zone_introspection; + // Ok to use internal_memset, these places are not performance-critical. + internal_memset(&sanitizer_zone_introspection, 0, + sizeof(sanitizer_zone_introspection)); + + sanitizer_zone_introspection.enumerator = &mi_enumerator; + sanitizer_zone_introspection.good_size = &mi_good_size; + sanitizer_zone_introspection.check = &mi_check; + sanitizer_zone_introspection.print = &mi_print; + sanitizer_zone_introspection.log = &mi_log; + sanitizer_zone_introspection.force_lock = &mi_force_lock; + sanitizer_zone_introspection.force_unlock = &mi_force_unlock; + sanitizer_zone_introspection.statistics = &mi_statistics; + sanitizer_zone_introspection.zone_locked = &mi_zone_locked; + + internal_memset(&sanitizer_zone, 0, sizeof(malloc_zone_t)); + + // Use version 6 for OSX >= 10.6. + sanitizer_zone.version = 6; + sanitizer_zone.zone_name = COMMON_MALLOC_ZONE_NAME; + sanitizer_zone.size = &__sanitizer_mz_size; + sanitizer_zone.malloc = &__sanitizer_mz_malloc; + sanitizer_zone.calloc = &__sanitizer_mz_calloc; + sanitizer_zone.valloc = &__sanitizer_mz_valloc; + sanitizer_zone.free = &__sanitizer_mz_free; + sanitizer_zone.realloc = &__sanitizer_mz_realloc; + sanitizer_zone.destroy = &__sanitizer_mz_destroy; + sanitizer_zone.batch_malloc = 0; + sanitizer_zone.batch_free = 0; + sanitizer_zone.free_definite_size = 0; + sanitizer_zone.memalign = &__sanitizer_mz_memalign; + sanitizer_zone.introspect = &sanitizer_zone_introspection; + + // Register the zone. + malloc_zone_register(&sanitizer_zone); +} + +} // namespace COMMON_MALLOC_NAMESPACE diff --git a/lib/sanitizer_common/sanitizer_persistent_allocator.h b/lib/sanitizer_common/sanitizer_persistent_allocator.h index 326406b12bfb..8e5ce06d4c3d 100644 --- a/lib/sanitizer_common/sanitizer_persistent_allocator.h +++ b/lib/sanitizer_common/sanitizer_persistent_allocator.h @@ -10,6 +10,7 @@ // A fast memory allocator that does not support free() nor realloc(). // All allocations are forever. //===----------------------------------------------------------------------===// + #ifndef SANITIZER_PERSISTENT_ALLOCATOR_H #define SANITIZER_PERSISTENT_ALLOCATOR_H @@ -36,7 +37,7 @@ inline void *PersistentAllocator::tryAlloc(uptr size) { for (;;) { uptr cmp = atomic_load(®ion_pos, memory_order_acquire); uptr end = atomic_load(®ion_end, memory_order_acquire); - if (cmp == 0 || cmp + size > end) return 0; + if (cmp == 0 || cmp + size > end) return nullptr; if (atomic_compare_exchange_weak(®ion_pos, &cmp, cmp + size, memory_order_acquire)) return (void *)cmp; @@ -68,4 +69,4 @@ inline void *PersistentAlloc(uptr sz) { } // namespace __sanitizer -#endif // SANITIZER_PERSISTENT_ALLOCATOR_H +#endif // SANITIZER_PERSISTENT_ALLOCATOR_H diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h index b47281b589e9..841cceb510a8 100644 --- a/lib/sanitizer_common/sanitizer_platform.h +++ b/lib/sanitizer_common/sanitizer_platform.h @@ -87,7 +87,7 @@ // For such platforms build this code with -DSANITIZER_CAN_USE_ALLOCATOR64=0 or // change the definition of SANITIZER_CAN_USE_ALLOCATOR64 here. #ifndef SANITIZER_CAN_USE_ALLOCATOR64 -# if defined(__aarch64__) || defined(__mips64) +# if defined(__mips64) || defined(__aarch64__) # define SANITIZER_CAN_USE_ALLOCATOR64 0 # else # define SANITIZER_CAN_USE_ALLOCATOR64 (SANITIZER_WORDSIZE == 64) @@ -95,12 +95,9 @@ #endif // The range of addresses which can be returned my mmap. -// FIXME: this value should be different on different platforms, -// e.g. on AArch64 it is most likely (1ULL << 39). Larger values will still work -// but will consume more memory for TwoLevelByteMap. -#if defined(__aarch64__) -# define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 39) -#elif defined(__mips__) +// FIXME: this value should be different on different platforms. Larger values +// will still work but will consume more memory for TwoLevelByteMap. +#if defined(__mips__) # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 40) #else # define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47) @@ -130,7 +127,7 @@ #define SANITIZER_USES_UID16_SYSCALLS 0 #endif -#ifdef __mips__ +#if defined(__mips__) # define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 10) #else # define SANITIZER_POINTER_FORMAT_LENGTH FIRST_32_SECOND_64(8, 12) @@ -142,4 +139,15 @@ # define HAVE_TIRPC_RPC_XDR_H 0 #endif +/// \macro MSC_PREREQ +/// \brief Is the compiler MSVC of at least the specified version? +/// The common \param version values to check for are: +/// * 1800: Microsoft Visual Studio 2013 / 12.0 +/// * 1900: Microsoft Visual Studio 2015 / 14.0 +#ifdef _MSC_VER +# define MSC_PREREQ(version) (_MSC_VER >= (version)) +#else +# define MSC_PREREQ(version) 0 +#endif + #endif // SANITIZER_PLATFORM_H diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h index 77cc84cd03af..430ad4839809 100644 --- a/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -60,6 +60,7 @@ #define SANITIZER_INTERCEPT_STRPBRK 1 #define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_MEMCMP 1 #define SANITIZER_INTERCEPT_MEMCHR 1 #define SANITIZER_INTERCEPT_MEMRCHR SI_FREEBSD || SI_LINUX @@ -132,7 +133,7 @@ #define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTRACE SI_LINUX_NOT_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__)) + defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__)) #define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX_NOT_ANDROID @@ -142,6 +143,8 @@ #define SANITIZER_INTERCEPT_WCSTOMBS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_WCSNRTOMBS \ SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_WCRTOMB \ + SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_REALPATH SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME SI_LINUX_NOT_ANDROID @@ -217,7 +220,7 @@ // FIXME: getline seems to be available on OSX 10.7 #define SANITIZER_INTERCEPT_GETLINE SI_FREEBSD || SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD +#define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD || SI_MAC #define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \ @@ -253,5 +256,13 @@ #define SANITIZER_INTERCEPT_MLOCKX SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_FOPENCOOKIE SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_SEM SI_LINUX || SI_FREEBSD +#define SANITIZER_INTERCEPT_PTHREAD_SETCANCEL SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_MINCORE SI_LINUX +#define SANITIZER_INTERCEPT_PROCESS_VM_READV SI_LINUX +#define SANITIZER_INTERCEPT_CTERMID SI_LINUX || SI_MAC || SI_FREEBSD +#define SANITIZER_INTERCEPT_CTERMID_R SI_MAC || SI_FREEBSD + +#define SANITIZER_INTERCEPTOR_HOOKS SI_LINUX #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc index aaa37ed02ebd..b642cba0fede 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc @@ -12,8 +12,8 @@ // Sizes and layouts of platform-specific POSIX data structures. //===----------------------------------------------------------------------===// - #include "sanitizer_platform.h" + #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC // Tests in this file assume that off_t-dependent data structures match the // libc ABI. For example, struct dirent here is what readdir() function (as @@ -119,9 +119,17 @@ #if SANITIZER_LINUX || SANITIZER_FREEBSD # include <utime.h> # include <sys/ptrace.h> -# if defined(__mips64) +# if defined(__mips64) || defined(__aarch64__) || defined(__arm__) # include <asm/ptrace.h> +# ifdef __arm__ +typedef struct user_fpregs elf_fpregset_t; +# define ARM_VFPREGS_SIZE_ASAN (32 * 8 /*fpregs*/ + 4 /*fpscr*/) +# if !defined(ARM_VFPREGS_SIZE) +# define ARM_VFPREGS_SIZE ARM_VFPREGS_SIZE_ASAN +# endif +# endif # endif +# include <semaphore.h> #endif #if !SANITIZER_ANDROID @@ -195,7 +203,7 @@ namespace __sanitizer { unsigned struct_stat_sz = sizeof(struct stat); #if !SANITIZER_IOS && !SANITIZER_FREEBSD unsigned struct_stat64_sz = sizeof(struct stat64); -#endif // !SANITIZER_IOS && !SANITIZER_FREEBSD +#endif // !SANITIZER_IOS && !SANITIZER_FREEBSD unsigned struct_rusage_sz = sizeof(struct rusage); unsigned struct_tm_sz = sizeof(struct tm); unsigned struct_passwd_sz = sizeof(struct passwd); @@ -236,27 +244,27 @@ namespace __sanitizer { unsigned struct_new_utsname_sz = sizeof(struct new_utsname); unsigned struct_old_utsname_sz = sizeof(struct old_utsname); unsigned struct_oldold_utsname_sz = sizeof(struct oldold_utsname); -#endif // SANITIZER_LINUX +#endif // SANITIZER_LINUX #if SANITIZER_LINUX || SANITIZER_FREEBSD unsigned struct_rlimit_sz = sizeof(struct rlimit); unsigned struct_timespec_sz = sizeof(struct timespec); unsigned struct_utimbuf_sz = sizeof(struct utimbuf); unsigned struct_itimerspec_sz = sizeof(struct itimerspec); -#endif // SANITIZER_LINUX || SANITIZER_FREEBSD +#endif // SANITIZER_LINUX || SANITIZER_FREEBSD #if SANITIZER_LINUX && !SANITIZER_ANDROID unsigned struct_ustat_sz = sizeof(struct ustat); unsigned struct_rlimit64_sz = sizeof(struct rlimit64); unsigned struct_statvfs64_sz = sizeof(struct statvfs64); -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID unsigned struct_timex_sz = sizeof(struct timex); unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); unsigned struct_mq_attr_sz = sizeof(struct mq_attr); unsigned struct_statvfs_sz = sizeof(struct statvfs); -#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID +#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID uptr sig_ign = (uptr)SIG_IGN; uptr sig_dfl = (uptr)SIG_DFL; @@ -290,6 +298,12 @@ namespace __sanitizer { return 0; } +#if SANITIZER_LINUX +unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr)); +#elif SANITIZER_FREEBSD +unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); +#endif + #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID int glob_nomatch = GLOB_NOMATCH; int glob_altdirfunc = GLOB_ALTDIRFUNC; @@ -297,34 +311,63 @@ namespace __sanitizer { #if SANITIZER_LINUX && !SANITIZER_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__)) -#if defined(__mips64) || defined(__powerpc64__) + defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__)) +#if defined(__mips64) || defined(__powerpc64__) || defined(__arm__) unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs); unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t); +#elif defined(__aarch64__) + unsigned struct_user_regs_struct_sz = sizeof(struct user_pt_regs); + unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpsimd_state); #else unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct); unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct); -#endif // __mips64 || __powerpc64__ -#if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) +#endif // __mips64 || __powerpc64__ || __aarch64__ +#if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \ + defined(__aarch64__) || defined(__arm__) unsigned struct_user_fpxregs_struct_sz = 0; #else unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct); -#endif // __x86_64 || __mips64 || __powerpc64__ +#endif // __x86_64 || __mips64 || __powerpc64__ || __aarch64__ || __arm__ +#ifdef __arm__ + unsigned struct_user_vfpregs_struct_sz = ARM_VFPREGS_SIZE; +#else + unsigned struct_user_vfpregs_struct_sz = 0; +#endif int ptrace_peektext = PTRACE_PEEKTEXT; int ptrace_peekdata = PTRACE_PEEKDATA; int ptrace_peekuser = PTRACE_PEEKUSER; +#if (defined(PTRACE_GETREGS) && defined(PTRACE_SETREGS)) || \ + (defined(PT_GETREGS) && defined(PT_SETREGS)) int ptrace_getregs = PTRACE_GETREGS; int ptrace_setregs = PTRACE_SETREGS; +#else + int ptrace_getregs = -1; + int ptrace_setregs = -1; +#endif +#if (defined(PTRACE_GETFPREGS) && defined(PTRACE_SETFPREGS)) || \ + (defined(PT_GETFPREGS) && defined(PT_SETFPREGS)) int ptrace_getfpregs = PTRACE_GETFPREGS; int ptrace_setfpregs = PTRACE_SETFPREGS; -#if defined(PTRACE_GETFPXREGS) && defined(PTRACE_SETFPXREGS) +#else + int ptrace_getfpregs = -1; + int ptrace_setfpregs = -1; +#endif +#if (defined(PTRACE_GETFPXREGS) && defined(PTRACE_SETFPXREGS)) || \ + (defined(PT_GETFPXREGS) && defined(PT_SETFPXREGS)) int ptrace_getfpxregs = PTRACE_GETFPXREGS; int ptrace_setfpxregs = PTRACE_SETFPXREGS; #else int ptrace_getfpxregs = -1; int ptrace_setfpxregs = -1; -#endif // PTRACE_GETFPXREGS/PTRACE_SETFPXREGS +#endif // PTRACE_GETFPXREGS/PTRACE_SETFPXREGS +#if defined(PTRACE_GETVFPREGS) && defined(PTRACE_SETVFPREGS) + int ptrace_getvfpregs = PTRACE_GETVFPREGS; + int ptrace_setvfpregs = PTRACE_SETVFPREGS; +#else + int ptrace_getvfpregs = -1; + int ptrace_setvfpregs = -1; +#endif int ptrace_geteventmsg = PTRACE_GETEVENTMSG; #if (defined(PTRACE_GETSIGINFO) && defined(PTRACE_SETSIGINFO)) || \ (defined(PT_GETSIGINFO) && defined(PT_SETSIGINFO)) @@ -333,14 +376,14 @@ namespace __sanitizer { #else int ptrace_getsiginfo = -1; int ptrace_setsiginfo = -1; -#endif // PTRACE_GETSIGINFO/PTRACE_SETSIGINFO +#endif // PTRACE_GETSIGINFO/PTRACE_SETSIGINFO #if defined(PTRACE_GETREGSET) && defined(PTRACE_SETREGSET) int ptrace_getregset = PTRACE_GETREGSET; int ptrace_setregset = PTRACE_SETREGSET; #else int ptrace_getregset = -1; int ptrace_setregset = -1; -#endif // PTRACE_GETREGSET/PTRACE_SETREGSET +#endif // PTRACE_GETREGSET/PTRACE_SETREGSET #endif unsigned path_max = PATH_MAX; @@ -378,7 +421,7 @@ namespace __sanitizer { unsigned struct_vt_consize_sz = sizeof(struct vt_consize); unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes); unsigned struct_vt_stat_sz = sizeof(struct vt_stat); -#endif // SANITIZER_LINUX +#endif // SANITIZER_LINUX #if SANITIZER_LINUX || SANITIZER_FREEBSD #if SOUND_VERSION >= 0x040000 @@ -398,7 +441,7 @@ namespace __sanitizer { unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec); unsigned struct_synth_info_sz = sizeof(struct synth_info); unsigned struct_vt_mode_sz = sizeof(struct vt_mode); -#endif // SANITIZER_LINUX || SANITIZER_FREEBSD +#endif // SANITIZER_LINUX || SANITIZER_FREEBSD #if SANITIZER_LINUX && !SANITIZER_ANDROID unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct); @@ -423,12 +466,12 @@ namespace __sanitizer { unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25); unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc); unsigned struct_unimapinit_sz = sizeof(struct unimapinit); -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); -#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID +#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID #if !SANITIZER_ANDROID && !SANITIZER_MAC unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); @@ -643,7 +686,7 @@ namespace __sanitizer { unsigned IOCTL_SOUND_PCM_READ_RATE = SOUND_PCM_READ_RATE; unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS = SOUND_PCM_WRITE_CHANNELS; unsigned IOCTL_SOUND_PCM_WRITE_FILTER = SOUND_PCM_WRITE_FILTER; -#endif // SOUND_VERSION +#endif // SOUND_VERSION unsigned IOCTL_TCFLSH = TCFLSH; unsigned IOCTL_TCGETA = TCGETA; unsigned IOCTL_TCGETS = TCGETS; @@ -766,7 +809,7 @@ namespace __sanitizer { unsigned IOCTL_VT_RELDISP = VT_RELDISP; unsigned IOCTL_VT_SETMODE = VT_SETMODE; unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; -#endif // SANITIZER_LINUX || SANITIZER_FREEBSD +#endif // SANITIZER_LINUX || SANITIZER_FREEBSD #if SANITIZER_LINUX && !SANITIZER_ANDROID unsigned IOCTL_CYGETDEFTHRESH = CYGETDEFTHRESH; @@ -857,7 +900,7 @@ namespace __sanitizer { unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI; unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI; unsigned IOCTL_TIOCSSERIAL = TIOCSSERIAL; -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID +#endif // SANITIZER_LINUX && !SANITIZER_ANDROID #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP; @@ -875,7 +918,7 @@ namespace __sanitizer { unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP; unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE; -#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID +#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID const int errno_EINVAL = EINVAL; // EOWNERDEAD is not present in some older platforms. @@ -887,7 +930,7 @@ namespace __sanitizer { const int si_SEGV_MAPERR = SEGV_MAPERR; const int si_SEGV_ACCERR = SEGV_ACCERR; -} // namespace __sanitizer +} // namespace __sanitizer COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t)); @@ -917,7 +960,7 @@ COMPILER_CHECK(IOC_SIZE(0x12345678) == _IOC_SIZE(0x12345678)); COMPILER_CHECK(IOC_DIR(0x12345678) == _IOC_DIR(0x12345678)); COMPILER_CHECK(IOC_NR(0x12345678) == _IOC_NR(0x12345678)); COMPILER_CHECK(IOC_TYPE(0x12345678) == _IOC_TYPE(0x12345678)); -#endif // SANITIZER_LINUX +#endif // SANITIZER_LINUX #if SANITIZER_LINUX || SANITIZER_FREEBSD // There are more undocumented fields in dl_phdr_info that we are not interested @@ -927,7 +970,7 @@ CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr); CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name); CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr); CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum); -#endif // SANITIZER_LINUX || SANITIZER_FREEBSD +#endif // SANITIZER_LINUX || SANITIZER_FREEBSD #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID CHECK_TYPE_SIZE(glob_t); @@ -1124,14 +1167,14 @@ CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask); # if SANITIZER_FREEBSD CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); # else -COMPILER_CHECK(sizeof(((__sanitizer_ifaddrs *)NULL)->ifa_dstaddr) == - sizeof(((ifaddrs *)NULL)->ifa_ifu)); +COMPILER_CHECK(sizeof(((__sanitizer_ifaddrs *)nullptr)->ifa_dstaddr) == + sizeof(((ifaddrs *)nullptr)->ifa_ifu)); COMPILER_CHECK(offsetof(__sanitizer_ifaddrs, ifa_dstaddr) == offsetof(ifaddrs, ifa_ifu)); -# endif // SANITIZER_FREEBSD +# endif // SANITIZER_FREEBSD #else CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr); -#endif // SANITIZER_LINUX +#endif // SANITIZER_LINUX CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); #endif @@ -1221,4 +1264,12 @@ CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, seek); CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, close); #endif -#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC +#if SANITIZER_LINUX || SANITIZER_FREEBSD +CHECK_TYPE_SIZE(sem_t); +#endif + +#if SANITIZER_LINUX && defined(__arm__) +COMPILER_CHECK(ARM_VFPREGS_SIZE == ARM_VFPREGS_SIZE_ASAN); +#endif + +#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h index 4da7c70da0a6..2978e7b9ce46 100644 --- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -150,6 +150,18 @@ namespace __sanitizer { }; const unsigned old_sigset_t_sz = sizeof(unsigned long); + + struct __sanitizer_sem_t { +#if SANITIZER_ANDROID && defined(_LP64) + int data[4]; +#elif SANITIZER_ANDROID && !defined(_LP64) + int data; +#elif SANITIZER_LINUX + uptr data[4]; +#elif SANITIZER_FREEBSD + u32 data[4]; +#endif + }; #endif // SANITIZER_LINUX || SANITIZER_FREEBSD #if SANITIZER_ANDROID @@ -609,6 +621,8 @@ namespace __sanitizer { const void *dlpi_phdr; short dlpi_phnum; }; + + extern unsigned struct_ElfW_Phdr_sz; #endif struct __sanitizer_addrinfo { @@ -722,10 +736,11 @@ namespace __sanitizer { #if SANITIZER_LINUX && !SANITIZER_ANDROID && \ (defined(__i386) || defined(__x86_64) || defined(__mips64) || \ - defined(__powerpc64__)) + defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__)) extern unsigned struct_user_regs_struct_sz; extern unsigned struct_user_fpregs_struct_sz; extern unsigned struct_user_fpxregs_struct_sz; + extern unsigned struct_user_vfpregs_struct_sz; extern int ptrace_peektext; extern int ptrace_peekdata; @@ -736,6 +751,8 @@ namespace __sanitizer { extern int ptrace_setfpregs; extern int ptrace_getfpxregs; extern int ptrace_setfpxregs; + extern int ptrace_getvfpregs; + extern int ptrace_setvfpregs; extern int ptrace_getsiginfo; extern int ptrace_setsiginfo; extern int ptrace_getregset; diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc index abf6738a8daa..5ae68663df0e 100644 --- a/lib/sanitizer_common/sanitizer_posix.cc +++ b/lib/sanitizer_common/sanitizer_posix.cc @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" + #if SANITIZER_POSIX #include "sanitizer_common.h" @@ -57,8 +58,8 @@ static uptr GetKernelAreaSize() { // mapped to top gigabyte (e.g. stack). MemoryMappingLayout proc_maps(/*cache_enabled*/true); uptr end, prot; - while (proc_maps.Next(/*start*/0, &end, - /*offset*/0, /*filename*/0, + while (proc_maps.Next(/*start*/nullptr, &end, + /*offset*/nullptr, /*filename*/nullptr, /*filename_size*/0, &prot)) { if ((end >= 3 * gbyte) && (prot & MemoryMappingLayout::kProtectionWrite) != 0) @@ -111,27 +112,14 @@ uptr GetMaxVirtualAddress() { #endif // SANITIZER_WORDSIZE } -void *MmapOrDie(uptr size, const char *mem_type) { +void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { size = RoundUpTo(size, GetPageSizeCached()); - uptr res = internal_mmap(0, size, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON, -1, 0); + uptr res = internal_mmap(nullptr, size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); int reserrno; - if (internal_iserror(res, &reserrno)) { - static int recursion_count; - if (recursion_count) { - // The Report() and CHECK calls below may call mmap recursively and fail. - // If we went into recursion, just die. - RawWrite("ERROR: Failed to mmap\n"); - Die(); - } - recursion_count++; - Report("ERROR: %s failed to " - "allocate 0x%zx (%zd) bytes of %s (errno: %d)\n", - SanitizerToolName, size, size, mem_type, reserrno); - DumpProcessMap(); - CHECK("unable to mmap" && 0); - } + if (internal_iserror(res, &reserrno)) + ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report); IncreaseTotalMmap(size); return (void *)res; } @@ -149,18 +137,14 @@ void UnmapOrDie(void *addr, uptr size) { void *MmapNoReserveOrDie(uptr size, const char *mem_type) { uptr PageSize = GetPageSizeCached(); - uptr p = internal_mmap(0, - RoundUpTo(size, PageSize), - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, - -1, 0); + uptr p = internal_mmap(nullptr, + RoundUpTo(size, PageSize), + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, + -1, 0); int reserrno; - if (internal_iserror(p, &reserrno)) { - Report("ERROR: %s failed to " - "allocate noreserve 0x%zx (%zd) bytes for '%s' (errno: %d)\n", - SanitizerToolName, size, size, mem_type, reserrno); - CHECK("unable to mmap" && 0); - } + if (internal_iserror(p, &reserrno)) + ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno); IncreaseTotalMmap(size); return (void *)p; } @@ -174,10 +158,10 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) { -1, 0); int reserrno; if (internal_iserror(p, &reserrno)) { - Report("ERROR: %s failed to " - "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n", - SanitizerToolName, size, size, fixed_addr, reserrno); - CHECK("unable to mmap" && 0); + char mem_type[30]; + internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx", + fixed_addr); + ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno); } IncreaseTotalMmap(size); return (void *)p; @@ -236,8 +220,8 @@ void *MapFileToMemory(const char *file_name, uptr *buff_size) { CHECK_NE(fsize, (uptr)-1); CHECK_GT(fsize, 0); *buff_size = RoundUpTo(fsize, GetPageSizeCached()); - uptr map = internal_mmap(0, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0); - return internal_iserror(map) ? 0 : (void *)map; + uptr map = internal_mmap(nullptr, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0); + return internal_iserror(map) ? nullptr : (void *)map; } void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { @@ -248,7 +232,7 @@ void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) { if (internal_iserror(p, &mmap_errno)) { Printf("could not map writable file (%d, %lld, %zu): %zd, errno: %d\n", fd, (long long)offset, size, p, mmap_errno); - return 0; + return nullptr; } return (void *)p; } @@ -268,8 +252,8 @@ bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) { MemoryMappingLayout proc_maps(/*cache_enabled*/true); uptr start, end; while (proc_maps.Next(&start, &end, - /*offset*/0, /*filename*/0, /*filename_size*/0, - /*protection*/0)) { + /*offset*/nullptr, /*filename*/nullptr, + /*filename_size*/0, /*protection*/nullptr)) { if (start == end) continue; // Empty range. CHECK_NE(0, end); if (!IntervalsAreSeparate(start, end - 1, range_start, range_end)) @@ -284,8 +268,8 @@ void DumpProcessMap() { const sptr kBufSize = 4095; char *filename = (char*)MmapOrDie(kBufSize, __func__); Report("Process memory map follows:\n"); - while (proc_maps.Next(&start, &end, /* file_offset */0, - filename, kBufSize, /* protection */0)) { + while (proc_maps.Next(&start, &end, /* file_offset */nullptr, + filename, kBufSize, /* protection */nullptr)) { Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename); } Report("End of process memory map.\n"); @@ -296,30 +280,6 @@ const char *GetPwd() { return GetEnv("PWD"); } -char *FindPathToBinary(const char *name) { - const char *path = GetEnv("PATH"); - if (!path) - return 0; - uptr name_len = internal_strlen(name); - InternalScopedBuffer<char> buffer(kMaxPathLength); - const char *beg = path; - while (true) { - const char *end = internal_strchrnul(beg, ':'); - uptr prefix_len = end - beg; - if (prefix_len + name_len + 2 <= kMaxPathLength) { - internal_memcpy(buffer.data(), beg, prefix_len); - buffer[prefix_len] = '/'; - internal_memcpy(&buffer[prefix_len + 1], name, name_len); - buffer[prefix_len + 1 + name_len] = '\0'; - if (FileExists(buffer.data())) - return internal_strdup(buffer.data()); - } - if (*end == '\0') break; - beg = end + 1; - } - return 0; -} - bool IsPathSeparator(const char c) { return c == '/'; } @@ -361,6 +321,6 @@ SignalContext SignalContext::Create(void *siginfo, void *context) { return SignalContext(context, addr, pc, sp, bp); } -} // namespace __sanitizer +} // namespace __sanitizer -#endif // SANITIZER_POSIX +#endif // SANITIZER_POSIX diff --git a/lib/sanitizer_common/sanitizer_posix.h b/lib/sanitizer_common/sanitizer_posix.h index 5a9e97d5b5a9..c0426a0b23fa 100644 --- a/lib/sanitizer_common/sanitizer_posix.h +++ b/lib/sanitizer_common/sanitizer_posix.h @@ -54,6 +54,7 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data); uptr internal_waitpid(int pid, int *status, int options); int internal_fork(); +int internal_forkpty(int *amaster); // These functions call appropriate pthread_ functions directly, bypassing // the interceptor. They are weak and may not be present in some tools. @@ -74,6 +75,8 @@ int real_pthread_join(void *th, void **ret); } \ } // namespace __sanitizer +int my_pthread_attr_getstack(void *attr, void **addr, uptr *size); + int internal_sigaction(int signum, const void *act, void *oldact); } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc index 3f0a4f453cb4..c158eedae0e3 100644 --- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc @@ -15,6 +15,7 @@ #include "sanitizer_platform.h" #if SANITIZER_POSIX + #include "sanitizer_common.h" #include "sanitizer_flags.h" #include "sanitizer_platform_limits_posix.h" @@ -30,9 +31,9 @@ #include <stdlib.h> #include <sys/mman.h> #include <sys/resource.h> +#include <sys/stat.h> #include <sys/time.h> #include <sys/types.h> -#include <sys/stat.h> #include <unistd.h> #if SANITIZER_FREEBSD @@ -141,7 +142,7 @@ static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough. void SetAlternateSignalStack() { stack_t altstack, oldstack; - CHECK_EQ(0, sigaltstack(0, &oldstack)); + CHECK_EQ(0, sigaltstack(nullptr, &oldstack)); // If the alternate stack is already in place, do nothing. // Android always sets an alternate stack, but it's too small for us. if (!SANITIZER_ANDROID && !(oldstack.ss_flags & SS_DISABLE)) return; @@ -152,12 +153,12 @@ void SetAlternateSignalStack() { altstack.ss_sp = (char*) base; altstack.ss_flags = 0; altstack.ss_size = kAltStackSize; - CHECK_EQ(0, sigaltstack(&altstack, 0)); + CHECK_EQ(0, sigaltstack(&altstack, nullptr)); } void UnsetAlternateSignalStack() { stack_t altstack, oldstack; - altstack.ss_sp = 0; + altstack.ss_sp = nullptr; altstack.ss_flags = SS_DISABLE; altstack.ss_size = kAltStackSize; // Some sane value required on Darwin. CHECK_EQ(0, sigaltstack(&altstack, &oldstack)); @@ -176,7 +177,7 @@ static void MaybeInstallSigaction(int signum, // Clients are responsible for handling this correctly. sigact.sa_flags = SA_SIGINFO | SA_NODEFER; if (common_flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; - CHECK_EQ(0, internal_sigaction(signum, &sigact, 0)); + CHECK_EQ(0, internal_sigaction(signum, &sigact, nullptr)); VReport(1, "Installed the sigaction for signal %d\n", signum); } @@ -188,6 +189,8 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) { MaybeInstallSigaction(SIGSEGV, handler); MaybeInstallSigaction(SIGBUS, handler); MaybeInstallSigaction(SIGABRT, handler); + MaybeInstallSigaction(SIGFPE, handler); + MaybeInstallSigaction(SIGILL, handler); } #endif // SANITIZER_GO @@ -226,7 +229,7 @@ void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { #endif } -#if SANITIZER_ANDROID +#if SANITIZER_ANDROID || SANITIZER_GO int GetNamedMappingFd(const char *name, uptr size) { return -1; } @@ -275,6 +278,48 @@ void *MmapNoAccess(uptr fixed_addr, uptr size, const char *name) { 0); } -} // namespace __sanitizer +// This function is defined elsewhere if we intercepted pthread_attr_getstack. +extern "C" { +SANITIZER_WEAK_ATTRIBUTE int +real_pthread_attr_getstack(void *attr, void **addr, size_t *size); +} // extern "C" + +int my_pthread_attr_getstack(void *attr, void **addr, uptr *size) { +#if !SANITIZER_GO && !SANITIZER_MAC + if (&real_pthread_attr_getstack) + return real_pthread_attr_getstack((pthread_attr_t *)attr, addr, + (size_t *)size); +#endif + return pthread_attr_getstack((pthread_attr_t *)attr, addr, (size_t *)size); +} + +#if !SANITIZER_GO +void AdjustStackSize(void *attr_) { + pthread_attr_t *attr = (pthread_attr_t *)attr_; + uptr stackaddr = 0; + uptr stacksize = 0; + my_pthread_attr_getstack(attr, (void**)&stackaddr, &stacksize); + // GLibC will return (0 - stacksize) as the stack address in the case when + // stacksize is set, but stackaddr is not. + bool stack_set = (stackaddr != 0) && (stackaddr + stacksize != 0); + // We place a lot of tool data into TLS, account for that. + const uptr minstacksize = GetTlsSize() + 128*1024; + if (stacksize < minstacksize) { + if (!stack_set) { + if (stacksize != 0) { + VPrintf(1, "Sanitizer: increasing stacksize %zu->%zu\n", stacksize, + minstacksize); + pthread_attr_setstacksize(attr, minstacksize); + } + } else { + Printf("Sanitizer: pre-allocated stack size is insufficient: " + "%zu < %zu\n", stacksize, minstacksize); + Printf("Sanitizer: pthread_create is likely to fail.\n"); + } + } +} +#endif // !SANITIZER_GO + +} // namespace __sanitizer -#endif // SANITIZER_POSIX +#endif // SANITIZER_POSIX diff --git a/lib/sanitizer_common/sanitizer_printf.cc b/lib/sanitizer_common/sanitizer_printf.cc index e4f67f5e0db5..2794e667e697 100644 --- a/lib/sanitizer_common/sanitizer_printf.cc +++ b/lib/sanitizer_common/sanitizer_printf.cc @@ -14,7 +14,6 @@ // inside it. //===----------------------------------------------------------------------===// - #include "sanitizer_common.h" #include "sanitizer_flags.h" #include "sanitizer_libc.h" @@ -98,7 +97,7 @@ static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num, static int AppendString(char **buff, const char *buff_end, int precision, const char *s) { - if (s == 0) + if (!s) s = "<null>"; int result = 0; for (; *s; s++) { @@ -260,7 +259,7 @@ static void SharedPrintfCode(bool append_pid, const char *format, } if (append_pid) { int pid = internal_getpid(); - const char *exe_name = GetBinaryBasename(); + const char *exe_name = GetProcessName(); if (common_flags()->log_exe_name && exe_name) { needed_length += internal_snprintf(buffer, buffer_size, "==%s", exe_name); @@ -279,7 +278,8 @@ static void SharedPrintfCode(bool append_pid, const char *format, # undef CHECK_NEEDED_LENGTH } RawWrite(buffer); - AndroidLogWrite(buffer); + if (common_flags()->log_to_syslog && ShouldLogAfterPrintf()) + WriteToSyslog(buffer); CallPrintfAndReportCallback(buffer); // If we had mapped any memory, clean up. if (buffer != local_buffer) @@ -328,4 +328,4 @@ void InternalScopedString::append(const char *format, ...) { CHECK_LT(length_, size()); } -} // namespace __sanitizer +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_procmaps_common.cc b/lib/sanitizer_common/sanitizer_procmaps_common.cc index 2c6ce8e2b211..d43432cae909 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_common.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_common.cc @@ -11,7 +11,9 @@ //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" + #if SANITIZER_FREEBSD || SANITIZER_LINUX + #include "sanitizer_common.h" #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" @@ -151,10 +153,11 @@ uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules, } void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { - char *smaps = 0; + char *smaps = nullptr; uptr smaps_cap = 0; - uptr smaps_len = ReadFileToBuffer("/proc/self/smaps", - &smaps, &smaps_cap, 64<<20); + uptr smaps_len = 0; + if (!ReadFileToBuffer("/proc/self/smaps", &smaps, &smaps_cap, &smaps_len)) + return; uptr start = 0; bool file = false; const char *pos = smaps; @@ -173,6 +176,6 @@ void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { UnmapOrDie(smaps, smaps_cap); } -} // namespace __sanitizer +} // namespace __sanitizer -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/lib/sanitizer_common/sanitizer_procmaps_linux.cc b/lib/sanitizer_common/sanitizer_procmaps_linux.cc index 79ca4dfd8fca..b6fb7034ded4 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_linux.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_linux.cc @@ -18,8 +18,8 @@ namespace __sanitizer { void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { - proc_maps->len = ReadFileToBuffer("/proc/self/maps", &proc_maps->data, - &proc_maps->mmaped_size, 1 << 26); + CHECK(ReadFileToBuffer("/proc/self/maps", &proc_maps->data, + &proc_maps->mmaped_size, &proc_maps->len)); } static bool IsOneOf(char c, char c1, char c2) { @@ -67,7 +67,7 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, while (IsDecimal(*current_)) current_++; // Qemu may lack the trailing space. - // http://code.google.com/p/address-sanitizer/issues/detail?id=160 + // https://github.com/google/sanitizers/issues/160 // CHECK_EQ(*current_++, ' '); // Skip spaces. while (current_ < next_line && *current_ == ' ') diff --git a/lib/sanitizer_common/sanitizer_procmaps_mac.cc b/lib/sanitizer_common/sanitizer_procmaps_mac.cc index 29d699609a6e..d10881e8a7f8 100644 --- a/lib/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/lib/sanitizer_common/sanitizer_procmaps_mac.cc @@ -65,7 +65,7 @@ void MemoryMappingLayout::LoadFromCache() { } // Next and NextSegmentLoad were inspired by base/sysinfo.cc in -// Google Perftools, http://code.google.com/p/google-perftools. +// Google Perftools, https://github.com/gperftools/gperftools. // NextSegmentLoad scans the current image for the next segment load command // and returns the start and end addresses and file offset of the corresponding diff --git a/lib/sanitizer_common/sanitizer_quarantine.h b/lib/sanitizer_common/sanitizer_quarantine.h index 404d3753f7e9..9e0bf2d18fec 100644 --- a/lib/sanitizer_common/sanitizer_quarantine.h +++ b/lib/sanitizer_common/sanitizer_quarantine.h @@ -153,7 +153,7 @@ class QuarantineCache { QuarantineBatch *DequeueBatch() { if (list_.empty()) - return 0; + return nullptr; QuarantineBatch *b = list_.front(); list_.pop_front(); SizeSub(b->size); @@ -180,6 +180,6 @@ class QuarantineCache { return b; } }; -} // namespace __sanitizer +} // namespace __sanitizer -#endif // #ifndef SANITIZER_QUARANTINE_H +#endif // SANITIZER_QUARANTINE_H diff --git a/lib/sanitizer_common/sanitizer_stackdepot.cc b/lib/sanitizer_common/sanitizer_stackdepot.cc index 59b53f4dcd84..985193d1ed5e 100644 --- a/lib/sanitizer_common/sanitizer_stackdepot.cc +++ b/lib/sanitizer_common/sanitizer_stackdepot.cc @@ -152,7 +152,7 @@ StackDepotReverseMap::StackDepotReverseMap() StackTrace StackDepotReverseMap::Get(u32 id) { if (!map_.size()) return StackTrace(); - IdDescPair pair = {id, 0}; + IdDescPair pair = {id, nullptr}; uptr idx = InternalBinarySearch(map_, 0, map_.size(), pair, IdDescPair::IdComparator); if (idx > map_.size()) @@ -160,4 +160,4 @@ StackTrace StackDepotReverseMap::Get(u32 id) { return map_[idx].desc->load(); } -} // namespace __sanitizer +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_stackdepot.h b/lib/sanitizer_common/sanitizer_stackdepot.h index 5e3a8b783ac7..cb7345002a40 100644 --- a/lib/sanitizer_common/sanitizer_stackdepot.h +++ b/lib/sanitizer_common/sanitizer_stackdepot.h @@ -10,6 +10,7 @@ // This file is shared between AddressSanitizer and ThreadSanitizer // run-time libraries. //===----------------------------------------------------------------------===// + #ifndef SANITIZER_STACKDEPOT_H #define SANITIZER_STACKDEPOT_H @@ -23,7 +24,7 @@ namespace __sanitizer { struct StackDepotNode; struct StackDepotHandle { StackDepotNode *node_; - StackDepotHandle() : node_(0) {} + StackDepotHandle() : node_(nullptr) {} explicit StackDepotHandle(StackDepotNode *node) : node_(node) {} bool valid() { return node_; } u32 id(); @@ -66,6 +67,6 @@ class StackDepotReverseMap { void operator=(const StackDepotReverseMap&); }; -} // namespace __sanitizer +} // namespace __sanitizer -#endif // SANITIZER_STACKDEPOT_H +#endif // SANITIZER_STACKDEPOT_H diff --git a/lib/sanitizer_common/sanitizer_stackdepotbase.h b/lib/sanitizer_common/sanitizer_stackdepotbase.h index 5de2e711fe45..4ec77b467b1f 100644 --- a/lib/sanitizer_common/sanitizer_stackdepotbase.h +++ b/lib/sanitizer_common/sanitizer_stackdepotbase.h @@ -10,6 +10,7 @@ // Implementation of a mapping from arbitrary values to unique 32-bit // identifiers. //===----------------------------------------------------------------------===// + #ifndef SANITIZER_STACKDEPOTBASE_H #define SANITIZER_STACKDEPOTBASE_H @@ -26,7 +27,7 @@ class StackDepotBase { typedef typename Node::args_type args_type; typedef typename Node::handle_type handle_type; // Maps stack trace to an unique id. - handle_type Put(args_type args, bool *inserted = 0); + handle_type Put(args_type args, bool *inserted = nullptr); // Retrieves a stored stack trace by the id. args_type Get(u32 id); @@ -66,7 +67,7 @@ Node *StackDepotBase<Node, kReservedBits, kTabSizeLog>::find(Node *s, return s; } } - return 0; + return nullptr; } template <class Node, int kReservedBits, int kTabSizeLog> @@ -172,5 +173,6 @@ void StackDepotBase<Node, kReservedBits, kTabSizeLog>::UnlockAll() { } } -} // namespace __sanitizer -#endif // SANITIZER_STACKDEPOTBASE_H +} // namespace __sanitizer + +#endif // SANITIZER_STACKDEPOTBASE_H diff --git a/lib/sanitizer_common/sanitizer_stacktrace.cc b/lib/sanitizer_common/sanitizer_stacktrace.cc index 84ff9d9d9e3b..7862575b37bb 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace.cc +++ b/lib/sanitizer_common/sanitizer_stacktrace.cc @@ -83,7 +83,18 @@ void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top, while (IsValidFrame((uptr)frame, stack_top, bottom) && IsAligned((uptr)frame, sizeof(*frame)) && size < max_depth) { +#ifdef __powerpc__ + // PowerPC ABIs specify that the return address is saved at offset + // 16 of the *caller's* stack frame. Thus we must dereference the + // back chain to find the caller frame before extracting it. + uhwptr *caller_frame = (uhwptr*)frame[0]; + if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) || + !IsAligned((uptr)caller_frame, sizeof(uhwptr))) + break; + uhwptr pc1 = caller_frame[2]; +#else uhwptr pc1 = frame[1]; +#endif if (pc1 != pc) { trace_buffer[size++] = (uptr) pc1; } @@ -107,7 +118,7 @@ void BufferedStackTrace::PopStackFrames(uptr count) { uptr BufferedStackTrace::LocatePcInTrace(uptr pc) { // Use threshold to find PC in stack trace, as PC we want to unwind from may // slightly differ from return address in the actual unwinded stack trace. - const int kPcThreshold = 304; + const int kPcThreshold = 320; for (uptr i = 0; i < size; ++i) { if (MatchPc(pc, trace[i], kPcThreshold)) return i; diff --git a/lib/sanitizer_common/sanitizer_stacktrace.h b/lib/sanitizer_common/sanitizer_stacktrace.h index 6c3a1511f337..969cedb165c8 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace.h +++ b/lib/sanitizer_common/sanitizer_stacktrace.h @@ -19,9 +19,7 @@ namespace __sanitizer { static const u32 kStackTraceMax = 256; -#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__powerpc__) || \ - defined(__powerpc64__) || defined(__sparc__) || \ - defined(__mips__)) +#if SANITIZER_LINUX && (defined(__sparc__) || defined(__mips__)) # define SANITIZER_CAN_FAST_UNWIND 0 #elif SANITIZER_WINDOWS # define SANITIZER_CAN_FAST_UNWIND 0 @@ -31,7 +29,7 @@ static const u32 kStackTraceMax = 256; // Fast unwind is the only option on Mac for now; we will need to // revisit this macro when slow unwind works on Mac, see -// https://code.google.com/p/address-sanitizer/issues/detail?id=137 +// https://github.com/google/sanitizers/issues/137 #if SANITIZER_MAC # define SANITIZER_CAN_SLOW_UNWIND 0 #else diff --git a/lib/sanitizer_common/sanitizer_stacktrace_printer.cc b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc index 3574fa3782c6..669b0ba28265 100644 --- a/lib/sanitizer_common/sanitizer_stacktrace_printer.cc +++ b/lib/sanitizer_common/sanitizer_stacktrace_printer.cc @@ -10,13 +10,14 @@ // This file is shared between sanitizers' run-time libraries. // //===----------------------------------------------------------------------===// + #include "sanitizer_stacktrace_printer.h" namespace __sanitizer { static const char *StripFunctionName(const char *function, const char *prefix) { - if (function == 0) return 0; - if (prefix == 0) return function; + if (!function) return nullptr; + if (!prefix) return function; uptr prefix_len = internal_strlen(prefix); if (0 == internal_strncmp(function, prefix, prefix_len)) return function + prefix_len; @@ -140,4 +141,4 @@ void RenderModuleLocation(InternalScopedString *buffer, const char *module, offset); } -} // namespace __sanitizer +} // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc index 47b27e7e5c75..2376ee56e1d7 100644 --- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -12,9 +12,10 @@ // //===----------------------------------------------------------------------===// - #include "sanitizer_platform.h" -#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)) + +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) || \ + defined(__aarch64__) || defined(__powerpc64__)) #include "sanitizer_stoptheworld.h" @@ -27,9 +28,15 @@ #include <sys/prctl.h> // for PR_* definitions #include <sys/ptrace.h> // for PTRACE_* definitions #include <sys/types.h> // for pid_t +#include <sys/uio.h> // for iovec +#include <elf.h> // for NT_PRSTATUS #if SANITIZER_ANDROID && defined(__arm__) # include <linux/user.h> // for pt_regs #else +# ifdef __aarch64__ +// GLIBC 2.20+ sys/user does not include asm/ptrace.h +# include <asm/ptrace.h> +# endif # include <sys/user.h> // for user_regs_struct #endif #include <sys/wait.h> // for signal-related stuff @@ -112,7 +119,7 @@ bool ThreadSuspender::SuspendThread(SuspendedThreadID tid) { if (suspended_threads_list_.Contains(tid)) return false; int pterrno; - if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, NULL, NULL), + if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, nullptr, nullptr), &pterrno)) { // Either the thread is dead, or something prevented us from attaching. // Log this event and move on. @@ -139,11 +146,12 @@ bool ThreadSuspender::SuspendThread(SuspendedThreadID tid) { // doesn't hurt to report it. VReport(1, "Waiting on thread %d failed, detaching (errno %d).\n", tid, wperrno); - internal_ptrace(PTRACE_DETACH, tid, NULL, NULL); + internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr); return false; } if (WIFSTOPPED(status) && WSTOPSIG(status) != SIGSTOP) { - internal_ptrace(PTRACE_CONT, tid, 0, (void*)(uptr)WSTOPSIG(status)); + internal_ptrace(PTRACE_CONT, tid, nullptr, + (void*)(uptr)WSTOPSIG(status)); continue; } break; @@ -157,7 +165,7 @@ void ThreadSuspender::ResumeAllThreads() { for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++) { pid_t tid = suspended_threads_list_.GetThreadID(i); int pterrno; - if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, NULL, NULL), + if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr), &pterrno)) { VReport(2, "Detached from thread %d.\n", tid); } else { @@ -172,7 +180,7 @@ void ThreadSuspender::ResumeAllThreads() { void ThreadSuspender::KillAllThreads() { for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++) internal_ptrace(PTRACE_KILL, suspended_threads_list_.GetThreadID(i), - NULL, NULL); + nullptr, nullptr); } bool ThreadSuspender::SuspendAllThreads() { @@ -198,13 +206,25 @@ bool ThreadSuspender::SuspendAllThreads() { } // Pointer to the ThreadSuspender instance for use in signal handler. -static ThreadSuspender *thread_suspender_instance = NULL; +static ThreadSuspender *thread_suspender_instance = nullptr; // Synchronous signals that should not be blocked. static const int kSyncSignals[] = { SIGABRT, SIGILL, SIGFPE, SIGSEGV, SIGBUS, SIGXCPU, SIGXFSZ }; -static DieCallbackType old_die_callback; +static void TracerThreadDieCallback() { + // Generally a call to Die() in the tracer thread should be fatal to the + // parent process as well, because they share the address space. + // This really only works correctly if all the threads are suspended at this + // point. So we correctly handle calls to Die() from within the callback, but + // not those that happen before or after the callback. Hopefully there aren't + // a lot of opportunities for that to happen... + ThreadSuspender *inst = thread_suspender_instance; + if (inst && stoptheworld_tracer_pid == internal_getpid()) { + inst->KillAllThreads(); + thread_suspender_instance = nullptr; + } +} // Signal handler to wake up suspended threads when the tracer thread dies. static void TracerThreadSignalHandler(int signum, void *siginfo, void *uctx) { @@ -212,37 +232,18 @@ static void TracerThreadSignalHandler(int signum, void *siginfo, void *uctx) { VPrintf(1, "Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n", signum, ctx.addr, ctx.pc, ctx.sp); ThreadSuspender *inst = thread_suspender_instance; - if (inst != NULL) { + if (inst) { if (signum == SIGABRT) inst->KillAllThreads(); else inst->ResumeAllThreads(); - SetDieCallback(old_die_callback); - old_die_callback = NULL; - thread_suspender_instance = NULL; + RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback)); + thread_suspender_instance = nullptr; atomic_store(&inst->arg->done, 1, memory_order_relaxed); } internal__exit((signum == SIGABRT) ? 1 : 2); } -static void TracerThreadDieCallback() { - // Generally a call to Die() in the tracer thread should be fatal to the - // parent process as well, because they share the address space. - // This really only works correctly if all the threads are suspended at this - // point. So we correctly handle calls to Die() from within the callback, but - // not those that happen before or after the callback. Hopefully there aren't - // a lot of opportunities for that to happen... - ThreadSuspender *inst = thread_suspender_instance; - if (inst != NULL && stoptheworld_tracer_pid == internal_getpid()) { - inst->KillAllThreads(); - thread_suspender_instance = NULL; - } - if (old_die_callback) - old_die_callback(); - SetDieCallback(old_die_callback); - old_die_callback = NULL; -} - // Size of alternative stack for signal handlers in the tracer thread. static const int kHandlerStackSize = 4096; @@ -260,8 +261,7 @@ static int TracerThread(void* argument) { tracer_thread_argument->mutex.Lock(); tracer_thread_argument->mutex.Unlock(); - old_die_callback = GetDieCallback(); - SetDieCallback(TracerThreadDieCallback); + RAW_CHECK(AddDieCallback(TracerThreadDieCallback)); ThreadSuspender thread_suspender(internal_getppid(), tracer_thread_argument); // Global pointer for the signal handler. @@ -273,7 +273,7 @@ static int TracerThread(void* argument) { internal_memset(&handler_stack, 0, sizeof(handler_stack)); handler_stack.ss_sp = handler_stack_memory.data(); handler_stack.ss_size = kHandlerStackSize; - internal_sigaltstack(&handler_stack, NULL); + internal_sigaltstack(&handler_stack, nullptr); // Install our handler for synchronous signals. Other signals should be // blocked by the mask we inherited from the parent thread. @@ -295,8 +295,8 @@ static int TracerThread(void* argument) { thread_suspender.ResumeAllThreads(); exit_code = 0; } - SetDieCallback(old_die_callback); - thread_suspender_instance = NULL; + RAW_CHECK(RemoveDieCallback(TracerThreadDieCallback)); + thread_suspender_instance = nullptr; atomic_store(&tracer_thread_argument->done, 1, memory_order_relaxed); return exit_code; } @@ -404,8 +404,8 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) { uptr tracer_pid = internal_clone( TracerThread, tracer_stack.Bottom(), CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED, - &tracer_thread_argument, 0 /* parent_tidptr */, 0 /* newtls */, 0 - /* child_tidptr */); + &tracer_thread_argument, nullptr /* parent_tidptr */, + nullptr /* newtls */, nullptr /* child_tidptr */); internal_sigprocmask(SIG_SETMASK, &old_sigset, 0); int local_errno = 0; if (internal_iserror(tracer_pid, &local_errno)) { @@ -432,7 +432,7 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) { // Now the tracer thread is about to exit and does not touch errno, // wait for it. for (;;) { - uptr waitpid_status = internal_waitpid(tracer_pid, NULL, __WALL); + uptr waitpid_status = internal_waitpid(tracer_pid, nullptr, __WALL); if (!internal_iserror(waitpid_status, &local_errno)) break; if (local_errno == EINTR) @@ -469,6 +469,11 @@ typedef pt_regs regs_struct; typedef struct user regs_struct; #define REG_SP regs[EF_REG29] +#elif defined(__aarch64__) +typedef struct user_pt_regs regs_struct; +#define REG_SP sp +#define ARCH_IOVEC_FOR_GETREGSET + #else #error "Unsupported architecture" #endif // SANITIZER_ANDROID && defined(__arm__) @@ -479,8 +484,18 @@ int SuspendedThreadsList::GetRegistersAndSP(uptr index, pid_t tid = GetThreadID(index); regs_struct regs; int pterrno; - if (internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, NULL, ®s), - &pterrno)) { +#ifdef ARCH_IOVEC_FOR_GETREGSET + struct iovec regset_io; + regset_io.iov_base = ®s; + regset_io.iov_len = sizeof(regs_struct); + bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid, + (void*)NT_PRSTATUS, (void*)®set_io), + &pterrno); +#else + bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, nullptr, + ®s), &pterrno); +#endif + if (isErr) { VReport(1, "Could not get registers from thread %d (errno %d).\n", tid, pterrno); return -1; @@ -494,6 +509,7 @@ int SuspendedThreadsList::GetRegistersAndSP(uptr index, uptr SuspendedThreadsList::RegisterCount() { return sizeof(regs_struct) / sizeof(uptr); } -} // namespace __sanitizer +} // namespace __sanitizer -#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)) +#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) + // || defined(__aarch64__) || defined(__powerpc64__) diff --git a/lib/sanitizer_common/sanitizer_suppressions.cc b/lib/sanitizer_common/sanitizer_suppressions.cc index 08cb497269bf..f0f2c9c725a1 100644 --- a/lib/sanitizer_common/sanitizer_suppressions.cc +++ b/lib/sanitizer_common/sanitizer_suppressions.cc @@ -60,15 +60,13 @@ void SuppressionContext::ParseFromFile(const char *filename) { } // Read the file. - char *file_contents; - uptr buffer_size; - const uptr max_len = 1 << 26; - uptr contents_size = - ReadFileToBuffer(filename, &file_contents, &buffer_size, max_len); VPrintf(1, "%s: reading suppressions file at %s\n", SanitizerToolName, filename); - - if (contents_size == 0) { + char *file_contents; + uptr buffer_size; + uptr contents_size; + if (!ReadFileToBuffer(filename, &file_contents, &buffer_size, + &contents_size)) { Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName, filename); Die(); @@ -114,7 +112,8 @@ void SuppressionContext::Parse(const char *str) { end = line + internal_strlen(line); if (line != end && line[0] != '#') { const char *end2 = end; - while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t')) + while (line != end2 && + (end2[-1] == ' ' || end2[-1] == '\t' || end2[-1] == '\r')) end2--; int type; for (type = 0; type < suppression_types_num_; type++) { @@ -133,8 +132,6 @@ void SuppressionContext::Parse(const char *str) { s.templ = (char*)InternalAlloc(end2 - line + 1); internal_memcpy(s.templ, line, end2 - line); s.templ[end2 - line] = 0; - s.hit_count = 0; - s.weight = 0; suppressions_.push_back(s); has_suppression_type_[type] = true; } @@ -164,7 +161,7 @@ const Suppression *SuppressionContext::SuppressionAt(uptr i) const { void SuppressionContext::GetMatched( InternalMmapVector<Suppression *> *matched) { for (uptr i = 0; i < suppressions_.size(); i++) - if (suppressions_[i].hit_count) + if (atomic_load_relaxed(&suppressions_[i].hit_count)) matched->push_back(&suppressions_[i]); } diff --git a/lib/sanitizer_common/sanitizer_suppressions.h b/lib/sanitizer_common/sanitizer_suppressions.h index 02dbf6f9690b..0ca875a2dde6 100644 --- a/lib/sanitizer_common/sanitizer_suppressions.h +++ b/lib/sanitizer_common/sanitizer_suppressions.h @@ -14,14 +14,16 @@ #define SANITIZER_SUPPRESSIONS_H #include "sanitizer_common.h" +#include "sanitizer_atomic.h" #include "sanitizer_internal_defs.h" namespace __sanitizer { struct Suppression { + Suppression() { internal_memset(this, 0, sizeof(*this)); } const char *type; char *templ; - unsigned hit_count; + atomic_uint32_t hit_count; uptr weight; }; @@ -41,7 +43,7 @@ class SuppressionContext { void GetMatched(InternalMmapVector<Suppression *> *matched); private: - static const int kMaxSuppressionTypes = 16; + static const int kMaxSuppressionTypes = 32; const char **const suppression_types_; const int suppression_types_num_; diff --git a/lib/sanitizer_common/sanitizer_symbolizer_internal.h b/lib/sanitizer_common/sanitizer_symbolizer_internal.h index 66ae809ed53e..12c70b602e24 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_internal.h +++ b/lib/sanitizer_common/sanitizer_symbolizer_internal.h @@ -74,24 +74,31 @@ class SymbolizerProcess { explicit SymbolizerProcess(const char *path, bool use_forkpty = false); const char *SendCommand(const char *command); - private: - bool Restart(); - const char *SendCommandImpl(const char *command); - bool ReadFromSymbolizer(char *buffer, uptr max_length); - bool WriteToSymbolizer(const char *buffer, uptr length); - bool StartSymbolizerSubprocess(); - + protected: virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const { UNIMPLEMENTED(); } - virtual void ExecuteWithDefaultArgs(const char *path_to_binary) const { + /// The maximum number of arguments required to invoke a tool process. + enum { kArgVMax = 6 }; + + /// Fill in an argv array to invoke the child process. + virtual void GetArgV(const char *path_to_binary, + const char *(&argv)[kArgVMax]) const { UNIMPLEMENTED(); } + virtual bool ReadFromSymbolizer(char *buffer, uptr max_length); + + private: + bool Restart(); + const char *SendCommandImpl(const char *command); + bool WriteToSymbolizer(const char *buffer, uptr length); + bool StartSymbolizerSubprocess(); + const char *path_; - int input_fd_; - int output_fd_; + fd_t input_fd_; + fd_t output_fd_; static const uptr kBufferSize = 16 * 1024; char buffer_[kBufferSize]; @@ -104,6 +111,41 @@ class SymbolizerProcess { bool use_forkpty_; }; +class LLVMSymbolizerProcess; + +// This tool invokes llvm-symbolizer in a subprocess. It should be as portable +// as the llvm-symbolizer tool is. +class LLVMSymbolizer : public SymbolizerTool { + public: + explicit LLVMSymbolizer(const char *path, LowLevelAllocator *allocator); + + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; + + bool SymbolizeData(uptr addr, DataInfo *info) override; + + private: + const char *SendCommand(bool is_data, const char *module_name, + uptr module_offset); + + LLVMSymbolizerProcess *symbolizer_process_; + static const uptr kBufferSize = 16 * 1024; + char buffer_[kBufferSize]; +}; + +// Parses one or more two-line strings in the following format: +// <function_name> +// <file_name>:<line_number>[:<column_number>] +// Used by LLVMSymbolizer, Addr2LinePool and InternalSymbolizer, since all of +// them use the same output format. Returns true if any useful debug +// information was found. +void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res); + +// Parses a two-line string in the following format: +// <symbol_name> +// <start_address> <size> +// Used by LLVMSymbolizer and InternalSymbolizer. +void ParseSymbolizeDataOutput(const char *str, DataInfo *info); + } // namespace __sanitizer #endif // SANITIZER_SYMBOLIZER_INTERNAL_H diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h index 00b465a72774..ddfd475592cb 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h +++ b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.h @@ -16,6 +16,7 @@ #include "sanitizer_platform.h" #include "sanitizer_common.h" +#include "sanitizer_allocator_internal.h" #include "sanitizer_symbolizer_internal.h" #ifndef SANITIZER_LIBBACKTRACE diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc index 160f55d422ca..8c3ad81f952a 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_libcdep.cc @@ -184,4 +184,245 @@ Symbolizer *Symbolizer::GetOrInit() { return symbolizer_; } +// For now we assume the following protocol: +// For each request of the form +// <module_name> <module_offset> +// passed to STDIN, external symbolizer prints to STDOUT response: +// <function_name> +// <file_name>:<line_number>:<column_number> +// <function_name> +// <file_name>:<line_number>:<column_number> +// ... +// <empty line> +class LLVMSymbolizerProcess : public SymbolizerProcess { + public: + explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {} + + private: + bool ReachedEndOfOutput(const char *buffer, uptr length) const override { + // Empty line marks the end of llvm-symbolizer output. + return length >= 2 && buffer[length - 1] == '\n' && + buffer[length - 2] == '\n'; + } + + void GetArgV(const char *path_to_binary, + const char *(&argv)[kArgVMax]) const override { +#if defined(__x86_64h__) + const char* const kSymbolizerArch = "--default-arch=x86_64h"; +#elif defined(__x86_64__) + const char* const kSymbolizerArch = "--default-arch=x86_64"; +#elif defined(__i386__) + const char* const kSymbolizerArch = "--default-arch=i386"; +#elif defined(__powerpc64__) && defined(__BIG_ENDIAN__) + const char* const kSymbolizerArch = "--default-arch=powerpc64"; +#elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__) + const char* const kSymbolizerArch = "--default-arch=powerpc64le"; +#else + const char* const kSymbolizerArch = "--default-arch=unknown"; +#endif + + const char *const inline_flag = common_flags()->symbolize_inline_frames + ? "--inlining=true" + : "--inlining=false"; + int i = 0; + argv[i++] = path_to_binary; + argv[i++] = inline_flag; + argv[i++] = kSymbolizerArch; + argv[i++] = nullptr; + } +}; + +LLVMSymbolizer::LLVMSymbolizer(const char *path, LowLevelAllocator *allocator) + : symbolizer_process_(new(*allocator) LLVMSymbolizerProcess(path)) {} + +// Parse a <file>:<line>[:<column>] buffer. The file path may contain colons on +// Windows, so extract tokens from the right hand side first. The column info is +// also optional. +static const char *ParseFileLineInfo(AddressInfo *info, const char *str) { + char *file_line_info = 0; + str = ExtractToken(str, "\n", &file_line_info); + CHECK(file_line_info); + // Parse the last :<int>, which must be there. + char *last_colon = internal_strrchr(file_line_info, ':'); + CHECK(last_colon); + int line_or_column = internal_atoll(last_colon + 1); + // Truncate the string at the last colon and find the next-to-last colon. + *last_colon = '\0'; + last_colon = internal_strrchr(file_line_info, ':'); + if (last_colon && IsDigit(last_colon[1])) { + // If the second-to-last colon is followed by a digit, it must be the line + // number, and the previous parsed number was a column. + info->line = internal_atoll(last_colon + 1); + info->column = line_or_column; + *last_colon = '\0'; + } else { + // Otherwise, we have line info but no column info. + info->line = line_or_column; + info->column = 0; + } + ExtractToken(file_line_info, "", &info->file); + InternalFree(file_line_info); + return str; +} + +// Parses one or more two-line strings in the following format: +// <function_name> +// <file_name>:<line_number>[:<column_number>] +// Used by LLVMSymbolizer, Addr2LinePool and InternalSymbolizer, since all of +// them use the same output format. +void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) { + bool top_frame = true; + SymbolizedStack *last = res; + while (true) { + char *function_name = 0; + str = ExtractToken(str, "\n", &function_name); + CHECK(function_name); + if (function_name[0] == '\0') { + // There are no more frames. + InternalFree(function_name); + break; + } + SymbolizedStack *cur; + if (top_frame) { + cur = res; + top_frame = false; + } else { + cur = SymbolizedStack::New(res->info.address); + cur->info.FillModuleInfo(res->info.module, res->info.module_offset); + last->next = cur; + last = cur; + } + + AddressInfo *info = &cur->info; + info->function = function_name; + str = ParseFileLineInfo(info, str); + + // Functions and filenames can be "??", in which case we write 0 + // to address info to mark that names are unknown. + if (0 == internal_strcmp(info->function, "??")) { + InternalFree(info->function); + info->function = 0; + } + if (0 == internal_strcmp(info->file, "??")) { + InternalFree(info->file); + info->file = 0; + } + } +} + +// Parses a two-line string in the following format: +// <symbol_name> +// <start_address> <size> +// Used by LLVMSymbolizer and InternalSymbolizer. +void ParseSymbolizeDataOutput(const char *str, DataInfo *info) { + str = ExtractToken(str, "\n", &info->name); + str = ExtractUptr(str, " ", &info->start); + str = ExtractUptr(str, "\n", &info->size); +} + +bool LLVMSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { + if (const char *buf = SendCommand(/*is_data*/ false, stack->info.module, + stack->info.module_offset)) { + ParseSymbolizePCOutput(buf, stack); + return true; + } + return false; +} + +bool LLVMSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { + if (const char *buf = + SendCommand(/*is_data*/ true, info->module, info->module_offset)) { + ParseSymbolizeDataOutput(buf, info); + info->start += (addr - info->module_offset); // Add the base address. + return true; + } + return false; +} + +const char *LLVMSymbolizer::SendCommand(bool is_data, const char *module_name, + uptr module_offset) { + CHECK(module_name); + internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n", + is_data ? "DATA " : "", module_name, module_offset); + return symbolizer_process_->SendCommand(buffer_); +} + +SymbolizerProcess::SymbolizerProcess(const char *path, bool use_forkpty) + : path_(path), + input_fd_(kInvalidFd), + output_fd_(kInvalidFd), + times_restarted_(0), + failed_to_start_(false), + reported_invalid_path_(false), + use_forkpty_(use_forkpty) { + CHECK(path_); + CHECK_NE(path_[0], '\0'); +} + +const char *SymbolizerProcess::SendCommand(const char *command) { + for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) { + // Start or restart symbolizer if we failed to send command to it. + if (const char *res = SendCommandImpl(command)) + return res; + Restart(); + } + if (!failed_to_start_) { + Report("WARNING: Failed to use and restart external symbolizer!\n"); + failed_to_start_ = true; + } + return 0; +} + +const char *SymbolizerProcess::SendCommandImpl(const char *command) { + if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd) + return 0; + if (!WriteToSymbolizer(command, internal_strlen(command))) + return 0; + if (!ReadFromSymbolizer(buffer_, kBufferSize)) + return 0; + return buffer_; +} + +bool SymbolizerProcess::Restart() { + if (input_fd_ != kInvalidFd) + CloseFile(input_fd_); + if (output_fd_ != kInvalidFd) + CloseFile(output_fd_); + return StartSymbolizerSubprocess(); +} + +bool SymbolizerProcess::ReadFromSymbolizer(char *buffer, uptr max_length) { + if (max_length == 0) + return true; + uptr read_len = 0; + while (true) { + uptr just_read = 0; + bool success = ReadFromFile(input_fd_, buffer + read_len, + max_length - read_len - 1, &just_read); + // We can't read 0 bytes, as we don't expect external symbolizer to close + // its stdout. + if (!success || just_read == 0) { + Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_); + return false; + } + read_len += just_read; + if (ReachedEndOfOutput(buffer, read_len)) + break; + } + buffer[read_len] = '\0'; + return true; +} + +bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) { + if (length == 0) + return true; + uptr write_len = 0; + bool success = WriteToFile(output_fd_, buffer, length, &write_len); + if (!success || write_len != length) { + Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_); + return false; + } + return true; +} + } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_mac.cc b/lib/sanitizer_common/sanitizer_symbolizer_mac.cc index 9a64192b0353..64048fa7e58e 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_mac.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_mac.cc @@ -33,39 +33,50 @@ bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { int result = dladdr((const void *)addr, &info); if (!result) return false; const char *demangled = DemangleCXXABI(info.dli_sname); - stack->info.function = internal_strdup(demangled); + stack->info.function = demangled ? internal_strdup(demangled) : nullptr; return true; } -bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { - return false; +bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) { + Dl_info info; + int result = dladdr((const void *)addr, &info); + if (!result) return false; + const char *demangled = DemangleCXXABI(info.dli_sname); + datainfo->name = internal_strdup(demangled); + datainfo->start = (uptr)info.dli_saddr; + return true; } class AtosSymbolizerProcess : public SymbolizerProcess { public: explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid) - : SymbolizerProcess(path, /*use_forkpty*/ true), - parent_pid_(parent_pid) {} + : SymbolizerProcess(path, /*use_forkpty*/ true) { + // Put the string command line argument in the object so that it outlives + // the call to GetArgV. + internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid); + } private: bool ReachedEndOfOutput(const char *buffer, uptr length) const override { return (length >= 1 && buffer[length - 1] == '\n'); } - void ExecuteWithDefaultArgs(const char *path_to_binary) const override { - char pid_str[16]; - internal_snprintf(pid_str, sizeof(pid_str), "%d", parent_pid_); + void GetArgV(const char *path_to_binary, + const char *(&argv)[kArgVMax]) const override { + int i = 0; + argv[i++] = path_to_binary; + argv[i++] = "-p"; + argv[i++] = &pid_str_[0]; if (GetMacosVersion() == MACOS_VERSION_MAVERICKS) { // On Mavericks atos prints a deprecation warning which we suppress by // passing -d. The warning isn't present on other OSX versions, even the // newer ones. - execl(path_to_binary, path_to_binary, "-p", pid_str, "-d", (char *)0); - } else { - execl(path_to_binary, path_to_binary, "-p", pid_str, (char *)0); + argv[i++] = "-d"; } + argv[i++] = nullptr; } - pid_t parent_pid_; + char pid_str_[16]; }; static const char *kAtosErrorMessages[] = { @@ -85,7 +96,9 @@ static bool IsAtosErrorMessage(const char *str) { return false; } -static bool ParseCommandOutput(const char *str, SymbolizedStack *res) { +static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, + char **out_module, char **out_file, uptr *line, + uptr *start_address) { // Trim ending newlines. char *trim; ExtractTokenUpToDelimiter(str, "\n", &trim); @@ -93,7 +106,9 @@ static bool ParseCommandOutput(const char *str, SymbolizedStack *res) { // The line from `atos` is in one of these formats: // myfunction (in library.dylib) (sourcefile.c:17) // myfunction (in library.dylib) + 0x1fe + // myfunction (in library.dylib) + 15 // 0xdeadbeef (in library.dylib) + 0x1fe + // 0xdeadbeef (in library.dylib) + 15 // 0xdeadbeef (in library.dylib) // 0xdeadbeef @@ -104,21 +119,33 @@ static bool ParseCommandOutput(const char *str, SymbolizedStack *res) { } const char *rest = trim; - char *function_name; - rest = ExtractTokenUpToDelimiter(rest, " (in ", &function_name); - if (internal_strncmp(function_name, "0x", 2) != 0) - res->info.function = function_name; + char *symbol_name; + rest = ExtractTokenUpToDelimiter(rest, " (in ", &symbol_name); + if (rest[0] == '\0') { + InternalFree(symbol_name); + InternalFree(trim); + return false; + } + + if (internal_strncmp(symbol_name, "0x", 2) != 0) + *out_name = symbol_name; else - InternalFree(function_name); - rest = ExtractTokenUpToDelimiter(rest, ") ", &res->info.module); + InternalFree(symbol_name); + rest = ExtractTokenUpToDelimiter(rest, ") ", out_module); if (rest[0] == '(') { - rest++; - rest = ExtractTokenUpToDelimiter(rest, ":", &res->info.file); - char *extracted_line_number; - rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number); - res->info.line = internal_atoll(extracted_line_number); - InternalFree(extracted_line_number); + if (out_file) { + rest++; + rest = ExtractTokenUpToDelimiter(rest, ":", out_file); + char *extracted_line_number; + rest = ExtractTokenUpToDelimiter(rest, ")", &extracted_line_number); + if (line) *line = (uptr)internal_atoll(extracted_line_number); + InternalFree(extracted_line_number); + } + } else if (rest[0] == '+') { + rest += 2; + uptr offset = internal_atoll(rest); + if (start_address) *start_address = addr - offset; } InternalFree(trim); @@ -134,14 +161,29 @@ bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { internal_snprintf(command, sizeof(command), "0x%zx\n", addr); const char *buf = process_->SendCommand(command); if (!buf) return false; - if (!ParseCommandOutput(buf, stack)) { + uptr line; + if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module, + &stack->info.file, &line, nullptr)) { process_ = nullptr; return false; } + stack->info.line = (int)line; return true; } -bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { return false; } +bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { + if (!process_) return false; + char command[32]; + internal_snprintf(command, sizeof(command), "0x%zx\n", addr); + const char *buf = process_->SendCommand(command); + if (!buf) return false; + if (!ParseCommandOutput(buf, addr, &info->name, &info->module, nullptr, + nullptr, &info->start)) { + process_ = nullptr; + return false; + } + return true; +} } // namespace __sanitizer diff --git a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index cb8455a21ae2..fc8a7d91ac73 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -20,13 +20,21 @@ #include "sanitizer_internal_defs.h" #include "sanitizer_linux.h" #include "sanitizer_placement_new.h" +#include "sanitizer_posix.h" #include "sanitizer_procmaps.h" #include "sanitizer_symbolizer_internal.h" #include "sanitizer_symbolizer_libbacktrace.h" #include "sanitizer_symbolizer_mac.h" +#include <errno.h> +#include <stdlib.h> +#include <sys/wait.h> #include <unistd.h> +#if SANITIZER_MAC +#include <util.h> // for forkpty() +#endif // SANITIZER_MAC + // C++ demangling function, as required by Itanium C++ ABI. This is weak, // because we do not require a C++ ABI library to be linked to a program // using sanitizers; if it's not present, we'll just use the mangled name. @@ -53,149 +61,130 @@ const char *DemangleCXXABI(const char *name) { return name; } -// Parses one or more two-line strings in the following format: -// <function_name> -// <file_name>:<line_number>[:<column_number>] -// Used by LLVMSymbolizer, Addr2LinePool and InternalSymbolizer, since all of -// them use the same output format. -static void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) { - bool top_frame = true; - SymbolizedStack *last = res; - while (true) { - char *function_name = 0; - str = ExtractToken(str, "\n", &function_name); - CHECK(function_name); - if (function_name[0] == '\0') { - // There are no more frames. - InternalFree(function_name); - break; - } - SymbolizedStack *cur; - if (top_frame) { - cur = res; - top_frame = false; - } else { - cur = SymbolizedStack::New(res->info.address); - cur->info.FillModuleInfo(res->info.module, res->info.module_offset); - last->next = cur; - last = cur; - } - - AddressInfo *info = &cur->info; - info->function = function_name; - // Parse <file>:<line>:<column> buffer. - char *file_line_info = 0; - str = ExtractToken(str, "\n", &file_line_info); - CHECK(file_line_info); - const char *line_info = ExtractToken(file_line_info, ":", &info->file); - line_info = ExtractInt(line_info, ":", &info->line); - line_info = ExtractInt(line_info, "", &info->column); - InternalFree(file_line_info); - - // Functions and filenames can be "??", in which case we write 0 - // to address info to mark that names are unknown. - if (0 == internal_strcmp(info->function, "??")) { - InternalFree(info->function); - info->function = 0; - } - if (0 == internal_strcmp(info->file, "??")) { - InternalFree(info->file); - info->file = 0; +bool SymbolizerProcess::StartSymbolizerSubprocess() { + if (!FileExists(path_)) { + if (!reported_invalid_path_) { + Report("WARNING: invalid path to external symbolizer!\n"); + reported_invalid_path_ = true; } - } -} - -// Parses a two-line string in the following format: -// <symbol_name> -// <start_address> <size> -// Used by LLVMSymbolizer and InternalSymbolizer. -static void ParseSymbolizeDataOutput(const char *str, DataInfo *info) { - str = ExtractToken(str, "\n", &info->name); - str = ExtractUptr(str, " ", &info->start); - str = ExtractUptr(str, "\n", &info->size); -} - -// For now we assume the following protocol: -// For each request of the form -// <module_name> <module_offset> -// passed to STDIN, external symbolizer prints to STDOUT response: -// <function_name> -// <file_name>:<line_number>:<column_number> -// <function_name> -// <file_name>:<line_number>:<column_number> -// ... -// <empty line> -class LLVMSymbolizerProcess : public SymbolizerProcess { - public: - explicit LLVMSymbolizerProcess(const char *path) : SymbolizerProcess(path) {} - - private: - bool ReachedEndOfOutput(const char *buffer, uptr length) const override { - // Empty line marks the end of llvm-symbolizer output. - return length >= 2 && buffer[length - 1] == '\n' && - buffer[length - 2] == '\n'; + return false; } - void ExecuteWithDefaultArgs(const char *path_to_binary) const override { -#if defined(__x86_64h__) - const char* const kSymbolizerArch = "--default-arch=x86_64h"; -#elif defined(__x86_64__) - const char* const kSymbolizerArch = "--default-arch=x86_64"; -#elif defined(__i386__) - const char* const kSymbolizerArch = "--default-arch=i386"; -#elif defined(__powerpc64__) && defined(__BIG_ENDIAN__) - const char* const kSymbolizerArch = "--default-arch=powerpc64"; -#elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__) - const char* const kSymbolizerArch = "--default-arch=powerpc64le"; -#else - const char* const kSymbolizerArch = "--default-arch=unknown"; -#endif - - const char *const inline_flag = common_flags()->symbolize_inline_frames - ? "--inlining=true" - : "--inlining=false"; - execl(path_to_binary, path_to_binary, inline_flag, kSymbolizerArch, - (char *)0); - } -}; + int pid; + if (use_forkpty_) { +#if SANITIZER_MAC + fd_t fd = kInvalidFd; + // Use forkpty to disable buffering in the new terminal. + pid = internal_forkpty(&fd); + if (pid == -1) { + // forkpty() failed. + Report("WARNING: failed to fork external symbolizer (errno: %d)\n", + errno); + return false; + } else if (pid == 0) { + // Child subprocess. + const char *argv[kArgVMax]; + GetArgV(path_, argv); + execv(path_, const_cast<char **>(&argv[0])); + internal__exit(1); + } -class LLVMSymbolizer : public SymbolizerTool { - public: - explicit LLVMSymbolizer(const char *path, LowLevelAllocator *allocator) - : symbolizer_process_(new(*allocator) LLVMSymbolizerProcess(path)) {} + // Continue execution in parent process. + input_fd_ = output_fd_ = fd; - bool SymbolizePC(uptr addr, SymbolizedStack *stack) override { - if (const char *buf = SendCommand(/*is_data*/ false, stack->info.module, - stack->info.module_offset)) { - ParseSymbolizePCOutput(buf, stack); - return true; + // Disable echo in the new terminal, disable CR. + struct termios termflags; + tcgetattr(fd, &termflags); + termflags.c_oflag &= ~ONLCR; + termflags.c_lflag &= ~ECHO; + tcsetattr(fd, TCSANOW, &termflags); +#else // SANITIZER_MAC + UNIMPLEMENTED(); +#endif // SANITIZER_MAC + } else { + int *infd = NULL; + int *outfd = NULL; + // The client program may close its stdin and/or stdout and/or stderr + // thus allowing socketpair to reuse file descriptors 0, 1 or 2. + // In this case the communication between the forked processes may be + // broken if either the parent or the child tries to close or duplicate + // these descriptors. The loop below produces two pairs of file + // descriptors, each greater than 2 (stderr). + int sock_pair[5][2]; + for (int i = 0; i < 5; i++) { + if (pipe(sock_pair[i]) == -1) { + for (int j = 0; j < i; j++) { + internal_close(sock_pair[j][0]); + internal_close(sock_pair[j][1]); + } + Report("WARNING: Can't create a socket pair to start " + "external symbolizer (errno: %d)\n", errno); + return false; + } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) { + if (infd == NULL) { + infd = sock_pair[i]; + } else { + outfd = sock_pair[i]; + for (int j = 0; j < i; j++) { + if (sock_pair[j] == infd) continue; + internal_close(sock_pair[j][0]); + internal_close(sock_pair[j][1]); + } + break; + } + } } - return false; - } - - bool SymbolizeData(uptr addr, DataInfo *info) override { - if (const char *buf = - SendCommand(/*is_data*/ true, info->module, info->module_offset)) { - ParseSymbolizeDataOutput(buf, info); - info->start += (addr - info->module_offset); // Add the base address. - return true; + CHECK(infd); + CHECK(outfd); + + // Real fork() may call user callbacks registered with pthread_atfork(). + pid = internal_fork(); + if (pid == -1) { + // Fork() failed. + internal_close(infd[0]); + internal_close(infd[1]); + internal_close(outfd[0]); + internal_close(outfd[1]); + Report("WARNING: failed to fork external symbolizer " + " (errno: %d)\n", errno); + return false; + } else if (pid == 0) { + // Child subprocess. + internal_close(STDOUT_FILENO); + internal_close(STDIN_FILENO); + internal_dup2(outfd[0], STDIN_FILENO); + internal_dup2(infd[1], STDOUT_FILENO); + internal_close(outfd[0]); + internal_close(outfd[1]); + internal_close(infd[0]); + internal_close(infd[1]); + for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) + internal_close(fd); + const char *argv[kArgVMax]; + GetArgV(path_, argv); + execv(path_, const_cast<char **>(&argv[0])); + internal__exit(1); } - return false; + + // Continue execution in parent process. + internal_close(outfd[0]); + internal_close(infd[1]); + input_fd_ = infd[0]; + output_fd_ = outfd[1]; } - private: - const char *SendCommand(bool is_data, const char *module_name, - uptr module_offset) { - CHECK(module_name); - internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n", - is_data ? "DATA " : "", module_name, module_offset); - return symbolizer_process_->SendCommand(buffer_); + // Check that symbolizer subprocess started successfully. + int pid_status; + SleepForMillis(kSymbolizerStartupTimeMillis); + int exited_pid = waitpid(pid, &pid_status, WNOHANG); + if (exited_pid != 0) { + // Either waitpid failed, or child has already exited. + Report("WARNING: external symbolizer didn't start up correctly!\n"); + return false; } - LLVMSymbolizerProcess *symbolizer_process_; - static const uptr kBufferSize = 16 * 1024; - char buffer_[kBufferSize]; -}; + return true; +} class Addr2LineProcess : public SymbolizerProcess { public: @@ -205,25 +194,54 @@ class Addr2LineProcess : public SymbolizerProcess { const char *module_name() const { return module_name_; } private: - bool ReachedEndOfOutput(const char *buffer, uptr length) const override { - // Output should consist of two lines. - int num_lines = 0; - for (uptr i = 0; i < length; ++i) { - if (buffer[i] == '\n') - num_lines++; - if (num_lines >= 2) - return true; - } - return false; + void GetArgV(const char *path_to_binary, + const char *(&argv)[kArgVMax]) const override { + int i = 0; + argv[i++] = path_to_binary; + argv[i++] = "-iCfe"; + argv[i++] = module_name_; + argv[i++] = nullptr; } - void ExecuteWithDefaultArgs(const char *path_to_binary) const override { - execl(path_to_binary, path_to_binary, "-Cfe", module_name_, (char *)0); + bool ReachedEndOfOutput(const char *buffer, uptr length) const override; + + bool ReadFromSymbolizer(char *buffer, uptr max_length) override { + if (!SymbolizerProcess::ReadFromSymbolizer(buffer, max_length)) + return false; + // We should cut out output_terminator_ at the end of given buffer, + // appended by addr2line to mark the end of its meaningful output. + // We cannot scan buffer from it's beginning, because it is legal for it + // to start with output_terminator_ in case given offset is invalid. So, + // scanning from second character. + char *garbage = internal_strstr(buffer + 1, output_terminator_); + // This should never be NULL since buffer must end up with + // output_terminator_. + CHECK(garbage); + // Trim the buffer. + garbage[0] = '\0'; + return true; } const char *module_name_; // Owned, leaked. + static const char output_terminator_[]; }; +const char Addr2LineProcess::output_terminator_[] = "??\n??:0\n"; + +bool Addr2LineProcess::ReachedEndOfOutput(const char *buffer, + uptr length) const { + const size_t kTerminatorLen = sizeof(output_terminator_) - 1; + // Skip, if we read just kTerminatorLen bytes, because Addr2Line output + // should consist at least of two pairs of lines: + // 1. First one, corresponding to given offset to be symbolized + // (may be equal to output_terminator_, if offset is not valid). + // 2. Second one for output_terminator_, itself to mark the end of output. + if (length <= kTerminatorLen) return false; + // Addr2Line output should end up with output_terminator_. + return !internal_memcmp(buffer + length - kTerminatorLen, + output_terminator_, kTerminatorLen); +} + class Addr2LinePool : public SymbolizerTool { public: explicit Addr2LinePool(const char *addr2line_path, @@ -260,15 +278,18 @@ class Addr2LinePool : public SymbolizerTool { addr2line_pool_.push_back(addr2line); } CHECK_EQ(0, internal_strcmp(module_name, addr2line->module_name())); - char buffer_[kBufferSize]; - internal_snprintf(buffer_, kBufferSize, "0x%zx\n", module_offset); - return addr2line->SendCommand(buffer_); + char buffer[kBufferSize]; + internal_snprintf(buffer, kBufferSize, "0x%zx\n0x%zx\n", + module_offset, dummy_address_); + return addr2line->SendCommand(buffer); } - static const uptr kBufferSize = 32; + static const uptr kBufferSize = 64; const char *addr2line_path_; LowLevelAllocator *allocator_; InternalMmapVector<Addr2LineProcess*> addr2line_pool_; + static const uptr dummy_address_ = + FIRST_32_SECOND_64(UINT32_MAX, UINT64_MAX); }; #if SANITIZER_SUPPORTS_WEAK_HOOKS @@ -425,8 +446,6 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list, if (SymbolizerTool *tool = ChooseExternalSymbolizer(allocator)) { list->push_back(tool); - } else { - VReport(2, "No internal or external symbolizer found.\n"); } #if SANITIZER_MAC diff --git a/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc b/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc deleted file mode 100644 index f1c01a332499..000000000000 --- a/lib/sanitizer_common/sanitizer_symbolizer_process_libcdep.cc +++ /dev/null @@ -1,229 +0,0 @@ -//===-- sanitizer_symbolizer_process_libcdep.cc ---------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Implementation of SymbolizerProcess used by external symbolizers. -// -//===----------------------------------------------------------------------===// - -#include "sanitizer_platform.h" -#if SANITIZER_POSIX -#include "sanitizer_posix.h" -#include "sanitizer_symbolizer_internal.h" - -#include <errno.h> -#include <stdlib.h> -#include <sys/wait.h> -#include <unistd.h> - -#if SANITIZER_MAC -#include <util.h> // for forkpty() -#endif // SANITIZER_MAC - -namespace __sanitizer { - -SymbolizerProcess::SymbolizerProcess(const char *path, bool use_forkpty) - : path_(path), - input_fd_(kInvalidFd), - output_fd_(kInvalidFd), - times_restarted_(0), - failed_to_start_(false), - reported_invalid_path_(false), - use_forkpty_(use_forkpty) { - CHECK(path_); - CHECK_NE(path_[0], '\0'); -} - -const char *SymbolizerProcess::SendCommand(const char *command) { - for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) { - // Start or restart symbolizer if we failed to send command to it. - if (const char *res = SendCommandImpl(command)) - return res; - Restart(); - } - if (!failed_to_start_) { - Report("WARNING: Failed to use and restart external symbolizer!\n"); - failed_to_start_ = true; - } - return 0; -} - -bool SymbolizerProcess::Restart() { - if (input_fd_ != kInvalidFd) - internal_close(input_fd_); - if (output_fd_ != kInvalidFd) - internal_close(output_fd_); - return StartSymbolizerSubprocess(); -} - -const char *SymbolizerProcess::SendCommandImpl(const char *command) { - if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd) - return 0; - if (!WriteToSymbolizer(command, internal_strlen(command))) - return 0; - if (!ReadFromSymbolizer(buffer_, kBufferSize)) - return 0; - return buffer_; -} - -bool SymbolizerProcess::ReadFromSymbolizer(char *buffer, uptr max_length) { - if (max_length == 0) - return true; - uptr read_len = 0; - while (true) { - uptr just_read = internal_read(input_fd_, buffer + read_len, - max_length - read_len - 1); - // We can't read 0 bytes, as we don't expect external symbolizer to close - // its stdout. - if (just_read == 0 || just_read == (uptr)-1) { - Report("WARNING: Can't read from symbolizer at fd %d\n", input_fd_); - return false; - } - read_len += just_read; - if (ReachedEndOfOutput(buffer, read_len)) - break; - } - buffer[read_len] = '\0'; - return true; -} - -bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) { - if (length == 0) - return true; - uptr write_len = internal_write(output_fd_, buffer, length); - if (write_len == 0 || write_len == (uptr)-1) { - Report("WARNING: Can't write to symbolizer at fd %d\n", output_fd_); - return false; - } - return true; -} - -bool SymbolizerProcess::StartSymbolizerSubprocess() { - if (!FileExists(path_)) { - if (!reported_invalid_path_) { - Report("WARNING: invalid path to external symbolizer!\n"); - reported_invalid_path_ = true; - } - return false; - } - - int pid; - if (use_forkpty_) { -#if SANITIZER_MAC - fd_t fd = kInvalidFd; - // Use forkpty to disable buffering in the new terminal. - pid = forkpty(&fd, 0, 0, 0); - if (pid == -1) { - // forkpty() failed. - Report("WARNING: failed to fork external symbolizer (errno: %d)\n", - errno); - return false; - } else if (pid == 0) { - // Child subprocess. - ExecuteWithDefaultArgs(path_); - internal__exit(1); - } - - // Continue execution in parent process. - input_fd_ = output_fd_ = fd; - - // Disable echo in the new terminal, disable CR. - struct termios termflags; - tcgetattr(fd, &termflags); - termflags.c_oflag &= ~ONLCR; - termflags.c_lflag &= ~ECHO; - tcsetattr(fd, TCSANOW, &termflags); -#else // SANITIZER_MAC - UNIMPLEMENTED(); -#endif // SANITIZER_MAC - } else { - int *infd = NULL; - int *outfd = NULL; - // The client program may close its stdin and/or stdout and/or stderr - // thus allowing socketpair to reuse file descriptors 0, 1 or 2. - // In this case the communication between the forked processes may be - // broken if either the parent or the child tries to close or duplicate - // these descriptors. The loop below produces two pairs of file - // descriptors, each greater than 2 (stderr). - int sock_pair[5][2]; - for (int i = 0; i < 5; i++) { - if (pipe(sock_pair[i]) == -1) { - for (int j = 0; j < i; j++) { - internal_close(sock_pair[j][0]); - internal_close(sock_pair[j][1]); - } - Report("WARNING: Can't create a socket pair to start " - "external symbolizer (errno: %d)\n", errno); - return false; - } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) { - if (infd == NULL) { - infd = sock_pair[i]; - } else { - outfd = sock_pair[i]; - for (int j = 0; j < i; j++) { - if (sock_pair[j] == infd) continue; - internal_close(sock_pair[j][0]); - internal_close(sock_pair[j][1]); - } - break; - } - } - } - CHECK(infd); - CHECK(outfd); - - // Real fork() may call user callbacks registered with pthread_atfork(). - pid = internal_fork(); - if (pid == -1) { - // Fork() failed. - internal_close(infd[0]); - internal_close(infd[1]); - internal_close(outfd[0]); - internal_close(outfd[1]); - Report("WARNING: failed to fork external symbolizer " - " (errno: %d)\n", errno); - return false; - } else if (pid == 0) { - // Child subprocess. - internal_close(STDOUT_FILENO); - internal_close(STDIN_FILENO); - internal_dup2(outfd[0], STDIN_FILENO); - internal_dup2(infd[1], STDOUT_FILENO); - internal_close(outfd[0]); - internal_close(outfd[1]); - internal_close(infd[0]); - internal_close(infd[1]); - for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) - internal_close(fd); - ExecuteWithDefaultArgs(path_); - internal__exit(1); - } - - // Continue execution in parent process. - internal_close(outfd[0]); - internal_close(infd[1]); - input_fd_ = infd[0]; - output_fd_ = outfd[1]; - } - - // Check that symbolizer subprocess started successfully. - int pid_status; - SleepForMillis(kSymbolizerStartupTimeMillis); - int exited_pid = waitpid(pid, &pid_status, WNOHANG); - if (exited_pid != 0) { - // Either waitpid failed, or child has already exited. - Report("WARNING: external symbolizer didn't start up correctly!\n"); - return false; - } - - return true; -} - -} // namespace __sanitizer - -#endif // SANITIZER_POSIX diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/lib/sanitizer_common/sanitizer_symbolizer_win.cc index 31f374687e96..b1dceebf45ce 100644 --- a/lib/sanitizer_common/sanitizer_symbolizer_win.cc +++ b/lib/sanitizer_common/sanitizer_symbolizer_win.cc @@ -14,17 +14,26 @@ #include "sanitizer_platform.h" #if SANITIZER_WINDOWS +#define WIN32_LEAN_AND_MEAN #include <windows.h> #include <dbghelp.h> #pragma comment(lib, "dbghelp.lib") -#include "sanitizer_symbolizer_win.h" #include "sanitizer_symbolizer_internal.h" namespace __sanitizer { namespace { +class WinSymbolizerTool : public SymbolizerTool { + public: + bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; + bool SymbolizeData(uptr addr, DataInfo *info) override { + return false; + } + const char *Demangle(const char *name) override; +}; + bool is_dbghelp_initialized = false; bool TrySymInitialize() { @@ -115,7 +124,9 @@ bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) { frame->info.file = internal_strdup(line_info.FileName); frame->info.line = line_info.LineNumber; } - return true; + // Only consider this a successful symbolization attempt if we got file info. + // Otherwise, try llvm-symbolizer. + return got_fileline; } const char *WinSymbolizerTool::Demangle(const char *name) { @@ -137,10 +148,134 @@ void Symbolizer::PlatformPrepareForSandboxing() { // Do nothing. } +namespace { +struct ScopedHandle { + ScopedHandle() : h_(nullptr) {} + explicit ScopedHandle(HANDLE h) : h_(h) {} + ~ScopedHandle() { + if (h_) + ::CloseHandle(h_); + } + HANDLE get() { return h_; } + HANDLE *receive() { return &h_; } + HANDLE release() { + HANDLE h = h_; + h_ = nullptr; + return h; + } + HANDLE h_; +}; +} // namespace + +bool SymbolizerProcess::StartSymbolizerSubprocess() { + // Create inherited pipes for stdin and stdout. + ScopedHandle stdin_read, stdin_write; + ScopedHandle stdout_read, stdout_write; + SECURITY_ATTRIBUTES attrs; + attrs.nLength = sizeof(SECURITY_ATTRIBUTES); + attrs.bInheritHandle = TRUE; + attrs.lpSecurityDescriptor = nullptr; + if (!::CreatePipe(stdin_read.receive(), stdin_write.receive(), &attrs, 0) || + !::CreatePipe(stdout_read.receive(), stdout_write.receive(), &attrs, 0)) { + VReport(2, "WARNING: %s CreatePipe failed (error code: %d)\n", + SanitizerToolName, path_, GetLastError()); + return false; + } + + // Don't inherit the writing end of stdin or the reading end of stdout. + if (!SetHandleInformation(stdin_write.get(), HANDLE_FLAG_INHERIT, 0) || + !SetHandleInformation(stdout_read.get(), HANDLE_FLAG_INHERIT, 0)) { + VReport(2, "WARNING: %s SetHandleInformation failed (error code: %d)\n", + SanitizerToolName, path_, GetLastError()); + return false; + } + + // Compute the command line. Wrap double quotes around everything. + const char *argv[kArgVMax]; + GetArgV(path_, argv); + InternalScopedString command_line(kMaxPathLength * 3); + for (int i = 0; argv[i]; i++) { + const char *arg = argv[i]; + int arglen = internal_strlen(arg); + // Check that tool command lines are simple and that complete escaping is + // unnecessary. + CHECK(!internal_strchr(arg, '"') && "quotes in args unsupported"); + CHECK(!internal_strstr(arg, "\\\\") && + "double backslashes in args unsupported"); + CHECK(arglen > 0 && arg[arglen - 1] != '\\' && + "args ending in backslash and empty args unsupported"); + command_line.append("\"%s\" ", arg); + } + VReport(3, "Launching symbolizer command: %s\n", command_line.data()); + + // Launch llvm-symbolizer with stdin and stdout redirected. + STARTUPINFOA si; + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags |= STARTF_USESTDHANDLES; + si.hStdInput = stdin_read.get(); + si.hStdOutput = stdout_write.get(); + PROCESS_INFORMATION pi; + memset(&pi, 0, sizeof(pi)); + if (!CreateProcessA(path_, // Executable + command_line.data(), // Command line + nullptr, // Process handle not inheritable + nullptr, // Thread handle not inheritable + TRUE, // Set handle inheritance to TRUE + 0, // Creation flags + nullptr, // Use parent's environment block + nullptr, // Use parent's starting directory + &si, &pi)) { + VReport(2, "WARNING: %s failed to create process for %s (error code: %d)\n", + SanitizerToolName, path_, GetLastError()); + return false; + } + + // Process creation succeeded, so transfer handle ownership into the fields. + input_fd_ = stdout_read.release(); + output_fd_ = stdin_write.release(); + + // The llvm-symbolizer process is responsible for quitting itself when the + // stdin pipe is closed, so we don't need these handles. Close them to prevent + // leaks. If we ever want to try to kill the symbolizer process from the + // parent, we'll want to hang on to these handles. + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return true; +} + +static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list, + LowLevelAllocator *allocator) { + if (!common_flags()->symbolize) { + VReport(2, "Symbolizer is disabled.\n"); + return; + } + + // Add llvm-symbolizer in case the binary has dwarf. + const char *user_path = common_flags()->external_symbolizer_path; + const char *path = + user_path ? user_path : FindPathToBinary("llvm-symbolizer.exe"); + if (path) { + VReport(2, "Using llvm-symbolizer at %spath: %s\n", + user_path ? "user-specified " : "", path); + list->push_back(new(*allocator) LLVMSymbolizer(path, allocator)); + } else { + if (user_path && user_path[0] == '\0') { + VReport(2, "External symbolizer is explicitly disabled.\n"); + } else { + VReport(2, "External symbolizer is not present.\n"); + } + } + + // Add the dbghelp based symbolizer. + list->push_back(new(*allocator) WinSymbolizerTool()); +} + Symbolizer *Symbolizer::PlatformInit() { IntrusiveList<SymbolizerTool> list; list.clear(); - list.push_back(new(symbolizer_allocator_) WinSymbolizerTool()); + ChooseSymbolizerTools(&list, &symbolizer_allocator_); + return new(symbolizer_allocator_) Symbolizer(list); } diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.h b/lib/sanitizer_common/sanitizer_symbolizer_win.h deleted file mode 100644 index 72ac5e5ee104..000000000000 --- a/lib/sanitizer_common/sanitizer_symbolizer_win.h +++ /dev/null @@ -1,31 +0,0 @@ -//===-- sanitizer_symbolizer_win.h ------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Header file for the Windows symbolizer tool. -// -//===----------------------------------------------------------------------===// -#ifndef SANITIZER_SYMBOLIZER_WIN_H -#define SANITIZER_SYMBOLIZER_WIN_H - -#include "sanitizer_symbolizer_internal.h" - -namespace __sanitizer { - -class WinSymbolizerTool : public SymbolizerTool { - public: - bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; - bool SymbolizeData(uptr addr, DataInfo *info) override { - return false; - } - const char *Demangle(const char *name) override; -}; - -} // namespace __sanitizer - -#endif // SANITIZER_SYMBOLIZER_WIN_H diff --git a/lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc b/lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc new file mode 100644 index 000000000000..7ab1d7641449 --- /dev/null +++ b/lib/sanitizer_common/sanitizer_syscall_linux_aarch64.inc @@ -0,0 +1,138 @@ +//===-- sanitizer_syscall_linux_aarch64.inc --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementations of internal_syscall and internal_iserror for Linux/aarch64. +// +//===----------------------------------------------------------------------===// + +#define SYSCALL(name) __NR_ ## name + +static uptr __internal_syscall(u64 nr) { + register u64 x8 asm("x8") = nr; + register u64 x0 asm("x0"); + asm volatile("svc 0" + : "=r"(x0) + : "r"(x8) + : "memory", "cc"); + return x0; +} +#define __internal_syscall0(n) \ + (__internal_syscall)(n) + +static uptr __internal_syscall(u64 nr, u64 arg1) { + register u64 x8 asm("x8") = nr; + register u64 x0 asm("x0") = arg1; + asm volatile("svc 0" + : "=r"(x0) + : "r"(x8), "0"(x0) + : "memory", "cc"); + return x0; +} +#define __internal_syscall1(n, a1) \ + (__internal_syscall)(n, (u64)(a1)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2) { + register u64 x8 asm("x8") = nr; + register u64 x0 asm("x0") = arg1; + register u64 x1 asm("x1") = arg2; + asm volatile("svc 0" + : "=r"(x0) + : "r"(x8), "0"(x0), "r"(x1) + : "memory", "cc"); + return x0; +} +#define __internal_syscall2(n, a1, a2) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3) { + register u64 x8 asm("x8") = nr; + register u64 x0 asm("x0") = arg1; + register u64 x1 asm("x1") = arg2; + register u64 x2 asm("x2") = arg3; + asm volatile("svc 0" + : "=r"(x0) + : "r"(x8), "0"(x0), "r"(x1), "r"(x2) + : "memory", "cc"); + return x0; +} +#define __internal_syscall3(n, a1, a2, a3) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, + u64 arg4) { + register u64 x8 asm("x8") = nr; + register u64 x0 asm("x0") = arg1; + register u64 x1 asm("x1") = arg2; + register u64 x2 asm("x2") = arg3; + register u64 x3 asm("x3") = arg4; + asm volatile("svc 0" + : "=r"(x0) + : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3) + : "memory", "cc"); + return x0; +} +#define __internal_syscall4(n, a1, a2, a3, a4) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, + u64 arg4, long arg5) { + register u64 x8 asm("x8") = nr; + register u64 x0 asm("x0") = arg1; + register u64 x1 asm("x1") = arg2; + register u64 x2 asm("x2") = arg3; + register u64 x3 asm("x3") = arg4; + register u64 x4 asm("x4") = arg5; + asm volatile("svc 0" + : "=r"(x0) + : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4) + : "memory", "cc"); + return x0; +} +#define __internal_syscall5(n, a1, a2, a3, a4, a5) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (u64)(a5)) + +static uptr __internal_syscall(u64 nr, u64 arg1, long arg2, long arg3, + u64 arg4, long arg5, long arg6) { + register u64 x8 asm("x8") = nr; + register u64 x0 asm("x0") = arg1; + register u64 x1 asm("x1") = arg2; + register u64 x2 asm("x2") = arg3; + register u64 x3 asm("x3") = arg4; + register u64 x4 asm("x4") = arg5; + register u64 x5 asm("x5") = arg6; + asm volatile("svc 0" + : "=r"(x0) + : "r"(x8), "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5) + : "memory", "cc"); + return x0; +} +#define __internal_syscall6(n, a1, a2, a3, a4, a5, a6) \ + (__internal_syscall)(n, (u64)(a1), (long)(a2), (long)(a3), (long)(a4), \ + (u64)(a5), (long)(a6)) + +#define __SYSCALL_NARGS_X(a1, a2, a3, a4, a5, a6, a7, a8, n, ...) n +#define __SYSCALL_NARGS(...) \ + __SYSCALL_NARGS_X(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0, ) +#define __SYSCALL_CONCAT_X(a, b) a##b +#define __SYSCALL_CONCAT(a, b) __SYSCALL_CONCAT_X(a, b) +#define __SYSCALL_DISP(b, ...) \ + __SYSCALL_CONCAT(b, __SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) + +#define internal_syscall(...) __SYSCALL_DISP(__internal_syscall, __VA_ARGS__) + +// Helper function used to avoid cobbler errno. +bool internal_iserror(uptr retval, int *rverrno) { + if (retval >= (uptr)-4095) { + if (rverrno) + *rverrno = -retval; + return true; + } + return false; +} diff --git a/lib/sanitizer_common/sanitizer_thread_registry.h b/lib/sanitizer_common/sanitizer_thread_registry.h index 5d9c3b9694e8..a27bbb376e85 100644 --- a/lib/sanitizer_common/sanitizer_thread_registry.h +++ b/lib/sanitizer_common/sanitizer_thread_registry.h @@ -79,7 +79,8 @@ class ThreadRegistry { ThreadRegistry(ThreadContextFactory factory, u32 max_threads, u32 thread_quarantine_size, u32 max_reuse = 0); - void GetNumberOfThreads(uptr *total = 0, uptr *running = 0, uptr *alive = 0); + void GetNumberOfThreads(uptr *total = nullptr, uptr *running = nullptr, + uptr *alive = nullptr); uptr GetMaxAliveThreads(); void Lock() { mtx_.Lock(); } @@ -142,7 +143,6 @@ class ThreadRegistry { typedef GenericScopedLock<ThreadRegistry> ThreadRegistryLock; -} // namespace __sanitizer - -#endif // SANITIZER_THREAD_REGISTRY_H +} // namespace __sanitizer +#endif // SANITIZER_THREAD_REGISTRY_H diff --git a/lib/sanitizer_common/sanitizer_tls_get_addr.cc b/lib/sanitizer_common/sanitizer_tls_get_addr.cc index ea037159d00b..213aced89da7 100644 --- a/lib/sanitizer_common/sanitizer_tls_get_addr.cc +++ b/lib/sanitizer_common/sanitizer_tls_get_addr.cc @@ -78,6 +78,15 @@ void DTLS_Destroy() { DTLS_Deallocate(dtls.dtv, s); } +#if defined(__powerpc64__) +// This is glibc's TLS_DTV_OFFSET: +// "Dynamic thread vector pointers point 0x8000 past the start of each +// TLS block." +static const uptr kDtvOffset = 0x8000; +#else +static const uptr kDtvOffset = 0; +#endif + DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res, uptr static_tls_begin, uptr static_tls_end) { if (!common_flags()->intercept_tls_get_addr) return 0; @@ -87,7 +96,7 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res, DTLS_Resize(dso_id + 1); if (dtls.dtv[dso_id].beg) return 0; uptr tls_size = 0; - uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset; + uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset - kDtvOffset; VPrintf(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p " "num_live_dtls %zd\n", arg, arg->dso_id, arg->offset, res, tls_beg, &tls_beg, diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc index d5bbe4565068..861261d8402c 100644 --- a/lib/sanitizer_common/sanitizer_win.cc +++ b/lib/sanitizer_common/sanitizer_win.cc @@ -51,7 +51,7 @@ uptr GetMaxVirtualAddress() { } bool FileExists(const char *filename) { - UNIMPLEMENTED(); + return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES; } uptr internal_getpid() { @@ -83,14 +83,11 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, } #endif // #if !SANITIZER_GO -void *MmapOrDie(uptr size, const char *mem_type) { +void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) { void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); - if (rv == 0) { - Report("ERROR: %s failed to " - "allocate 0x%zx (%zd) bytes of %s (error code: %d)\n", - SanitizerToolName, size, size, mem_type, GetLastError()); - CHECK("unable to mmap" && 0); - } + if (rv == 0) + ReportMmapFailureAndDie(size, mem_type, "allocate", + GetLastError(), raw_report); return rv; } @@ -224,12 +221,14 @@ struct ModuleInfo { uptr end_address; }; +#ifndef SANITIZER_GO int CompareModulesBase(const void *pl, const void *pr) { const ModuleInfo *l = (ModuleInfo *)pl, *r = (ModuleInfo *)pr; if (l->base_address < r->base_address) return -1; return l->base_address > r->base_address; } +#endif } // namespace #ifndef SANITIZER_GO @@ -292,11 +291,6 @@ void SetAddressSpaceUnlimited() { UNIMPLEMENTED(); } -char *FindPathToBinary(const char *name) { - // Nothing here for now. - return 0; -} - bool IsPathSeparator(const char c) { return c == '\\' || c == '/'; } @@ -323,6 +317,59 @@ void Abort() { internal__exit(3); } +// Read the file to extract the ImageBase field from the PE header. If ASLR is +// disabled and this virtual address is available, the loader will typically +// load the image at this address. Therefore, we call it the preferred base. Any +// addresses in the DWARF typically assume that the object has been loaded at +// this address. +static uptr GetPreferredBase(const char *modname) { + fd_t fd = OpenFile(modname, RdOnly, nullptr); + if (fd == kInvalidFd) + return 0; + FileCloser closer(fd); + + // Read just the DOS header. + IMAGE_DOS_HEADER dos_header; + uptr bytes_read; + if (!ReadFromFile(fd, &dos_header, sizeof(dos_header), &bytes_read) || + bytes_read != sizeof(dos_header)) + return 0; + + // The file should start with the right signature. + if (dos_header.e_magic != IMAGE_DOS_SIGNATURE) + return 0; + + // The layout at e_lfanew is: + // "PE\0\0" + // IMAGE_FILE_HEADER + // IMAGE_OPTIONAL_HEADER + // Seek to e_lfanew and read all that data. + char buf[4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER)]; + if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) == + INVALID_SET_FILE_POINTER) + return 0; + if (!ReadFromFile(fd, &buf[0], sizeof(buf), &bytes_read) || + bytes_read != sizeof(buf)) + return 0; + + // Check for "PE\0\0" before the PE header. + char *pe_sig = &buf[0]; + if (internal_memcmp(pe_sig, "PE\0\0", 4) != 0) + return 0; + + // Skip over IMAGE_FILE_HEADER. We could do more validation here if we wanted. + IMAGE_OPTIONAL_HEADER *pe_header = + (IMAGE_OPTIONAL_HEADER *)(pe_sig + 4 + sizeof(IMAGE_FILE_HEADER)); + + // Check for more magic in the PE header. + if (pe_header->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) + return 0; + + // Finally, return the ImageBase. + return (uptr)pe_header->ImageBase; +} + +#ifndef SANITIZER_GO uptr GetListOfModules(LoadedModule *modules, uptr max_modules, string_predicate_t filter) { HANDLE cur_process = GetCurrentProcess(); @@ -355,19 +402,33 @@ uptr GetListOfModules(LoadedModule *modules, uptr max_modules, if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi))) continue; - char module_name[MAX_PATH]; - bool got_module_name = - GetModuleFileNameA(handle, module_name, sizeof(module_name)); - if (!got_module_name) - module_name[0] = '\0'; + // Get the UTF-16 path and convert to UTF-8. + wchar_t modname_utf16[kMaxPathLength]; + int modname_utf16_len = + GetModuleFileNameW(handle, modname_utf16, kMaxPathLength); + if (modname_utf16_len == 0) + modname_utf16[0] = '\0'; + char module_name[kMaxPathLength]; + int module_name_len = + ::WideCharToMultiByte(CP_UTF8, 0, modname_utf16, modname_utf16_len + 1, + &module_name[0], kMaxPathLength, NULL, NULL); + module_name[module_name_len] = '\0'; if (filter && !filter(module_name)) continue; uptr base_address = (uptr)mi.lpBaseOfDll; uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage; + + // Adjust the base address of the module so that we get a VA instead of an + // RVA when computing the module offset. This helps llvm-symbolizer find the + // right DWARF CU. In the common case that the image is loaded at it's + // preferred address, we will now print normal virtual addresses. + uptr preferred_base = GetPreferredBase(&module_name[0]); + uptr adjusted_base = base_address - preferred_base; + LoadedModule *cur_module = &modules[count]; - cur_module->set(module_name, base_address); + cur_module->set(module_name, adjusted_base); // We add the whole module as one single address range. cur_module->addAddressRange(base_address, end_address, /*executable*/ true); count++; @@ -377,7 +438,6 @@ uptr GetListOfModules(LoadedModule *modules, uptr max_modules, return count; }; -#ifndef SANITIZER_GO // We can't use atexit() directly at __asan_init time as the CRT is not fully // initialized at this point. Place the functions into a vector and use // atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers). @@ -397,15 +457,22 @@ static int RunAtexit() { } #pragma section(".CRT$XID", long, read) // NOLINT -static __declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit; +__declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit; #endif // ------------------ sanitizer_libc.h fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) { - if (mode != WrOnly) + fd_t res; + if (mode == RdOnly) { + res = CreateFile(filename, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + } else if (mode == WrOnly) { + res = CreateFile(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, nullptr); + } else { UNIMPLEMENTED(); - fd_t res = CreateFile(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, nullptr); + } CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd); CHECK(res != kStderrFd || kStderrFd == kInvalidFd); if (res == kInvalidFd && last_error) @@ -419,7 +486,18 @@ void CloseFile(fd_t fd) { bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read, error_t *error_p) { - UNIMPLEMENTED(); + CHECK(fd != kInvalidFd); + + // bytes_read can't be passed directly to ReadFile: + // uptr is unsigned long long on 64-bit Windows. + unsigned long num_read_long; + + bool success = ::ReadFile(fd, buff, buff_size, &num_read_long, nullptr); + if (!success && error_p) + *error_p = GetLastError(); + if (bytes_read) + *bytes_read = num_read_long; + return success; } bool SupportsColoredOutput(fd_t fd) { @@ -431,21 +509,32 @@ bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written, error_t *error_p) { CHECK(fd != kInvalidFd); - if (fd == kStdoutFd) { - fd = GetStdHandle(STD_OUTPUT_HANDLE); - if (fd == 0) fd = kInvalidFd; - } else if (fd == kStderrFd) { - fd = GetStdHandle(STD_ERROR_HANDLE); - if (fd == 0) fd = kInvalidFd; + // Handle null optional parameters. + error_t dummy_error; + error_p = error_p ? error_p : &dummy_error; + uptr dummy_bytes_written; + bytes_written = bytes_written ? bytes_written : &dummy_bytes_written; + + // Initialize output parameters in case we fail. + *error_p = 0; + *bytes_written = 0; + + // Map the conventional Unix fds 1 and 2 to Windows handles. They might be + // closed, in which case this will fail. + if (fd == kStdoutFd || fd == kStderrFd) { + fd = GetStdHandle(fd == kStdoutFd ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE); + if (fd == 0) { + *error_p = ERROR_INVALID_HANDLE; + return false; + } } - DWORD internal_bytes_written; - if (fd == kInvalidFd || - WriteFile(fd, buff, buff_size, &internal_bytes_written, 0)) { - if (error_p) *error_p = GetLastError(); + DWORD bytes_written_32; + if (!WriteFile(fd, buff, buff_size, &bytes_written_32, 0)) { + *error_p = GetLastError(); return false; } else { - if (bytes_written) *bytes_written = internal_bytes_written; + *bytes_written = bytes_written_32; return true; } } @@ -665,6 +754,22 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { return 0; } +uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) { + return ReadBinaryName(buf, buf_len); +} + +void CheckVMASize() { + // Do nothing. +} + +void DisableReexec() { + // No need to re-exec on Windows. +} + +void MaybeReexec() { + // No need to re-exec on Windows. +} + } // namespace __sanitizer #endif // _WIN32 diff --git a/lib/sanitizer_common/scripts/gen_dynamic_list.py b/lib/sanitizer_common/scripts/gen_dynamic_list.py index f055bb44ba21..b8b79b5994b7 100755 --- a/lib/sanitizer_common/scripts/gen_dynamic_list.py +++ b/lib/sanitizer_common/scripts/gen_dynamic_list.py @@ -100,7 +100,7 @@ def main(argv): print('global:') result.sort() for f in result: - print(' ' + f.encode('utf-8') + ';') + print(u' %s;' % f) if args.version_list: print('local:') print(' *;') diff --git a/lib/sanitizer_common/tests/CMakeLists.txt b/lib/sanitizer_common/tests/CMakeLists.txt index b0165eac25f0..18b76369a675 100644 --- a/lib/sanitizer_common/tests/CMakeLists.txt +++ b/lib/sanitizer_common/tests/CMakeLists.txt @@ -4,6 +4,9 @@ clang_compiler_add_cxx_check() # FIXME: use SANITIZER_COMMON_SUPPORTED_ARCH here filter_available_targets(SANITIZER_UNITTEST_SUPPORTED_ARCH x86_64 i386 mips64 mips64el) +if(APPLE) + darwin_filter_host_archs(SANITIZER_UNITTEST_SUPPORTED_ARCH SANITIZER_COMMON_SUPPORTED_ARCH) +endif() set(SANITIZER_UNITTESTS sanitizer_allocator_test.cc @@ -72,7 +75,7 @@ if(ANDROID) endif() set(SANITIZER_TEST_LINK_LIBS) -append_list_if(ANDROID log SANITIZER_TEST_LINK_LIBS) +append_list_if(COMPILER_RT_HAS_LIBLOG log SANITIZER_TEST_LINK_LIBS) # NDK r10 requires -latomic almost always. append_list_if(ANDROID atomic SANITIZER_TEST_LINK_LIBS) @@ -168,11 +171,13 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT ANDROID) # be sure that produced binaries would work. if(APPLE) add_sanitizer_common_lib("RTSanitizerCommon.test.osx" - $<TARGET_OBJECTS:RTSanitizerCommon.osx>) + $<TARGET_OBJECTS:RTSanitizerCommon.osx> + $<TARGET_OBJECTS:RTSanitizerCommonLibc.osx>) else() if(CAN_TARGET_x86_64) add_sanitizer_common_lib("RTSanitizerCommon.test.nolibc.x86_64" - $<TARGET_OBJECTS:RTSanitizerCommon.x86_64>) + $<TARGET_OBJECTS:RTSanitizerCommon.x86_64> + $<TARGET_OBJECTS:RTSanitizerCommonNoLibc.x86_64>) endif() foreach(arch ${SANITIZER_UNITTEST_SUPPORTED_ARCH}) add_sanitizer_common_lib("RTSanitizerCommon.test.${arch}" diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc index be8fc91aa861..7ba334568146 100644 --- a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc @@ -40,6 +40,8 @@ typedef SizeClassAllocator64< kAllocatorSpace, kAllocatorSize, 16, CompactSizeClassMap> Allocator64Compact; #elif defined(__mips64) static const u64 kAddressSpaceSize = 1ULL << 40; +#elif defined(__aarch64__) +static const u64 kAddressSpaceSize = 1ULL << 39; #else static const u64 kAddressSpaceSize = 1ULL << 32; #endif @@ -94,7 +96,7 @@ void TestSizeClassAllocator() { uptr size = sizes[s]; if (!a->CanAllocate(size, 1)) continue; // printf("s = %ld\n", size); - uptr n_iter = std::max((uptr)6, 8000000 / size); + uptr n_iter = std::max((uptr)6, 4000000 / size); // fprintf(stderr, "size: %ld iter: %ld\n", size, n_iter); for (uptr i = 0; i < n_iter; i++) { uptr class_id0 = Allocator::SizeClassMapT::ClassID(size); diff --git a/lib/sanitizer_common/tests/sanitizer_common_test.cc b/lib/sanitizer_common/tests/sanitizer_common_test.cc index e08a38c82450..6fc308ad14d4 100644 --- a/lib/sanitizer_common/tests/sanitizer_common_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_common_test.cc @@ -188,6 +188,15 @@ TEST(SanitizerCommon, FindPathToBinary) { InternalFree(true_path); EXPECT_EQ(0, FindPathToBinary("unexisting_binary.ergjeorj")); } +#elif SANITIZER_WINDOWS +TEST(SanitizerCommon, FindPathToBinary) { + // ntdll.dll should be on PATH in all supported test environments on all + // supported Windows versions. + char *ntdll_path = FindPathToBinary("ntdll.dll"); + EXPECT_NE((char*)0, internal_strstr(ntdll_path, "ntdll.dll")); + InternalFree(ntdll_path); + EXPECT_EQ(0, FindPathToBinary("unexisting_binary.ergjeorj")); +} #endif TEST(SanitizerCommon, StripPathPrefix) { @@ -199,6 +208,30 @@ TEST(SanitizerCommon, StripPathPrefix) { EXPECT_STREQ("file.h", StripPathPrefix("/usr/lib/./file.h", "/usr/lib/")); } +TEST(SanitizerCommon, RemoveANSIEscapeSequencesFromString) { + RemoveANSIEscapeSequencesFromString(nullptr); + const char *buffs[22] = { + "Default", "Default", + "\033[95mLight magenta", "Light magenta", + "\033[30mBlack\033[32mGreen\033[90mGray", "BlackGreenGray", + "\033[106mLight cyan \033[107mWhite ", "Light cyan White ", + "\033[31mHello\033[0m World", "Hello World", + "\033[38;5;82mHello \033[38;5;198mWorld", "Hello World", + "123[653456789012", "123[653456789012", + "Normal \033[5mBlink \033[25mNormal", "Normal Blink Normal", + "\033[106m\033[107m", "", + "", "", + " ", " ", + }; + + for (size_t i = 0; i < ARRAY_SIZE(buffs); i+=2) { + char *buffer_copy = internal_strdup(buffs[i]); + RemoveANSIEscapeSequencesFromString(buffer_copy); + EXPECT_STREQ(buffer_copy, buffs[i+1]); + InternalFree(buffer_copy); + } +} + TEST(SanitizerCommon, InternalScopedString) { InternalScopedString str(10); EXPECT_EQ(0U, str.length()); diff --git a/lib/sanitizer_common/tests/sanitizer_libc_test.cc b/lib/sanitizer_common/tests/sanitizer_libc_test.cc index 3252db77653d..015e32a09e37 100644 --- a/lib/sanitizer_common/tests/sanitizer_libc_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_libc_test.cc @@ -8,18 +8,21 @@ //===----------------------------------------------------------------------===// // Tests for sanitizer_libc.h. //===----------------------------------------------------------------------===// +#include <algorithm> #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_platform.h" #include "gtest/gtest.h" -#if SANITIZER_LINUX || SANITIZER_MAC -# define SANITIZER_TEST_HAS_STAT_H 1 +#if SANITIZER_WINDOWS +#define NOMINMAX +#include <windows.h> +#undef NOMINMAX +#endif +#if SANITIZER_POSIX # include <sys/stat.h> # include "sanitizer_common/sanitizer_posix.h" -#else -# define SANITIZER_TEST_HAS_STAT_H 0 #endif // A regression test for internal_memmove() implementation. @@ -57,6 +60,17 @@ struct stat_and_more { }; static void temp_file_name(char *buf, size_t bufsize, const char *prefix) { +#if SANITIZER_WINDOWS + buf[0] = '\0'; + char tmp_dir[MAX_PATH]; + if (!::GetTempPathA(MAX_PATH, tmp_dir)) + return; + // GetTempFileNameA needs a MAX_PATH buffer. + char tmp_path[MAX_PATH]; + if (!::GetTempFileNameA(tmp_dir, prefix, 0, tmp_path)) + return; + internal_strncpy(buf, tmp_path, bufsize); +#else const char *tmpdir = "/tmp"; #if SANITIZER_ANDROID // I don't know a way to query temp directory location on Android without @@ -67,10 +81,9 @@ static void temp_file_name(char *buf, size_t bufsize, const char *prefix) { #endif u32 uid = GetUid(); internal_snprintf(buf, bufsize, "%s/%s%d", tmpdir, prefix, uid); +#endif } -// FIXME: File manipulations are not yet supported on Windows -#if !defined(_WIN32) TEST(SanitizerCommon, FileOps) { const char *str1 = "qwerty"; uptr len1 = internal_strlen(str1); @@ -81,16 +94,23 @@ TEST(SanitizerCommon, FileOps) { temp_file_name(tmpfile, sizeof(tmpfile), "sanitizer_common.fileops.tmp."); fd_t fd = OpenFile(tmpfile, WrOnly); ASSERT_NE(fd, kInvalidFd); - EXPECT_EQ(len1, internal_write(fd, str1, len1)); - EXPECT_EQ(len2, internal_write(fd, str2, len2)); + uptr bytes_written = 0; + EXPECT_TRUE(WriteToFile(fd, str1, len1, &bytes_written)); + EXPECT_EQ(len1, bytes_written); + EXPECT_TRUE(WriteToFile(fd, str2, len2, &bytes_written)); + EXPECT_EQ(len2, bytes_written); CloseFile(fd); + EXPECT_TRUE(FileExists(tmpfile)); + fd = OpenFile(tmpfile, RdOnly); ASSERT_NE(fd, kInvalidFd); + +#if SANITIZER_POSIX + // The stat wrappers are posix-only. uptr fsize = internal_filesize(fd); EXPECT_EQ(len1 + len2, fsize); -#if SANITIZER_TEST_HAS_STAT_H struct stat st1, st2, st3; EXPECT_EQ(0u, internal_stat(tmpfile, &st1)); EXPECT_EQ(0u, internal_lstat(tmpfile, &st2)); @@ -108,16 +128,43 @@ TEST(SanitizerCommon, FileOps) { #endif char buf[64] = {}; - EXPECT_EQ(len1, internal_read(fd, buf, len1)); + uptr bytes_read = 0; + EXPECT_TRUE(ReadFromFile(fd, buf, len1, &bytes_read)); + EXPECT_EQ(len1, bytes_read); EXPECT_EQ(0, internal_memcmp(buf, str1, len1)); EXPECT_EQ((char)0, buf[len1 + 1]); internal_memset(buf, 0, len1); - EXPECT_EQ(len2, internal_read(fd, buf, len2)); + EXPECT_TRUE(ReadFromFile(fd, buf, len2, &bytes_read)); + EXPECT_EQ(len2, bytes_read); EXPECT_EQ(0, internal_memcmp(buf, str2, len2)); CloseFile(fd); + +#if SANITIZER_WINDOWS + // No sanitizer needs to delete a file on Windows yet. If we ever do, we can + // add a portable wrapper and test it from here. + ::DeleteFileA(&tmpfile[0]); +#else internal_unlink(tmpfile); -} #endif +} + +static const size_t kStrlcpyBufSize = 8; +void test_internal_strlcpy(char *dbuf, const char *sbuf) { + uptr retval = 0; + retval = internal_strlcpy(dbuf, sbuf, kStrlcpyBufSize); + EXPECT_EQ(internal_strncmp(dbuf, sbuf, kStrlcpyBufSize - 1), 0); + EXPECT_EQ(internal_strlen(dbuf), + std::min(internal_strlen(sbuf), (uptr)(kStrlcpyBufSize - 1))); + EXPECT_EQ(retval, internal_strlen(sbuf)); + + // Test with shorter maxlen. + uptr maxlen = 2; + if (internal_strlen(sbuf) > maxlen) { + retval = internal_strlcpy(dbuf, sbuf, maxlen); + EXPECT_EQ(internal_strncmp(dbuf, sbuf, maxlen - 1), 0); + EXPECT_EQ(internal_strlen(dbuf), maxlen - 1); + } +} TEST(SanitizerCommon, InternalStrFunctions) { const char *haystack = "haystack"; @@ -125,10 +172,45 @@ TEST(SanitizerCommon, InternalStrFunctions) { EXPECT_EQ(haystack + 2, internal_strchrnul(haystack, 'y')); EXPECT_EQ(0, internal_strchr(haystack, 'z')); EXPECT_EQ(haystack + 8, internal_strchrnul(haystack, 'z')); + + char dbuf[kStrlcpyBufSize] = {}; + const char *samesizestr = "1234567"; + const char *shortstr = "123"; + const char *longerstr = "123456789"; + + // Test internal_strlcpy. + internal_strlcpy(dbuf, shortstr, 0); + EXPECT_EQ(dbuf[0], 0); + EXPECT_EQ(dbuf[0], 0); + test_internal_strlcpy(dbuf, samesizestr); + test_internal_strlcpy(dbuf, shortstr); + test_internal_strlcpy(dbuf, longerstr); + + // Test internal_strlcat. + char dcatbuf[kStrlcpyBufSize] = {}; + uptr retval = 0; + retval = internal_strlcat(dcatbuf, "aaa", 0); + EXPECT_EQ(internal_strlen(dcatbuf), (uptr)0); + EXPECT_EQ(retval, (uptr)3); + + retval = internal_strlcat(dcatbuf, "123", kStrlcpyBufSize); + EXPECT_EQ(internal_strcmp(dcatbuf, "123"), 0); + EXPECT_EQ(internal_strlen(dcatbuf), (uptr)3); + EXPECT_EQ(retval, (uptr)3); + + retval = internal_strlcat(dcatbuf, "123", kStrlcpyBufSize); + EXPECT_EQ(internal_strcmp(dcatbuf, "123123"), 0); + EXPECT_EQ(internal_strlen(dcatbuf), (uptr)6); + EXPECT_EQ(retval, (uptr)6); + + retval = internal_strlcat(dcatbuf, "123", kStrlcpyBufSize); + EXPECT_EQ(internal_strcmp(dcatbuf, "1231231"), 0); + EXPECT_EQ(internal_strlen(dcatbuf), (uptr)7); + EXPECT_EQ(retval, (uptr)9); } // FIXME: File manipulations are not yet supported on Windows -#if !defined(_WIN32) && !SANITIZER_MAC +#if SANITIZER_POSIX && !SANITIZER_MAC TEST(SanitizerCommon, InternalMmapWithOffset) { char tmpfile[128]; temp_file_name(tmpfile, sizeof(tmpfile), diff --git a/lib/sanitizer_common/tests/sanitizer_linux_test.cc b/lib/sanitizer_common/tests/sanitizer_linux_test.cc index 11342b775cc7..eef71010afe6 100644 --- a/lib/sanitizer_common/tests/sanitizer_linux_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_linux_test.cc @@ -195,7 +195,7 @@ TEST(SanitizerCommon, SetEnvTest) { EXPECT_EQ(0, getenv(kEnvName)); } -#if defined(__x86_64__) || defined(__i386__) +#if (defined(__x86_64__) || defined(__i386__)) && !SANITIZER_ANDROID void *thread_self_offset_test_func(void *arg) { bool result = *(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf(); diff --git a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc index 654ea1db82fb..3d57eded948f 100644 --- a/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_stacktrace_test.cc @@ -82,7 +82,7 @@ TEST_F(FastUnwindTest, Basic) { } } -// From: http://code.google.com/p/address-sanitizer/issues/detail?id=162 +// From: https://github.com/google/sanitizers/issues/162 TEST_F(FastUnwindTest, FramePointerLoop) { // Make one fp point to itself. fake_stack[4] = (uhwptr)&fake_stack[4]; diff --git a/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc index e8c30d07e78c..224ab0538377 100644 --- a/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc +++ b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc @@ -105,9 +105,10 @@ TEST_F(SuppressionContextTest, Parse3) { ctx_.Parse( "# last suppression w/o line-feed\n" "race:foo\n" - "race:bar" + "race:bar\r\n" + "race:baz" ); // NOLINT - CheckSuppressions(2, {"race", "race"}, {"foo", "bar"}); + CheckSuppressions(3, {"race", "race", "race"}, {"foo", "bar", "baz"}); } TEST_F(SuppressionContextTest, ParseType) { diff --git a/lib/sanitizer_common/tests/sanitizer_test_main.cc b/lib/sanitizer_common/tests/sanitizer_test_main.cc index b7fd3dafab26..20f8f53975d0 100644 --- a/lib/sanitizer_common/tests/sanitizer_test_main.cc +++ b/lib/sanitizer_common/tests/sanitizer_test_main.cc @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// #include "gtest/gtest.h" +#include "sanitizer_common/sanitizer_flags.h" const char *argv0; @@ -18,5 +19,6 @@ int main(int argc, char **argv) { argv0 = argv[0]; testing::GTEST_FLAG(death_test_style) = "threadsafe"; testing::InitGoogleTest(&argc, argv); + SetCommonFlagsDefaults(); return RUN_ALL_TESTS(); } |