diff options
Diffstat (limited to 'libsanitizer/sanitizer_common')
60 files changed, 2867 insertions, 1051 deletions
diff --git a/libsanitizer/sanitizer_common/Makefile.am b/libsanitizer/sanitizer_common/Makefile.am index 089c6936e2a..bc1f18c2a18 100644 --- a/libsanitizer/sanitizer_common/Makefile.am +++ b/libsanitizer/sanitizer_common/Makefile.am @@ -21,7 +21,8 @@ sanitizer_common_files = \ sanitizer_allocator.cc \ sanitizer_common.cc \ sanitizer_common_libcdep.cc \ - sanitizer_coverage.cc \ + sanitizer_coverage_libcdep.cc \ + sanitizer_coverage_mapping_libcdep.cc \ sanitizer_deadlock_detector1.cc \ sanitizer_deadlock_detector2.cc \ sanitizer_flags.cc \ @@ -30,11 +31,14 @@ sanitizer_common_files = \ sanitizer_linux.cc \ sanitizer_linux_libcdep.cc \ sanitizer_mac.cc \ + sanitizer_persistent_allocator.cc \ sanitizer_platform_limits_linux.cc \ sanitizer_platform_limits_posix.cc \ sanitizer_posix.cc \ sanitizer_posix_libcdep.cc \ sanitizer_printf.cc \ + sanitizer_procmaps_common.cc \ + sanitizer_procmaps_freebsd.cc \ sanitizer_procmaps_linux.cc \ sanitizer_procmaps_mac.cc \ sanitizer_stackdepot.cc \ @@ -49,8 +53,10 @@ sanitizer_common_files = \ sanitizer_symbolizer_win.cc \ sanitizer_thread_registry.cc \ sanitizer_tls_get_addr.cc \ + sanitizer_unwind_posix_libcdep.cc \ sanitizer_win.cc + libsanitizer_common_la_SOURCES = $(sanitizer_common_files) # Work around what appears to be a GNU make bug handling MAKEFLAGS diff --git a/libsanitizer/sanitizer_common/Makefile.in b/libsanitizer/sanitizer_common/Makefile.in index 1ea631590c0..d82b4834efc 100644 --- a/libsanitizer/sanitizer_common/Makefile.in +++ b/libsanitizer/sanitizer_common/Makefile.in @@ -64,14 +64,17 @@ CONFIG_CLEAN_VPATH_FILES = LTLIBRARIES = $(noinst_LTLIBRARIES) libsanitizer_common_la_LIBADD = am__objects_1 = sanitizer_allocator.lo sanitizer_common.lo \ - sanitizer_common_libcdep.lo sanitizer_coverage.lo \ + sanitizer_common_libcdep.lo sanitizer_coverage_libcdep.lo \ + sanitizer_coverage_mapping_libcdep.lo \ sanitizer_deadlock_detector1.lo \ sanitizer_deadlock_detector2.lo sanitizer_flags.lo \ sanitizer_libc.lo sanitizer_libignore.lo sanitizer_linux.lo \ sanitizer_linux_libcdep.lo sanitizer_mac.lo \ + sanitizer_persistent_allocator.lo \ sanitizer_platform_limits_linux.lo \ sanitizer_platform_limits_posix.lo sanitizer_posix.lo \ sanitizer_posix_libcdep.lo sanitizer_printf.lo \ + sanitizer_procmaps_common.lo sanitizer_procmaps_freebsd.lo \ sanitizer_procmaps_linux.lo sanitizer_procmaps_mac.lo \ sanitizer_stackdepot.lo sanitizer_stacktrace.lo \ sanitizer_stacktrace_libcdep.lo \ @@ -81,7 +84,8 @@ am__objects_1 = sanitizer_allocator.lo sanitizer_common.lo \ sanitizer_symbolizer_libcdep.lo \ sanitizer_symbolizer_posix_libcdep.lo \ sanitizer_symbolizer_win.lo sanitizer_thread_registry.lo \ - sanitizer_tls_get_addr.lo sanitizer_win.lo + sanitizer_tls_get_addr.lo sanitizer_unwind_posix_libcdep.lo \ + sanitizer_win.lo am_libsanitizer_common_la_OBJECTS = $(am__objects_1) libsanitizer_common_la_OBJECTS = $(am_libsanitizer_common_la_OBJECTS) DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) @@ -256,7 +260,8 @@ sanitizer_common_files = \ sanitizer_allocator.cc \ sanitizer_common.cc \ sanitizer_common_libcdep.cc \ - sanitizer_coverage.cc \ + sanitizer_coverage_libcdep.cc \ + sanitizer_coverage_mapping_libcdep.cc \ sanitizer_deadlock_detector1.cc \ sanitizer_deadlock_detector2.cc \ sanitizer_flags.cc \ @@ -265,11 +270,14 @@ sanitizer_common_files = \ sanitizer_linux.cc \ sanitizer_linux_libcdep.cc \ sanitizer_mac.cc \ + sanitizer_persistent_allocator.cc \ sanitizer_platform_limits_linux.cc \ sanitizer_platform_limits_posix.cc \ sanitizer_posix.cc \ sanitizer_posix_libcdep.cc \ sanitizer_printf.cc \ + sanitizer_procmaps_common.cc \ + sanitizer_procmaps_freebsd.cc \ sanitizer_procmaps_linux.cc \ sanitizer_procmaps_mac.cc \ sanitizer_stackdepot.cc \ @@ -284,6 +292,7 @@ sanitizer_common_files = \ sanitizer_symbolizer_win.cc \ sanitizer_thread_registry.cc \ sanitizer_tls_get_addr.cc \ + sanitizer_unwind_posix_libcdep.cc \ sanitizer_win.cc libsanitizer_common_la_SOURCES = $(sanitizer_common_files) @@ -382,7 +391,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_allocator.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_common.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_common_libcdep.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_coverage.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_coverage_libcdep.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_coverage_mapping_libcdep.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_deadlock_detector1.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_deadlock_detector2.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_flags.Plo@am__quote@ @@ -391,11 +401,14 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux_libcdep.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_mac.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_persistent_allocator.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_platform_limits_linux.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_platform_limits_posix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_posix.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_posix_libcdep.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_printf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_procmaps_common.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_procmaps_freebsd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_procmaps_linux.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_procmaps_mac.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stackdepot.Plo@am__quote@ @@ -410,6 +423,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_win.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_thread_registry.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_tls_get_addr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_unwind_posix_libcdep.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_win.Plo@am__quote@ .cc.o: diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.h b/libsanitizer/sanitizer_common/sanitizer_allocator.h index 99be09ba9ba..fb394129202 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator.h +++ b/libsanitizer/sanitizer_common/sanitizer_allocator.h @@ -271,9 +271,9 @@ class AllocatorGlobalStats : public AllocatorStats { if (stats == this) break; } - // All stats must be positive. + // All stats must be non-negative. for (int i = 0; i < AllocatorStatCount; i++) - s[i] = ((sptr)s[i]) > 0 ? s[i] : 1; + s[i] = ((sptr)s[i]) >= 0 ? s[i] : 0; } private: diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h b/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h new file mode 100644 index 00000000000..fd5bed30c4b --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h @@ -0,0 +1,36 @@ +//===-- sanitizer_allocator_interface.h ------------------------- C++ -----===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Re-declaration of functions from public sanitizer allocator interface. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_ALLOCATOR_INTERFACE_H +#define SANITIZER_ALLOCATOR_INTERFACE_H + +#include "sanitizer_internal_defs.h" + +using __sanitizer::uptr; + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE +uptr __sanitizer_get_estimated_allocated_size(uptr size); +SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_get_ownership(const void *p); +SANITIZER_INTERFACE_ATTRIBUTE uptr +__sanitizer_get_allocated_size(const void *p); +SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_current_allocated_bytes(); +SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_heap_size(); +SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_free_bytes(); +SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_unmapped_bytes(); + +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + /* OPTIONAL */ void __sanitizer_malloc_hook(void *ptr, uptr size); +SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE + /* OPTIONAL */ void __sanitizer_free_hook(void *ptr); +} // extern "C" + +#endif // SANITIZER_ALLOCATOR_INTERFACE_H diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h b/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h index 74e4402f736..5e8cc107706 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h @@ -23,38 +23,25 @@ typedef CompactSizeClassMap InternalSizeClassMap; static const uptr kInternalAllocatorSpace = 0; static const u64 kInternalAllocatorSize = SANITIZER_MMAP_RANGE_SIZE; -#if SANITIZER_WORDSIZE == 32 static const uptr kInternalAllocatorRegionSizeLog = 20; +#if SANITIZER_WORDSIZE == 32 static const uptr kInternalAllocatorNumRegions = kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog; typedef FlatByteMap<kInternalAllocatorNumRegions> ByteMap; #else -static const uptr kInternalAllocatorRegionSizeLog = 24; static const uptr kInternalAllocatorNumRegions = kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog; typedef TwoLevelByteMap<(kInternalAllocatorNumRegions >> 12), 1 << 12> ByteMap; #endif typedef SizeClassAllocator32< - kInternalAllocatorSpace, kInternalAllocatorSize, 16, InternalSizeClassMap, + kInternalAllocatorSpace, kInternalAllocatorSize, 0, InternalSizeClassMap, kInternalAllocatorRegionSizeLog, ByteMap> PrimaryInternalAllocator; typedef SizeClassAllocatorLocalCache<PrimaryInternalAllocator> InternalAllocatorCache; -// We don't want our internal allocator to do any map/unmap operations from -// LargeMmapAllocator. -struct CrashOnMapUnmap { - void OnMap(uptr p, uptr size) const { - RAW_CHECK_MSG(0, "Unexpected mmap in InternalAllocator!\n"); - } - void OnUnmap(uptr p, uptr size) const { - RAW_CHECK_MSG(0, "Unexpected munmap in InternalAllocator!\n"); - } -}; - typedef CombinedAllocator<PrimaryInternalAllocator, InternalAllocatorCache, - LargeMmapAllocator<CrashOnMapUnmap> > - InternalAllocator; + LargeMmapAllocator<> > InternalAllocator; void *InternalAlloc(uptr size, InternalAllocatorCache *cache = 0); void InternalFree(void *p, InternalAllocatorCache *cache = 0); diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h b/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h index 7e18fa38748..1198dec3e97 100644 --- a/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h +++ b/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h @@ -31,33 +31,20 @@ long long _InterlockedCompareExchange64( // NOLINT long long volatile *Destination, // NOLINT long long Exchange, long long Comparand); // NOLINT #pragma intrinsic(_InterlockedCompareExchange64) - -#ifdef _WIN64 -extern "C" long long _InterlockedExchangeAdd64( // NOLINT - long long volatile * Addend, long long Value); // NOLINT -#pragma intrinsic(_InterlockedExchangeAdd64) extern "C" void *_InterlockedCompareExchangePointer( void *volatile *Destination, void *Exchange, void *Comparand); #pragma intrinsic(_InterlockedCompareExchangePointer) -#else -// There's no _InterlockedCompareExchangePointer intrinsic on x86, -// so call _InterlockedCompareExchange instead. extern "C" long __cdecl _InterlockedCompareExchange( // NOLINT long volatile *Destination, // NOLINT long Exchange, long Comparand); // NOLINT #pragma intrinsic(_InterlockedCompareExchange) -inline static void *_InterlockedCompareExchangePointer( - void *volatile *Destination, - void *Exchange, void *Comparand) { - return reinterpret_cast<void*>( - _InterlockedCompareExchange( - reinterpret_cast<long volatile*>(Destination), // NOLINT - reinterpret_cast<long>(Exchange), // NOLINT - reinterpret_cast<long>(Comparand))); // NOLINT -} +#ifdef _WIN64 +extern "C" long long _InterlockedExchangeAdd64( // NOLINT + long long volatile * Addend, long long Value); // NOLINT +#pragma intrinsic(_InterlockedExchangeAdd64) #endif namespace __sanitizer { diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cc b/libsanitizer/sanitizer_common/sanitizer_common.cc index e76d4d558a1..d4da3206e13 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common.cc +++ b/libsanitizer/sanitizer_common/sanitizer_common.cc @@ -12,8 +12,6 @@ #include "sanitizer_common.h" #include "sanitizer_flags.h" #include "sanitizer_libc.h" -#include "sanitizer_stacktrace.h" -#include "sanitizer_symbolizer.h" namespace __sanitizer { @@ -195,31 +193,17 @@ void ReportErrorSummary(const char *error_type, const char *file, ReportErrorSummary(buff.data()); } -void ReportErrorSummary(const char *error_type, StackTrace *stack) { - if (!common_flags()->print_summary) - return; - AddressInfo ai; -#if !SANITIZER_GO - if (stack->size > 0 && Symbolizer::Get()->CanReturnFileLineInfo()) { - // Currently, we include the first stack frame into the report summary. - // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc). - uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]); - Symbolizer::Get()->SymbolizePC(pc, &ai, 1); - } -#endif - ReportErrorSummary(error_type, ai.file, ai.line, ai.function); -} - LoadedModule::LoadedModule(const char *module_name, uptr base_address) { full_name_ = internal_strdup(module_name); base_address_ = base_address; n_ranges_ = 0; } -void LoadedModule::addAddressRange(uptr beg, uptr end) { +void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) { CHECK_LT(n_ranges_, kMaxNumberOfAddressRanges); ranges_[n_ranges_].beg = beg; ranges_[n_ranges_].end = end; + exec_[n_ranges_] = executable; n_ranges_++; } @@ -261,11 +245,6 @@ void DecreaseTotalMmap(uptr size) { atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed); } -static void (*sandboxing_callback)(); -void SetSandboxingCallback(void (*f)()) { - sandboxing_callback = f; -} - } // namespace __sanitizer using namespace __sanitizer; // NOLINT @@ -298,13 +277,6 @@ void __sanitizer_set_report_path(const char *path) { } } -void NOINLINE -__sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args) { - PrepareForSandboxing(args); - if (sandboxing_callback) - sandboxing_callback(); -} - void __sanitizer_report_error_summary(const char *error_summary) { Printf("%s\n", error_summary); } diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h index 93317132c49..a9db1082f48 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common.h +++ b/libsanitizer/sanitizer_common/sanitizer_common.h @@ -163,6 +163,9 @@ uptr ReadFileToBuffer(const char *file_name, char **buff, // (or NULL if the mapping failes). Stores the size of mmaped region // in '*buff_size'. void *MapFileToMemory(const char *file_name, uptr *buff_size); +void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset); + +bool IsAccessibleMemoryRange(uptr beg, uptr size); // Error report formatting. const char *StripPathPrefix(const char *filepath, @@ -173,7 +176,7 @@ void PrintModuleAndOffset(InternalScopedString *buffer, const char *module, uptr offset); // OS -void DisableCoreDumper(); +void DisableCoreDumperIfNecessary(); void DumpProcessMap(); bool FileExists(const char *filename); const char *GetEnv(const char *name); @@ -184,11 +187,17 @@ u32 GetUid(); void ReExec(); bool StackSizeIsUnlimited(); void SetStackSizeLimitInBytes(uptr limit); +bool AddressSpaceIsUnlimited(); +void SetAddressSpaceUnlimited(); void AdjustStackSize(void *attr); void PrepareForSandboxing(__sanitizer_sandbox_arguments *args); void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args); void SetSandboxingCallback(void (*f)()); +void CovUpdateMapping(uptr caller_pc = 0); +void CovBeforeFork(); +void CovAfterFork(int child_pid); + void InitTlsSize(); uptr GetTlsSize(); @@ -239,7 +248,7 @@ const int kMaxSummaryLength = 1024; // and pass it to __sanitizer_report_error_summary. void ReportErrorSummary(const char *error_message); // Same as above, but construct error_message as: -// error_type: file:line function +// error_type file:line function void ReportErrorSummary(const char *error_type, const char *file, int line, const char *function); void ReportErrorSummary(const char *error_type, StackTrace *trace); @@ -475,12 +484,17 @@ uptr InternalBinarySearch(const Container &v, uptr first, uptr last, class LoadedModule { public: LoadedModule(const char *module_name, uptr base_address); - void addAddressRange(uptr beg, uptr end); + void addAddressRange(uptr beg, uptr end, bool executable); bool containsAddress(uptr address) const; const char *full_name() const { return full_name_; } uptr base_address() const { return base_address_; } + uptr n_ranges() const { return n_ranges_; } + uptr address_range_start(int i) const { return ranges_[i].beg; } + uptr address_range_end(int i) const { return ranges_[i].end; } + bool address_range_executable(int i) const { return exec_[i]; } + private: struct AddressRange { uptr beg; @@ -490,6 +504,7 @@ class LoadedModule { uptr base_address_; static const uptr kMaxNumberOfAddressRanges = 6; AddressRange ranges_[kMaxNumberOfAddressRanges]; + bool exec_[kMaxNumberOfAddressRanges]; uptr n_ranges_; }; @@ -529,10 +544,13 @@ F IndirectExternCall(F f) { #endif #if SANITIZER_ANDROID +// Initialize Android logging. Any writes before this are silently lost. +void AndroidLogInit(); void AndroidLogWrite(const char *buffer); void GetExtraActivationFlags(char *buf, uptr size); void SanitizerInitializeUnwinder(); #else +INLINE void AndroidLogInit() {} INLINE void AndroidLogWrite(const char *buffer_unused) {} INLINE void GetExtraActivationFlags(char *buf, uptr size) { *buf = '\0'; } INLINE void SanitizerInitializeUnwinder() {} @@ -544,4 +562,9 @@ inline void *operator new(__sanitizer::operator_new_size_type size, return alloc.Allocate(size); } +struct StackDepotStats { + uptr n_uniq_ids; + uptr allocated; +}; + #endif // SANITIZER_COMMON_H diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc index 6cbe03ae34a..f55a31de77e 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc @@ -11,6 +11,7 @@ // This file should be included into the tool's interceptor file, // which has to define it's own macros: // COMMON_INTERCEPTOR_ENTER +// COMMON_INTERCEPTOR_ENTER_NOIGNORE // COMMON_INTERCEPTOR_READ_RANGE // COMMON_INTERCEPTOR_WRITE_RANGE // COMMON_INTERCEPTOR_INITIALIZE_RANGE @@ -24,6 +25,7 @@ // COMMON_INTERCEPTOR_MUTEX_REPAIR // COMMON_INTERCEPTOR_SET_PTHREAD_NAME // COMMON_INTERCEPTOR_HANDLE_RECVMSG +// COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED //===----------------------------------------------------------------------===// #include "interception/interception.h" #include "sanitizer_addrhashmap.h" @@ -73,6 +75,23 @@ #define COMMON_INTERCEPTOR_FILE_CLOSE(ctx, file) {} #endif +#ifndef COMMON_INTERCEPTOR_LIBRARY_LOADED +#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, map) {} +#endif + +#ifndef COMMON_INTERCEPTOR_LIBRARY_UNLOADED +#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() {} +#endif + +#ifndef COMMON_INTERCEPTOR_ENTER_NOIGNORE +#define COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, ...) \ + COMMON_INTERCEPTOR_ENTER(ctx, __VA_ARGS__) +#endif + +#ifndef COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED +#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (0) +#endif + struct FileMetadata { // For open_memstream(). char **addr; @@ -158,6 +177,8 @@ INTERCEPTOR(int, strcmp, const char *s1, const char *s2) { } 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); unsigned char c1 = 0, c2 = 0; @@ -255,8 +276,9 @@ INTERCEPTOR(void*, memrchr, const void *s, int c, SIZE_T n) { INTERCEPTOR(double, frexp, double x, int *exp) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, frexp, x, exp); - double res = REAL(frexp)(x, exp); + // Assuming frexp() always writes to |exp|. COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp)); + double res = REAL(frexp)(x, exp); return res; } @@ -269,6 +291,9 @@ INTERCEPTOR(double, frexp, double x, int *exp) { INTERCEPTOR(float, frexpf, float x, int *exp) { void *ctx; 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. float res = REAL(frexpf)(x, exp); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp)); return res; @@ -277,6 +302,9 @@ INTERCEPTOR(float, frexpf, float x, int *exp) { INTERCEPTOR(long double, frexpl, long double x, int *exp) { void *ctx; 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. long double res = REAL(frexpl)(x, exp); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, exp, sizeof(*exp)); return res; @@ -315,6 +343,9 @@ INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, read, fd, ptr, 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. 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); @@ -330,6 +361,9 @@ INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, pread, fd, ptr, count, 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. 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); @@ -345,6 +379,9 @@ INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, pread64, fd, ptr, count, 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. 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); @@ -523,9 +560,11 @@ INTERCEPTOR(int, prctl, int option, unsigned long arg2, INTERCEPTOR(unsigned long, time, unsigned long *t) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, time, t); - unsigned long res = REAL(time)(t); + unsigned long local_t; + unsigned long res = REAL(time)(&local_t); if (t && res != (unsigned long)-1) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, t, sizeof(*t)); + *t = local_t; } return res; } @@ -587,6 +626,9 @@ INTERCEPTOR(__sanitizer_tm *, gmtime_r, unsigned long *timep, void *result) { INTERCEPTOR(char *, ctime, unsigned long *timep) { void *ctx; 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. char *res = REAL(ctime)(timep); if (res) { COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); @@ -597,6 +639,9 @@ INTERCEPTOR(char *, ctime, unsigned long *timep) { INTERCEPTOR(char *, ctime_r, unsigned long *timep, char *result) { void *ctx; 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. char *res = REAL(ctime_r)(timep, result); if (res) { COMMON_INTERCEPTOR_READ_RANGE(ctx, timep, sizeof(*timep)); @@ -607,6 +652,9 @@ INTERCEPTOR(char *, ctime_r, unsigned long *timep, char *result) { INTERCEPTOR(char *, asctime, __sanitizer_tm *tm) { void *ctx; 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. char *res = REAL(asctime)(tm); if (res) { COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm)); @@ -617,6 +665,9 @@ INTERCEPTOR(char *, asctime, __sanitizer_tm *tm) { INTERCEPTOR(char *, asctime_r, __sanitizer_tm *tm, char *result) { void *ctx; 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. char *res = REAL(asctime_r)(tm, result); if (res) { COMMON_INTERCEPTOR_READ_RANGE(ctx, tm, sizeof(*tm)); @@ -658,6 +709,9 @@ INTERCEPTOR(char *, strptime, char *s, char *format, __sanitizer_tm *tm) { COMMON_INTERCEPTOR_ENTER(ctx, strptime, s, format, tm); if (format) 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. char *res = REAL(strptime)(s, format, tm); if (res) { COMMON_INTERCEPTOR_READ_RANGE(ctx, s, res - s); @@ -792,6 +846,9 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format) return res; \ } +// 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. #define VSPRINTF_INTERCEPTOR_IMPL(vname, str, ...) \ { \ VPRINTF_INTERCEPTOR_ENTER(vname, str, __VA_ARGS__) \ @@ -806,6 +863,9 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format) return res; \ } +// 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. #define VSNPRINTF_INTERCEPTOR_IMPL(vname, str, size, ...) \ { \ VPRINTF_INTERCEPTOR_ENTER(vname, str, size, __VA_ARGS__) \ @@ -820,6 +880,9 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format) return res; \ } +// 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. #define VASPRINTF_INTERCEPTOR_IMPL(vname, strp, ...) \ { \ VPRINTF_INTERCEPTOR_ENTER(vname, strp, __VA_ARGS__) \ @@ -972,7 +1035,8 @@ INTERCEPTOR(int, ioctl, int d, unsigned request, void *arg) { #endif #if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS || \ - SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT + SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT || \ + SANITIZER_INTERCEPT_GETPWENT_R || SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS static void unpoison_passwd(void *ctx, __sanitizer_passwd *pwd) { if (pwd) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pwd, sizeof(*pwd)); @@ -1019,7 +1083,9 @@ static void unpoison_group(void *ctx, __sanitizer_group *grp) { } } #endif // SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS || - // SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT + // SANITIZER_INTERCEPT_GETPWENT || SANITIZER_INTERCEPT_FGETPWENT || + // SANITIZER_INTERCEPT_GETPWENT_R || + // SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS #if SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS INTERCEPTOR(__sanitizer_passwd *, getpwnam, const char *name) { @@ -1067,6 +1133,9 @@ INTERCEPTOR(int, getpwnam_r, const char *name, __sanitizer_passwd *pwd, void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getpwnam_r, name, pwd, buf, buflen, result); 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. int res = REAL(getpwnam_r)(name, pwd, buf, buflen, result); if (!res) { if (result && *result) unpoison_passwd(ctx, *result); @@ -1079,6 +1148,9 @@ INTERCEPTOR(int, getpwuid_r, u32 uid, __sanitizer_passwd *pwd, char *buf, SIZE_T buflen, __sanitizer_passwd **result) { void *ctx; 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. int res = REAL(getpwuid_r)(uid, pwd, buf, buflen, result); if (!res) { if (result && *result) unpoison_passwd(ctx, *result); @@ -1092,6 +1164,9 @@ INTERCEPTOR(int, getgrnam_r, const char *name, __sanitizer_group *grp, void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, getgrnam_r, name, grp, buf, buflen, result); 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. int res = REAL(getgrnam_r)(name, grp, buf, buflen, result); if (!res) { if (result && *result) unpoison_group(ctx, *result); @@ -1104,6 +1179,9 @@ INTERCEPTOR(int, getgrgid_r, u32 gid, __sanitizer_group *grp, char *buf, SIZE_T buflen, __sanitizer_group **result) { void *ctx; 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. int res = REAL(getgrgid_r)(gid, grp, buf, buflen, result); if (!res) { if (result && *result) unpoison_group(ctx, *result); @@ -1170,6 +1248,9 @@ INTERCEPTOR(int, getpwent_r, __sanitizer_passwd *pwbuf, char *buf, SIZE_T buflen, __sanitizer_passwd **pwbufp) { void *ctx; 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. int res = REAL(getpwent_r)(pwbuf, buf, buflen, pwbufp); if (!res) { if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp); @@ -1182,6 +1263,9 @@ INTERCEPTOR(int, fgetpwent_r, void *fp, __sanitizer_passwd *pwbuf, char *buf, SIZE_T buflen, __sanitizer_passwd **pwbufp) { void *ctx; 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. int res = REAL(fgetpwent_r)(fp, pwbuf, buf, buflen, pwbufp); if (!res) { if (pwbufp && *pwbufp) unpoison_passwd(ctx, *pwbufp); @@ -1194,6 +1278,9 @@ INTERCEPTOR(int, getgrent_r, __sanitizer_group *pwbuf, char *buf, SIZE_T buflen, __sanitizer_group **pwbufp) { void *ctx; 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. int res = REAL(getgrent_r)(pwbuf, buf, buflen, pwbufp); if (!res) { if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp); @@ -1206,6 +1293,9 @@ INTERCEPTOR(int, fgetgrent_r, void *fp, __sanitizer_group *pwbuf, char *buf, SIZE_T buflen, __sanitizer_group **pwbufp) { void *ctx; 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. int res = REAL(fgetgrent_r)(fp, pwbuf, buf, buflen, pwbufp); if (!res) { if (pwbufp && *pwbufp) unpoison_group(ctx, *pwbufp); @@ -1260,6 +1350,9 @@ INTERCEPTOR(void, endgrent, int dummy) { INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) { void *ctx; 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. int res = REAL(clock_getres)(clk_id, tp); if (!res && tp) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz); @@ -1269,6 +1362,9 @@ INTERCEPTOR(int, clock_getres, u32 clk_id, void *tp) { INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) { void *ctx; 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. int res = REAL(clock_gettime)(clk_id, tp); if (!res) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, struct_timespec_sz); @@ -1293,6 +1389,9 @@ INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) { INTERCEPTOR(int, getitimer, int which, void *curr_value) { void *ctx; 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. int res = REAL(getitimer)(which, curr_value); if (!res && curr_value) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerval_sz); @@ -1304,6 +1403,9 @@ INTERCEPTOR(int, setitimer, int which, const void *new_value, void *old_value) { COMMON_INTERCEPTOR_ENTER(ctx, setitimer, which, new_value, old_value); if (new_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. int res = REAL(setitimer)(which, new_value, old_value); if (!res && old_value) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerval_sz); @@ -1433,15 +1535,27 @@ INTERCEPTOR(int, glob64, const char *pattern, int flags, INTERCEPTOR_WITH_SUFFIX(int, wait, int *status) { void *ctx; 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. int res = REAL(wait)(status); if (res != -1 && status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); return res; } +// On FreeBSD id_t is always 64-bit wide. +#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) +INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, long long id, void *infop, + int options) { +#else INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop, int options) { +#endif void *ctx; 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. int res = REAL(waitid)(idtype, id, infop, options); if (res != -1 && infop) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, infop, siginfo_t_sz); @@ -1450,6 +1564,9 @@ INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop, INTERCEPTOR_WITH_SUFFIX(int, waitpid, int pid, int *status, int options) { void *ctx; 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. int res = REAL(waitpid)(pid, status, options); if (res != -1 && status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); @@ -1458,6 +1575,9 @@ INTERCEPTOR_WITH_SUFFIX(int, waitpid, int pid, int *status, int options) { INTERCEPTOR(int, wait3, int *status, int options, void *rusage) { void *ctx; 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. int res = REAL(wait3)(status, options, rusage); if (res != -1) { if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); @@ -1469,6 +1589,9 @@ INTERCEPTOR(int, wait3, int *status, int options, void *rusage) { INTERCEPTOR(int, __wait4, int pid, int *status, int options, void *rusage) { void *ctx; 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. int res = REAL(__wait4)(pid, status, options, rusage); if (res != -1) { if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); @@ -1481,6 +1604,9 @@ INTERCEPTOR(int, __wait4, int pid, int *status, int options, void *rusage) { INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) { void *ctx; 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. int res = REAL(wait4)(pid, status, options, rusage); if (res != -1) { if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status)); @@ -1507,6 +1633,9 @@ INTERCEPTOR(char *, inet_ntop, int af, const void *src, char *dst, u32 size) { uptr sz = __sanitizer_in_addr_sz(af); if (sz) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sz); // 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. char *res = REAL(inet_ntop)(af, src, dst, size); if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); return res; @@ -1515,6 +1644,9 @@ INTERCEPTOR(int, inet_pton, int af, const char *src, void *dst) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, inet_pton, af, src, 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. int res = REAL(inet_pton)(af, src, dst); if (res == 1) { uptr sz = __sanitizer_in_addr_sz(af); @@ -1534,6 +1666,9 @@ INTERCEPTOR(int, inet_aton, const char *cp, void *dst) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, inet_aton, cp, 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. int res = REAL(inet_aton)(cp, dst); if (res != 0) { uptr sz = __sanitizer_in_addr_sz(af_inet); @@ -1550,6 +1685,9 @@ INTERCEPTOR(int, inet_aton, const char *cp, void *dst) { INTERCEPTOR(int, pthread_getschedparam, uptr thread, int *policy, int *param) { void *ctx; 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. int res = REAL(pthread_getschedparam)(thread, policy, param); if (res == 0) { if (policy) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, policy, sizeof(*policy)); @@ -1574,6 +1712,9 @@ INTERCEPTOR(int, getaddrinfo, char *node, char *service, COMMON_INTERCEPTOR_READ_RANGE(ctx, service, REAL(strlen)(service) + 1); if (hints) 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. int res = REAL(getaddrinfo)(node, service, hints, out); if (res == 0 && out) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, out, sizeof(*out)); @@ -1603,6 +1744,9 @@ INTERCEPTOR(int, getnameinfo, void *sockaddr, unsigned salen, char *host, serv, servlen, flags); // FIXME: consider adding READ_RANGE(sockaddr, salen) // 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. int res = REAL(getnameinfo)(sockaddr, salen, host, hostlen, serv, servlen, flags); if (res == 0) { @@ -1624,6 +1768,9 @@ INTERCEPTOR(int, getsockname, int sock_fd, void *addr, int *addrlen) { COMMON_INTERCEPTOR_ENTER(ctx, getsockname, sock_fd, addr, addrlen); COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*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. int res = REAL(getsockname)(sock_fd, addr, addrlen); if (res == 0) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addrlen_in, *addrlen)); @@ -1701,11 +1848,38 @@ INTERCEPTOR(struct __sanitizer_hostent *, gethostbyname2, char *name, int af) { #endif #if SANITIZER_INTERCEPT_GETHOSTBYNAME_R +INTERCEPTOR(int, gethostbyname_r, char *name, struct __sanitizer_hostent *ret, + char *buf, SIZE_T buflen, __sanitizer_hostent **result, + int *h_errnop) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname_r, name, ret, buf, buflen, 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. + int res = REAL(gethostbyname_r)(name, ret, buf, buflen, result, h_errnop); + if (result) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); + if (res == 0 && *result) write_hostent(ctx, *result); + } + if (h_errnop) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop)); + return res; +} +#define INIT_GETHOSTBYNAME_R COMMON_INTERCEPT_FUNCTION(gethostbyname_r); +#else +#define INIT_GETHOSTBYNAME_R +#endif + +#if SANITIZER_INTERCEPT_GETHOSTENT_R INTERCEPTOR(int, gethostent_r, struct __sanitizer_hostent *ret, char *buf, SIZE_T buflen, __sanitizer_hostent **result, int *h_errnop) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, gethostent_r, ret, buf, buflen, 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. int res = REAL(gethostent_r)(ret, buf, buflen, result, h_errnop); if (result) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); @@ -1715,7 +1889,13 @@ INTERCEPTOR(int, gethostent_r, struct __sanitizer_hostent *ret, char *buf, COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop)); return res; } +#define INIT_GETHOSTENT_R \ + COMMON_INTERCEPT_FUNCTION(gethostent_r); +#else +#define INIT_GETHOSTENT_R +#endif +#if SANITIZER_INTERCEPT_GETHOSTBYADDR_R INTERCEPTOR(int, gethostbyaddr_r, void *addr, int len, int type, struct __sanitizer_hostent *ret, char *buf, SIZE_T buflen, __sanitizer_hostent **result, int *h_errnop) { @@ -1723,6 +1903,9 @@ INTERCEPTOR(int, gethostbyaddr_r, void *addr, int len, int type, COMMON_INTERCEPTOR_ENTER(ctx, gethostbyaddr_r, addr, len, type, ret, buf, buflen, result, h_errnop); 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. int res = REAL(gethostbyaddr_r)(addr, len, type, ret, buf, buflen, result, h_errnop); if (result) { @@ -1733,29 +1916,22 @@ INTERCEPTOR(int, gethostbyaddr_r, void *addr, int len, int type, COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop)); return res; } +#define INIT_GETHOSTBYADDR_R \ + COMMON_INTERCEPT_FUNCTION(gethostbyaddr_r); +#else +#define INIT_GETHOSTBYADDR_R +#endif -INTERCEPTOR(int, gethostbyname_r, char *name, struct __sanitizer_hostent *ret, - char *buf, SIZE_T buflen, __sanitizer_hostent **result, - int *h_errnop) { - void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname_r, name, ret, buf, buflen, result, - h_errnop); - int res = REAL(gethostbyname_r)(name, ret, buf, buflen, result, h_errnop); - if (result) { - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); - if (res == 0 && *result) write_hostent(ctx, *result); - } - if (h_errnop) - COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop)); - return res; -} - +#if SANITIZER_INTERCEPT_GETHOSTBYNAME2_R INTERCEPTOR(int, gethostbyname2_r, char *name, int af, struct __sanitizer_hostent *ret, char *buf, SIZE_T buflen, __sanitizer_hostent **result, int *h_errnop) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname2_r, name, af, ret, buf, buflen, 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. int res = REAL(gethostbyname2_r)(name, af, ret, buf, buflen, result, h_errnop); if (result) { @@ -1766,13 +1942,10 @@ INTERCEPTOR(int, gethostbyname2_r, char *name, int af, COMMON_INTERCEPTOR_WRITE_RANGE(ctx, h_errnop, sizeof(*h_errnop)); return res; } -#define INIT_GETHOSTBYNAME_R \ - COMMON_INTERCEPT_FUNCTION(gethostent_r); \ - COMMON_INTERCEPT_FUNCTION(gethostbyaddr_r); \ - COMMON_INTERCEPT_FUNCTION(gethostbyname_r); \ +#define INIT_GETHOSTBYNAME2_R \ COMMON_INTERCEPT_FUNCTION(gethostbyname2_r); #else -#define INIT_GETHOSTBYNAME_R +#define INIT_GETHOSTBYNAME2_R #endif #if SANITIZER_INTERCEPT_GETSOCKOPT @@ -1782,6 +1955,9 @@ INTERCEPTOR(int, getsockopt, int sockfd, int level, int optname, void *optval, COMMON_INTERCEPTOR_ENTER(ctx, getsockopt, sockfd, level, optname, optval, optlen); 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. int res = REAL(getsockopt)(sockfd, level, optname, optval, optlen); if (res == 0) if (optval && optlen) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, optval, *optlen); @@ -1823,6 +1999,9 @@ INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) { COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen)); addrlen0 = *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. int fd2 = REAL(accept4)(fd, addr, addrlen, f); if (fd2 >= 0) { if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2); @@ -1840,6 +2019,9 @@ INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) { INTERCEPTOR(double, modf, double x, double *iptr) { void *ctx; 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. double res = REAL(modf)(x, iptr); if (iptr) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr)); @@ -1849,6 +2031,9 @@ INTERCEPTOR(double, modf, double x, double *iptr) { INTERCEPTOR(float, modff, float x, float *iptr) { void *ctx; 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. float res = REAL(modff)(x, iptr); if (iptr) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr)); @@ -1858,6 +2043,9 @@ INTERCEPTOR(float, modff, float x, float *iptr) { INTERCEPTOR(long double, modfl, long double x, long double *iptr) { void *ctx; 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. long double res = REAL(modfl)(x, iptr); if (iptr) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iptr, sizeof(*iptr)); @@ -1890,6 +2078,9 @@ INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg, int flags) { void *ctx; 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. SSIZE_T res = REAL(recvmsg)(fd, msg, flags); if (res >= 0) { if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); @@ -1911,6 +2102,9 @@ INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) { COMMON_INTERCEPTOR_ENTER(ctx, getpeername, sockfd, addr, addrlen); unsigned addr_sz; 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. int res = REAL(getpeername)(sockfd, addr, addrlen); if (!res && addr && addrlen) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, Min(addr_sz, *addrlen)); @@ -1924,6 +2118,9 @@ INTERCEPTOR(int, getpeername, int sockfd, void *addr, unsigned *addrlen) { #if SANITIZER_INTERCEPT_SYSINFO 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. COMMON_INTERCEPTOR_ENTER(ctx, sysinfo, info); int res = REAL(sysinfo)(info); if (!res && info) @@ -1939,6 +2136,9 @@ INTERCEPTOR(int, sysinfo, void *info) { INTERCEPTOR(__sanitizer_dirent *, readdir, void *dirp) { void *ctx; 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. __sanitizer_dirent *res = REAL(readdir)(dirp); if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen); return res; @@ -1948,6 +2148,9 @@ INTERCEPTOR(int, readdir_r, void *dirp, __sanitizer_dirent *entry, __sanitizer_dirent **result) { void *ctx; 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. int res = REAL(readdir_r)(dirp, entry, result); if (!res) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); @@ -1968,6 +2171,9 @@ INTERCEPTOR(int, readdir_r, void *dirp, __sanitizer_dirent *entry, INTERCEPTOR(__sanitizer_dirent64 *, readdir64, void *dirp) { void *ctx; 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. __sanitizer_dirent64 *res = REAL(readdir64)(dirp); if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, res->d_reclen); return res; @@ -1977,6 +2183,9 @@ INTERCEPTOR(int, readdir64_r, void *dirp, __sanitizer_dirent64 *entry, __sanitizer_dirent64 **result) { void *ctx; 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. int res = REAL(readdir64_r)(dirp, entry, result); if (!res) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); @@ -2012,10 +2221,13 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) { } } + // 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. uptr res = REAL(ptrace)(request, pid, addr, data); if (!res && data) { - // Note that PEEK* requests assing different meaning to the return value. + // Note that PEEK* requests assign different meaning to the return value. // This function does not handle them (nor does it need to). if (request == ptrace_getregs) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_regs_struct_sz); @@ -2025,6 +2237,8 @@ INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_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); @@ -2058,6 +2272,9 @@ INTERCEPTOR(char *, setlocale, int category, char *locale) { INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) { void *ctx; 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. char *res = REAL(getcwd)(buf, size); if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); return res; @@ -2071,6 +2288,9 @@ INTERCEPTOR(char *, getcwd, char *buf, SIZE_T size) { INTERCEPTOR(char *, get_current_dir_name, int fake) { void *ctx; 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. char *res = REAL(get_current_dir_name)(fake); if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); return res; @@ -2086,6 +2306,9 @@ INTERCEPTOR(char *, get_current_dir_name, int fake) { INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) { void *ctx; 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. INTMAX_T res = REAL(strtoimax)(nptr, endptr, base); if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr)); return res; @@ -2094,6 +2317,9 @@ INTERCEPTOR(INTMAX_T, strtoimax, const char *nptr, char **endptr, int base) { INTERCEPTOR(INTMAX_T, strtoumax, const char *nptr, char **endptr, int base) { void *ctx; 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. INTMAX_T res = REAL(strtoumax)(nptr, endptr, base); if (endptr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, endptr, sizeof(*endptr)); return res; @@ -2110,6 +2336,9 @@ INTERCEPTOR(INTMAX_T, strtoumax, const char *nptr, char **endptr, int base) { INTERCEPTOR(SIZE_T, mbstowcs, wchar_t *dest, const char *src, SIZE_T len) { void *ctx; 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. SIZE_T res = REAL(mbstowcs)(dest, src, len); if (res != (SIZE_T) - 1 && dest) { SIZE_T write_cnt = res + (res < len); @@ -2124,6 +2353,9 @@ INTERCEPTOR(SIZE_T, mbsrtowcs, wchar_t *dest, const char **src, SIZE_T len, COMMON_INTERCEPTOR_ENTER(ctx, mbsrtowcs, dest, src, len, ps); if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); 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. 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 @@ -2151,6 +2383,9 @@ INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms, if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, 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. SIZE_T res = REAL(mbsnrtowcs)(dest, src, nms, len, ps); if (res != (SIZE_T)(-1) && dest && src) { SIZE_T write_cnt = res + !*src; @@ -2168,6 +2403,9 @@ INTERCEPTOR(SIZE_T, mbsnrtowcs, wchar_t *dest, const char **src, SIZE_T nms, INTERCEPTOR(SIZE_T, wcstombs, char *dest, const wchar_t *src, SIZE_T len) { void *ctx; 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. SIZE_T res = REAL(wcstombs)(dest, src, len); if (res != (SIZE_T) - 1 && dest) { SIZE_T write_cnt = res + (res < len); @@ -2182,6 +2420,9 @@ INTERCEPTOR(SIZE_T, wcsrtombs, char *dest, const wchar_t **src, SIZE_T len, COMMON_INTERCEPTOR_ENTER(ctx, wcsrtombs, dest, src, len, ps); if (src) COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src)); 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. SIZE_T res = REAL(wcsrtombs)(dest, src, len, ps); if (res != (SIZE_T) - 1 && dest && src) { SIZE_T write_cnt = res + !*src; @@ -2207,6 +2448,9 @@ INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms, if (nms) COMMON_INTERCEPTOR_READ_RANGE(ctx, *src, 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. SIZE_T res = REAL(wcsnrtombs)(dest, src, nms, len, ps); if (res != (SIZE_T) - 1 && dest && src) { SIZE_T write_cnt = res + !*src; @@ -2224,6 +2468,9 @@ INTERCEPTOR(SIZE_T, wcsnrtombs, char *dest, const wchar_t **src, SIZE_T nms, 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. int res = REAL(tcgetattr)(fd, termios_p); if (!res && termios_p) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, termios_p, struct_termios_sz); @@ -2278,6 +2525,9 @@ INTERCEPTOR(char *, canonicalize_file_name, const char *path) { INTERCEPTOR(SIZE_T, confstr, int name, char *buf, SIZE_T len) { void *ctx; 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. SIZE_T res = REAL(confstr)(name, buf, len); if (buf && res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res < len ? res : len); @@ -2292,6 +2542,9 @@ INTERCEPTOR(SIZE_T, confstr, int name, char *buf, SIZE_T len) { INTERCEPTOR(int, sched_getaffinity, int pid, SIZE_T cpusetsize, void *mask) { void *ctx; 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. int res = REAL(sched_getaffinity)(pid, cpusetsize, mask); if (mask && !res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mask, cpusetsize); return res; @@ -2318,6 +2571,9 @@ INTERCEPTOR(char *, strerror, int errnum) { INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) { void *ctx; 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. 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, @@ -2346,6 +2602,9 @@ INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) { INTERCEPTOR(int, __xpg_strerror_r, int errnum, char *buf, SIZE_T buflen) { void *ctx; 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. int res = REAL(__xpg_strerror_r)(errnum, buf, buflen); // This version always returns a null-terminated string. if (buf && buflen) @@ -2388,6 +2647,9 @@ INTERCEPTOR(int, scandir, char *dirp, __sanitizer_dirent ***namelist, if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, REAL(strlen)(dirp) + 1); scandir_filter = filter; 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; @@ -2437,6 +2699,9 @@ INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist, if (dirp) COMMON_INTERCEPTOR_READ_RANGE(ctx, dirp, REAL(strlen)(dirp) + 1); scandir64_filter = filter; 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. int res = REAL(scandir64)(dirp, namelist, filter ? wrapped_scandir64_filter : 0, compar ? wrapped_scandir64_compar : 0); @@ -2460,6 +2725,9 @@ INTERCEPTOR(int, scandir64, char *dirp, __sanitizer_dirent64 ***namelist, INTERCEPTOR(int, getgroups, int size, u32 *lst) { void *ctx; 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. int res = REAL(getgroups)(size, lst); if (res && lst) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lst, res * sizeof(*lst)); return res; @@ -2523,6 +2791,9 @@ INTERCEPTOR(int, wordexp, char *s, __sanitizer_wordexp_t *p, int flags) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, wordexp, s, p, 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. int res = REAL(wordexp)(s, p, flags); if (!res && p) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); @@ -2546,6 +2817,9 @@ INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sigwait, set, 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. int res = REAL(sigwait)(set, sig); if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig)); return res; @@ -2560,6 +2834,9 @@ INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sigwaitinfo, set, 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. int res = REAL(sigwaitinfo)(set, info); if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz); return res; @@ -2576,6 +2853,9 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info, COMMON_INTERCEPTOR_ENTER(ctx, sigtimedwait, set, info, timeout); if (timeout) COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout, struct_timespec_sz); // 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. int res = REAL(sigtimedwait)(set, info, timeout); if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz); return res; @@ -2589,6 +2869,9 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info, INTERCEPTOR(int, sigemptyset, __sanitizer_sigset_t *set) { void *ctx; 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. int res = REAL(sigemptyset)(set); if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set)); return res; @@ -2597,6 +2880,9 @@ INTERCEPTOR(int, sigemptyset, __sanitizer_sigset_t *set) { INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) { void *ctx; 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. int res = REAL(sigfillset)(set); if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set)); return res; @@ -2612,6 +2898,9 @@ INTERCEPTOR(int, sigfillset, __sanitizer_sigset_t *set) { INTERCEPTOR(int, sigpending, __sanitizer_sigset_t *set) { void *ctx; 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. int res = REAL(sigpending)(set); if (!res && set) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, set, sizeof(*set)); return res; @@ -2627,6 +2916,9 @@ INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set, void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset); // 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. int res = REAL(sigprocmask)(how, set, oldset); if (!res && oldset) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldset, sizeof(*oldset)); @@ -2641,6 +2933,9 @@ INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set, INTERCEPTOR(int, backtrace, void **buffer, int size) { void *ctx; 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. int res = REAL(backtrace)(buffer, size); if (res && buffer) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buffer, res * sizeof(*buffer)); @@ -2652,6 +2947,9 @@ INTERCEPTOR(char **, backtrace_symbols, void **buffer, int size) { COMMON_INTERCEPTOR_ENTER(ctx, backtrace_symbols, buffer, size); if (buffer && 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. char **res = REAL(backtrace_symbols)(buffer, size); if (res && size) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, size * sizeof(*res)); @@ -2757,6 +3055,9 @@ INTERCEPTOR(int, statfs, char *path, void *buf) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, statfs, path, 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. int res = REAL(statfs)(path, buf); if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz); return res; @@ -2764,6 +3065,9 @@ INTERCEPTOR(int, statfs, char *path, void *buf) { INTERCEPTOR(int, fstatfs, int fd, void *buf) { void *ctx; 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. int res = REAL(fstatfs)(fd, buf); if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs_sz); return res; @@ -2780,6 +3084,9 @@ INTERCEPTOR(int, statfs64, char *path, void *buf) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, statfs64, path, 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. int res = REAL(statfs64)(path, buf); if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz); return res; @@ -2787,6 +3094,9 @@ INTERCEPTOR(int, statfs64, char *path, void *buf) { INTERCEPTOR(int, fstatfs64, int fd, void *buf) { void *ctx; 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. int res = REAL(fstatfs64)(fd, buf); if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statfs64_sz); return res; @@ -2803,6 +3113,9 @@ INTERCEPTOR(int, statvfs, char *path, void *buf) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, statvfs, path, 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. int res = REAL(statvfs)(path, buf); if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz); return res; @@ -2810,6 +3123,9 @@ INTERCEPTOR(int, statvfs, char *path, void *buf) { INTERCEPTOR(int, fstatvfs, int fd, void *buf) { void *ctx; 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. int res = REAL(fstatvfs)(fd, buf); if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz); return res; @@ -2826,6 +3142,9 @@ INTERCEPTOR(int, statvfs64, char *path, void *buf) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, statvfs64, path, 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. int res = REAL(statvfs64)(path, buf); if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz); return res; @@ -2833,6 +3152,9 @@ INTERCEPTOR(int, statvfs64, char *path, void *buf) { INTERCEPTOR(int, fstatvfs64, int fd, void *buf) { void *ctx; 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. int res = REAL(fstatvfs64)(fd, buf); if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs64_sz); return res; @@ -2857,7 +3179,7 @@ INTERCEPTOR(int, initgroups, char *user, u32 group) { #define INIT_INITGROUPS #endif -#if SANITIZER_INTERCEPT_ETHER +#if SANITIZER_INTERCEPT_ETHER_NTOA_ATON INTERCEPTOR(char *, ether_ntoa, __sanitizer_ether_addr *addr) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa, addr); @@ -2874,10 +3196,21 @@ INTERCEPTOR(__sanitizer_ether_addr *, ether_aton, char *buf) { if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, sizeof(*res)); return res; } +#define INIT_ETHER_NTOA_ATON \ + COMMON_INTERCEPT_FUNCTION(ether_ntoa); \ + COMMON_INTERCEPT_FUNCTION(ether_aton); +#else +#define INIT_ETHER_NTOA_ATON +#endif + +#if SANITIZER_INTERCEPT_ETHER_HOST INTERCEPTOR(int, ether_ntohost, char *hostname, __sanitizer_ether_addr *addr) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, ether_ntohost, hostname, 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. int res = REAL(ether_ntohost)(hostname, addr); if (!res && hostname) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hostname, REAL(strlen)(hostname) + 1); @@ -2888,6 +3221,9 @@ INTERCEPTOR(int, ether_hostton, char *hostname, __sanitizer_ether_addr *addr) { COMMON_INTERCEPTOR_ENTER(ctx, ether_hostton, hostname, addr); if (hostname) 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. int res = REAL(ether_hostton)(hostname, addr); if (!res && addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr)); return res; @@ -2897,6 +3233,9 @@ INTERCEPTOR(int, ether_line, char *line, __sanitizer_ether_addr *addr, void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, ether_line, line, addr, hostname); 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. int res = REAL(ether_line)(line, addr, hostname); if (!res) { if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr)); @@ -2905,14 +3244,12 @@ INTERCEPTOR(int, ether_line, char *line, __sanitizer_ether_addr *addr, } return res; } -#define INIT_ETHER \ - COMMON_INTERCEPT_FUNCTION(ether_ntoa); \ - COMMON_INTERCEPT_FUNCTION(ether_aton); \ +#define INIT_ETHER_HOST \ COMMON_INTERCEPT_FUNCTION(ether_ntohost); \ COMMON_INTERCEPT_FUNCTION(ether_hostton); \ COMMON_INTERCEPT_FUNCTION(ether_line); #else -#define INIT_ETHER +#define INIT_ETHER_HOST #endif #if SANITIZER_INTERCEPT_ETHER_R @@ -2920,6 +3257,9 @@ INTERCEPTOR(char *, ether_ntoa_r, __sanitizer_ether_addr *addr, char *buf) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, ether_ntoa_r, addr, 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. char *res = REAL(ether_ntoa_r)(addr, buf); if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1); return res; @@ -2929,6 +3269,9 @@ INTERCEPTOR(__sanitizer_ether_addr *, ether_aton_r, char *buf, void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, ether_aton_r, buf, addr); 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. __sanitizer_ether_addr *res = REAL(ether_aton_r)(buf, addr); if (res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(*res)); return res; @@ -2944,6 +3287,9 @@ INTERCEPTOR(__sanitizer_ether_addr *, ether_aton_r, char *buf, INTERCEPTOR(int, shmctl, int shmid, int cmd, void *buf) { void *ctx; 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. int res = REAL(shmctl)(shmid, cmd, buf); if (res >= 0) { unsigned sz = 0; @@ -2966,6 +3312,9 @@ INTERCEPTOR(int, shmctl, int shmid, int cmd, void *buf) { INTERCEPTOR(int, random_r, void *buf, u32 *result) { void *ctx; 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. int res = REAL(random_r)(buf, result); if (!res && result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); @@ -2976,16 +3325,33 @@ INTERCEPTOR(int, random_r, void *buf, u32 *result) { #define INIT_RANDOM_R #endif -#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET || \ - SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSSCHED -#define INTERCEPTOR_PTHREAD_ATTR_GET(what, sz) \ - INTERCEPTOR(int, pthread_attr_get##what, void *attr, void *r) { \ - void *ctx; \ - COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_get##what, attr, r); \ - int res = REAL(pthread_attr_get##what)(attr, r); \ - if (!res && r) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, r, sz); \ - return res; \ +// 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. +#if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET || \ + SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSSCHED || \ + SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GET || \ + SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GET || \ + SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GET || \ + SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GET +#define INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(fn, sz) \ + INTERCEPTOR(int, fn, void *attr, void *r) { \ + void *ctx; \ + COMMON_INTERCEPTOR_ENTER(ctx, fn, attr, r); \ + int res = REAL(fn)(attr, r); \ + if (!res && r) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, r, sz); \ + return res; \ } +#define INTERCEPTOR_PTHREAD_ATTR_GET(what, sz) \ + INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_attr_get##what, sz) +#define INTERCEPTOR_PTHREAD_MUTEXATTR_GET(what, sz) \ + INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_mutexattr_get##what, sz) +#define INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(what, sz) \ + INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_rwlockattr_get##what, sz) +#define INTERCEPTOR_PTHREAD_CONDATTR_GET(what, sz) \ + INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_condattr_get##what, sz) +#define INTERCEPTOR_PTHREAD_BARRIERATTR_GET(what, sz) \ + INTERCEPTOR_PTHREAD_OBJECT_ATTR_GET(pthread_barrierattr_get##what, sz) #endif #if SANITIZER_INTERCEPT_PTHREAD_ATTR_GET @@ -2998,6 +3364,9 @@ INTERCEPTOR_PTHREAD_ATTR_GET(stacksize, sizeof(SIZE_T)) INTERCEPTOR(int, pthread_attr_getstack, void *attr, void **addr, SIZE_T *size) { void *ctx; 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. int res = REAL(pthread_attr_getstack)(attr, addr, size); if (!res) { if (addr) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, addr, sizeof(*addr)); @@ -3044,6 +3413,9 @@ INTERCEPTOR(int, pthread_attr_getaffinity_np, void *attr, SIZE_T cpusetsize, void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, pthread_attr_getaffinity_np, attr, 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. int res = REAL(pthread_attr_getaffinity_np)(attr, cpusetsize, cpuset); if (!res && cpusetsize && cpuset) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cpuset, cpusetsize); @@ -3056,6 +3428,94 @@ INTERCEPTOR(int, pthread_attr_getaffinity_np, void *attr, SIZE_T cpusetsize, #define INIT_PTHREAD_ATTR_GETAFFINITY_NP #endif +#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED +INTERCEPTOR_PTHREAD_MUTEXATTR_GET(pshared, sizeof(int)) +#define INIT_PTHREAD_MUTEXATTR_GETPSHARED \ + COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getpshared); +#else +#define INIT_PTHREAD_MUTEXATTR_GETPSHARED +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE +INTERCEPTOR_PTHREAD_MUTEXATTR_GET(type, sizeof(int)) +#define INIT_PTHREAD_MUTEXATTR_GETTYPE \ + COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_gettype); +#else +#define INIT_PTHREAD_MUTEXATTR_GETTYPE +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL +INTERCEPTOR_PTHREAD_MUTEXATTR_GET(protocol, sizeof(int)) +#define INIT_PTHREAD_MUTEXATTR_GETPROTOCOL \ + COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getprotocol); +#else +#define INIT_PTHREAD_MUTEXATTR_GETPROTOCOL +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING +INTERCEPTOR_PTHREAD_MUTEXATTR_GET(prioceiling, sizeof(int)) +#define INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING \ + COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getprioceiling); +#else +#define INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST +INTERCEPTOR_PTHREAD_MUTEXATTR_GET(robust, sizeof(int)) +#define INIT_PTHREAD_MUTEXATTR_GETROBUST \ + COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getrobust); +#else +#define INIT_PTHREAD_MUTEXATTR_GETROBUST +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP +INTERCEPTOR_PTHREAD_MUTEXATTR_GET(robust_np, sizeof(int)) +#define INIT_PTHREAD_MUTEXATTR_GETROBUST_NP \ + COMMON_INTERCEPT_FUNCTION(pthread_mutexattr_getrobust_np); +#else +#define INIT_PTHREAD_MUTEXATTR_GETROBUST_NP +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED +INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(pshared, sizeof(int)) +#define INIT_PTHREAD_RWLOCKATTR_GETPSHARED \ + COMMON_INTERCEPT_FUNCTION(pthread_rwlockattr_getpshared); +#else +#define INIT_PTHREAD_RWLOCKATTR_GETPSHARED +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP +INTERCEPTOR_PTHREAD_RWLOCKATTR_GET(kind_np, sizeof(int)) +#define INIT_PTHREAD_RWLOCKATTR_GETKIND_NP \ + COMMON_INTERCEPT_FUNCTION(pthread_rwlockattr_getkind_np); +#else +#define INIT_PTHREAD_RWLOCKATTR_GETKIND_NP +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED +INTERCEPTOR_PTHREAD_CONDATTR_GET(pshared, sizeof(int)) +#define INIT_PTHREAD_CONDATTR_GETPSHARED \ + COMMON_INTERCEPT_FUNCTION(pthread_condattr_getpshared); +#else +#define INIT_PTHREAD_CONDATTR_GETPSHARED +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK +INTERCEPTOR_PTHREAD_CONDATTR_GET(clock, sizeof(int)) +#define INIT_PTHREAD_CONDATTR_GETCLOCK \ + COMMON_INTERCEPT_FUNCTION(pthread_condattr_getclock); +#else +#define INIT_PTHREAD_CONDATTR_GETCLOCK +#endif + +#if SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED +INTERCEPTOR_PTHREAD_BARRIERATTR_GET(pshared, sizeof(int)) // !mac !android +#define INIT_PTHREAD_BARRIERATTR_GETPSHARED \ + COMMON_INTERCEPT_FUNCTION(pthread_barrierattr_getpshared); +#else +#define INIT_PTHREAD_BARRIERATTR_GETPSHARED +#endif + #if SANITIZER_INTERCEPT_TMPNAM INTERCEPTOR(char *, tmpnam, char *s) { void *ctx; @@ -3063,6 +3523,9 @@ INTERCEPTOR(char *, tmpnam, char *s) { char *res = REAL(tmpnam)(s); if (res) { 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. COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1); else COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1); @@ -3078,6 +3541,9 @@ INTERCEPTOR(char *, tmpnam, char *s) { INTERCEPTOR(char *, tmpnam_r, char *s) { void *ctx; 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. char *res = REAL(tmpnam_r)(s); if (res && s) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, s, REAL(strlen)(s) + 1); return res; @@ -3118,6 +3584,9 @@ INTERCEPTOR(int, pthread_setname_np, uptr thread, const char *name) { INTERCEPTOR(void, sincos, double x, double *sin, double *cos) { void *ctx; 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. 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)); @@ -3125,6 +3594,9 @@ INTERCEPTOR(void, sincos, double x, double *sin, double *cos) { INTERCEPTOR(void, sincosf, float x, float *sin, float *cos) { void *ctx; 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. 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)); @@ -3132,6 +3604,9 @@ INTERCEPTOR(void, sincosf, float x, float *sin, float *cos) { INTERCEPTOR(void, sincosl, long double x, long double *sin, long double *cos) { void *ctx; 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. 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)); @@ -3148,6 +3623,9 @@ INTERCEPTOR(void, sincosl, long double x, long double *sin, long double *cos) { INTERCEPTOR(double, remquo, double x, double y, int *quo) { void *ctx; 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. double res = REAL(remquo)(x, y, quo); if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo)); return res; @@ -3155,6 +3633,9 @@ INTERCEPTOR(double, remquo, double x, double y, int *quo) { INTERCEPTOR(float, remquof, float x, float y, int *quo) { void *ctx; 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. float res = REAL(remquof)(x, y, quo); if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo)); return res; @@ -3162,6 +3643,9 @@ INTERCEPTOR(float, remquof, float x, float y, int *quo) { INTERCEPTOR(long double, remquol, long double x, long double y, int *quo) { void *ctx; 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. long double res = REAL(remquol)(x, y, quo); if (quo) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, quo, sizeof(*quo)); return res; @@ -3209,6 +3693,9 @@ INTERCEPTOR(long double, lgammal, long double x) { INTERCEPTOR(double, lgamma_r, double x, int *signp) { void *ctx; 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. double res = REAL(lgamma_r)(x, signp); if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp)); return res; @@ -3216,29 +3703,43 @@ INTERCEPTOR(double, lgamma_r, double x, int *signp) { INTERCEPTOR(float, lgammaf_r, float x, int *signp) { void *ctx; 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. float res = REAL(lgammaf_r)(x, signp); if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp)); return res; } +#define INIT_LGAMMA_R \ + COMMON_INTERCEPT_FUNCTION(lgamma_r); \ + COMMON_INTERCEPT_FUNCTION(lgammaf_r); +#else +#define INIT_LGAMMA_R +#endif + +#if SANITIZER_INTERCEPT_LGAMMAL_R INTERCEPTOR(long double, lgammal_r, long double x, int *signp) { void *ctx; 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. long double res = REAL(lgammal_r)(x, signp); if (signp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, signp, sizeof(*signp)); return res; } -#define INIT_LGAMMA_R \ - COMMON_INTERCEPT_FUNCTION(lgamma_r); \ - COMMON_INTERCEPT_FUNCTION(lgammaf_r); \ - COMMON_INTERCEPT_FUNCTION(lgammal_r); +#define INIT_LGAMMAL_R COMMON_INTERCEPT_FUNCTION(lgammal_r); #else -#define INIT_LGAMMA_R +#define INIT_LGAMMAL_R #endif #if SANITIZER_INTERCEPT_DRAND48_R INTERCEPTOR(int, drand48_r, void *buffer, double *result) { void *ctx; 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. int res = REAL(drand48_r)(buffer, result); if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); return res; @@ -3246,6 +3747,9 @@ INTERCEPTOR(int, drand48_r, void *buffer, double *result) { INTERCEPTOR(int, lrand48_r, void *buffer, long *result) { void *ctx; 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. int res = REAL(lrand48_r)(buffer, result); if (result) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, result, sizeof(*result)); return res; @@ -3273,6 +3777,9 @@ INTERCEPTOR(int, rand_r, unsigned *seedp) { INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) { void *ctx; 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. SSIZE_T res = REAL(getline)(lineptr, n, stream); if (res > 0) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr)); @@ -3281,11 +3788,14 @@ INTERCEPTOR(SSIZE_T, getline, char **lineptr, SIZE_T *n, void *stream) { } return res; } -INTERCEPTOR(SSIZE_T, getdelim, char **lineptr, SIZE_T *n, int delim, +INTERCEPTOR(SSIZE_T, __getdelim, char **lineptr, SIZE_T *n, int delim, void *stream) { void *ctx; - COMMON_INTERCEPTOR_ENTER(ctx, getdelim, lineptr, n, delim, stream); - SSIZE_T res = REAL(getdelim)(lineptr, n, delim, stream); + COMMON_INTERCEPTOR_ENTER(ctx, __getdelim, lineptr, n, delim, 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. + SSIZE_T res = REAL(__getdelim)(lineptr, n, delim, stream); if (res > 0) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineptr, sizeof(*lineptr)); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n)); @@ -3293,8 +3803,13 @@ INTERCEPTOR(SSIZE_T, getdelim, char **lineptr, SIZE_T *n, int delim, } return res; } -#define INIT_GETLINE \ - COMMON_INTERCEPT_FUNCTION(getline); \ +INTERCEPTOR(SSIZE_T, getdelim, char **lineptr, SIZE_T *n, int delim, + void *stream) { + return __getdelim(lineptr, n, delim, stream); +} +#define INIT_GETLINE \ + COMMON_INTERCEPT_FUNCTION(getline); \ + COMMON_INTERCEPT_FUNCTION(__getdelim); \ COMMON_INTERCEPT_FUNCTION(getdelim); #else #define INIT_GETLINE @@ -3313,6 +3828,9 @@ INTERCEPTOR(SIZE_T, iconv, void *cd, char **inbuf, SIZE_T *inbytesleft, if (outbytesleft) COMMON_INTERCEPTOR_READ_RANGE(ctx, outbytesleft, sizeof(*outbytesleft)); void *outbuf_orig = outbuf ? *outbuf : 0; + // 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. 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; @@ -3329,6 +3847,9 @@ INTERCEPTOR(SIZE_T, iconv, void *cd, char **inbuf, SIZE_T *inbytesleft, INTERCEPTOR(__sanitizer_clock_t, times, void *tms) { void *ctx; 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. __sanitizer_clock_t res = REAL(times)(tms); if (res != (__sanitizer_clock_t)-1 && tms) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tms, struct_tms_sz); @@ -3345,7 +3866,11 @@ INTERCEPTOR(void *, __tls_get_addr, void *arg) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, __tls_get_addr, arg); void *res = REAL(__tls_get_addr)(arg); - DTLS_on_tls_get_addr(arg, res); + DTLS::DTV *dtv = DTLS_on_tls_get_addr(arg, res); + if (dtv) { + // New DTLS block has been allocated. + COMMON_INTERCEPTOR_INITIALIZE_RANGE((void *)dtv->beg, dtv->size); + } return res; } #else @@ -3357,6 +3882,9 @@ INTERCEPTOR(SSIZE_T, listxattr, const char *path, char *list, SIZE_T size) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, listxattr, path, list, 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. 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. @@ -3367,6 +3895,9 @@ INTERCEPTOR(SSIZE_T, llistxattr, const char *path, char *list, SIZE_T size) { void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, llistxattr, path, list, 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. SSIZE_T res = REAL(llistxattr)(path, list, size); if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res); return res; @@ -3374,6 +3905,9 @@ INTERCEPTOR(SSIZE_T, llistxattr, const char *path, char *list, SIZE_T size) { INTERCEPTOR(SSIZE_T, flistxattr, int fd, char *list, SIZE_T size) { void *ctx; 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. SSIZE_T res = REAL(flistxattr)(fd, list, size); if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res); return res; @@ -3393,6 +3927,9 @@ INTERCEPTOR(SSIZE_T, getxattr, const char *path, const char *name, char *value, COMMON_INTERCEPTOR_ENTER(ctx, getxattr, path, name, value, size); if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); 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. SSIZE_T res = REAL(getxattr)(path, name, value, size); if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res); return res; @@ -3403,6 +3940,9 @@ INTERCEPTOR(SSIZE_T, lgetxattr, const char *path, const char *name, char *value, COMMON_INTERCEPTOR_ENTER(ctx, lgetxattr, path, name, value, size); if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); 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. SSIZE_T res = REAL(lgetxattr)(path, name, value, size); if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res); return res; @@ -3412,6 +3952,9 @@ INTERCEPTOR(SSIZE_T, fgetxattr, int fd, const char *name, char *value, void *ctx; COMMON_INTERCEPTOR_ENTER(ctx, fgetxattr, fd, name, value, size); 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. SSIZE_T res = REAL(fgetxattr)(fd, name, value, size); if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res); return res; @@ -3428,6 +3971,9 @@ INTERCEPTOR(SSIZE_T, fgetxattr, int fd, const char *name, char *value, INTERCEPTOR(int, getresuid, void *ruid, void *euid, void *suid) { void *ctx; 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. int res = REAL(getresuid)(ruid, euid, suid); if (res >= 0) { if (ruid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ruid, uid_t_sz); @@ -3439,6 +3985,9 @@ INTERCEPTOR(int, getresuid, void *ruid, void *euid, void *suid) { INTERCEPTOR(int, getresgid, void *rgid, void *egid, void *sgid) { void *ctx; 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. int res = REAL(getresgid)(rgid, egid, sgid); if (res >= 0) { if (rgid) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rgid, gid_t_sz); @@ -3461,6 +4010,9 @@ INTERCEPTOR(int, getresgid, void *rgid, void *egid, void *sgid) { INTERCEPTOR(int, getifaddrs, __sanitizer_ifaddrs **ifap) { void *ctx; 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. int res = REAL(getifaddrs)(ifap); if (res == 0 && ifap) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifap, sizeof(void *)); @@ -3494,6 +4046,9 @@ INTERCEPTOR(int, getifaddrs, __sanitizer_ifaddrs **ifap) { INTERCEPTOR(char *, if_indextoname, unsigned int ifindex, char* ifname) { void *ctx; 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. char *res = REAL(if_indextoname)(ifindex, ifname); if (res && ifname) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ifname, REAL(strlen)(ifname) + 1); @@ -3519,6 +4074,9 @@ INTERCEPTOR(int, capget, void *hdrp, void *datap) { COMMON_INTERCEPTOR_ENTER(ctx, capget, hdrp, datap); if (hdrp) 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. int res = REAL(capget)(hdrp, datap); if (res == 0 && datap) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datap, __user_cap_data_struct_sz); @@ -3617,6 +4175,9 @@ INTERCEPTOR(void *, __bzero, void *block, uptr size) { INTERCEPTOR(int, ftime, __sanitizer_timeb *tp) { void *ctx; 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. int res = REAL(ftime)(tp); if (tp) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tp, sizeof(*tp)); @@ -3632,6 +4193,9 @@ INTERCEPTOR(void, xdrmem_create, __sanitizer_XDR *xdrs, uptr addr, unsigned size, int op) { void *ctx; 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. REAL(xdrmem_create)(xdrs, addr, size, op); COMMON_INTERCEPTOR_WRITE_RANGE(ctx, xdrs, sizeof(*xdrs)); if (op == __sanitizer_XDR_ENCODE) { @@ -3644,10 +4208,16 @@ INTERCEPTOR(void, xdrmem_create, __sanitizer_XDR *xdrs, uptr addr, INTERCEPTOR(void, xdrstdio_create, __sanitizer_XDR *xdrs, void *file, int op) { void *ctx; 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. 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. #define XDR_INTERCEPTOR(F, T) \ INTERCEPTOR(int, F, __sanitizer_XDR *xdrs, T *p) { \ void *ctx; \ @@ -3699,6 +4269,9 @@ INTERCEPTOR(int, xdr_bytes, __sanitizer_XDR *xdrs, char **p, unsigned *sizep, COMMON_INTERCEPTOR_READ_RANGE(ctx, sizep, sizeof(*sizep)); COMMON_INTERCEPTOR_READ_RANGE(ctx, *p, *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. 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)); @@ -3716,6 +4289,9 @@ INTERCEPTOR(int, xdr_string, __sanitizer_XDR *xdrs, char **p, COMMON_INTERCEPTOR_READ_RANGE(ctx, p, sizeof(*p)); COMMON_INTERCEPTOR_READ_RANGE(ctx, *p, REAL(strlen)(*p) + 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. int res = REAL(xdr_string)(xdrs, p, maxsize); if (p && xdrs->x_op == __sanitizer_XDR_DECODE) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p, sizeof(*p)); @@ -3765,6 +4341,9 @@ INTERCEPTOR(void *, tsearch, void *key, void **rootp, int (*compar)(const void *, const void *)) { void *ctx; 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. void *res = REAL(tsearch)(key, rootp, compar); if (res && *(void **)res == key) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, sizeof(void *)); @@ -3915,6 +4494,9 @@ INTERCEPTOR(__sanitizer_FILE *, freopen64, const char *path, const char *mode, INTERCEPTOR(__sanitizer_FILE *, open_memstream, char **ptr, SIZE_T *sizeloc) { void *ctx; 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. __sanitizer_FILE *res = REAL(open_memstream)(ptr, sizeloc); if (res) { COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, sizeof(*ptr)); @@ -3943,6 +4525,9 @@ INTERCEPTOR(__sanitizer_FILE *, fmemopen, void *buf, SIZE_T size, const char *mode) { void *ctx; 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. __sanitizer_FILE *res = REAL(fmemopen)(buf, size, mode); if (res) unpoison_file(res); return res; @@ -4034,6 +4619,114 @@ INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) { #define INIT_FCLOSE #endif +#if SANITIZER_INTERCEPT_DLOPEN_DLCLOSE +INTERCEPTOR(void*, dlopen, const char *filename, int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlopen, filename, flag); + void *res = REAL(dlopen)(filename, flag); + COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res); + return res; +} + +INTERCEPTOR(int, dlclose, void *handle) { + void *ctx; + COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlclose, handle); + int res = REAL(dlclose)(handle); + COMMON_INTERCEPTOR_LIBRARY_UNLOADED(); + return res; +} +#define INIT_DLOPEN_DLCLOSE \ + COMMON_INTERCEPT_FUNCTION(dlopen); \ + COMMON_INTERCEPT_FUNCTION(dlclose); +#else +#define INIT_DLOPEN_DLCLOSE +#endif + +#if SANITIZER_INTERCEPT_GETPASS +INTERCEPTOR(char *, getpass, const char *prompt) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getpass, prompt); + if (prompt) + COMMON_INTERCEPTOR_READ_RANGE(ctx, prompt, REAL(strlen)(prompt)+1); + char *res = REAL(getpass)(prompt); + if (res) COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res)+1); + return res; +} + +#define INIT_GETPASS COMMON_INTERCEPT_FUNCTION(getpass); +#else +#define INIT_GETPASS +#endif + +#if SANITIZER_INTERCEPT_TIMERFD +INTERCEPTOR(int, timerfd_settime, int fd, int flags, void *new_value, + void *old_value) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, timerfd_settime, fd, flags, new_value, + old_value); + COMMON_INTERCEPTOR_READ_RANGE(ctx, new_value, struct_itimerspec_sz); + int res = REAL(timerfd_settime)(fd, flags, new_value, old_value); + if (res != -1 && old_value) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, old_value, struct_itimerspec_sz); + return res; +} + +INTERCEPTOR(int, timerfd_gettime, int fd, void *curr_value) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, timerfd_gettime, fd, curr_value); + int res = REAL(timerfd_gettime)(fd, curr_value); + if (res != -1 && curr_value) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, curr_value, struct_itimerspec_sz); + return res; +} +#define INIT_TIMERFD \ + COMMON_INTERCEPT_FUNCTION(timerfd_settime); \ + COMMON_INTERCEPT_FUNCTION(timerfd_gettime); +#else +#define INIT_TIMERFD +#endif + +#if SANITIZER_INTERCEPT_MLOCKX +// Linux kernel has a bug that leads to kernel deadlock if a process +// maps TBs of memory and then calls mlock(). +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", + SanitizerToolName); +} + +INTERCEPTOR(int, mlock, const void *addr, uptr len) { + MlockIsUnsupported(); + return 0; +} + +INTERCEPTOR(int, munlock, const void *addr, uptr len) { + MlockIsUnsupported(); + return 0; +} + +INTERCEPTOR(int, mlockall, int flags) { + MlockIsUnsupported(); + return 0; +} + +INTERCEPTOR(int, munlockall, void) { + MlockIsUnsupported(); + return 0; +} + +#define INIT_MLOCKX \ + COMMON_INTERCEPT_FUNCTION(mlock); \ + COMMON_INTERCEPT_FUNCTION(munlock); \ + COMMON_INTERCEPT_FUNCTION(mlockall); \ + COMMON_INTERCEPT_FUNCTION(munlockall); + +#else +#define INIT_MLOCKX +#endif // SANITIZER_INTERCEPT_MLOCKX + static void InitializeCommonInterceptors() { static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1]; interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap(); @@ -4085,6 +4778,9 @@ static void InitializeCommonInterceptors() { INIT_GETSOCKNAME; INIT_GETHOSTBYNAME; INIT_GETHOSTBYNAME_R; + INIT_GETHOSTBYNAME2_R; + INIT_GETHOSTBYADDR_R; + INIT_GETHOSTENT_R; INIT_GETSOCKOPT; INIT_ACCEPT; INIT_ACCEPT4; @@ -4136,13 +4832,25 @@ static void InitializeCommonInterceptors() { INIT_STATVFS; INIT_STATVFS64; INIT_INITGROUPS; - INIT_ETHER; + INIT_ETHER_NTOA_ATON; + INIT_ETHER_HOST; INIT_ETHER_R; INIT_SHMCTL; INIT_RANDOM_R; INIT_PTHREAD_ATTR_GET; INIT_PTHREAD_ATTR_GETINHERITSCHED; INIT_PTHREAD_ATTR_GETAFFINITY_NP; + INIT_PTHREAD_MUTEXATTR_GETPSHARED; + INIT_PTHREAD_MUTEXATTR_GETTYPE; + INIT_PTHREAD_MUTEXATTR_GETPROTOCOL; + INIT_PTHREAD_MUTEXATTR_GETPRIOCEILING; + INIT_PTHREAD_MUTEXATTR_GETROBUST; + INIT_PTHREAD_MUTEXATTR_GETROBUST_NP; + INIT_PTHREAD_RWLOCKATTR_GETPSHARED; + INIT_PTHREAD_RWLOCKATTR_GETKIND_NP; + INIT_PTHREAD_CONDATTR_GETPSHARED; + INIT_PTHREAD_CONDATTR_GETCLOCK; + INIT_PTHREAD_BARRIERATTR_GETPSHARED; INIT_TMPNAM; INIT_TMPNAM_R; INIT_TEMPNAM; @@ -4151,6 +4859,7 @@ static void InitializeCommonInterceptors() { INIT_REMQUO; INIT_LGAMMA; INIT_LGAMMA_R; + INIT_LGAMMAL_R; INIT_DRAND48_R; INIT_RAND_R; INIT_GETLINE; @@ -4175,4 +4884,8 @@ static void InitializeCommonInterceptors() { INIT_OBSTACK; INIT_FFLUSH; INIT_FCLOSE; + INIT_DLOPEN_DLCLOSE; + INIT_GETPASS; + INIT_TIMERFD; + INIT_MLOCKX; } diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc index dfc4ac6b556..26cbe68dc99 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc @@ -457,6 +457,9 @@ static int printf_get_value_size(PrintfDirective *dir) { case 8: \ va_arg(*aq, double); \ break; \ + case 12: \ + va_arg(*aq, long double); \ + break; \ case 16: \ va_arg(*aq, long double); \ break; \ diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc index 96d171a92f5..ca264d899a7 100755 --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc @@ -527,7 +527,7 @@ static bool ioctl_decode(unsigned req, ioctl_desc *desc) { desc->name = "<DECODED_IOCTL>"; desc->size = IOC_SIZE(req); // Sanity check. - if (desc->size > 1024) return false; + if (desc->size > 0xFFFF) return false; unsigned dir = IOC_DIR(req); switch (dir) { case IOC_NONE: @@ -545,10 +545,10 @@ static bool ioctl_decode(unsigned req, ioctl_desc *desc) { default: return false; } - if (desc->type != IOC_NONE && desc->size == 0) return false; - char id = IOC_TYPE(req); + // Size can be 0 iff type is NONE. + if ((desc->type == IOC_NONE) != (desc->size == 0)) return false; // Sanity check. - if (!(id >= 'a' && id <= 'z') && !(id >= 'A' && id <= 'Z')) return false; + if (IOC_TYPE(req) == 0) return false; return true; } diff --git a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc index d8330630b5f..b5251444f0f 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc +++ b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc @@ -11,6 +11,8 @@ #include "sanitizer_common.h" #include "sanitizer_flags.h" +#include "sanitizer_stacktrace.h" +#include "sanitizer_symbolizer.h" namespace __sanitizer { @@ -39,4 +41,32 @@ bool ColorizeReports() { return internal_strcmp(flag, "always") == 0 || (internal_strcmp(flag, "auto") == 0 && PrintsToTtyCached()); } + +static void (*sandboxing_callback)(); +void SetSandboxingCallback(void (*f)()) { + sandboxing_callback = f; +} + +void ReportErrorSummary(const char *error_type, StackTrace *stack) { + if (!common_flags()->print_summary) + return; + AddressInfo ai; +#if !SANITIZER_GO + if (stack->size > 0 && Symbolizer::GetOrInit()->CanReturnFileLineInfo()) { + // Currently, we include the first stack frame into the report summary. + // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc). + uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]); + Symbolizer::GetOrInit()->SymbolizePC(pc, &ai, 1); + } +#endif + ReportErrorSummary(error_type, ai.file, ai.line, ai.function); +} + } // namespace __sanitizer + +void NOINLINE +__sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args) { + PrepareForSandboxing(args); + if (sandboxing_callback) + sandboxing_callback(); +} diff --git a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc index 6be2f51b80a..24e1b7ec452 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc +++ b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc @@ -829,6 +829,7 @@ POST_SYSCALL(stat)(long res, const void *filename, void *statbuf) { } } +#if !SANITIZER_ANDROID PRE_SYSCALL(statfs)(const void *path, void *buf) { if (path) PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1); @@ -866,6 +867,7 @@ POST_SYSCALL(fstatfs64)(long res, long fd, long sz, void *buf) { if (buf) POST_WRITE(buf, struct_statfs64_sz); } } +#endif // !SANITIZER_ANDROID PRE_SYSCALL(lstat)(const void *filename, void *statbuf) { if (filename) @@ -1322,13 +1324,13 @@ PRE_SYSCALL(io_submit)(long ctx_id, long nr, __sanitizer_iocb **iocbpp) { } else if (op == iocb_cmd_pread && buf && len) { POST_WRITE(buf, len); } else if (op == iocb_cmd_pwritev) { - __sanitizer_iovec *iovec = (__sanitizer_iovec*)iocbpp[i]->aio_buf; + __sanitizer_iovec *iovec = (__sanitizer_iovec*)buf; for (uptr v = 0; v < len; v++) - PRE_READ(iovec[i].iov_base, iovec[i].iov_len); + PRE_READ(iovec[v].iov_base, iovec[v].iov_len); } else if (op == iocb_cmd_preadv) { - __sanitizer_iovec *iovec = (__sanitizer_iovec*)iocbpp[i]->aio_buf; + __sanitizer_iovec *iovec = (__sanitizer_iovec*)buf; for (uptr v = 0; v < len; v++) - POST_WRITE(iovec[i].iov_base, iovec[i].iov_len); + POST_WRITE(iovec[v].iov_base, iovec[v].iov_len); } // See comment in io_getevents. COMMON_SYSCALL_RELEASE(data); @@ -2293,7 +2295,7 @@ PRE_SYSCALL(ni_syscall)() {} POST_SYSCALL(ni_syscall)(long res) {} PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) { -#if defined(__i386) || defined (__x86_64) +#if !SANITIZER_ANDROID && (defined(__i386) || defined (__x86_64)) if (data) { if (request == ptrace_setregs) { PRE_READ((void *)data, struct_user_regs_struct_sz); @@ -2312,7 +2314,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 defined(__i386) || defined (__x86_64) +#if !SANITIZER_ANDROID && (defined(__i386) || defined (__x86_64)) if (res >= 0 && data) { // Note that this is different from the interceptor in // sanitizer_common_interceptors.inc. diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage.cc b/libsanitizer/sanitizer_common/sanitizer_coverage.cc deleted file mode 100644 index b88e9e7ed0a..00000000000 --- a/libsanitizer/sanitizer_common/sanitizer_coverage.cc +++ /dev/null @@ -1,214 +0,0 @@ -//===-- sanitizer_coverage.cc ---------------------------------------------===// -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Sanitizer Coverage. -// This file implements run-time support for a poor man's coverage tool. -// -// Compiler instrumentation: -// For every interesting basic block the compiler injects the following code: -// if (*Guard) { -// __sanitizer_cov(); -// *Guard = 1; -// } -// It's fine to call __sanitizer_cov more than once for a given block. -// -// Run-time: -// - __sanitizer_cov(): record that we've executed the PC (GET_CALLER_PC). -// - __sanitizer_cov_dump: dump the coverage data to disk. -// For every module of the current process that has coverage data -// this will create a file module_name.PID.sancov. The file format is simple: -// it's just a sorted sequence of 4-byte offsets in the module. -// -// Eventually, this coverage implementation should be obsoleted by a more -// powerful general purpose Clang/LLVM coverage instrumentation. -// Consider this implementation as prototype. -// -// FIXME: support (or at least test with) dlclose. -//===----------------------------------------------------------------------===// - -#include "sanitizer_allocator_internal.h" -#include "sanitizer_common.h" -#include "sanitizer_libc.h" -#include "sanitizer_mutex.h" -#include "sanitizer_procmaps.h" -#include "sanitizer_stacktrace.h" -#include "sanitizer_flags.h" - -atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once. - -// pc_array is the array containing the covered PCs. -// To make the pc_array thread- and async-signal-safe it has to be large enough. -// 128M counters "ought to be enough for anybody" (4M on 32-bit). -// pc_array is allocated with MmapNoReserveOrDie and so it uses only as -// much RAM as it really needs. -static const uptr kPcArraySize = FIRST_32_SECOND_64(1 << 22, 1 << 27); -static uptr *pc_array; -static atomic_uintptr_t pc_array_index; - -static bool cov_sandboxed = false; -static int cov_fd = kInvalidFd; -static unsigned int cov_max_block_size = 0; - -namespace __sanitizer { - -// Simply add the pc into the vector under lock. If the function is called more -// than once for a given PC it will be inserted multiple times, which is fine. -static void CovAdd(uptr pc) { - if (!pc_array) return; - uptr idx = atomic_fetch_add(&pc_array_index, 1, memory_order_relaxed); - CHECK_LT(idx, kPcArraySize); - pc_array[idx] = pc; -} - -void CovInit() { - pc_array = reinterpret_cast<uptr *>( - MmapNoReserveOrDie(sizeof(uptr) * kPcArraySize, "CovInit")); -} - -static inline bool CompareLess(const uptr &a, const uptr &b) { - return a < b; -} - -// Block layout for packed file format: header, followed by module name (no -// trailing zero), followed by data blob. -struct CovHeader { - int pid; - unsigned int module_name_length; - unsigned int data_length; -}; - -static void CovWritePacked(int pid, const char *module, const void *blob, - unsigned int blob_size) { - CHECK_GE(cov_fd, 0); - unsigned module_name_length = internal_strlen(module); - CovHeader header = {pid, module_name_length, blob_size}; - - if (cov_max_block_size == 0) { - // Writing to a file. Just go ahead. - internal_write(cov_fd, &header, sizeof(header)); - internal_write(cov_fd, module, module_name_length); - internal_write(cov_fd, blob, blob_size); - } else { - // Writing to a socket. We want to split the data into appropriately sized - // blocks. - InternalScopedBuffer<char> block(cov_max_block_size); - CHECK_EQ((uptr)block.data(), (uptr)(CovHeader *)block.data()); - uptr header_size_with_module = sizeof(header) + module_name_length; - CHECK_LT(header_size_with_module, cov_max_block_size); - unsigned int max_payload_size = - cov_max_block_size - header_size_with_module; - char *block_pos = block.data(); - internal_memcpy(block_pos, &header, sizeof(header)); - block_pos += sizeof(header); - internal_memcpy(block_pos, module, module_name_length); - block_pos += module_name_length; - char *block_data_begin = block_pos; - char *blob_pos = (char *)blob; - while (blob_size > 0) { - unsigned int payload_size = Min(blob_size, max_payload_size); - blob_size -= payload_size; - internal_memcpy(block_data_begin, blob_pos, payload_size); - blob_pos += payload_size; - ((CovHeader *)block.data())->data_length = payload_size; - internal_write(cov_fd, block.data(), - header_size_with_module + payload_size); - } - } -} - -// Dump the coverage on disk. -static void CovDump() { - if (!common_flags()->coverage) return; -#if !SANITIZER_WINDOWS - if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed)) - return; - uptr size = atomic_load(&pc_array_index, memory_order_relaxed); - InternalSort(&pc_array, size, CompareLess); - InternalMmapVector<u32> offsets(size); - const uptr *vb = pc_array; - const uptr *ve = vb + size; - MemoryMappingLayout proc_maps(/*cache_enabled*/true); - uptr mb, me, off, prot; - InternalScopedBuffer<char> module(4096); - InternalScopedBuffer<char> path(4096 * 2); - for (int i = 0; - proc_maps.Next(&mb, &me, &off, module.data(), module.size(), &prot); - i++) { - if ((prot & MemoryMappingLayout::kProtectionExecute) == 0) - continue; - while (vb < ve && *vb < mb) vb++; - if (vb >= ve) break; - if (*vb < me) { - offsets.clear(); - const uptr *old_vb = vb; - CHECK_LE(off, *vb); - for (; vb < ve && *vb < me; vb++) { - uptr diff = *vb - (i ? mb : 0) + off; - CHECK_LE(diff, 0xffffffffU); - offsets.push_back(static_cast<u32>(diff)); - } - char *module_name = StripModuleName(module.data()); - if (cov_sandboxed) { - CovWritePacked(internal_getpid(), module_name, offsets.data(), - offsets.size() * sizeof(u32)); - VReport(1, " CovDump: %zd PCs written to packed file\n", vb - old_vb); - } else { - // One file per module per process. - internal_snprintf((char *)path.data(), path.size(), "%s.%zd.sancov", - module_name, internal_getpid()); - uptr fd = OpenFile(path.data(), true); - if (internal_iserror(fd)) { - Report(" CovDump: failed to open %s for writing\n", path.data()); - } else { - internal_write(fd, offsets.data(), offsets.size() * sizeof(u32)); - internal_close(fd); - VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), - vb - old_vb); - } - } - InternalFree(module_name); - } - } - if (cov_fd >= 0) - internal_close(cov_fd); -#endif // !SANITIZER_WINDOWS -} - -static void OpenPackedFileForWriting() { - CHECK(cov_fd == kInvalidFd); - InternalScopedBuffer<char> path(1024); - internal_snprintf((char *)path.data(), path.size(), "%zd.sancov.packed", - internal_getpid()); - uptr fd = OpenFile(path.data(), true); - if (internal_iserror(fd)) { - Report(" Coverage: failed to open %s for writing\n", path.data()); - Die(); - } - cov_fd = fd; -} - -void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { - if (!args) return; - if (!common_flags()->coverage) return; - cov_sandboxed = args->coverage_sandboxed; - if (!cov_sandboxed) return; - cov_fd = args->coverage_fd; - cov_max_block_size = args->coverage_max_block_size; - if (cov_fd < 0) - // Pre-open the file now. The sandbox won't allow us to do it later. - OpenPackedFileForWriting(); -} - -} // namespace __sanitizer - -extern "C" { -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov() { - CovAdd(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC())); -} -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); } -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() { CovInit(); } -} // extern "C" diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc new file mode 100644 index 00000000000..9b02cd75017 --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -0,0 +1,377 @@ +//===-- sanitizer_coverage.cc ---------------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Sanitizer Coverage. +// This file implements run-time support for a poor man's coverage tool. +// +// Compiler instrumentation: +// For every interesting basic block the compiler injects the following code: +// if (*Guard) { +// __sanitizer_cov(); +// *Guard = 1; +// } +// It's fine to call __sanitizer_cov more than once for a given block. +// +// Run-time: +// - __sanitizer_cov(): record that we've executed the PC (GET_CALLER_PC). +// - __sanitizer_cov_dump: dump the coverage data to disk. +// For every module of the current process that has coverage data +// this will create a file module_name.PID.sancov. The file format is simple: +// it's just a sorted sequence of 4-byte offsets in the module. +// +// Eventually, this coverage implementation should be obsoleted by a more +// powerful general purpose Clang/LLVM coverage instrumentation. +// Consider this implementation as prototype. +// +// FIXME: support (or at least test with) dlclose. +//===----------------------------------------------------------------------===// + +#include "sanitizer_allocator_internal.h" +#include "sanitizer_common.h" +#include "sanitizer_libc.h" +#include "sanitizer_mutex.h" +#include "sanitizer_procmaps.h" +#include "sanitizer_stacktrace.h" +#include "sanitizer_flags.h" + +atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once. + +// pc_array is the array containing the covered PCs. +// To make the pc_array thread- and async-signal-safe it has to be large enough. +// 128M counters "ought to be enough for anybody" (4M on 32-bit). + +// With coverage_direct=1 in ASAN_OPTIONS, pc_array memory is mapped to a file. +// In this mode, __sanitizer_cov_dump does nothing, and CovUpdateMapping() +// dump current memory layout to another file. + +static bool cov_sandboxed = false; +static int cov_fd = kInvalidFd; +static unsigned int cov_max_block_size = 0; + +namespace __sanitizer { + +class CoverageData { + public: + void Init(); + void BeforeFork(); + void AfterFork(int child_pid); + void Extend(uptr npcs); + void Add(uptr pc); + + uptr *data(); + uptr size(); + + private: + // Maximal size pc array may ever grow. + // We MmapNoReserve this space to ensure that the array is contiguous. + static const uptr kPcArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 27); + // The amount file mapping for the pc array is grown by. + static const uptr kPcArrayMmapSize = 64 * 1024; + + // pc_array is allocated with MmapNoReserveOrDie and so it uses only as + // much RAM as it really needs. + uptr *pc_array; + // Index of the first available pc_array slot. + atomic_uintptr_t pc_array_index; + // Array size. + atomic_uintptr_t pc_array_size; + // Current file mapped size of the pc array. + uptr pc_array_mapped_size; + // Descriptor of the file mapped pc array. + int pc_fd; + StaticSpinMutex mu; + + void DirectOpen(); + void ReInit(); +}; + +static CoverageData coverage_data; + +void CoverageData::DirectOpen() { + InternalScopedString path(1024); + internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.raw", + common_flags()->coverage_dir, internal_getpid()); + pc_fd = OpenFile(path.data(), true); + if (internal_iserror(pc_fd)) { + Report(" Coverage: failed to open %s for writing\n", path.data()); + Die(); + } + + pc_array_mapped_size = 0; + CovUpdateMapping(); +} + +void CoverageData::Init() { + pc_array = reinterpret_cast<uptr *>( + MmapNoReserveOrDie(sizeof(uptr) * kPcArrayMaxSize, "CovInit")); + pc_fd = kInvalidFd; + if (common_flags()->coverage_direct) { + atomic_store(&pc_array_size, 0, memory_order_relaxed); + atomic_store(&pc_array_index, 0, memory_order_relaxed); + } else { + atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed); + atomic_store(&pc_array_index, 0, memory_order_relaxed); + } +} + +void CoverageData::ReInit() { + internal_munmap(pc_array, sizeof(uptr) * kPcArrayMaxSize); + if (pc_fd != kInvalidFd) internal_close(pc_fd); + if (common_flags()->coverage_direct) { + // In memory-mapped mode we must extend the new file to the known array + // size. + uptr size = atomic_load(&pc_array_size, memory_order_relaxed); + Init(); + if (size) Extend(size); + } else { + Init(); + } +} + +void CoverageData::BeforeFork() { + mu.Lock(); +} + +void CoverageData::AfterFork(int child_pid) { + // We are single-threaded so it's OK to release the lock early. + mu.Unlock(); + if (child_pid == 0) ReInit(); +} + +// Extend coverage PC array to fit additional npcs elements. +void CoverageData::Extend(uptr npcs) { + if (!common_flags()->coverage_direct) return; + SpinMutexLock l(&mu); + + if (pc_fd == kInvalidFd) DirectOpen(); + CHECK_NE(pc_fd, kInvalidFd); + + uptr size = atomic_load(&pc_array_size, memory_order_relaxed); + size += npcs * sizeof(uptr); + + if (size > pc_array_mapped_size) { + uptr new_mapped_size = pc_array_mapped_size; + while (size > new_mapped_size) new_mapped_size += kPcArrayMmapSize; + + // Extend the file and map the new space at the end of pc_array. + uptr res = internal_ftruncate(pc_fd, new_mapped_size); + int err; + if (internal_iserror(res, &err)) { + Printf("failed to extend raw coverage file: %d\n", err); + Die(); + } + void *p = MapWritableFileToMemory(pc_array + pc_array_mapped_size, + new_mapped_size - pc_array_mapped_size, + pc_fd, pc_array_mapped_size); + CHECK_EQ(p, pc_array + pc_array_mapped_size); + pc_array_mapped_size = new_mapped_size; + } + + atomic_store(&pc_array_size, size, memory_order_release); +} + +// Simply add the pc into the vector under lock. If the function is called more +// than once for a given PC it will be inserted multiple times, which is fine. +void CoverageData::Add(uptr pc) { + if (!pc_array) return; + uptr idx = atomic_fetch_add(&pc_array_index, 1, memory_order_relaxed); + CHECK_LT(idx * sizeof(uptr), + atomic_load(&pc_array_size, memory_order_acquire)); + pc_array[idx] = pc; +} + +uptr *CoverageData::data() { + return pc_array; +} + +uptr CoverageData::size() { + return atomic_load(&pc_array_index, memory_order_relaxed); +} + +// Block layout for packed file format: header, followed by module name (no +// trailing zero), followed by data blob. +struct CovHeader { + int pid; + unsigned int module_name_length; + unsigned int data_length; +}; + +static void CovWritePacked(int pid, const char *module, const void *blob, + unsigned int blob_size) { + if (cov_fd < 0) return; + unsigned module_name_length = internal_strlen(module); + CovHeader header = {pid, module_name_length, blob_size}; + + if (cov_max_block_size == 0) { + // Writing to a file. Just go ahead. + internal_write(cov_fd, &header, sizeof(header)); + internal_write(cov_fd, module, module_name_length); + internal_write(cov_fd, blob, blob_size); + } else { + // Writing to a socket. We want to split the data into appropriately sized + // blocks. + InternalScopedBuffer<char> block(cov_max_block_size); + CHECK_EQ((uptr)block.data(), (uptr)(CovHeader *)block.data()); + uptr header_size_with_module = sizeof(header) + module_name_length; + CHECK_LT(header_size_with_module, cov_max_block_size); + unsigned int max_payload_size = + cov_max_block_size - header_size_with_module; + char *block_pos = block.data(); + internal_memcpy(block_pos, &header, sizeof(header)); + block_pos += sizeof(header); + internal_memcpy(block_pos, module, module_name_length); + block_pos += module_name_length; + char *block_data_begin = block_pos; + char *blob_pos = (char *)blob; + while (blob_size > 0) { + unsigned int payload_size = Min(blob_size, max_payload_size); + blob_size -= payload_size; + internal_memcpy(block_data_begin, blob_pos, payload_size); + blob_pos += payload_size; + ((CovHeader *)block.data())->data_length = payload_size; + internal_write(cov_fd, block.data(), + header_size_with_module + payload_size); + } + } +} + +// If packed = false: <name>.<pid>.<sancov> (name = module name). +// If packed = true and name == 0: <pid>.<sancov>.<packed>. +// If packed = true and name != 0: <name>.<sancov>.<packed> (name is +// user-supplied). +static int CovOpenFile(bool packed, const char* name) { + InternalScopedBuffer<char> path(1024); + if (!packed) { + CHECK(name); + internal_snprintf((char *)path.data(), path.size(), "%s/%s.%zd.sancov", + common_flags()->coverage_dir, name, internal_getpid()); + } else { + if (!name) + internal_snprintf((char *)path.data(), path.size(), + "%s/%zd.sancov.packed", common_flags()->coverage_dir, + internal_getpid()); + else + internal_snprintf((char *)path.data(), path.size(), "%s/%s.sancov.packed", + common_flags()->coverage_dir, name); + } + uptr fd = OpenFile(path.data(), true); + if (internal_iserror(fd)) { + Report(" SanitizerCoverage: failed to open %s for writing\n", path.data()); + return -1; + } + return fd; +} + +// Dump the coverage on disk. +static void CovDump() { + if (!common_flags()->coverage || common_flags()->coverage_direct) return; +#if !SANITIZER_WINDOWS + if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed)) + return; + uptr size = coverage_data.size(); + InternalMmapVector<u32> offsets(size); + uptr *vb = coverage_data.data(); + uptr *ve = vb + size; + SortArray(vb, size); + MemoryMappingLayout proc_maps(/*cache_enabled*/true); + uptr mb, me, off, prot; + InternalScopedBuffer<char> module(4096); + InternalScopedBuffer<char> path(4096 * 2); + for (int i = 0; + proc_maps.Next(&mb, &me, &off, module.data(), module.size(), &prot); + i++) { + if ((prot & MemoryMappingLayout::kProtectionExecute) == 0) + continue; + while (vb < ve && *vb < mb) vb++; + if (vb >= ve) break; + if (*vb < me) { + offsets.clear(); + const uptr *old_vb = vb; + CHECK_LE(off, *vb); + for (; vb < ve && *vb < me; vb++) { + uptr diff = *vb - (i ? mb : 0) + off; + CHECK_LE(diff, 0xffffffffU); + offsets.push_back(static_cast<u32>(diff)); + } + char *module_name = StripModuleName(module.data()); + if (cov_sandboxed) { + if (cov_fd >= 0) { + CovWritePacked(internal_getpid(), module_name, offsets.data(), + offsets.size() * sizeof(u32)); + VReport(1, " CovDump: %zd PCs written to packed file\n", vb - old_vb); + } + } else { + // One file per module per process. + internal_snprintf((char *)path.data(), path.size(), "%s/%s.%zd.sancov", + common_flags()->coverage_dir, module_name, + internal_getpid()); + int fd = CovOpenFile(false /* packed */, module_name); + if (fd > 0) { + internal_write(fd, offsets.data(), offsets.size() * sizeof(u32)); + internal_close(fd); + VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), + vb - old_vb); + } + } + InternalFree(module_name); + } + } + if (cov_fd >= 0) + internal_close(cov_fd); +#endif // !SANITIZER_WINDOWS +} + +void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { + if (!args) return; + if (!common_flags()->coverage) return; + cov_sandboxed = args->coverage_sandboxed; + if (!cov_sandboxed) return; + cov_fd = args->coverage_fd; + cov_max_block_size = args->coverage_max_block_size; + if (cov_fd < 0) + // Pre-open the file now. The sandbox won't allow us to do it later. + cov_fd = CovOpenFile(true /* packed */, 0); +} + +int MaybeOpenCovFile(const char *name) { + CHECK(name); + if (!common_flags()->coverage) return -1; + return CovOpenFile(true /* packed */, name); +} + +void CovBeforeFork() { + coverage_data.BeforeFork(); +} + +void CovAfterFork(int child_pid) { + coverage_data.AfterFork(child_pid); +} + +} // namespace __sanitizer + +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov() { + coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC())); +} +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); } +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() { + coverage_data.Init(); +} +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_module_init(uptr npcs) { + if (!common_flags()->coverage || !common_flags()->coverage_direct) return; + if (SANITIZER_ANDROID) { + // dlopen/dlclose interceptors do not work on Android, so we rely on + // Extend() calls to update .sancov.map. + CovUpdateMapping(GET_CALLER_PC()); + } + coverage_data.Extend(npcs); +} +SANITIZER_INTERFACE_ATTRIBUTE +sptr __sanitizer_maybe_open_cov_file(const char *name) { + return MaybeOpenCovFile(name); +} +} // extern "C" diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc new file mode 100644 index 00000000000..a134053a719 --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc @@ -0,0 +1,126 @@ +//===-- sanitizer_coverage_mapping.cc -------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Mmap-based implementation of sanitizer coverage. +// +// This is part of the implementation of code coverage that does not require +// __sanitizer_cov_dump() call. Data is stored in 2 files per process. +// +// $pid.sancov.map describes process memory layout in the following text-based +// format: +// <pointer size in bits> // 1 line, 32 or 64 +// <mapping start> <mapping end> <base address> <dso name> // repeated +// ... +// Mapping lines are NOT sorted. This file is updated every time memory layout +// is changed (i.e. in dlopen() and dlclose() interceptors). +// +// $pid.sancov.raw is a binary dump of PC values, sizeof(uptr) each. Again, not +// sorted. This file is extended by 64Kb at a time and mapped into memory. It +// contains one or more 0 words at the end, up to the next 64Kb aligned offset. +// +// To convert these 2 files to the usual .sancov format, run sancov.py rawunpack +// $pid.sancov.raw. +// +//===----------------------------------------------------------------------===// + +#include "sanitizer_allocator_internal.h" +#include "sanitizer_libc.h" +#include "sanitizer_procmaps.h" + +namespace __sanitizer { + +static const uptr kMaxNumberOfModules = 1 << 14; +static const uptr kMaxTextSize = 64 * 1024; + +struct CachedMapping { + public: + bool NeedsUpdate(uptr pc) { + int new_pid = internal_getpid(); + if (last_pid == new_pid && pc && pc >= last_range_start && + pc < last_range_end) + return false; + last_pid = new_pid; + return true; + } + + void SetModuleRange(uptr start, uptr end) { + last_range_start = start; + last_range_end = end; + } + + private: + uptr last_range_start, last_range_end; + int last_pid; +}; + +static CachedMapping cached_mapping; +static StaticSpinMutex mapping_mu; + +void CovUpdateMapping(uptr caller_pc) { + if (!common_flags()->coverage || !common_flags()->coverage_direct) return; + + SpinMutexLock l(&mapping_mu); + + if (!cached_mapping.NeedsUpdate(caller_pc)) + return; + + InternalScopedString text(kMaxTextSize); + InternalScopedBuffer<char> modules_data(kMaxNumberOfModules * + sizeof(LoadedModule)); + LoadedModule *modules = (LoadedModule *)modules_data.data(); + CHECK(modules); + int n_modules = GetListOfModules(modules, kMaxNumberOfModules, + /* filter */ 0); + + text.append("%d\n", sizeof(uptr) * 8); + for (int i = 0; i < n_modules; ++i) { + char *module_name = StripModuleName(modules[i].full_name()); + for (unsigned j = 0; j < modules[i].n_ranges(); ++j) { + if (modules[i].address_range_executable(j)) { + uptr start = modules[i].address_range_start(j); + uptr end = modules[i].address_range_end(j); + uptr base = modules[i].base_address(); + text.append("%zx %zx %zx %s\n", start, end, base, module_name); + if (caller_pc && caller_pc >= start && caller_pc < end) + cached_mapping.SetModuleRange(start, end); + } + } + InternalFree(module_name); + } + + int err; + InternalScopedString tmp_path(64 + + internal_strlen(common_flags()->coverage_dir)); + uptr res = internal_snprintf((char *)tmp_path.data(), tmp_path.size(), + "%s/%zd.sancov.map.tmp", common_flags()->coverage_dir, + internal_getpid()); + CHECK_LE(res, tmp_path.size()); + uptr map_fd = OpenFile(tmp_path.data(), true); + if (internal_iserror(map_fd)) { + Report(" Coverage: failed to open %s for writing\n", tmp_path.data()); + Die(); + } + + res = internal_write(map_fd, text.data(), text.length()); + if (internal_iserror(res, &err)) { + Printf("sancov.map write failed: %d\n", err); + Die(); + } + internal_close(map_fd); + + InternalScopedString path(64 + internal_strlen(common_flags()->coverage_dir)); + res = internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.map", + common_flags()->coverage_dir, internal_getpid()); + CHECK_LE(res, path.size()); + res = internal_rename(tmp_path.data(), path.data()); + if (internal_iserror(res, &err)) { + Printf("sancov.map rename failed: %d\n", err); + Die(); + } +} + +} // namespace __sanitizer diff --git a/libsanitizer/sanitizer_common/sanitizer_deadlock_detector2.cc b/libsanitizer/sanitizer_common/sanitizer_deadlock_detector2.cc index f4d46d99736..bc96ad230db 100644 --- a/libsanitizer/sanitizer_common/sanitizer_deadlock_detector2.cc +++ b/libsanitizer/sanitizer_common/sanitizer_deadlock_detector2.cc @@ -185,8 +185,7 @@ u32 DD::allocateId(DDCallback *cb) { id = id_gen++; } CHECK_LE(id, kMaxMutex); - VPrintf(3, "#%llu: DD::allocateId assign id %d\n", - cb->lt->ctx, id); + VPrintf(3, "#%llu: DD::allocateId assign id %d\n", cb->lt->ctx, id); return id; } diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.cc b/libsanitizer/sanitizer_common/sanitizer_flags.cc index e90d79e4360..476f793c27d 100644 --- a/libsanitizer/sanitizer_common/sanitizer_flags.cc +++ b/libsanitizer/sanitizer_common/sanitizer_flags.cc @@ -27,6 +27,11 @@ struct FlagDescription { IntrusiveList<FlagDescription> flag_descriptions; +// If set, the tool will install its own SEGV signal handler by default. +#ifndef SANITIZER_NEEDS_SEGV +# define SANITIZER_NEEDS_SEGV 1 +#endif + void SetCommonFlagsDefaults(CommonFlags *f) { f->symbolize = true; f->external_symbolizer_path = 0; @@ -53,7 +58,12 @@ void SetCommonFlagsDefaults(CommonFlags *f) { f->legacy_pthread_cond = false; f->intercept_tls_get_addr = false; f->coverage = false; + f->coverage_direct = SANITIZER_ANDROID; + f->coverage_dir = "."; f->full_address_space = false; + f->suppressions = ""; + f->print_suppressions = true; + f->disable_coredump = (SANITIZER_WORDSIZE == 64); } void ParseCommonFlagsFromString(CommonFlags *f, const char *str) { @@ -125,9 +135,23 @@ void ParseCommonFlagsFromString(CommonFlags *f, const char *str) { ParseFlag(str, &f->coverage, "coverage", "If set, coverage information will be dumped at program shutdown (if the " "coverage instrumentation was enabled at compile time)."); + ParseFlag(str, &f->coverage_direct, "coverage_direct", + "If set, coverage information will be dumped directly to a memory " + "mapped file. This way data is not lost even if the process is " + "suddenly killed."); + ParseFlag(str, &f->coverage_dir, "coverage_dir", + "Target directory for coverage dumps. Defaults to the current " + "directory."); ParseFlag(str, &f->full_address_space, "full_address_space", "Sanitize complete address space; " "by default kernel area on 32-bit platforms will not be sanitized"); + ParseFlag(str, &f->suppressions, "suppressions", "Suppressions file name."); + ParseFlag(str, &f->print_suppressions, "print_suppressions", + "Print matched suppressions at exit."); + ParseFlag(str, &f->disable_coredump, "disable_coredump", + "Disable core dumping. By default, disable_core=1 on 64-bit to avoid " + "dumping a 16T+ core file. Ignored on OSes that don't dump core by" + "default and for sanitizers that don't reserve lots of virtual memory."); // Do a sanity check for certain flags. if (f->malloc_context_size < 1) @@ -143,14 +167,17 @@ static bool GetFlagValue(const char *env, const char *name, pos = internal_strstr(env, name); if (pos == 0) return false; - if (pos != env && ((pos[-1] >= 'a' && pos[-1] <= 'z') || pos[-1] == '_')) { + const char *name_end = pos + internal_strlen(name); + if ((pos != env && + ((pos[-1] >= 'a' && pos[-1] <= 'z') || pos[-1] == '_')) || + *name_end != '=') { // Seems to be middle of another flag name or value. env = pos + 1; continue; } + pos = name_end; break; } - pos += internal_strlen(name); const char *end; if (pos[0] != '=') { end = pos; diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.h b/libsanitizer/sanitizer_common/sanitizer_flags.h index 107b6776b3a..a906c9e4535 100644 --- a/libsanitizer/sanitizer_common/sanitizer_flags.h +++ b/libsanitizer/sanitizer_common/sanitizer_flags.h @@ -52,7 +52,12 @@ struct CommonFlags { bool help; uptr mmap_limit_mb; bool coverage; + bool coverage_direct; + const char *coverage_dir; bool full_address_space; + const char *suppressions; + bool print_suppressions; + bool disable_coredump; }; inline CommonFlags *common_flags() { diff --git a/libsanitizer/sanitizer_common/sanitizer_freebsd.h b/libsanitizer/sanitizer_common/sanitizer_freebsd.h new file mode 100644 index 00000000000..47bb1313e6f --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_freebsd.h @@ -0,0 +1,135 @@ +//===-- sanitizer_freebsd.h -------------------------------------*- C++ -*-===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is a part of Sanitizer runtime. It contains FreeBSD-specific +// definitions. +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_FREEBSD_H +#define SANITIZER_FREEBSD_H + +#include "sanitizer_internal_defs.h" + +// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in +// 32-bit mode. +#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) +# include <osreldate.h> +# if __FreeBSD_version <= 902001 // v9.2 +# include <link.h> +# include <sys/param.h> +# include <ucontext.h> + +namespace __sanitizer { + +typedef unsigned long long __xuint64_t; + +typedef __int32_t __xregister_t; + +typedef struct __xmcontext { + __xregister_t mc_onstack; + __xregister_t mc_gs; + __xregister_t mc_fs; + __xregister_t mc_es; + __xregister_t mc_ds; + __xregister_t mc_edi; + __xregister_t mc_esi; + __xregister_t mc_ebp; + __xregister_t mc_isp; + __xregister_t mc_ebx; + __xregister_t mc_edx; + __xregister_t mc_ecx; + __xregister_t mc_eax; + __xregister_t mc_trapno; + __xregister_t mc_err; + __xregister_t mc_eip; + __xregister_t mc_cs; + __xregister_t mc_eflags; + __xregister_t mc_esp; + __xregister_t mc_ss; + + int mc_len; + int mc_fpformat; + int mc_ownedfp; + __xregister_t mc_flags; + + int mc_fpstate[128] __aligned(16); + __xregister_t mc_fsbase; + __xregister_t mc_gsbase; + __xregister_t mc_xfpustate; + __xregister_t mc_xfpustate_len; + + int mc_spare2[4]; +} xmcontext_t; + +typedef struct __xucontext { + sigset_t uc_sigmask; + xmcontext_t uc_mcontext; + + struct __ucontext *uc_link; + stack_t uc_stack; + int uc_flags; + int __spare__[4]; +} xucontext_t; + +struct xkinfo_vmentry { + int kve_structsize; + int kve_type; + __xuint64_t kve_start; + __xuint64_t kve_end; + __xuint64_t kve_offset; + __xuint64_t kve_vn_fileid; + __uint32_t kve_vn_fsid; + int kve_flags; + int kve_resident; + int kve_private_resident; + int kve_protection; + int kve_ref_count; + int kve_shadow_count; + int kve_vn_type; + __xuint64_t kve_vn_size; + __uint32_t kve_vn_rdev; + __uint16_t kve_vn_mode; + __uint16_t kve_status; + int _kve_ispare[12]; + char kve_path[PATH_MAX]; +}; + +typedef struct { + __uint32_t p_type; + __uint32_t p_offset; + __uint32_t p_vaddr; + __uint32_t p_paddr; + __uint32_t p_filesz; + __uint32_t p_memsz; + __uint32_t p_flags; + __uint32_t p_align; +} XElf32_Phdr; + +struct xdl_phdr_info { + Elf_Addr dlpi_addr; + const char *dlpi_name; + const XElf32_Phdr *dlpi_phdr; + Elf_Half dlpi_phnum; + unsigned long long int dlpi_adds; + unsigned long long int dlpi_subs; + size_t dlpi_tls_modid; + void *dlpi_tls_data; +}; + +typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info*, size_t, void*); +typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void*); + +#define xdl_iterate_phdr(callback, param) \ + (((xdl_iterate_phdr_t*) dl_iterate_phdr)((callback), (param))) + +} // namespace __sanitizer + +# endif // __FreeBSD_version <= 902001 +#endif // SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) + +#endif // SANITIZER_FREEBSD_H diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h index a925d306b61..f1f243c17e2 100644 --- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h +++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h @@ -32,9 +32,13 @@ # define SANITIZER_SUPPORTS_WEAK_HOOKS 0 #endif -// If set, the tool will install its own SEGV signal handler. -#ifndef SANITIZER_NEEDS_SEGV -# define SANITIZER_NEEDS_SEGV 1 +// We can use .preinit_array section on Linux to call sanitizer initialization +// functions very early in the process startup (unless PIC macro is defined). +// FIXME: do we have anything like this on Mac? +#if SANITIZER_LINUX && !SANITIZER_ANDROID && !defined(PIC) +# define SANITIZER_CAN_USE_PREINIT_ARRAY 1 +#else +# define SANITIZER_CAN_USE_PREINIT_ARRAY 0 #endif // GCC does not understand __has_feature diff --git a/libsanitizer/sanitizer_common/sanitizer_libc.h b/libsanitizer/sanitizer_common/sanitizer_libc.h index fd03b791c58..680b888e219 100644 --- a/libsanitizer/sanitizer_common/sanitizer_libc.h +++ b/libsanitizer/sanitizer_common/sanitizer_libc.h @@ -72,6 +72,7 @@ uptr internal_open(const char *filename, int flags, u32 mode); uptr internal_read(fd_t fd, void *buf, uptr count); uptr internal_write(fd_t fd, const void *buf, uptr count); +uptr internal_ftruncate(fd_t fd, uptr size); // OS uptr internal_filesize(fd_t fd); // -1 on error. @@ -81,6 +82,7 @@ uptr internal_fstat(fd_t fd, void *buf); uptr internal_dup2(int oldfd, int newfd); uptr internal_readlink(const char *path, char *buf, uptr bufsize); uptr internal_unlink(const char *path); +uptr internal_rename(const char *oldpath, const char *newpath); void NORETURN internal__exit(int exitcode); uptr internal_lseek(fd_t fd, OFF_T offset, int whence); diff --git a/libsanitizer/sanitizer_common/sanitizer_libignore.cc b/libsanitizer/sanitizer_common/sanitizer_libignore.cc index c88550dec8d..9877d668658 100644 --- a/libsanitizer/sanitizer_common/sanitizer_libignore.cc +++ b/libsanitizer/sanitizer_common/sanitizer_libignore.cc @@ -6,7 +6,7 @@ //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" -#if SANITIZER_LINUX +#if SANITIZER_FREEBSD || SANITIZER_LINUX #include "sanitizer_libignore.h" #include "sanitizer_flags.h" @@ -101,4 +101,4 @@ void LibIgnore::OnLibraryUnloaded() { } // namespace __sanitizer -#endif // #if SANITIZER_LINUX +#endif // #if SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cc b/libsanitizer/sanitizer_common/sanitizer_linux.cc index faa85acd696..8c7979fc6b5 100644 --- a/libsanitizer/sanitizer_common/sanitizer_linux.cc +++ b/libsanitizer/sanitizer_common/sanitizer_linux.cc @@ -44,15 +44,16 @@ #include <sys/time.h> #include <sys/types.h> #include <unistd.h> -#include <unwind.h> #if SANITIZER_FREEBSD +#include <sys/sysctl.h> #include <machine/atomic.h> extern "C" { // <sys/umtx.h> must be included after <errno.h> and <sys/types.h> on // FreeBSD 9.2 and 10.0. #include <sys/umtx.h> } +extern char **environ; // provided by crt1 #endif // SANITIZER_FREEBSD #if !SANITIZER_ANDROID @@ -132,7 +133,7 @@ uptr internal_open(const char *filename, int flags, u32 mode) { uptr OpenFile(const char *filename, bool write) { return internal_open(filename, - write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660); + write ? O_RDWR | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660); } uptr internal_read(fd_t fd, void *buf, uptr count) { @@ -149,6 +150,12 @@ uptr internal_write(fd_t fd, const void *buf, uptr count) { return res; } +uptr internal_ftruncate(fd_t fd, uptr size) { + sptr res; + HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, size)); + return res; +} + #if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && !SANITIZER_FREEBSD static void stat64_to_stat(struct stat64 *in, struct stat *out) { internal_memset(out, 0, sizeof(*out)); @@ -244,6 +251,15 @@ uptr internal_unlink(const char *path) { #endif } +uptr internal_rename(const char *oldpath, const char *newpath) { +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD, + (uptr)newpath); +#else + return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath); +#endif +} + uptr internal_sched_yield() { return internal_syscall(SYSCALL(sched_yield)); } @@ -297,9 +313,20 @@ u64 NanoTime() { return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000; } -// Like getenv, but reads env directly from /proc and does not use libc. -// This function should be called first inside __asan_init. +// Like getenv, but reads env directly from /proc (on Linux) or parses the +// 'environ' array (on FreeBSD) and does not use libc. This function should be +// called first inside __asan_init. const char *GetEnv(const char *name) { +#if SANITIZER_FREEBSD + if (::environ != 0) { + uptr NameLen = internal_strlen(name); + for (char **Env = ::environ; *Env != 0; Env++) { + if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=') + return (*Env) + NameLen + 1; + } + } + return 0; // Not found. +#elif SANITIZER_LINUX static char *environ; static uptr len; static bool inited; @@ -323,6 +350,9 @@ const char *GetEnv(const char *name) { p = endp + 1; } return 0; // Not found. +#else +#error "Unsupported platform" +#endif } extern "C" { @@ -388,20 +418,6 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, } #endif // SANITIZER_GO -void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { - // Some kinds of sandboxes may forbid filesystem access, so we won't be able - // to read the file mappings from /proc/self/maps. Luckily, neither the - // process will be able to load additional libraries, so it's fine to use the - // cached mappings. - MemoryMappingLayout::CacheMemoryMappings(); - // Same for /proc/self/exe in the symbolizer. -#if !SANITIZER_GO - if (Symbolizer *sym = Symbolizer::GetOrNull()) - sym->PrepareForSandboxing(); - CovPrepareForSandboxing(args); -#endif -} - enum MutexState { MtxUnlocked = 0, MtxLocked = 1, @@ -506,7 +522,11 @@ uptr internal_sigaltstack(const struct sigaltstack *ss, } int internal_fork() { +#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS + return internal_syscall(SYSCALL(clone), SIGCHLD, 0); +#else return internal_syscall(SYSCALL(fork)); +#endif } #if SANITIZER_LINUX @@ -660,24 +680,32 @@ static char proc_self_exe_cache_str[kMaxPathLength]; static uptr proc_self_exe_cache_len = 0; uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { + if (proc_self_exe_cache_len > 0) { + // If available, use the cached module name. + uptr module_name_len = + internal_snprintf(buf, buf_len, "%s", proc_self_exe_cache_str); + CHECK_LT(module_name_len, buf_len); + return module_name_len; + } +#if SANITIZER_FREEBSD + const int Mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + size_t Size = buf_len; + bool IsErr = (sysctl(Mib, 4, buf, &Size, NULL, 0) != 0); + int readlink_error = IsErr ? errno : 0; + uptr module_name_len = Size; +#else uptr module_name_len = internal_readlink( "/proc/self/exe", buf, buf_len); int readlink_error; - if (internal_iserror(module_name_len, &readlink_error)) { - if (proc_self_exe_cache_len) { - // If available, use the cached module name. - CHECK_LE(proc_self_exe_cache_len, buf_len); - internal_strncpy(buf, proc_self_exe_cache_str, buf_len); - module_name_len = internal_strlen(proc_self_exe_cache_str); - } else { - // We can't read /proc/self/exe for some reason, assume the name of the - // binary is unknown. - Report("WARNING: readlink(\"/proc/self/exe\") failed with errno %d, " - "some stack frames may not be symbolized\n", readlink_error); - module_name_len = internal_snprintf(buf, buf_len, "/proc/self/exe"); - } + bool IsErr = internal_iserror(module_name_len, &readlink_error); +#endif + if (IsErr) { + // We can't read /proc/self/exe for some reason, assume the name of the + // binary is unknown. + Report("WARNING: readlink(\"/proc/self/exe\") failed with errno %d, " + "some stack frames may not be symbolized\n", readlink_error); + module_name_len = internal_snprintf(buf, buf_len, "/proc/self/exe"); CHECK_LT(module_name_len, buf_len); - buf[module_name_len] = '\0'; } return module_name_len; } @@ -806,11 +834,19 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, #endif // defined(__x86_64__) && SANITIZER_LINUX #if SANITIZER_ANDROID +static atomic_uint8_t android_log_initialized; + +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; + char *copy = internal_strdup(buffer); char *p = copy; char *q; diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc index e754b26e693..36aaafdcc4b 100644 --- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc +++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc @@ -15,23 +15,25 @@ #include "sanitizer_common.h" #include "sanitizer_flags.h" +#include "sanitizer_freebsd.h" #include "sanitizer_linux.h" #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" #include "sanitizer_stacktrace.h" #include "sanitizer_atomic.h" +#include "sanitizer_symbolizer.h" + +#if SANITIZER_ANDROID || SANITIZER_FREEBSD +#include <dlfcn.h> // for dlsym() +#endif -#include <dlfcn.h> #include <pthread.h> #include <signal.h> #include <sys/resource.h> -#if SANITIZER_FREEBSD -#define _GNU_SOURCE // to declare _Unwind_Backtrace() from <unwind.h> -#endif -#include <unwind.h> #if SANITIZER_FREEBSD #include <pthread_np.h> +#include <osreldate.h> #define pthread_getattr_np pthread_attr_get_np #endif @@ -147,127 +149,6 @@ bool SanitizerGetThreadName(char *name, int max_len) { #endif } -//------------------------- SlowUnwindStack ----------------------------------- - -typedef struct { - uptr absolute_pc; - uptr stack_top; - uptr stack_size; -} backtrace_frame_t; - -extern "C" { -typedef void *(*acquire_my_map_info_list_func)(); -typedef void (*release_my_map_info_list_func)(void *map); -typedef sptr (*unwind_backtrace_signal_arch_func)( - void *siginfo, void *sigcontext, void *map_info_list, - backtrace_frame_t *backtrace, uptr ignore_depth, uptr max_depth); -acquire_my_map_info_list_func acquire_my_map_info_list; -release_my_map_info_list_func release_my_map_info_list; -unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch; -} // extern "C" - -#if SANITIZER_ANDROID -void SanitizerInitializeUnwinder() { - void *p = dlopen("libcorkscrew.so", RTLD_LAZY); - if (!p) { - VReport(1, - "Failed to open libcorkscrew.so. You may see broken stack traces " - "in SEGV reports."); - return; - } - acquire_my_map_info_list = - (acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list"); - release_my_map_info_list = - (release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list"); - unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym( - p, "unwind_backtrace_signal_arch"); - if (!acquire_my_map_info_list || !release_my_map_info_list || - !unwind_backtrace_signal_arch) { - VReport(1, - "Failed to find one of the required symbols in libcorkscrew.so. " - "You may see broken stack traces in SEGV reports."); - acquire_my_map_info_list = NULL; - unwind_backtrace_signal_arch = NULL; - release_my_map_info_list = NULL; - } -} -#endif - -#ifdef __arm__ -#define UNWIND_STOP _URC_END_OF_STACK -#define UNWIND_CONTINUE _URC_NO_REASON -#else -#define UNWIND_STOP _URC_NORMAL_STOP -#define UNWIND_CONTINUE _URC_NO_REASON -#endif - -uptr Unwind_GetIP(struct _Unwind_Context *ctx) { -#ifdef __arm__ - uptr val; - _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE, - 15 /* r15 = PC */, _UVRSD_UINT32, &val); - CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed"); - // Clear the Thumb bit. - return val & ~(uptr)1; -#else - return _Unwind_GetIP(ctx); -#endif -} - -struct UnwindTraceArg { - StackTrace *stack; - uptr max_depth; -}; - -_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { - UnwindTraceArg *arg = (UnwindTraceArg*)param; - CHECK_LT(arg->stack->size, arg->max_depth); - uptr pc = Unwind_GetIP(ctx); - arg->stack->trace[arg->stack->size++] = pc; - if (arg->stack->size == arg->max_depth) return UNWIND_STOP; - return UNWIND_CONTINUE; -} - -void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) { - CHECK_GE(max_depth, 2); - size = 0; - UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; - _Unwind_Backtrace(Unwind_Trace, &arg); - // We need to pop a few frames so that pc is on top. - uptr to_pop = LocatePcInTrace(pc); - // trace[0] belongs to the current function so we always pop it. - if (to_pop == 0) - to_pop = 1; - PopStackFrames(to_pop); - trace[0] = pc; -} - -void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context, - uptr max_depth) { - CHECK_GE(max_depth, 2); - if (!unwind_backtrace_signal_arch) { - SlowUnwindStack(pc, max_depth); - return; - } - - void *map = acquire_my_map_info_list(); - CHECK(map); - InternalScopedBuffer<backtrace_frame_t> frames(kStackTraceMax); - // siginfo argument appears to be unused. - sptr res = unwind_backtrace_signal_arch(/* siginfo */ NULL, context, map, - frames.data(), - /* ignore_depth */ 0, max_depth); - release_my_map_info_list(map); - if (res < 0) return; - CHECK_LE((uptr)res, kStackTraceMax); - - size = 0; - // +2 compensate for libcorkscrew unwinder returning addresses of call - // instructions instead of raw return addresses. - for (sptr i = 0; i < res; ++i) - trace[size++] = frames[i].absolute_pc + 2; -} - #if !SANITIZER_FREEBSD static uptr g_tls_size; #endif @@ -299,11 +180,11 @@ void InitTlsSize() { static atomic_uintptr_t kThreadDescriptorSize; uptr ThreadDescriptorSize() { - char buf[64]; uptr val = atomic_load(&kThreadDescriptorSize, memory_order_relaxed); if (val) return val; #ifdef _CS_GNU_LIBC_VERSION + char buf[64]; uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf)); if (len < sizeof(buf) && internal_strncmp(buf, "glibc 2.", 8) == 0) { char *end; @@ -468,6 +349,10 @@ uptr GetListOfModules(LoadedModule *modules, uptr max_modules, #else // SANITIZER_ANDROID # if !SANITIZER_FREEBSD typedef ElfW(Phdr) Elf_Phdr; +# elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001 // v9.2 +# define Elf_Phdr XElf32_Phdr +# define dl_phdr_info xdl_phdr_info +# define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b)) # endif struct DlIteratePhdrData { @@ -504,7 +389,8 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) { if (phdr->p_type == PT_LOAD) { uptr cur_beg = info->dlpi_addr + phdr->p_vaddr; uptr cur_end = cur_beg + phdr->p_memsz; - cur_module->addAddressRange(cur_beg, cur_end); + bool executable = phdr->p_flags & PF_X; + cur_module->addAddressRange(cur_beg, cur_end, executable); } } return 0; @@ -527,6 +413,19 @@ void SetIndirectCallWrapper(uptr wrapper) { indirect_call_wrapper = wrapper; } +void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) { + // Some kinds of sandboxes may forbid filesystem access, so we won't be able + // to read the file mappings from /proc/self/maps. Luckily, neither the + // process will be able to load additional libraries, so it's fine to use the + // cached mappings. + MemoryMappingLayout::CacheMemoryMappings(); + // Same for /proc/self/exe in the symbolizer. +#if !SANITIZER_GO + Symbolizer::GetOrInit()->PrepareForSandboxing(); + CovPrepareForSandboxing(args); +#endif +} + } // namespace __sanitizer #endif // SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cc b/libsanitizer/sanitizer_common/sanitizer_mac.cc index 6deba53d3e8..2c2a1d74be7 100644 --- a/libsanitizer/sanitizer_common/sanitizer_mac.cc +++ b/libsanitizer/sanitizer_common/sanitizer_mac.cc @@ -129,6 +129,14 @@ int internal_fork() { return fork(); } +uptr internal_rename(const char *oldpath, const char *newpath) { + return rename(oldpath, newpath); +} + +uptr internal_ftruncate(fd_t fd, uptr size) { + return ftruncate(fd, size); +} + // ----------------- sanitizer_common.h bool FileExists(const char *filename) { struct stat st; diff --git a/libsanitizer/sanitizer_common/sanitizer_persistent_allocator.cc b/libsanitizer/sanitizer_common/sanitizer_persistent_allocator.cc new file mode 100644 index 00000000000..b989ed0c90f --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_persistent_allocator.cc @@ -0,0 +1,17 @@ +//===-- sanitizer_persistent_allocator.cc -----------------------*- C++ -*-===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file is shared between AddressSanitizer and ThreadSanitizer +// run-time libraries. +//===----------------------------------------------------------------------===// +#include "sanitizer_persistent_allocator.h" + +namespace __sanitizer { + +PersistentAllocator thePersistentAllocator; + +} // namespace __sanitizer diff --git a/libsanitizer/sanitizer_common/sanitizer_persistent_allocator.h b/libsanitizer/sanitizer_common/sanitizer_persistent_allocator.h new file mode 100644 index 00000000000..e29b7bd57aa --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_persistent_allocator.h @@ -0,0 +1,69 @@ +//===-- sanitizer_persistent_allocator.h ------------------------*- C++ -*-===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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 + +#include "sanitizer_internal_defs.h" +#include "sanitizer_mutex.h" +#include "sanitizer_atomic.h" +#include "sanitizer_common.h" + +namespace __sanitizer { + +class PersistentAllocator { + public: + void *alloc(uptr size); + + private: + void *tryAlloc(uptr size); + StaticSpinMutex mtx; // Protects alloc of new blocks for region allocator. + atomic_uintptr_t region_pos; // Region allocator for Node's. + atomic_uintptr_t region_end; +}; + +inline void *PersistentAllocator::tryAlloc(uptr size) { + // Optimisic lock-free allocation, essentially try to bump the region ptr. + 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 (atomic_compare_exchange_weak(®ion_pos, &cmp, cmp + size, + memory_order_acquire)) + return (void *)cmp; + } +} + +inline void *PersistentAllocator::alloc(uptr size) { + // First, try to allocate optimisitically. + void *s = tryAlloc(size); + if (s) return s; + // If failed, lock, retry and alloc new superblock. + SpinMutexLock l(&mtx); + for (;;) { + s = tryAlloc(size); + if (s) return s; + atomic_store(®ion_pos, 0, memory_order_relaxed); + uptr allocsz = 64 * 1024; + if (allocsz < size) allocsz = size; + uptr mem = (uptr)MmapOrDie(allocsz, "stack depot"); + atomic_store(®ion_end, mem + allocsz, memory_order_release); + atomic_store(®ion_pos, mem, memory_order_release); + } +} + +extern PersistentAllocator thePersistentAllocator; +inline void *PersistentAlloc(uptr sz) { + return thePersistentAllocator.alloc(sz); +} + +} // namespace __sanitizer + +#endif // SANITIZER_PERSISTENT_ALLOCATOR_H diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h index 92bbc005106..81a09927d79 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h @@ -27,6 +27,12 @@ # define SI_LINUX_NOT_ANDROID 0 #endif +#if SANITIZER_FREEBSD +# define SI_FREEBSD 1 +#else +# define SI_FREEBSD 0 +#endif + #if SANITIZER_LINUX # define SI_LINUX 1 #else @@ -73,11 +79,11 @@ #define SANITIZER_INTERCEPT_STRPTIME SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_SCANF SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX +#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX_NOT_ANDROID #ifndef SANITIZER_INTERCEPT_PRINTF # define SANITIZER_INTERCEPT_PRINTF SI_NOT_WINDOWS -# define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX +# define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID #endif #define SANITIZER_INTERCEPT_FREXP 1 @@ -86,10 +92,10 @@ #define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \ SI_MAC || SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_GETPWENT SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_GETPWENT SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETPWENT_R SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_SETPWENT SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_SETPWENT SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_CLOCK_GETTIME SI_LINUX #define SANITIZER_INTERCEPT_GETITIMER SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_TIME SI_NOT_WINDOWS @@ -102,9 +108,12 @@ #define SANITIZER_INTERCEPT_GETSOCKNAME SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETHOSTBYNAME SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETHOSTBYNAME_R SI_LINUX +#define SANITIZER_INTERCEPT_GETHOSTBYNAME2_R SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_GETHOSTBYADDR_R SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_GETHOSTENT_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETSOCKOPT SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_ACCEPT SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX +#define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_MODF SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_RECVMSG SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETPEERNAME SI_NOT_WINDOWS @@ -117,13 +126,13 @@ (defined(__i386) || defined (__x86_64)) // NOLINT #define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX +#define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STRTOIMAX SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_MBSTOWCS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_MBSNRTOWCS SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_WCSTOMBS SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_WCSNRTOMBS SI_MAC || SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX +#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 #define SANITIZER_INTERCEPT_CONFSTR SI_MAC || SI_LINUX_NOT_ANDROID @@ -140,19 +149,21 @@ #define SANITIZER_INTERCEPT_SIGWAIT SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_SIGWAITINFO SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_SIGSETOPS SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_SIGSETOPS \ + SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SIGPENDING SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_SIGPROCMASK SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_BACKTRACE SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX #define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT_STATFS SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_STATFS SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STATFS64 \ (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STATVFS SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_INITGROUPS SI_NOT_WINDOWS -#define SANITIZER_INTERCEPT_ETHER SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_ETHER_NTOA_ATON SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_ETHER_HOST SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_ETHER_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SHMCTL \ (SI_LINUX_NOT_ANDROID && SANITIZER_WORDSIZE == 64) @@ -161,6 +172,19 @@ #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \ SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL \ + SI_MAC || SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING \ + SI_MAC || SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK SI_LINUX_NOT_ANDROID +#define SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TMPNAM SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_TEMPNAM SI_NOT_WINDOWS @@ -168,6 +192,7 @@ #define SANITIZER_INTERCEPT_REMQUO SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_LGAMMA SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_LGAMMA_R SI_LINUX +#define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_RAND_R SI_MAC || SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_ICONV SI_LINUX_NOT_ANDROID @@ -176,7 +201,7 @@ // FIXME: getline seems to be available on OSX 10.7 #define SANITIZER_INTERCEPT_GETLINE SI_LINUX_NOT_ANDROID -#define SANITIZER_INTERCEPT__EXIT SI_LINUX +#define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD #define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP SI_LINUX_NOT_ANDROID @@ -201,5 +226,10 @@ #define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_FFLUSH SI_NOT_WINDOWS #define SANITIZER_INTERCEPT_FCLOSE SI_NOT_WINDOWS +#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE SI_LINUX_NOT_ANDROID || SI_MAC +#define SANITIZER_INTERCEPT_GETPASS SI_LINUX_NOT_ANDROID || SI_MAC +#define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID + +#define SANITIZER_INTERCEPT_MLOCKX SI_NOT_WINDOWS #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc index 76ee9001b7d..8779d8adf72 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cc @@ -27,7 +27,7 @@ // are not defined anywhere in userspace headers. Fake them. This seems to work // fine with newer headers, too. #include <asm/posix_types.h> -#if defined(__x86_64__) +#if defined(__x86_64__) || defined(__mips__) #include <sys/stat.h> #else #define ino_t __kernel_ino_t @@ -48,21 +48,19 @@ #include <linux/aio_abi.h> -#if SANITIZER_ANDROID -#include <asm/statfs.h> -#else -#include <sys/statfs.h> -#endif - #if !SANITIZER_ANDROID +#include <sys/statfs.h> #include <linux/perf_event.h> #endif namespace __sanitizer { +#if !SANITIZER_ANDROID unsigned struct_statfs64_sz = sizeof(struct statfs64); +#endif } // namespace __sanitizer -#if !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__aarch64__) +#if !defined(__powerpc64__) && !defined(__x86_64__) && !defined(__aarch64__)\ + && !defined(__mips__) COMPILER_CHECK(struct___old_kernel_stat_sz == sizeof(struct __old_kernel_stat)); #endif diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc index a93d38d8aac..f5678dceccc 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc @@ -33,7 +33,6 @@ #include <sys/socket.h> #include <sys/stat.h> #include <sys/time.h> -#include <sys/timeb.h> #include <sys/times.h> #include <sys/types.h> #include <sys/utsname.h> @@ -43,6 +42,7 @@ #if !SANITIZER_ANDROID #include <sys/mount.h> +#include <sys/timeb.h> #endif #if SANITIZER_LINUX @@ -189,13 +189,14 @@ namespace __sanitizer { unsigned struct_tms_sz = sizeof(struct tms); unsigned struct_sigevent_sz = sizeof(struct sigevent); unsigned struct_sched_param_sz = sizeof(struct sched_param); - unsigned struct_statfs_sz = sizeof(struct statfs); + #if SANITIZER_MAC && !SANITIZER_IOS unsigned struct_statfs64_sz = sizeof(struct statfs64); #endif // SANITIZER_MAC && !SANITIZER_IOS #if !SANITIZER_ANDROID + unsigned struct_statfs_sz = sizeof(struct statfs); unsigned struct_sockaddr_sz = sizeof(struct sockaddr); unsigned ucontext_t_sz = sizeof(ucontext_t); #endif // !SANITIZER_ANDROID @@ -287,6 +288,7 @@ namespace __sanitizer { int ptrace_setfpregs = PTRACE_SETFPREGS; int ptrace_getfpxregs = PTRACE_GETFPXREGS; int ptrace_setfpxregs = PTRACE_SETFPXREGS; + int ptrace_geteventmsg = PTRACE_GETEVENTMSG; #if (defined(PTRACE_GETSIGINFO) && defined(PTRACE_SETSIGINFO)) || \ (defined(PT_GETSIGINFO) && defined(PT_SETSIGINFO)) int ptrace_getsiginfo = PTRACE_GETSIGINFO; @@ -396,7 +398,7 @@ namespace __sanitizer { unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); #endif - unsigned IOCTL_NOT_PRESENT = 0; + const unsigned IOCTL_NOT_PRESENT = 0; unsigned IOCTL_FIOASYNC = FIOASYNC; unsigned IOCTL_FIOCLEX = FIOCLEX; @@ -1056,6 +1058,10 @@ CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch); CHECK_TYPE_SIZE(clock_t); +#if SANITIZER_LINUX +CHECK_TYPE_SIZE(clockid_t); +#endif + #if !SANITIZER_ANDROID CHECK_TYPE_SIZE(ifaddrs); CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); @@ -1086,11 +1092,13 @@ CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); COMPILER_CHECK(sizeof(__sanitizer_mallinfo) == sizeof(struct mallinfo)); #endif +#if !SANITIZER_ANDROID CHECK_TYPE_SIZE(timeb); CHECK_SIZE_AND_OFFSET(timeb, time); CHECK_SIZE_AND_OFFSET(timeb, millitm); CHECK_SIZE_AND_OFFSET(timeb, timezone); CHECK_SIZE_AND_OFFSET(timeb, dstflag); +#endif CHECK_TYPE_SIZE(passwd); CHECK_SIZE_AND_OFFSET(passwd, pw_name); diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h index dece2d3cbdd..caa36a4071b 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h @@ -37,11 +37,11 @@ namespace __sanitizer { extern unsigned struct_itimerspec_sz; extern unsigned struct_sigevent_sz; extern unsigned struct_sched_param_sz; - extern unsigned struct_statfs_sz; extern unsigned struct_statfs64_sz; - extern unsigned struct_sockaddr_sz; #if !SANITIZER_ANDROID + extern unsigned struct_statfs_sz; + extern unsigned struct_sockaddr_sz; extern unsigned ucontext_t_sz; #endif // !SANITIZER_ANDROID @@ -65,6 +65,13 @@ namespace __sanitizer { #elif defined(__powerpc64__) const unsigned struct_kernel_stat_sz = 144; const unsigned struct_kernel_stat64_sz = 104; +#elif defined(__mips__) + #if SANITIZER_WORDSIZE == 64 + const unsigned struct_kernel_stat_sz = 216; + #else + const unsigned struct_kernel_stat_sz = 144; + #endif + const unsigned struct_kernel_stat64_sz = 104; #endif struct __sanitizer_perf_event_attr { unsigned type; @@ -160,6 +167,12 @@ namespace __sanitizer { unsigned __seq; u64 __unused1; u64 __unused2; +#elif defined(__mips__) + unsigned int mode; + unsigned short __seq; + unsigned short __pad1; + unsigned long __unused1; + unsigned long __unused2; #else unsigned short mode; unsigned short __pad1; @@ -188,15 +201,15 @@ namespace __sanitizer { u64 shm_ctime; #else uptr shm_atime; - #ifndef _LP64 + #if !defined(_LP64) && !defined(__mips__) uptr __unused1; #endif uptr shm_dtime; - #ifndef _LP64 + #if !defined(_LP64) && !defined(__mips__) uptr __unused2; #endif uptr shm_ctime; - #ifndef _LP64 + #if !defined(_LP64) && !defined(__mips__) uptr __unused3; #endif #endif @@ -438,8 +451,13 @@ namespace __sanitizer { typedef long __sanitizer_clock_t; #endif +#if SANITIZER_LINUX + typedef int __sanitizer_clockid_t; +#endif + #if SANITIZER_LINUX || SANITIZER_FREEBSD -#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__) +#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__)\ + || defined(__mips__) typedef unsigned __sanitizer___kernel_uid_t; typedef unsigned __sanitizer___kernel_gid_t; #else @@ -452,7 +470,7 @@ namespace __sanitizer { typedef long __sanitizer___kernel_off_t; #endif -#if defined(__powerpc__) || defined(__aarch64__) +#if defined(__powerpc__) || defined(__aarch64__) || defined(__mips__) typedef unsigned int __sanitizer___kernel_old_uid_t; typedef unsigned int __sanitizer___kernel_old_gid_t; #else @@ -492,6 +510,9 @@ namespace __sanitizer { // Linux system headers define the 'sa_handler' and 'sa_sigaction' macros. struct __sanitizer_sigaction { +#if defined(__mips__) && !SANITIZER_FREEBSD + unsigned int sa_flags; +#endif union { void (*sigaction)(int sig, void *siginfo, void *uctx); void (*handler)(int sig); @@ -501,11 +522,16 @@ namespace __sanitizer { __sanitizer_sigset_t sa_mask; #else __sanitizer_sigset_t sa_mask; +#ifndef __mips__ int sa_flags; #endif +#endif #if SANITIZER_LINUX void (*sa_restorer)(); #endif +#if defined(__mips__) && (SANITIZER_WORDSIZE == 32) + int sa_resv[1]; +#endif }; #if SANITIZER_FREEBSD @@ -676,6 +702,7 @@ namespace __sanitizer { extern int ptrace_setsiginfo; extern int ptrace_getregset; extern int ptrace_setregset; + extern int ptrace_geteventmsg; #endif #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID @@ -718,7 +745,7 @@ struct __sanitizer_obstack { #define IOC_NRBITS 8 #define IOC_TYPEBITS 8 -#if defined(__powerpc__) || defined(__powerpc64__) +#if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__) #define IOC_SIZEBITS 13 #define IOC_DIRBITS 3 #define IOC_NONE 1U @@ -832,7 +859,7 @@ struct __sanitizer_obstack { // A special value to mark ioctls that are not present on the target platform, // when it can not be determined without including any system headers. - extern unsigned IOCTL_NOT_PRESENT; + extern const unsigned IOCTL_NOT_PRESENT; extern unsigned IOCTL_FIOASYNC; extern unsigned IOCTL_FIOCLEX; diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cc b/libsanitizer/sanitizer_common/sanitizer_posix.cc index e24d5ed5031..24e99f9472d 100644 --- a/libsanitizer/sanitizer_common/sanitizer_posix.cc +++ b/libsanitizer/sanitizer_common/sanitizer_posix.cc @@ -204,6 +204,17 @@ void *MapFileToMemory(const char *file_name, uptr *buff_size) { return internal_iserror(map) ? 0 : (void *)map; } +void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) { + uptr flags = MAP_SHARED; + if (addr) flags |= MAP_FIXED; + uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset); + if (internal_iserror(p)) { + Printf("could not map writable file (%zd, %zu, %zu): %zd\n", fd, offset, + size, p); + return 0; + } + return (void *)p; +} static inline bool IntervalsAreSeparate(uptr start1, uptr end1, uptr start2, uptr end2) { diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc index 8e3a96f01e4..b4e42c72462 100644 --- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc +++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc @@ -42,30 +42,49 @@ void FlushUnneededShadowMemory(uptr addr, uptr size) { madvise((void*)addr, size, MADV_DONTNEED); } -void DisableCoreDumper() { - struct rlimit nocore; - nocore.rlim_cur = 0; - nocore.rlim_max = 0; - setrlimit(RLIMIT_CORE, &nocore); +static rlim_t getlim(int res) { + rlimit rlim; + CHECK_EQ(0, getrlimit(res, &rlim)); + return rlim.rlim_cur; +} + +static void setlim(int res, rlim_t lim) { + // The following magic is to prevent clang from replacing it with memset. + volatile struct rlimit rlim; + rlim.rlim_cur = lim; + rlim.rlim_max = lim; + if (setrlimit(res, (struct rlimit*)&rlim)) { + Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno); + Die(); + } +} + +void DisableCoreDumperIfNecessary() { + if (common_flags()->disable_coredump) { + setlim(RLIMIT_CORE, 0); + } } bool StackSizeIsUnlimited() { - struct rlimit rlim; - CHECK_EQ(0, getrlimit(RLIMIT_STACK, &rlim)); - return ((uptr)rlim.rlim_cur == (uptr)-1); + rlim_t stack_size = getlim(RLIMIT_STACK); + return (stack_size == RLIM_INFINITY); } void SetStackSizeLimitInBytes(uptr limit) { - struct rlimit rlim; - rlim.rlim_cur = limit; - rlim.rlim_max = limit; - if (setrlimit(RLIMIT_STACK, &rlim)) { - Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno); - Die(); - } + setlim(RLIMIT_STACK, (rlim_t)limit); CHECK(!StackSizeIsUnlimited()); } +bool AddressSpaceIsUnlimited() { + rlim_t as_size = getlim(RLIMIT_AS); + return (as_size == RLIM_INFINITY); +} + +void SetAddressSpaceUnlimited() { + setlim(RLIMIT_AS, RLIM_INFINITY); + CHECK(AddressSpaceIsUnlimited()); +} + void SleepForSeconds(int seconds) { sleep(seconds); } @@ -127,7 +146,9 @@ static void MaybeInstallSigaction(int signum, struct sigaction sigact; internal_memset(&sigact, 0, sizeof(sigact)); sigact.sa_sigaction = (sa_sigaction_t)handler; - sigact.sa_flags = SA_SIGINFO; + // Do not block the signal from being received in that signal's handler. + // 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)); VReport(1, "Installed the sigaction for signal %d\n", signum); @@ -143,6 +164,28 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) { } #endif // SANITIZER_GO +bool IsAccessibleMemoryRange(uptr beg, uptr size) { + uptr page_size = GetPageSizeCached(); + // Checking too large memory ranges is slow. + CHECK_LT(size, page_size * 10); + int sock_pair[2]; + if (pipe(sock_pair)) + return false; + uptr bytes_written = + internal_write(sock_pair[1], reinterpret_cast<void *>(beg), size); + int write_errno; + bool result; + if (internal_iserror(bytes_written, &write_errno)) { + CHECK_EQ(EFAULT, write_errno); + result = false; + } else { + result = (bytes_written == size); + } + internal_close(sock_pair[0]); + internal_close(sock_pair[1]); + return result; +} + } // namespace __sanitizer #endif // SANITIZER_POSIX diff --git a/libsanitizer/sanitizer_common/sanitizer_printf.cc b/libsanitizer/sanitizer_common/sanitizer_printf.cc index 4fc26308ee4..fc0c357ba86 100644 --- a/libsanitizer/sanitizer_common/sanitizer_printf.cc +++ b/libsanitizer/sanitizer_common/sanitizer_printf.cc @@ -20,7 +20,8 @@ #include <stdio.h> #include <stdarg.h> -#if SANITIZER_WINDOWS && !defined(va_copy) +#if SANITIZER_WINDOWS && defined(_MSC_VER) && _MSC_VER < 1800 && \ + !defined(va_copy) # define va_copy(dst, src) ((dst) = (src)) #endif diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps.h b/libsanitizer/sanitizer_common/sanitizer_procmaps.h index d140c47fda9..7477abf30b6 100644 --- a/libsanitizer/sanitizer_common/sanitizer_procmaps.h +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps.h @@ -24,6 +24,9 @@ struct ProcSelfMapsBuff { uptr mmaped_size; uptr len; }; + +// Reads process memory map in an OS-specific way. +void ReadProcMaps(ProcSelfMapsBuff *proc_maps); #endif // SANITIZER_FREEBSD || SANITIZER_LINUX class MemoryMappingLayout { @@ -55,7 +58,7 @@ class MemoryMappingLayout { // platform-specific files. # if SANITIZER_FREEBSD || SANITIZER_LINUX ProcSelfMapsBuff proc_self_maps_; - char *current_; + const char *current_; // Static mappings cache. static ProcSelfMapsBuff cached_proc_self_maps_; @@ -84,6 +87,11 @@ void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size); // Returns code range for the specified module. bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end); +bool IsDecimal(char c); +uptr ParseDecimal(const char **p); +bool IsHex(char c); +uptr ParseHex(const char **p); + } // namespace __sanitizer #endif // SANITIZER_PROCMAPS_H diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cc b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cc new file mode 100644 index 00000000000..ca9900fe9ee --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cc @@ -0,0 +1,176 @@ +//===-- sanitizer_procmaps_common.cc --------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Information about the process mappings (common parts). +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_FREEBSD || SANITIZER_LINUX +#include "sanitizer_common.h" +#include "sanitizer_placement_new.h" +#include "sanitizer_procmaps.h" + +namespace __sanitizer { + +// Linker initialized. +ProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_; +StaticSpinMutex MemoryMappingLayout::cache_lock_; // Linker initialized. + +static int TranslateDigit(char c) { + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +// Parse a number and promote 'p' up to the first non-digit character. +static uptr ParseNumber(const char **p, int base) { + uptr n = 0; + int d; + CHECK(base >= 2 && base <= 16); + while ((d = TranslateDigit(**p)) >= 0 && d < base) { + n = n * base + d; + (*p)++; + } + return n; +} + +bool IsDecimal(char c) { + int d = TranslateDigit(c); + return d >= 0 && d < 10; +} + +uptr ParseDecimal(const char **p) { + return ParseNumber(p, 10); +} + +bool IsHex(char c) { + int d = TranslateDigit(c); + return d >= 0 && d < 16; +} + +uptr ParseHex(const char **p) { + return ParseNumber(p, 16); +} + +MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { + ReadProcMaps(&proc_self_maps_); + if (cache_enabled) { + if (proc_self_maps_.mmaped_size == 0) { + LoadFromCache(); + CHECK_GT(proc_self_maps_.len, 0); + } + } else { + CHECK_GT(proc_self_maps_.mmaped_size, 0); + } + Reset(); + // FIXME: in the future we may want to cache the mappings on demand only. + if (cache_enabled) + CacheMemoryMappings(); +} + +MemoryMappingLayout::~MemoryMappingLayout() { + // Only unmap the buffer if it is different from the cached one. Otherwise + // it will be unmapped when the cache is refreshed. + if (proc_self_maps_.data != cached_proc_self_maps_.data) { + UnmapOrDie(proc_self_maps_.data, proc_self_maps_.mmaped_size); + } +} + +void MemoryMappingLayout::Reset() { + current_ = proc_self_maps_.data; +} + +// static +void MemoryMappingLayout::CacheMemoryMappings() { + SpinMutexLock l(&cache_lock_); + // Don't invalidate the cache if the mappings are unavailable. + ProcSelfMapsBuff old_proc_self_maps; + old_proc_self_maps = cached_proc_self_maps_; + ReadProcMaps(&cached_proc_self_maps_); + if (cached_proc_self_maps_.mmaped_size == 0) { + cached_proc_self_maps_ = old_proc_self_maps; + } else { + if (old_proc_self_maps.mmaped_size) { + UnmapOrDie(old_proc_self_maps.data, + old_proc_self_maps.mmaped_size); + } + } +} + +void MemoryMappingLayout::LoadFromCache() { + SpinMutexLock l(&cache_lock_); + if (cached_proc_self_maps_.data) { + proc_self_maps_ = cached_proc_self_maps_; + } +} + +uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules, + uptr max_modules, + string_predicate_t filter) { + Reset(); + uptr cur_beg, cur_end, cur_offset, prot; + InternalScopedBuffer<char> module_name(kMaxPathLength); + uptr n_modules = 0; + for (uptr i = 0; n_modules < max_modules && + Next(&cur_beg, &cur_end, &cur_offset, module_name.data(), + module_name.size(), &prot); + i++) { + const char *cur_name = module_name.data(); + if (cur_name[0] == '\0') + continue; + if (filter && !filter(cur_name)) + continue; + void *mem = &modules[n_modules]; + // Don't subtract 'cur_beg' from the first entry: + // * If a binary is compiled w/o -pie, then the first entry in + // process maps is likely the binary itself (all dynamic libs + // are mapped higher in address space). For such a binary, + // instruction offset in binary coincides with the actual + // instruction address in virtual memory (as code section + // is mapped to a fixed memory range). + // * If a binary is compiled with -pie, all the modules are + // mapped high at address space (in particular, higher than + // shadow memory of the tool), so the module can't be the + // first entry. + uptr base_address = (i ? cur_beg : 0) - cur_offset; + LoadedModule *cur_module = new(mem) LoadedModule(cur_name, base_address); + cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute); + n_modules++; + } + return n_modules; +} + +void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { + char *smaps = 0; + uptr smaps_cap = 0; + uptr smaps_len = ReadFileToBuffer("/proc/self/smaps", + &smaps, &smaps_cap, 64<<20); + uptr start = 0; + bool file = false; + const char *pos = smaps; + while (pos < smaps + smaps_len) { + if (IsHex(pos[0])) { + start = ParseHex(&pos); + for (; *pos != '/' && *pos > '\n'; pos++) {} + file = *pos == '/'; + } else if (internal_strncmp(pos, "Rss:", 4) == 0) { + while (!IsDecimal(*pos)) pos++; + uptr rss = ParseDecimal(&pos) * 1024; + cb(start, rss, file, stats, stats_size); + } + while (*pos++ != '\n') {} + } + UnmapOrDie(smaps, smaps_cap); +} + +} // namespace __sanitizer + +#endif // SANITIZER_FREEBSD || SANITIZER_LINUX diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_freebsd.cc b/libsanitizer/sanitizer_common/sanitizer_procmaps_freebsd.cc new file mode 100644 index 00000000000..fbc55203ab4 --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_freebsd.cc @@ -0,0 +1,86 @@ +//===-- sanitizer_procmaps_freebsd.cc -------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Information about the process mappings (FreeBSD-specific parts). +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_FREEBSD +#include "sanitizer_common.h" +#include "sanitizer_freebsd.h" +#include "sanitizer_procmaps.h" + +#include <unistd.h> +#include <sys/sysctl.h> +#include <sys/user.h> + +// Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode. +#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) +# include <osreldate.h> +# if __FreeBSD_version <= 902001 // v9.2 +# define kinfo_vmentry xkinfo_vmentry +# endif +#endif + +namespace __sanitizer { + +void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { + const int Mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid() }; + size_t Size = 0; + int Err = sysctl(Mib, 4, NULL, &Size, NULL, 0); + CHECK_EQ(Err, 0); + CHECK_GT(Size, 0); + + size_t MmapedSize = Size * 4 / 3; + void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()"); + Size = MmapedSize; + Err = sysctl(Mib, 4, VmMap, &Size, NULL, 0); + CHECK_EQ(Err, 0); + + proc_maps->data = (char*)VmMap; + proc_maps->mmaped_size = MmapedSize; + proc_maps->len = Size; +} + +bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, + char filename[], uptr filename_size, + uptr *protection) { + char *last = proc_self_maps_.data + proc_self_maps_.len; + if (current_ >= last) return false; + uptr dummy; + if (!start) start = &dummy; + if (!end) end = &dummy; + if (!offset) offset = &dummy; + if (!protection) protection = &dummy; + struct kinfo_vmentry *VmEntry = (struct kinfo_vmentry*)current_; + + *start = (uptr)VmEntry->kve_start; + *end = (uptr)VmEntry->kve_end; + *offset = (uptr)VmEntry->kve_offset; + + *protection = 0; + if ((VmEntry->kve_protection & KVME_PROT_READ) != 0) + *protection |= kProtectionRead; + if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0) + *protection |= kProtectionWrite; + if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0) + *protection |= kProtectionExecute; + + if (filename != NULL && filename_size > 0) { + internal_snprintf(filename, + Min(filename_size, (uptr)PATH_MAX), + "%s", VmEntry->kve_path); + } + + current_ += VmEntry->kve_structsize; + + return true; +} + +} // namespace __sanitizer + +#endif // SANITIZER_FREEBSD diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_linux.cc b/libsanitizer/sanitizer_common/sanitizer_procmaps_linux.cc index 20a074a799f..43babf89319 100644 --- a/libsanitizer/sanitizer_common/sanitizer_procmaps_linux.cc +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_linux.cc @@ -9,151 +9,20 @@ //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" -#if SANITIZER_FREEBSD || SANITIZER_LINUX +#if SANITIZER_LINUX #include "sanitizer_common.h" -#include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" -#if SANITIZER_FREEBSD -#include <unistd.h> -#include <sys/sysctl.h> -#include <sys/user.h> -#endif - namespace __sanitizer { -// Linker initialized. -ProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_; -StaticSpinMutex MemoryMappingLayout::cache_lock_; // Linker initialized. - -static void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { -#if SANITIZER_FREEBSD - const int Mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid() }; - size_t Size = 0; - int Err = sysctl(Mib, 4, NULL, &Size, NULL, 0); - CHECK_EQ(Err, 0); - CHECK_GT(Size, 0); - - size_t MmapedSize = Size * 4 / 3; - void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()"); - Size = MmapedSize; - Err = sysctl(Mib, 4, VmMap, &Size, NULL, 0); - CHECK_EQ(Err, 0); - - proc_maps->data = (char*)VmMap; - proc_maps->mmaped_size = MmapedSize; - proc_maps->len = Size; -#else +void ReadProcMaps(ProcSelfMapsBuff *proc_maps) { proc_maps->len = ReadFileToBuffer("/proc/self/maps", &proc_maps->data, &proc_maps->mmaped_size, 1 << 26); -#endif -} - -MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) { - ReadProcMaps(&proc_self_maps_); - if (cache_enabled) { - if (proc_self_maps_.mmaped_size == 0) { - LoadFromCache(); - CHECK_GT(proc_self_maps_.len, 0); - } - } else { - CHECK_GT(proc_self_maps_.mmaped_size, 0); - } - Reset(); - // FIXME: in the future we may want to cache the mappings on demand only. - if (cache_enabled) - CacheMemoryMappings(); -} - -MemoryMappingLayout::~MemoryMappingLayout() { - // Only unmap the buffer if it is different from the cached one. Otherwise - // it will be unmapped when the cache is refreshed. - if (proc_self_maps_.data != cached_proc_self_maps_.data) { - UnmapOrDie(proc_self_maps_.data, proc_self_maps_.mmaped_size); - } -} - -void MemoryMappingLayout::Reset() { - current_ = proc_self_maps_.data; -} - -// static -void MemoryMappingLayout::CacheMemoryMappings() { - SpinMutexLock l(&cache_lock_); - // Don't invalidate the cache if the mappings are unavailable. - ProcSelfMapsBuff old_proc_self_maps; - old_proc_self_maps = cached_proc_self_maps_; - ReadProcMaps(&cached_proc_self_maps_); - if (cached_proc_self_maps_.mmaped_size == 0) { - cached_proc_self_maps_ = old_proc_self_maps; - } else { - if (old_proc_self_maps.mmaped_size) { - UnmapOrDie(old_proc_self_maps.data, - old_proc_self_maps.mmaped_size); - } - } -} - -void MemoryMappingLayout::LoadFromCache() { - SpinMutexLock l(&cache_lock_); - if (cached_proc_self_maps_.data) { - proc_self_maps_ = cached_proc_self_maps_; - } -} - -#if !SANITIZER_FREEBSD -// Parse a hex value in str and update str. -static uptr ParseHex(char **str) { - uptr x = 0; - char *s; - for (s = *str; ; s++) { - char c = *s; - uptr v = 0; - if (c >= '0' && c <= '9') - v = c - '0'; - else if (c >= 'a' && c <= 'f') - v = c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - v = c - 'A' + 10; - else - break; - x = x * 16 + v; - } - *str = s; - return x; } static bool IsOneOf(char c, char c1, char c2) { return c == c1 || c == c2; } -#endif - -static bool IsDecimal(char c) { - return c >= '0' && c <= '9'; -} - -static bool IsHex(char c) { - return (c >= '0' && c <= '9') - || (c >= 'a' && c <= 'f'); -} - -static uptr ReadHex(const char *p) { - uptr v = 0; - for (; IsHex(p[0]); p++) { - if (p[0] >= '0' && p[0] <= '9') - v = v * 16 + p[0] - '0'; - else - v = v * 16 + p[0] - 'a' + 10; - } - return v; -} - -static uptr ReadDecimal(const char *p) { - uptr v = 0; - for (; IsDecimal(p[0]); p++) - v = v * 10 + p[0] - '0'; - return v; -} bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, char filename[], uptr filename_size, @@ -165,29 +34,6 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, if (!end) end = &dummy; if (!offset) offset = &dummy; if (!protection) protection = &dummy; -#if SANITIZER_FREEBSD - struct kinfo_vmentry *VmEntry = (struct kinfo_vmentry*)current_; - - *start = (uptr)VmEntry->kve_start; - *end = (uptr)VmEntry->kve_end; - *offset = (uptr)VmEntry->kve_offset; - - *protection = 0; - if ((VmEntry->kve_protection & KVME_PROT_READ) != 0) - *protection |= kProtectionRead; - if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0) - *protection |= kProtectionWrite; - if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0) - *protection |= kProtectionExecute; - - if (filename != NULL && filename_size > 0) { - internal_snprintf(filename, - Min(filename_size, (uptr)PATH_MAX), - "%s", VmEntry->kve_path); - } - - current_ += VmEntry->kve_structsize; -#else // !SANITIZER_FREEBSD char *next_line = (char*)internal_memchr(current_, '\n', last - current_); if (next_line == 0) next_line = last; @@ -234,69 +80,9 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, if (filename && i < filename_size) filename[i] = 0; current_ = next_line + 1; -#endif // !SANITIZER_FREEBSD return true; } -uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules, - uptr max_modules, - string_predicate_t filter) { - Reset(); - uptr cur_beg, cur_end, cur_offset; - InternalScopedBuffer<char> module_name(kMaxPathLength); - uptr n_modules = 0; - for (uptr i = 0; n_modules < max_modules && - Next(&cur_beg, &cur_end, &cur_offset, module_name.data(), - module_name.size(), 0); - i++) { - const char *cur_name = module_name.data(); - if (cur_name[0] == '\0') - continue; - if (filter && !filter(cur_name)) - continue; - void *mem = &modules[n_modules]; - // Don't subtract 'cur_beg' from the first entry: - // * If a binary is compiled w/o -pie, then the first entry in - // process maps is likely the binary itself (all dynamic libs - // are mapped higher in address space). For such a binary, - // instruction offset in binary coincides with the actual - // instruction address in virtual memory (as code section - // is mapped to a fixed memory range). - // * If a binary is compiled with -pie, all the modules are - // mapped high at address space (in particular, higher than - // shadow memory of the tool), so the module can't be the - // first entry. - uptr base_address = (i ? cur_beg : 0) - cur_offset; - LoadedModule *cur_module = new(mem) LoadedModule(cur_name, base_address); - cur_module->addAddressRange(cur_beg, cur_end); - n_modules++; - } - return n_modules; -} - -void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { - char *smaps = 0; - uptr smaps_cap = 0; - uptr smaps_len = ReadFileToBuffer("/proc/self/smaps", - &smaps, &smaps_cap, 64<<20); - uptr start = 0; - bool file = false; - const char *pos = smaps; - while (pos < smaps + smaps_len) { - if (IsHex(pos[0])) { - start = ReadHex(pos); - for (; *pos != '/' && *pos > '\n'; pos++) {} - file = *pos == '/'; - } else if (internal_strncmp(pos, "Rss:", 4) == 0) { - for (; *pos < '0' || *pos > '9'; pos++) {} - uptr rss = ReadDecimal(pos) * 1024; - cb(start, rss, file, stats, stats_size); - } - while (*pos++ != '\n') {} - } - UnmapOrDie(smaps, smaps_cap); -} - } // namespace __sanitizer -#endif // SANITIZER_FREEBSD || SANITIZER_LINUX +#endif // SANITIZER_LINUX diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cc b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cc index c6853068346..81874c21b1f 100644 --- a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cc +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cc @@ -73,14 +73,16 @@ template<u32 kLCSegment, typename SegmentCommand> bool MemoryMappingLayout::NextSegmentLoad( uptr *start, uptr *end, uptr *offset, char filename[], uptr filename_size, uptr *protection) { - if (protection) - UNIMPLEMENTED(); const char* lc = current_load_cmd_addr_; current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize; if (((const load_command *)lc)->cmd == kLCSegment) { const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); const SegmentCommand* sc = (const SegmentCommand *)lc; if (start) *start = sc->vmaddr + dlloff; + if (protection) { + // Return the initial protection. + *protection = sc->initprot; + } if (end) *end = sc->vmaddr + sc->vmsize + dlloff; if (offset) { if (current_filetype_ == /*MH_EXECUTE*/ 0x2) { @@ -155,12 +157,12 @@ uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules, uptr max_modules, string_predicate_t filter) { Reset(); - uptr cur_beg, cur_end; + uptr cur_beg, cur_end, prot; InternalScopedBuffer<char> module_name(kMaxPathLength); uptr n_modules = 0; for (uptr i = 0; n_modules < max_modules && Next(&cur_beg, &cur_end, 0, module_name.data(), - module_name.size(), 0); + module_name.size(), &prot); i++) { const char *cur_name = module_name.data(); if (cur_name[0] == '\0') @@ -176,7 +178,7 @@ uptr MemoryMappingLayout::DumpListOfModules(LoadedModule *modules, cur_module = new(mem) LoadedModule(cur_name, cur_beg); n_modules++; } - cur_module->addAddressRange(cur_beg, cur_end); + cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute); } return n_modules; } diff --git a/libsanitizer/sanitizer_common/sanitizer_report_decorator.h b/libsanitizer/sanitizer_common/sanitizer_report_decorator.h index c8510585111..e9be29fb3d5 100644 --- a/libsanitizer/sanitizer_common/sanitizer_report_decorator.h +++ b/libsanitizer/sanitizer_common/sanitizer_report_decorator.h @@ -18,12 +18,16 @@ #include "sanitizer_common.h" namespace __sanitizer { -class AnsiColorDecorator { +class SanitizerCommonDecorator { // FIXME: This is not portable. It assumes the special strings are printed to // stdout, which is not the case on Windows (see SetConsoleTextAttribute()). public: - explicit AnsiColorDecorator(bool use_ansi_colors) : ansi_(use_ansi_colors) { } + SanitizerCommonDecorator() : ansi_(ColorizeReports()) {} const char *Bold() const { return ansi_ ? "\033[1m" : ""; } + const char *Default() const { return ansi_ ? "\033[1m\033[0m" : ""; } + const char *Warning() { return Red(); } + const char *EndWarning() { return Default(); } + protected: const char *Black() const { return ansi_ ? "\033[1m\033[30m" : ""; } const char *Red() const { return ansi_ ? "\033[1m\033[31m" : ""; } const char *Green() const { return ansi_ ? "\033[1m\033[32m" : ""; } @@ -32,19 +36,10 @@ class AnsiColorDecorator { const char *Magenta() const { return ansi_ ? "\033[1m\033[35m" : ""; } const char *Cyan() const { return ansi_ ? "\033[1m\033[36m" : ""; } const char *White() const { return ansi_ ? "\033[1m\033[37m" : ""; } - const char *Default() const { return ansi_ ? "\033[1m\033[0m" : ""; } private: bool ansi_; }; -class SanitizerCommonDecorator: protected AnsiColorDecorator { - public: - SanitizerCommonDecorator() - : __sanitizer::AnsiColorDecorator(ColorizeReports()) { } - const char *Warning() { return Red(); } - const char *EndWarning() { return Default(); } -}; - } // namespace __sanitizer #endif // SANITIZER_REPORT_DECORATOR_H diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cc b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cc index e8d9f01e7f9..e1915cb808f 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cc +++ b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cc @@ -10,193 +10,128 @@ //===----------------------------------------------------------------------===// #include "sanitizer_stackdepot.h" + #include "sanitizer_common.h" -#include "sanitizer_internal_defs.h" -#include "sanitizer_mutex.h" -#include "sanitizer_atomic.h" +#include "sanitizer_stackdepotbase.h" namespace __sanitizer { -const int kTabSize = 1024 * 1024; // Hash table size. -const int kPartBits = 8; -const int kPartShift = sizeof(u32) * 8 - kPartBits - 1; -const int kPartCount = 1 << kPartBits; // Number of subparts in the table. -const int kPartSize = kTabSize / kPartCount; -const int kMaxId = 1 << kPartShift; +struct StackDepotDesc { + const uptr *stack; + uptr size; + u32 hash() const { + // murmur2 + const u32 m = 0x5bd1e995; + const u32 seed = 0x9747b28c; + const u32 r = 24; + u32 h = seed ^ (size * sizeof(uptr)); + for (uptr i = 0; i < size; i++) { + u32 k = stack[i]; + k *= m; + k ^= k >> r; + k *= m; + h *= m; + h ^= k; + } + h ^= h >> 13; + h *= m; + h ^= h >> 15; + return h; + } + bool is_valid() { return size > 0 && stack; } +}; -struct StackDesc { - StackDesc *link; +struct StackDepotNode { + StackDepotNode *link; u32 id; - u32 hash; + atomic_uint32_t hash_and_use_count; // hash_bits : 12; use_count : 20; uptr size; uptr stack[1]; // [size] -}; -static struct { - StaticSpinMutex mtx; // Protects alloc of new blocks for region allocator. - atomic_uintptr_t region_pos; // Region allocator for StackDesc's. - atomic_uintptr_t region_end; - atomic_uintptr_t tab[kTabSize]; // Hash table of StackDesc's. - atomic_uint32_t seq[kPartCount]; // Unique id generators. -} depot; + static const u32 kTabSizeLog = 20; + // Lower kTabSizeLog bits are equal for all items in one bucket. + // We use these bits to store the per-stack use counter. + static const u32 kUseCountBits = kTabSizeLog; + static const u32 kMaxUseCount = 1 << kUseCountBits; + static const u32 kUseCountMask = (1 << kUseCountBits) - 1; + static const u32 kHashMask = ~kUseCountMask; + + typedef StackDepotDesc args_type; + bool eq(u32 hash, const args_type &args) const { + u32 hash_bits = + atomic_load(&hash_and_use_count, memory_order_relaxed) & kHashMask; + if ((hash & kHashMask) != hash_bits || args.size != size) return false; + uptr i = 0; + for (; i < size; i++) { + if (stack[i] != args.stack[i]) return false; + } + return true; + } + static uptr storage_size(const args_type &args) { + return sizeof(StackDepotNode) + (args.size - 1) * sizeof(uptr); + } + void store(const args_type &args, u32 hash) { + atomic_store(&hash_and_use_count, hash & kHashMask, memory_order_relaxed); + size = args.size; + internal_memcpy(stack, args.stack, size * sizeof(uptr)); + } + args_type load() const { + args_type ret = {&stack[0], size}; + return ret; + } + StackDepotHandle get_handle() { return StackDepotHandle(this); } -static StackDepotStats stats; + typedef StackDepotHandle handle_type; +}; -StackDepotStats *StackDepotGetStats() { - return &stats; -} +COMPILER_CHECK(StackDepotNode::kMaxUseCount == (u32)kStackDepotMaxUseCount); -static u32 hash(const uptr *stack, uptr size) { - // murmur2 - const u32 m = 0x5bd1e995; - const u32 seed = 0x9747b28c; - const u32 r = 24; - u32 h = seed ^ (size * sizeof(uptr)); - for (uptr i = 0; i < size; i++) { - u32 k = stack[i]; - k *= m; - k ^= k >> r; - k *= m; - h *= m; - h ^= k; - } - h ^= h >> 13; - h *= m; - h ^= h >> 15; - return h; +u32 StackDepotHandle::id() { return node_->id; } +int StackDepotHandle::use_count() { + return atomic_load(&node_->hash_and_use_count, memory_order_relaxed) & + StackDepotNode::kUseCountMask; } - -static StackDesc *tryallocDesc(uptr memsz) { - // Optimisic lock-free allocation, essentially try to bump the region ptr. - for (;;) { - uptr cmp = atomic_load(&depot.region_pos, memory_order_acquire); - uptr end = atomic_load(&depot.region_end, memory_order_acquire); - if (cmp == 0 || cmp + memsz > end) - return 0; - if (atomic_compare_exchange_weak( - &depot.region_pos, &cmp, cmp + memsz, - memory_order_acquire)) - return (StackDesc*)cmp; - } +void StackDepotHandle::inc_use_count_unsafe() { + u32 prev = + atomic_fetch_add(&node_->hash_and_use_count, 1, memory_order_relaxed) & + StackDepotNode::kUseCountMask; + CHECK_LT(prev + 1, StackDepotNode::kMaxUseCount); } +uptr StackDepotHandle::size() { return node_->size; } +uptr *StackDepotHandle::stack() { return &node_->stack[0]; } -static StackDesc *allocDesc(uptr size) { - // First, try to allocate optimisitically. - uptr memsz = sizeof(StackDesc) + (size - 1) * sizeof(uptr); - StackDesc *s = tryallocDesc(memsz); - if (s) - return s; - // If failed, lock, retry and alloc new superblock. - SpinMutexLock l(&depot.mtx); - for (;;) { - s = tryallocDesc(memsz); - if (s) - return s; - atomic_store(&depot.region_pos, 0, memory_order_relaxed); - uptr allocsz = 64 * 1024; - if (allocsz < memsz) - allocsz = memsz; - uptr mem = (uptr)MmapOrDie(allocsz, "stack depot"); - stats.mapped += allocsz; - atomic_store(&depot.region_end, mem + allocsz, memory_order_release); - atomic_store(&depot.region_pos, mem, memory_order_release); - } +// FIXME(dvyukov): this single reserved bit is used in TSan. +typedef StackDepotBase<StackDepotNode, 1, StackDepotNode::kTabSizeLog> + StackDepot; +static StackDepot theDepot; + +StackDepotStats *StackDepotGetStats() { + return theDepot.GetStats(); } -static u32 find(StackDesc *s, const uptr *stack, uptr size, u32 hash) { - // Searches linked list s for the stack, returns its id. - for (; s; s = s->link) { - if (s->hash == hash && s->size == size) { - uptr i = 0; - for (; i < size; i++) { - if (stack[i] != s->stack[i]) - break; - } - if (i == size) - return s->id; - } - } - return 0; +u32 StackDepotPut(const uptr *stack, uptr size) { + StackDepotDesc desc = {stack, size}; + StackDepotHandle h = theDepot.Put(desc); + return h.valid() ? h.id() : 0; } -static StackDesc *lock(atomic_uintptr_t *p) { - // Uses the pointer lsb as mutex. - for (int i = 0;; i++) { - uptr cmp = atomic_load(p, memory_order_relaxed); - if ((cmp & 1) == 0 - && atomic_compare_exchange_weak(p, &cmp, cmp | 1, - memory_order_acquire)) - return (StackDesc*)cmp; - if (i < 10) - proc_yield(10); - else - internal_sched_yield(); - } +StackDepotHandle StackDepotPut_WithHandle(const uptr *stack, uptr size) { + StackDepotDesc desc = {stack, size}; + return theDepot.Put(desc); } -static void unlock(atomic_uintptr_t *p, StackDesc *s) { - DCHECK_EQ((uptr)s & 1, 0); - atomic_store(p, (uptr)s, memory_order_release); +const uptr *StackDepotGet(u32 id, uptr *size) { + StackDepotDesc desc = theDepot.Get(id); + *size = desc.size; + return desc.stack; } -u32 StackDepotPut(const uptr *stack, uptr size) { - if (stack == 0 || size == 0) - return 0; - uptr h = hash(stack, size); - atomic_uintptr_t *p = &depot.tab[h % kTabSize]; - uptr v = atomic_load(p, memory_order_consume); - StackDesc *s = (StackDesc*)(v & ~1); - // First, try to find the existing stack. - u32 id = find(s, stack, size, h); - if (id) - return id; - // If failed, lock, retry and insert new. - StackDesc *s2 = lock(p); - if (s2 != s) { - id = find(s2, stack, size, h); - if (id) { - unlock(p, s2); - return id; - } - } - uptr part = (h % kTabSize) / kPartSize; - id = atomic_fetch_add(&depot.seq[part], 1, memory_order_relaxed) + 1; - stats.n_uniq_ids++; - CHECK_LT(id, kMaxId); - id |= part << kPartShift; - CHECK_NE(id, 0); - CHECK_EQ(id & (1u << 31), 0); - s = allocDesc(size); - s->id = id; - s->hash = h; - s->size = size; - internal_memcpy(s->stack, stack, size * sizeof(uptr)); - s->link = s2; - unlock(p, s); - return id; +void StackDepotLockAll() { + theDepot.LockAll(); } -const uptr *StackDepotGet(u32 id, uptr *size) { - if (id == 0) - return 0; - CHECK_EQ(id & (1u << 31), 0); - // High kPartBits contain part id, so we need to scan at most kPartSize lists. - uptr part = id >> kPartShift; - for (int i = 0; i != kPartSize; i++) { - uptr idx = part * kPartSize + i; - CHECK_LT(idx, kTabSize); - atomic_uintptr_t *p = &depot.tab[idx]; - uptr v = atomic_load(p, memory_order_consume); - StackDesc *s = (StackDesc*)(v & ~1); - for (; s; s = s->link) { - if (s->id == id) { - *size = s->size; - return s->stack; - } - } - } - *size = 0; - return 0; +void StackDepotUnlockAll() { + theDepot.UnlockAll(); } bool StackDepotReverseMap::IdDescPair::IdComparator( @@ -207,10 +142,10 @@ bool StackDepotReverseMap::IdDescPair::IdComparator( StackDepotReverseMap::StackDepotReverseMap() : map_(StackDepotGetStats()->n_uniq_ids + 100) { - for (int idx = 0; idx < kTabSize; idx++) { - atomic_uintptr_t *p = &depot.tab[idx]; + for (int idx = 0; idx < StackDepot::kTabSize; idx++) { + atomic_uintptr_t *p = &theDepot.tab[idx]; uptr v = atomic_load(p, memory_order_consume); - StackDesc *s = (StackDesc*)(v & ~1); + StackDepotNode *s = (StackDepotNode*)(v & ~1); for (; s; s = s->link) { IdDescPair pair = {s->id, s}; map_.push_back(pair); @@ -228,7 +163,7 @@ const uptr *StackDepotReverseMap::Get(u32 id, uptr *size) { *size = 0; return 0; } - StackDesc *desc = map_[idx].desc; + StackDepotNode *desc = map_[idx].desc; *size = desc->size; return desc->stack; } diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepot.h b/libsanitizer/sanitizer_common/sanitizer_stackdepot.h index c2c04ef9d64..2b1da4ee14f 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stackdepot.h +++ b/libsanitizer/sanitizer_common/sanitizer_stackdepot.h @@ -17,20 +17,29 @@ namespace __sanitizer { // StackDepot efficiently stores huge amounts of stack traces. +struct StackDepotNode; +struct StackDepotHandle { + StackDepotNode *node_; + StackDepotHandle() : node_(0) {} + explicit StackDepotHandle(StackDepotNode *node) : node_(node) {} + bool valid() { return node_; } + u32 id(); + int use_count(); + void inc_use_count_unsafe(); + uptr size(); + uptr *stack(); +}; + +const int kStackDepotMaxUseCount = 1U << 20; -// Maps stack trace to an unique id. +StackDepotStats *StackDepotGetStats(); u32 StackDepotPut(const uptr *stack, uptr size); +StackDepotHandle StackDepotPut_WithHandle(const uptr *stack, uptr size); // Retrieves a stored stack trace by the id. const uptr *StackDepotGet(u32 id, uptr *size); -struct StackDepotStats { - uptr n_uniq_ids; - uptr mapped; -}; - -StackDepotStats *StackDepotGetStats(); - -struct StackDesc; +void StackDepotLockAll(); +void StackDepotUnlockAll(); // Instantiating this class creates a snapshot of StackDepot which can be // efficiently queried with StackDepotGet(). You can use it concurrently with @@ -44,7 +53,7 @@ class StackDepotReverseMap { private: struct IdDescPair { u32 id; - StackDesc *desc; + StackDepotNode *desc; static bool IdComparator(const IdDescPair &a, const IdDescPair &b); }; @@ -55,6 +64,7 @@ class StackDepotReverseMap { StackDepotReverseMap(const StackDepotReverseMap&); void operator=(const StackDepotReverseMap&); }; + } // namespace __sanitizer #endif // SANITIZER_STACKDEPOT_H diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepotbase.h b/libsanitizer/sanitizer_common/sanitizer_stackdepotbase.h new file mode 100644 index 00000000000..b9dedec2621 --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_stackdepotbase.h @@ -0,0 +1,174 @@ +//===-- sanitizer_stackdepotbase.h ------------------------------*- C++ -*-===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implementation of a mapping from arbitrary values to unique 32-bit +// identifiers. +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_STACKDEPOTBASE_H +#define SANITIZER_STACKDEPOTBASE_H + +#include "sanitizer_internal_defs.h" +#include "sanitizer_mutex.h" +#include "sanitizer_atomic.h" +#include "sanitizer_persistent_allocator.h" + +namespace __sanitizer { + +template <class Node, int kReservedBits, int kTabSizeLog> +class StackDepotBase { + public: + 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); + // Retrieves a stored stack trace by the id. + args_type Get(u32 id); + + StackDepotStats *GetStats() { return &stats; } + + void LockAll(); + void UnlockAll(); + + private: + static Node *find(Node *s, args_type args, u32 hash); + static Node *lock(atomic_uintptr_t *p); + static void unlock(atomic_uintptr_t *p, Node *s); + + static const int kTabSize = 1 << kTabSizeLog; // Hash table size. + static const int kPartBits = 8; + static const int kPartShift = sizeof(u32) * 8 - kPartBits - kReservedBits; + static const int kPartCount = + 1 << kPartBits; // Number of subparts in the table. + static const int kPartSize = kTabSize / kPartCount; + static const int kMaxId = 1 << kPartShift; + + atomic_uintptr_t tab[kTabSize]; // Hash table of Node's. + atomic_uint32_t seq[kPartCount]; // Unique id generators. + + StackDepotStats stats; + + friend class StackDepotReverseMap; +}; + +template <class Node, int kReservedBits, int kTabSizeLog> +Node *StackDepotBase<Node, kReservedBits, kTabSizeLog>::find(Node *s, + args_type args, + u32 hash) { + // Searches linked list s for the stack, returns its id. + for (; s; s = s->link) { + if (s->eq(hash, args)) { + return s; + } + } + return 0; +} + +template <class Node, int kReservedBits, int kTabSizeLog> +Node *StackDepotBase<Node, kReservedBits, kTabSizeLog>::lock( + atomic_uintptr_t *p) { + // Uses the pointer lsb as mutex. + for (int i = 0;; i++) { + uptr cmp = atomic_load(p, memory_order_relaxed); + if ((cmp & 1) == 0 && + atomic_compare_exchange_weak(p, &cmp, cmp | 1, memory_order_acquire)) + return (Node *)cmp; + if (i < 10) + proc_yield(10); + else + internal_sched_yield(); + } +} + +template <class Node, int kReservedBits, int kTabSizeLog> +void StackDepotBase<Node, kReservedBits, kTabSizeLog>::unlock( + atomic_uintptr_t *p, Node *s) { + DCHECK_EQ((uptr)s & 1, 0); + atomic_store(p, (uptr)s, memory_order_release); +} + +template <class Node, int kReservedBits, int kTabSizeLog> +typename StackDepotBase<Node, kReservedBits, kTabSizeLog>::handle_type +StackDepotBase<Node, kReservedBits, kTabSizeLog>::Put(args_type args, + bool *inserted) { + if (inserted) *inserted = false; + if (!args.is_valid()) return handle_type(); + uptr h = args.hash(); + atomic_uintptr_t *p = &tab[h % kTabSize]; + uptr v = atomic_load(p, memory_order_consume); + Node *s = (Node *)(v & ~1); + // First, try to find the existing stack. + Node *node = find(s, args, h); + if (node) return node->get_handle(); + // If failed, lock, retry and insert new. + Node *s2 = lock(p); + if (s2 != s) { + node = find(s2, args, h); + if (node) { + unlock(p, s2); + return node->get_handle(); + } + } + uptr part = (h % kTabSize) / kPartSize; + u32 id = atomic_fetch_add(&seq[part], 1, memory_order_relaxed) + 1; + stats.n_uniq_ids++; + CHECK_LT(id, kMaxId); + id |= part << kPartShift; + CHECK_NE(id, 0); + CHECK_EQ(id & (((u32)-1) >> kReservedBits), id); + uptr memsz = Node::storage_size(args); + s = (Node *)PersistentAlloc(memsz); + stats.allocated += memsz; + s->id = id; + s->store(args, h); + s->link = s2; + unlock(p, s); + if (inserted) *inserted = true; + return s->get_handle(); +} + +template <class Node, int kReservedBits, int kTabSizeLog> +typename StackDepotBase<Node, kReservedBits, kTabSizeLog>::args_type +StackDepotBase<Node, kReservedBits, kTabSizeLog>::Get(u32 id) { + if (id == 0) { + return args_type(); + } + CHECK_EQ(id & (((u32)-1) >> kReservedBits), id); + // High kPartBits contain part id, so we need to scan at most kPartSize lists. + uptr part = id >> kPartShift; + for (int i = 0; i != kPartSize; i++) { + uptr idx = part * kPartSize + i; + CHECK_LT(idx, kTabSize); + atomic_uintptr_t *p = &tab[idx]; + uptr v = atomic_load(p, memory_order_consume); + Node *s = (Node *)(v & ~1); + for (; s; s = s->link) { + if (s->id == id) { + return s->load(); + } + } + } + return args_type(); +} + +template <class Node, int kReservedBits, int kTabSizeLog> +void StackDepotBase<Node, kReservedBits, kTabSizeLog>::LockAll() { + for (int i = 0; i < kTabSize; ++i) { + lock(&tab[i]); + } +} + +template <class Node, int kReservedBits, int kTabSizeLog> +void StackDepotBase<Node, kReservedBits, kTabSizeLog>::UnlockAll() { + for (int i = 0; i < kTabSize; ++i) { + atomic_uintptr_t *p = &tab[i]; + uptr s = atomic_load(p, memory_order_relaxed); + unlock(p, (Node *)(s & ~1UL)); + } +} + +} // namespace __sanitizer +#endif // SANITIZER_STACKDEPOTBASE_H diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc index 244ac36f5f8..0ce5ae475f6 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc @@ -19,7 +19,8 @@ uptr StackTrace::GetPreviousInstructionPc(uptr pc) { #if defined(__arm__) // Cancel Thumb bit. pc = pc & (~1); -#elif defined(__powerpc__) || defined(__powerpc64__) +#endif +#if defined(__powerpc__) || defined(__powerpc64__) // PCs are always 4 byte aligned. return pc - 4; #elif defined(__sparc__) @@ -33,19 +34,39 @@ uptr StackTrace::GetCurrentPc() { return GET_CALLER_PC(); } +// Check if given pointer points into allocated stack area. +static inline bool IsValidFrame(uptr frame, uptr stack_top, uptr stack_bottom) { + return frame > stack_bottom && frame < stack_top - 2 * sizeof (uhwptr); +} + +// In GCC on ARM bp points to saved lr, not fp, so we should check the next +// cell in stack to be a saved frame pointer. GetCanonicFrame returns the +// pointer to saved frame pointer in any case. +static inline uhwptr *GetCanonicFrame(uptr bp, + uptr stack_top, + uptr stack_bottom) { +#ifdef __arm__ + if (!IsValidFrame(bp, stack_top, stack_bottom)) return 0; + uhwptr *bp_prev = (uhwptr *)bp; + if (IsValidFrame((uptr)bp_prev[0], stack_top, stack_bottom)) return bp_prev; + return bp_prev - 1; +#else + return (uhwptr*)bp; +#endif +} + void StackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom, uptr max_depth) { CHECK_GE(max_depth, 2); trace[0] = pc; size = 1; - uhwptr *frame = (uhwptr *)bp; - uhwptr *prev_frame = frame - 1; if (stack_top < 4096) return; // Sanity check for stack top. + uhwptr *frame = GetCanonicFrame(bp, stack_top, stack_bottom); + uhwptr *prev_frame = 0; // Avoid infinite loop when frame == frame[0] by using frame > prev_frame. while (frame > prev_frame && - frame < (uhwptr *)stack_top - 2 && - frame > (uhwptr *)stack_bottom && + IsValidFrame((uptr)frame, stack_top, stack_bottom) && IsAligned((uptr)frame, sizeof(*frame)) && size < max_depth) { uhwptr pc1 = frame[1]; @@ -53,7 +74,7 @@ void StackTrace::FastUnwindStack(uptr pc, uptr bp, trace[size++] = (uptr) pc1; } prev_frame = frame; - frame = (uhwptr *)frame[0]; + frame = GetCanonicFrame((uptr)frame[0], stack_top, stack_bottom); } } diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h index f66857ed1fb..0e0f1702228 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h @@ -50,9 +50,12 @@ struct StackTrace { static bool WillUseFastUnwind(bool request_fast_unwind) { // Check if fast unwind is available. Fast unwind is the only option on Mac. + // It is also the only option on FreeBSD as the slow unwinding that + // leverages _Unwind_Backtrace() yields the call stack of the signal's + // handler and not of the code that raised the signal (as it does on Linux). if (!SANITIZER_CAN_FAST_UNWIND) return false; - else if (SANITIZER_MAC) + else if (SANITIZER_MAC != 0 || SANITIZER_FREEBSD != 0) return true; return request_fast_unwind; } @@ -83,6 +86,10 @@ struct StackTrace { uptr local_stack; \ uptr sp = (uptr)&local_stack +#define GET_CALLER_PC_BP \ + uptr bp = GET_CURRENT_FRAME(); \ + uptr pc = GET_CALLER_PC(); + // Use this macro if you want to print stack trace with the current // function in the top frame. #define GET_CURRENT_PC_BP_SP \ diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc index c3c1045ee04..5dcc0e9ed15 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc @@ -35,6 +35,14 @@ void StackTrace::PrintStack(const uptr *addr, uptr size) { uptr pc = GetPreviousInstructionPc(addr[i]); uptr addr_frames_num = Symbolizer::GetOrInit()->SymbolizePC( pc, addr_frames.data(), addr_frames.size()); + if (addr_frames_num == 0) { + frame_desc.clear(); + PrintStackFramePrefix(&frame_desc, frame_num, pc); + frame_desc.append(" (<unknown module>)"); + Printf("%s\n", frame_desc.data()); + frame_num++; + continue; + } for (uptr j = 0; j < addr_frames_num; j++) { AddressInfo &info = addr_frames[j]; frame_desc.clear(); diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.cc b/libsanitizer/sanitizer_common/sanitizer_suppressions.cc index 1766fb5a319..ab40598ae8e 100644 --- a/libsanitizer/sanitizer_common/sanitizer_suppressions.cc +++ b/libsanitizer/sanitizer_common/sanitizer_suppressions.cc @@ -13,13 +13,15 @@ #include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" +#include "sanitizer_flags.h" #include "sanitizer_libc.h" +#include "sanitizer_placement_new.h" namespace __sanitizer { static const char *const kTypeStrings[SuppressionTypeCount] = { - "none", "race", "mutex", "thread", - "signal", "leak", "called_from_lib", "deadlock"}; + "none", "race", "mutex", "thread", "signal", + "leak", "called_from_lib", "deadlock", "vptr_check"}; bool TemplateMatch(char *templ, const char *str) { if (str == 0 || str[0] == 0) @@ -63,6 +65,33 @@ bool TemplateMatch(char *templ, const char *str) { return true; } +ALIGNED(64) static char placeholder[sizeof(SuppressionContext)]; +static SuppressionContext *suppression_ctx = 0; + +SuppressionContext *SuppressionContext::Get() { + CHECK(suppression_ctx); + return suppression_ctx; +} + +void SuppressionContext::InitIfNecessary() { + if (suppression_ctx) + return; + suppression_ctx = new(placeholder) SuppressionContext; + if (common_flags()->suppressions[0] == '\0') + return; + char *suppressions_from_file; + uptr buffer_size; + uptr contents_size = + ReadFileToBuffer(common_flags()->suppressions, &suppressions_from_file, + &buffer_size, 1 << 26 /* max_len */); + if (contents_size == 0) { + Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName, + common_flags()->suppressions); + Die(); + } + suppression_ctx->Parse(suppressions_from_file); +} + bool SuppressionContext::Match(const char *str, SuppressionType type, Suppression **s) { can_parse_ = false; diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.h b/libsanitizer/sanitizer_common/sanitizer_suppressions.h index 033ddc5f52a..84ee834a9fd 100644 --- a/libsanitizer/sanitizer_common/sanitizer_suppressions.h +++ b/libsanitizer/sanitizer_common/sanitizer_suppressions.h @@ -25,6 +25,7 @@ enum SuppressionType { SuppressionLeak, SuppressionLib, SuppressionDeadlock, + SuppressionVptrCheck, SuppressionTypeCount }; @@ -37,14 +38,21 @@ struct Suppression { class SuppressionContext { public: - SuppressionContext() : suppressions_(1), can_parse_(true) {} void Parse(const char *str); bool Match(const char* str, SuppressionType type, Suppression **s); uptr SuppressionCount() const; const Suppression *SuppressionAt(uptr i) const; void GetMatched(InternalMmapVector<Suppression *> *matched); + // Create a SuppressionContext singleton if it hasn't been created earlier. + // Not thread safe. Must be called early during initialization (but after + // runtime flags are parsed). + static void InitIfNecessary(); + // Returns a SuppressionContext singleton. + static SuppressionContext *Get(); + private: + SuppressionContext() : suppressions_(1), can_parse_(true) {} InternalMmapVector<Suppression> suppressions_; bool can_parse_; diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc index f417b087ae2..6821e5a3262 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc @@ -20,17 +20,6 @@ Symbolizer *Symbolizer::symbolizer_; StaticSpinMutex Symbolizer::init_mu_; LowLevelAllocator Symbolizer::symbolizer_allocator_; -Symbolizer *Symbolizer::GetOrNull() { - SpinMutexLock l(&init_mu_); - return symbolizer_; -} - -Symbolizer *Symbolizer::Get() { - SpinMutexLock l(&init_mu_); - RAW_CHECK_MSG(symbolizer_ != 0, "Using uninitialized symbolizer!"); - return symbolizer_; -} - Symbolizer *Symbolizer::Disable() { CHECK_EQ(0, symbolizer_); // Initialize a dummy symbolizer. diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h index 05fc6a7cbb9..73a68b2ee11 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h @@ -70,20 +70,9 @@ struct DataInfo { class Symbolizer { public: - /// Returns platform-specific implementation of Symbolizer. The symbolizer - /// must be initialized (with init or disable) before calling this function. - static Symbolizer *Get(); - /// Returns platform-specific implementation of Symbolizer, or null if not - /// initialized. - static Symbolizer *GetOrNull(); - /// Returns platform-specific implementation of Symbolizer. Will - /// automatically initialize symbolizer as if by calling Init(0) if needed. + /// Initialize and return platform-specific implementation of symbolizer + /// (if it wasn't already initialized). static Symbolizer *GetOrInit(); - /// Initialize and return the symbolizer, given an optional path to an - /// external symbolizer. The path argument is only required for legacy - /// reasons as this function will check $PATH for an external symbolizer. Not - /// thread safe. - static Symbolizer *Init(const char* path_to_external = 0); // Fills at most "max_frames" elements of "frames" with descriptions // for a given address (in all inlined functions). Returns the number // of descriptions actually filled. @@ -120,10 +109,7 @@ class Symbolizer { private: /// Platform-specific function for creating a Symbolizer object. - static Symbolizer *PlatformInit(const char *path_to_external); - /// Create a symbolizer and store it to symbolizer_ without checking if one - /// already exists. Not thread safe. - static Symbolizer *CreateAndStore(const char *path_to_external); + static Symbolizer *PlatformInit(); /// Initialize the symbolizer in a disabled state. Not thread safe. static Symbolizer *Disable(); diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc index 2d9caaf4e85..9afd805a82c 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc @@ -14,24 +14,13 @@ namespace __sanitizer { -Symbolizer *Symbolizer::CreateAndStore(const char *path_to_external) { - Symbolizer *platform_symbolizer = PlatformInit(path_to_external); - if (!platform_symbolizer) - return Disable(); - symbolizer_ = platform_symbolizer; - return platform_symbolizer; -} - -Symbolizer *Symbolizer::Init(const char *path_to_external) { - CHECK_EQ(0, symbolizer_); - return CreateAndStore(path_to_external); -} - Symbolizer *Symbolizer::GetOrInit() { SpinMutexLock l(&init_mu_); - if (symbolizer_ == 0) - return CreateAndStore(0); - return symbolizer_; + if (symbolizer_) + return symbolizer_; + if ((symbolizer_ = PlatformInit())) + return symbolizer_; + return Disable(); } } // namespace __sanitizer diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc index 161c21b3aad..4f30225a4c8 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc @@ -253,7 +253,7 @@ class SymbolizerProcess : public ExternalSymbolizerInterface { internal_close(outfd[1]); internal_close(infd[0]); internal_close(infd[1]); - for (int fd = getdtablesize(); fd > 2; fd--) + for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd); ExecuteWithDefaultArgs(path_); internal__exit(1); @@ -714,7 +714,7 @@ class POSIXSymbolizer : public Symbolizer { LibbacktraceSymbolizer *libbacktrace_symbolizer_; // Leaked. }; -Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) { +Symbolizer *Symbolizer::PlatformInit() { if (!common_flags()->symbolize) { return new(symbolizer_allocator_) POSIXSymbolizer(0, 0, 0); } @@ -727,6 +727,7 @@ Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) { libbacktrace_symbolizer = LibbacktraceSymbolizer::get(&symbolizer_allocator_); if (!libbacktrace_symbolizer) { + const char *path_to_external = common_flags()->external_symbolizer_path; if (path_to_external && path_to_external[0] == '\0') { // External symbolizer is explicitly disabled. Do nothing. } else { diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc index c014c6af42b..a1ed4e9a7b7 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc @@ -30,11 +30,22 @@ class WinSymbolizer : public Symbolizer { BlockingMutexLock l(&dbghelp_mu_); if (!initialized_) { - SymSetOptions(SYMOPT_DEFERRED_LOADS | - SYMOPT_UNDNAME | - SYMOPT_LOAD_LINES); - CHECK(SymInitialize(GetCurrentProcess(), 0, TRUE)); - // FIXME: We don't call SymCleanup() on exit yet - should we? + if (!TrySymInitialize()) { + // OK, maybe the client app has called SymInitialize already. + // That's a bit unfortunate for us as all the DbgHelp functions are + // single-threaded and we can't coordinate with the app. + // FIXME: Can we stop the other threads at this point? + // Anyways, we have to reconfigure stuff to make sure that SymInitialize + // has all the appropriate options set. + // Cross our fingers and reinitialize DbgHelp. + Report("*** WARNING: Failed to initialize DbgHelp! ***\n"); + Report("*** Most likely this means that the app is already ***\n"); + Report("*** using DbgHelp, possibly with incompatible flags. ***\n"); + Report("*** Due to technical reasons, symbolization might crash ***\n"); + Report("*** or produce wrong results. ***\n"); + SymCleanup(GetCurrentProcess()); + TrySymInitialize(); + } initialized_ = true; } @@ -90,13 +101,19 @@ class WinSymbolizer : public Symbolizer { // FIXME: Implement GetModuleNameAndOffsetForPC(). private: + bool TrySymInitialize() { + SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES); + return SymInitialize(GetCurrentProcess(), 0, TRUE); + // FIXME: We don't call SymCleanup() on exit yet - should we? + } + // All DbgHelp functions are single threaded, so we should use a mutex to // serialize accesses. BlockingMutex dbghelp_mu_; bool initialized_; }; -Symbolizer *Symbolizer::PlatformInit(const char *path_to_external) { +Symbolizer *Symbolizer::PlatformInit() { static bool called_once = false; CHECK(!called_once && "Shouldn't create more than one symbolizer"); called_once = true; diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc index 0ad47561b8b..bfa610443c1 100644 --- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc +++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc @@ -216,7 +216,7 @@ void ThreadRegistry::SetThreadNameByUserId(uptr user_id, const char *name) { } } -void ThreadRegistry::DetachThread(u32 tid) { +void ThreadRegistry::DetachThread(u32 tid, void *arg) { BlockingMutexLock l(&mtx_); CHECK_LT(tid, n_contexts_); ThreadContextBase *tctx = threads_[tid]; @@ -225,6 +225,7 @@ void ThreadRegistry::DetachThread(u32 tid) { Report("%s: Detach of non-existent thread\n", SanitizerToolName); return; } + tctx->OnDetached(arg); if (tctx->status == ThreadStatusFinished) { tctx->SetDead(); QuarantinePush(tctx); diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h index 2d7f9e90e0d..d5a741bbfc4 100644 --- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h +++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h @@ -66,6 +66,7 @@ class ThreadContextBase { virtual void OnStarted(void *arg) {} virtual void OnCreated(void *arg) {} virtual void OnReset() {} + virtual void OnDetached(void *arg) {} }; typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid); @@ -108,7 +109,7 @@ class ThreadRegistry { void SetThreadName(u32 tid, const char *name); void SetThreadNameByUserId(uptr user_id, const char *name); - void DetachThread(u32 tid); + void DetachThread(u32 tid, void *arg); void JoinThread(u32 tid, void *arg); void FinishThread(u32 tid); void StartThread(u32 tid, uptr os_id, void *arg); diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cc b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cc index 1d6170f9157..af828045b59 100644 --- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cc +++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cc @@ -76,14 +76,13 @@ void DTLS_Destroy() { DTLS_Deallocate(dtls.dtv, s); } -void DTLS_on_tls_get_addr(void *arg_void, void *res) { - if (!common_flags()->intercept_tls_get_addr) return; +DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res) { + if (!common_flags()->intercept_tls_get_addr) return 0; TlsGetAddrParam *arg = reinterpret_cast<TlsGetAddrParam *>(arg_void); uptr dso_id = arg->dso_id; - if (dtls.dtv_size == kDestroyedThread) return; + if (dtls.dtv_size == kDestroyedThread) return 0; DTLS_Resize(dso_id + 1); - if (dtls.dtv[dso_id].beg) - return; + if (dtls.dtv[dso_id].beg) return 0; uptr tls_size = 0; uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset; VPrintf(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p " @@ -108,6 +107,7 @@ void DTLS_on_tls_get_addr(void *arg_void, void *res) { } dtls.dtv[dso_id].beg = tls_beg; dtls.dtv[dso_id].size = tls_size; + return dtls.dtv + dso_id; } void DTLS_on_libc_memalign(void *ptr, uptr size) { @@ -121,7 +121,7 @@ DTLS *DTLS_Get() { return &dtls; } #else void DTLS_on_libc_memalign(void *ptr, uptr size) {} -void DTLS_on_tls_get_addr(void *arg, void *res) {} +DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res) { return 0; } DTLS *DTLS_Get() { return 0; } void DTLS_Destroy() {} #endif // SANITIZER_INTERCEPT_TLS_GET_ADDR diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h index 22a5e1c41c2..8dc629f630e 100644 --- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h +++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h @@ -46,7 +46,9 @@ struct DTLS { uptr last_memalign_ptr; }; -void DTLS_on_tls_get_addr(void *arg, void *res); +// Returns pointer and size of a linker-allocated TLS block. +// Each block is returned exactly once. +DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res); void DTLS_on_libc_memalign(void *ptr, uptr size); DTLS *DTLS_Get(); void DTLS_Destroy(); // Make sure to call this before the thread is destroyed. diff --git a/libsanitizer/sanitizer_common/sanitizer_unwind_posix_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_unwind_posix_libcdep.cc new file mode 100644 index 00000000000..c49113e1d0b --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_unwind_posix_libcdep.cc @@ -0,0 +1,151 @@ +//===-- sanitizer_unwind_posix.cc ----------------------------------------===// +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the unwind.h-based (aka "slow") stack unwinding routines +// available to the tools on Linux, Android, FreeBSD and OS X. +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_POSIX +#include "sanitizer_common.h" +#include "sanitizer_stacktrace.h" + +#if SANITIZER_ANDROID +#include <dlfcn.h> // for dlopen() +#endif + +#if SANITIZER_FREEBSD +#define _GNU_SOURCE // to declare _Unwind_Backtrace() from <unwind.h> +#endif +#include <unwind.h> + +namespace __sanitizer { + +//------------------------- SlowUnwindStack ----------------------------------- + +typedef struct { + uptr absolute_pc; + uptr stack_top; + uptr stack_size; +} backtrace_frame_t; + +extern "C" { +typedef void *(*acquire_my_map_info_list_func)(); +typedef void (*release_my_map_info_list_func)(void *map); +typedef sptr (*unwind_backtrace_signal_arch_func)( + void *siginfo, void *sigcontext, void *map_info_list, + backtrace_frame_t *backtrace, uptr ignore_depth, uptr max_depth); +acquire_my_map_info_list_func acquire_my_map_info_list; +release_my_map_info_list_func release_my_map_info_list; +unwind_backtrace_signal_arch_func unwind_backtrace_signal_arch; +} // extern "C" + +#if SANITIZER_ANDROID +void SanitizerInitializeUnwinder() { + void *p = dlopen("libcorkscrew.so", RTLD_LAZY); + if (!p) { + VReport(1, + "Failed to open libcorkscrew.so. You may see broken stack traces " + "in SEGV reports."); + return; + } + acquire_my_map_info_list = + (acquire_my_map_info_list_func)(uptr)dlsym(p, "acquire_my_map_info_list"); + release_my_map_info_list = + (release_my_map_info_list_func)(uptr)dlsym(p, "release_my_map_info_list"); + unwind_backtrace_signal_arch = (unwind_backtrace_signal_arch_func)(uptr)dlsym( + p, "unwind_backtrace_signal_arch"); + if (!acquire_my_map_info_list || !release_my_map_info_list || + !unwind_backtrace_signal_arch) { + VReport(1, + "Failed to find one of the required symbols in libcorkscrew.so. " + "You may see broken stack traces in SEGV reports."); + acquire_my_map_info_list = 0; + unwind_backtrace_signal_arch = 0; + release_my_map_info_list = 0; + } +} +#endif + +#ifdef __arm__ +#define UNWIND_STOP _URC_END_OF_STACK +#define UNWIND_CONTINUE _URC_NO_REASON +#else +#define UNWIND_STOP _URC_NORMAL_STOP +#define UNWIND_CONTINUE _URC_NO_REASON +#endif + +uptr Unwind_GetIP(struct _Unwind_Context *ctx) { +#ifdef __arm__ + uptr val; + _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE, + 15 /* r15 = PC */, _UVRSD_UINT32, &val); + CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed"); + // Clear the Thumb bit. + return val & ~(uptr)1; +#else + return _Unwind_GetIP(ctx); +#endif +} + +struct UnwindTraceArg { + StackTrace *stack; + uptr max_depth; +}; + +_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) { + UnwindTraceArg *arg = (UnwindTraceArg*)param; + CHECK_LT(arg->stack->size, arg->max_depth); + uptr pc = Unwind_GetIP(ctx); + arg->stack->trace[arg->stack->size++] = pc; + if (arg->stack->size == arg->max_depth) return UNWIND_STOP; + return UNWIND_CONTINUE; +} + +void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) { + CHECK_GE(max_depth, 2); + size = 0; + UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)}; + _Unwind_Backtrace(Unwind_Trace, &arg); + // We need to pop a few frames so that pc is on top. + uptr to_pop = LocatePcInTrace(pc); + // trace[0] belongs to the current function so we always pop it. + if (to_pop == 0) + to_pop = 1; + PopStackFrames(to_pop); + trace[0] = pc; +} + +void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context, + uptr max_depth) { + CHECK_GE(max_depth, 2); + if (!unwind_backtrace_signal_arch) { + SlowUnwindStack(pc, max_depth); + return; + } + + void *map = acquire_my_map_info_list(); + CHECK(map); + InternalScopedBuffer<backtrace_frame_t> frames(kStackTraceMax); + // siginfo argument appears to be unused. + sptr res = unwind_backtrace_signal_arch(/* siginfo */ 0, context, map, + frames.data(), + /* ignore_depth */ 0, max_depth); + release_my_map_info_list(map); + if (res < 0) return; + CHECK_LE((uptr)res, kStackTraceMax); + + size = 0; + // +2 compensate for libcorkscrew unwinder returning addresses of call + // instructions instead of raw return addresses. + for (sptr i = 0; i < res; ++i) + trace[size++] = frames[i].absolute_pc + 2; +} + +} // namespace __sanitizer + +#endif // SANITIZER_POSIX diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cc b/libsanitizer/sanitizer_common/sanitizer_win.cc index 6065838cefe..9f24510dbd0 100644 --- a/libsanitizer/sanitizer_common/sanitizer_win.cc +++ b/libsanitizer/sanitizer_common/sanitizer_win.cc @@ -15,9 +15,10 @@ #define WIN32_LEAN_AND_MEAN #define NOGDI -#include <stdlib.h> -#include <io.h> #include <windows.h> +#include <dbghelp.h> +#include <io.h> +#include <stdlib.h> #include "sanitizer_common.h" #include "sanitizer_libc.h" @@ -62,6 +63,7 @@ uptr GetThreadSelf() { return GetTid(); } +#if !SANITIZER_GO void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, uptr *stack_bottom) { CHECK(stack_top); @@ -74,6 +76,7 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize; *stack_bottom = (uptr)mbi.AllocationBase; } +#endif // #if !SANITIZER_GO void *MmapOrDie(uptr size, const char *mem_type) { void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); @@ -135,6 +138,10 @@ void *MapFileToMemory(const char *file_name, uptr *buff_size) { UNIMPLEMENTED(); } +void *MapWritableFileToMemory(void *addr, uptr size, uptr fd, uptr offset) { + UNIMPLEMENTED(); +} + static const int kMaxEnvNameLength = 128; static const DWORD kMaxEnvValueLength = 32767; @@ -182,7 +189,7 @@ void DumpProcessMap() { UNIMPLEMENTED(); } -void DisableCoreDumper() { +void DisableCoreDumperIfNecessary() { // Do nothing. } @@ -203,6 +210,14 @@ void SetStackSizeLimitInBytes(uptr limit) { UNIMPLEMENTED(); } +bool AddressSpaceIsUnlimited() { + UNIMPLEMENTED(); +} + +void SetAddressSpaceUnlimited() { + UNIMPLEMENTED(); +} + char *FindPathToBinary(const char *name) { // Nothing here for now. return 0; @@ -350,6 +365,14 @@ void internal__exit(int exitcode) { ExitProcess(exitcode); } +uptr internal_ftruncate(fd_t fd, uptr size) { + UNIMPLEMENTED(); +} + +uptr internal_rename(const char *oldpath, const char *newpath) { + UNIMPLEMENTED(); +} + // ---------------------- BlockingMutex ---------------- {{{1 const uptr LOCK_UNINITIALIZED = 0; const uptr LOCK_READY = (uptr)-1; @@ -418,6 +441,7 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size, #endif } +#if !SANITIZER_GO void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) { CHECK_GE(max_depth, 2); // FIXME: CaptureStackBackTrace might be too slow for us. @@ -435,8 +459,32 @@ void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) { void StackTrace::SlowUnwindStackWithContext(uptr pc, void *context, uptr max_depth) { - UNREACHABLE("no signal context on windows"); + CONTEXT ctx = *(CONTEXT *)context; + STACKFRAME64 stack_frame; + memset(&stack_frame, 0, sizeof(stack_frame)); + size = 0; +#if defined(_WIN64) + int machine_type = IMAGE_FILE_MACHINE_AMD64; + stack_frame.AddrPC.Offset = ctx.Rip; + stack_frame.AddrFrame.Offset = ctx.Rbp; + stack_frame.AddrStack.Offset = ctx.Rsp; +#else + int machine_type = IMAGE_FILE_MACHINE_I386; + stack_frame.AddrPC.Offset = ctx.Eip; + stack_frame.AddrFrame.Offset = ctx.Ebp; + stack_frame.AddrStack.Offset = ctx.Esp; +#endif + stack_frame.AddrPC.Mode = AddrModeFlat; + stack_frame.AddrFrame.Mode = AddrModeFlat; + stack_frame.AddrStack.Mode = AddrModeFlat; + while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(), + &stack_frame, &ctx, NULL, &SymFunctionTableAccess64, + &SymGetModuleBase64, NULL) && + size < Min(max_depth, kStackTraceMax)) { + trace[size++] = (uptr)stack_frame.AddrPC.Offset; + } } +#endif // #if !SANITIZER_GO void MaybeOpenReportFile() { // Windows doesn't have native fork, and we don't support Cygwin or other @@ -472,6 +520,11 @@ bool IsDeadlySignal(int signum) { return false; } +bool IsAccessibleMemoryRange(uptr beg, uptr size) { + // FIXME: Actually implement this function. + return true; +} + } // namespace __sanitizer #endif // _WIN32 |