From 3c6331c29f1376ed220246e7dead94bc527a9aa9 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Mon, 1 Jun 2020 21:15:18 +0200 Subject: [PATCH] Libsanitizer: merge from master. Merged from revision b638b63b99d66786cb37336292604a2ae3490cfd. The patch successfully bootstraps on x86_64-linux-gnu and ppc64le-linux-gnu. I also tested ppc64-linux-gnu that exposed: https://reviews.llvm.org/D80864 (which is fixed on master). Abidiff looks happy and I made UBSAN and ASAN bootstrap on x86_64-linux-gnu. I'm planning to do merge from master twice a year, once now and next time short before stage1 closes. I am going to install the patches as merge from master is obvious and I haven't made anything special. libsanitizer/ChangeLog: * MERGE: Merge from master. --- libsanitizer/MERGE | 2 +- libsanitizer/asan/asan_globals.cpp | 19 + libsanitizer/asan/asan_interceptors.h | 7 +- libsanitizer/asan/asan_mapping.h | 2 +- libsanitizer/asan/asan_report.cpp | 3 + libsanitizer/asan/asan_thread.cpp | 2 + .../include/sanitizer/linux_syscall_hooks.h | 8 +- .../include/sanitizer/netbsd_syscall_hooks.h | 2 +- .../include/sanitizer/tsan_interface.h | 20 +- libsanitizer/lsan/lsan.cpp | 17 +- libsanitizer/lsan/lsan.h | 6 + libsanitizer/lsan/lsan_allocator.h | 5 +- libsanitizer/lsan/lsan_common.cpp | 51 +- libsanitizer/lsan/lsan_common.h | 17 +- libsanitizer/lsan/lsan_common_fuchsia.cpp | 166 +++++ libsanitizer/lsan/lsan_common_linux.cpp | 3 +- libsanitizer/lsan/lsan_common_mac.cpp | 3 +- libsanitizer/lsan/lsan_fuchsia.cpp | 123 ++++ libsanitizer/lsan/lsan_fuchsia.h | 35 + libsanitizer/lsan/lsan_interceptors.cpp | 19 +- libsanitizer/lsan/lsan_linux.cpp | 6 +- libsanitizer/lsan/lsan_posix.cpp | 96 +++ libsanitizer/lsan/lsan_posix.h | 49 ++ libsanitizer/lsan/lsan_thread.cpp | 98 +-- libsanitizer/lsan/lsan_thread.h | 35 +- .../sanitizer_common/sanitizer_allocator.cpp | 4 +- .../sanitizer_allocator_primary64.h | 10 +- .../sanitizer_common/sanitizer_common.cpp | 2 + .../sanitizer_common/sanitizer_common.h | 5 +- .../sanitizer_common_interceptors.inc | 190 +++++- ...izer_common_interceptors_netbsd_compat.inc | 128 ++++ .../sanitizer_common_libcdep.cpp | 12 +- .../sanitizer_common_syscalls.inc | 17 + .../sanitizer_coverage_fuchsia.cpp | 25 +- .../sanitizer_coverage_interface.inc | 1 + .../sanitizer_coverage_libcdep_new.cpp | 1 + .../sanitizer_common/sanitizer_file.h | 4 +- .../sanitizer_flag_parser.cpp | 11 +- .../sanitizer_common/sanitizer_flag_parser.h | 49 ++ .../sanitizer_common/sanitizer_flags.cpp | 10 +- .../sanitizer_common/sanitizer_freebsd.h | 23 +- .../sanitizer_common/sanitizer_fuchsia.cpp | 4 + .../sanitizer_common/sanitizer_fuchsia.h | 6 + .../sanitizer_interceptors_ioctl_netbsd.inc | 18 +- .../sanitizer_interface_internal.h | 6 +- .../sanitizer_internal_defs.h | 2 +- .../sanitizer_common/sanitizer_libc.h | 2 + .../sanitizer_common/sanitizer_linux.cpp | 151 ++++- .../sanitizer_common/sanitizer_linux.h | 2 + .../sanitizer_linux_libcdep.cpp | 17 +- .../sanitizer_common/sanitizer_linux_s390.cpp | 11 +- .../sanitizer_common/sanitizer_mac.cpp | 81 ++- libsanitizer/sanitizer_common/sanitizer_mac.h | 21 +- .../sanitizer_common/sanitizer_malloc_mac.inc | 18 +- .../sanitizer_common/sanitizer_netbsd.cpp | 7 +- .../sanitizer_platform_interceptors.h | 24 + .../sanitizer_platform_limits_freebsd.cpp | 614 +++++++++--------- .../sanitizer_platform_limits_freebsd.h | 32 +- .../sanitizer_platform_limits_linux.cpp | 7 +- .../sanitizer_platform_limits_netbsd.cpp | 191 ++++++ .../sanitizer_platform_limits_netbsd.h | 33 +- .../sanitizer_platform_limits_openbsd.cpp | 1 + .../sanitizer_platform_limits_openbsd.h | 1 + .../sanitizer_platform_limits_posix.cpp | 1 + .../sanitizer_platform_limits_posix.h | 3 +- .../sanitizer_platform_limits_solaris.cpp | 1 + .../sanitizer_platform_limits_solaris.h | 1 + .../sanitizer_common/sanitizer_posix.cpp | 10 +- .../sanitizer_common/sanitizer_posix.h | 4 +- .../sanitizer_posix_libcdep.cpp | 6 +- .../sanitizer_common/sanitizer_procmaps.h | 7 +- .../sanitizer_procmaps_fuchsia.cpp | 80 +++ .../sanitizer_common/sanitizer_ptrauth.h | 21 + .../sanitizer_common/sanitizer_rtems.cpp | 4 + .../sanitizer_common/sanitizer_stacktrace.cpp | 17 +- .../sanitizer_stoptheworld_fuchsia.cpp | 42 ++ .../sanitizer_stoptheworld_mac.cpp | 9 +- .../sanitizer_stoptheworld_netbsd_libcdep.cpp | 12 +- .../sanitizer_common/sanitizer_symbolizer.cpp | 6 + .../sanitizer_common/sanitizer_symbolizer.h | 3 + .../sanitizer_symbolizer_internal.h | 7 + .../sanitizer_symbolizer_libcdep.cpp | 89 ++- .../sanitizer_symbolizer_mac.cpp | 88 ++- .../sanitizer_symbolizer_mac.h | 1 + .../sanitizer_symbolizer_markup.cpp | 4 +- .../sanitizer_symbolizer_posix_libcdep.cpp | 16 +- .../sanitizer_symbolizer_win.cpp | 2 +- .../sanitizer_syscalls_netbsd.inc | 22 +- .../sanitizer_common/sanitizer_win.cpp | 9 +- libsanitizer/tsan/tsan_clock.cpp | 68 +- libsanitizer/tsan/tsan_clock.h | 58 ++ libsanitizer/tsan/tsan_interceptors_posix.cpp | 21 +- libsanitizer/tsan/tsan_platform.h | 1 + libsanitizer/tsan/tsan_platform_mac.cpp | 10 +- libsanitizer/tsan/tsan_rtl.cpp | 12 +- libsanitizer/tsan/tsan_rtl.h | 4 +- libsanitizer/tsan/tsan_rtl_mutex.cpp | 25 +- libsanitizer/tsan/tsan_rtl_ppc64.S | 1 - libsanitizer/tsan/tsan_rtl_thread.cpp | 34 +- libsanitizer/tsan/tsan_stat.h | 1 + libsanitizer/ubsan/ubsan_checks.inc | 6 + libsanitizer/ubsan/ubsan_flags.cpp | 1 - libsanitizer/ubsan/ubsan_handlers.cpp | 65 +- libsanitizer/ubsan/ubsan_handlers.h | 8 - libsanitizer/ubsan/ubsan_init.cpp | 2 + libsanitizer/ubsan/ubsan_platform.h | 2 - .../ubsan/ubsan_type_hash_itanium.cpp | 2 + 107 files changed, 2551 insertions(+), 770 deletions(-) create mode 100644 libsanitizer/lsan/lsan_common_fuchsia.cpp create mode 100644 libsanitizer/lsan/lsan_fuchsia.cpp create mode 100644 libsanitizer/lsan/lsan_fuchsia.h create mode 100644 libsanitizer/lsan/lsan_posix.cpp create mode 100644 libsanitizer/lsan/lsan_posix.h create mode 100644 libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc create mode 100644 libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp create mode 100644 libsanitizer/sanitizer_common/sanitizer_ptrauth.h create mode 100644 libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE index 49ee2c3bab8..e14e830ea7d 100644 --- a/libsanitizer/MERGE +++ b/libsanitizer/MERGE @@ -1,4 +1,4 @@ -82588e05cc32bb30807e480abd4e689b0dee132a +b638b63b99d66786cb37336292604a2ae3490cfd The first line of this file holds the git revision number of the last merge done from the master library sources. diff --git a/libsanitizer/asan/asan_globals.cpp b/libsanitizer/asan/asan_globals.cpp index e045c31cd1c..9d7dbc6f264 100644 --- a/libsanitizer/asan/asan_globals.cpp +++ b/libsanitizer/asan/asan_globals.cpp @@ -154,6 +154,23 @@ static void CheckODRViolationViaIndicator(const Global *g) { } } +// Check ODR violation for given global G by checking if it's already poisoned. +// We use this method in case compiler doesn't use private aliases for global +// variables. +static void CheckODRViolationViaPoisoning(const Global *g) { + if (__asan_region_is_poisoned(g->beg, g->size_with_redzone)) { + // This check may not be enough: if the first global is much larger + // the entire redzone of the second global may be within the first global. + for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) { + if (g->beg == l->g->beg && + (flags()->detect_odr_violation >= 2 || g->size != l->g->size) && + !IsODRViolationSuppressed(g->name)) + ReportODRViolation(g, FindRegistrationSite(g), + l->g, FindRegistrationSite(l->g)); + } + } +} + // Clang provides two different ways for global variables protection: // it can poison the global itself or its private alias. In former // case we may poison same symbol multiple times, that can help us to @@ -199,6 +216,8 @@ static void RegisterGlobal(const Global *g) { // where two globals with the same name are defined in different modules. if (UseODRIndicator(g)) CheckODRViolationViaIndicator(g); + else + CheckODRViolationViaPoisoning(g); } if (CanPoisonMemory()) PoisonRedZones(*g); diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h index b7a85fedbdf..344a64bd83d 100644 --- a/libsanitizer/asan/asan_interceptors.h +++ b/libsanitizer/asan/asan_interceptors.h @@ -80,12 +80,7 @@ void InitializePlatformInterceptors(); #if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && !SANITIZER_SOLARIS && \ !SANITIZER_NETBSD # define ASAN_INTERCEPT___CXA_THROW 1 -# if ! defined(ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION) \ - || ASAN_HAS_CXA_RETHROW_PRIMARY_EXCEPTION -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1 -# else -# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 0 -# endif +# define ASAN_INTERCEPT___CXA_RETHROW_PRIMARY_EXCEPTION 1 # if defined(_GLIBCXX_SJLJ_EXCEPTIONS) || (SANITIZER_IOS && defined(__arm__)) # define ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION 1 # else diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h index 09be904270c..41fb49ee46d 100644 --- a/libsanitizer/asan/asan_mapping.h +++ b/libsanitizer/asan/asan_mapping.h @@ -163,7 +163,7 @@ static const u64 kDefaultShort64bitShadowOffset = static const u64 kAArch64_ShadowOffset64 = 1ULL << 36; static const u64 kMIPS32_ShadowOffset32 = 0x0aaa0000; static const u64 kMIPS64_ShadowOffset64 = 1ULL << 37; -static const u64 kPPC64_ShadowOffset64 = 1ULL << 41; +static const u64 kPPC64_ShadowOffset64 = 1ULL << 44; static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52; static const u64 kSPARC64_ShadowOffset64 = 1ULL << 43; // 0x80000000000 static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000 diff --git a/libsanitizer/asan/asan_report.cpp b/libsanitizer/asan/asan_report.cpp index 2e6ce436d03..99e8678aa78 100644 --- a/libsanitizer/asan/asan_report.cpp +++ b/libsanitizer/asan/asan_report.cpp @@ -160,6 +160,9 @@ class ScopedInErrorReport { BlockingMutexLock l(&error_message_buf_mutex); internal_memcpy(buffer_copy.data(), error_message_buffer, kErrorMessageBufferSize); + // Clear error_message_buffer so that if we find other errors + // we don't re-log this error. + error_message_buffer_pos = 0; } LogFullErrorReport(buffer_copy.data()); diff --git a/libsanitizer/asan/asan_thread.cpp b/libsanitizer/asan/asan_thread.cpp index 6734d9a1668..f0df8bd4b37 100644 --- a/libsanitizer/asan/asan_thread.cpp +++ b/libsanitizer/asan/asan_thread.cpp @@ -480,6 +480,8 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, return true; } +void GetAllThreadAllocatorCachesLocked(InternalMmapVector *caches) {} + void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, void *arg) { __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id); diff --git a/libsanitizer/include/sanitizer/linux_syscall_hooks.h b/libsanitizer/include/sanitizer/linux_syscall_hooks.h index a1794b71af5..56eae3d40f9 100644 --- a/libsanitizer/include/sanitizer/linux_syscall_hooks.h +++ b/libsanitizer/include/sanitizer/linux_syscall_hooks.h @@ -1845,6 +1845,10 @@ #define __sanitizer_syscall_post_rt_sigaction(res, signum, act, oldact, sz) \ __sanitizer_syscall_post_impl_rt_sigaction(res, (long)signum, (long)act, \ (long)oldact, (long)sz) +#define __sanitizer_syscall_pre_sigaltstack(ss, oss) \ + __sanitizer_syscall_pre_impl_sigaltstack((long)ss, (long)oss) +#define __sanitizer_syscall_post_sigaltstack(res, ss, oss) \ + __sanitizer_syscall_post_impl_sigaltstack(res, (long)ss, (long)oss) // And now a few syscalls we don't handle yet. #define __sanitizer_syscall_pre_afs_syscall(...) @@ -1912,7 +1916,6 @@ #define __sanitizer_syscall_pre_setreuid32(...) #define __sanitizer_syscall_pre_set_thread_area(...) #define __sanitizer_syscall_pre_setuid32(...) -#define __sanitizer_syscall_pre_sigaltstack(...) #define __sanitizer_syscall_pre_sigreturn(...) #define __sanitizer_syscall_pre_sigsuspend(...) #define __sanitizer_syscall_pre_stty(...) @@ -1992,7 +1995,6 @@ #define __sanitizer_syscall_post_setreuid32(res, ...) #define __sanitizer_syscall_post_set_thread_area(res, ...) #define __sanitizer_syscall_post_setuid32(res, ...) -#define __sanitizer_syscall_post_sigaltstack(res, ...) #define __sanitizer_syscall_post_sigreturn(res, ...) #define __sanitizer_syscall_post_sigsuspend(res, ...) #define __sanitizer_syscall_post_stty(res, ...) @@ -3075,6 +3077,8 @@ void __sanitizer_syscall_pre_impl_rt_sigaction(long signum, long act, long oldact, long sz); void __sanitizer_syscall_post_impl_rt_sigaction(long res, long signum, long act, long oldact, long sz); +void __sanitizer_syscall_pre_impl_sigaltstack(long ss, long oss); +void __sanitizer_syscall_post_impl_sigaltstack(long res, long ss, long oss); #ifdef __cplusplus } // extern "C" #endif diff --git a/libsanitizer/include/sanitizer/netbsd_syscall_hooks.h b/libsanitizer/include/sanitizer/netbsd_syscall_hooks.h index 174b4bf06de..370da0ea72e 100644 --- a/libsanitizer/include/sanitizer/netbsd_syscall_hooks.h +++ b/libsanitizer/include/sanitizer/netbsd_syscall_hooks.h @@ -20,7 +20,7 @@ // DO NOT EDIT! THIS FILE HAS BEEN GENERATED! // // Generated with: generate_netbsd_syscalls.awk -// Generated date: 2019-11-01 +// Generated date: 2019-12-24 // Generated from: syscalls.master,v 1.296 2019/09/22 22:59:39 christos Exp // //===----------------------------------------------------------------------===// diff --git a/libsanitizer/include/sanitizer/tsan_interface.h b/libsanitizer/include/sanitizer/tsan_interface.h index 011b23350ca..96b8ad58541 100644 --- a/libsanitizer/include/sanitizer/tsan_interface.h +++ b/libsanitizer/include/sanitizer/tsan_interface.h @@ -38,34 +38,34 @@ void __tsan_release(void *addr); // Mutex has static storage duration and no-op constructor and destructor. // This effectively makes tsan ignore destroy annotation. -const unsigned __tsan_mutex_linker_init = 1 << 0; +static const unsigned __tsan_mutex_linker_init = 1 << 0; // Mutex is write reentrant. -const unsigned __tsan_mutex_write_reentrant = 1 << 1; +static const unsigned __tsan_mutex_write_reentrant = 1 << 1; // Mutex is read reentrant. -const unsigned __tsan_mutex_read_reentrant = 1 << 2; +static const unsigned __tsan_mutex_read_reentrant = 1 << 2; // Mutex does not have static storage duration, and must not be used after // its destructor runs. The opposite of __tsan_mutex_linker_init. // If this flag is passed to __tsan_mutex_destroy, then the destruction // is ignored unless this flag was previously set on the mutex. -const unsigned __tsan_mutex_not_static = 1 << 8; +static const unsigned __tsan_mutex_not_static = 1 << 8; // Mutex operation flags: // Denotes read lock operation. -const unsigned __tsan_mutex_read_lock = 1 << 3; +static const unsigned __tsan_mutex_read_lock = 1 << 3; // Denotes try lock operation. -const unsigned __tsan_mutex_try_lock = 1 << 4; +static const unsigned __tsan_mutex_try_lock = 1 << 4; // Denotes that a try lock operation has failed to acquire the mutex. -const unsigned __tsan_mutex_try_lock_failed = 1 << 5; +static const unsigned __tsan_mutex_try_lock_failed = 1 << 5; // Denotes that the lock operation acquires multiple recursion levels. // Number of levels is passed in recursion parameter. // This is useful for annotation of e.g. Java builtin monitors, // for which wait operation releases all recursive acquisitions of the mutex. -const unsigned __tsan_mutex_recursive_lock = 1 << 6; +static const unsigned __tsan_mutex_recursive_lock = 1 << 6; // Denotes that the unlock operation releases all recursion levels. // Number of released levels is returned and later must be passed to // the corresponding __tsan_mutex_post_lock annotation. -const unsigned __tsan_mutex_recursive_unlock = 1 << 7; +static const unsigned __tsan_mutex_recursive_unlock = 1 << 7; // Annotate creation of a mutex. // Supported flags: mutex creation flags. @@ -152,7 +152,7 @@ void __tsan_set_fiber_name(void *fiber, const char *name); // Flags for __tsan_switch_to_fiber: // Do not establish a happens-before relation between fibers -const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0; +static const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0; #ifdef __cplusplus } // extern "C" diff --git a/libsanitizer/lsan/lsan.cpp b/libsanitizer/lsan/lsan.cpp index 4ce03046ffb..80a6e2fa701 100644 --- a/libsanitizer/lsan/lsan.cpp +++ b/libsanitizer/lsan/lsan.cpp @@ -15,7 +15,6 @@ #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_flag_parser.h" -#include "sanitizer_common/sanitizer_stacktrace.h" #include "lsan_allocator.h" #include "lsan_common.h" #include "lsan_thread.h" @@ -87,17 +86,6 @@ static void InitializeFlags() { __sanitizer_set_report_path(common_flags()->log_path); } -static void OnStackUnwind(const SignalContext &sig, const void *, - BufferedStackTrace *stack) { - stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context, - common_flags()->fast_unwind_on_fatal); -} - -static void LsanOnDeadlySignal(int signo, void *siginfo, void *context) { - HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind, - nullptr); -} - extern "C" void __lsan_init() { CHECK(!lsan_init_is_running); if (lsan_inited) @@ -114,10 +102,7 @@ extern "C" void __lsan_init() { InitializeInterceptors(); InitializeThreadRegistry(); InstallDeadlySignalHandlers(LsanOnDeadlySignal); - u32 tid = ThreadCreate(0, 0, true); - CHECK_EQ(tid, 0); - ThreadStart(tid, GetTid()); - SetCurrentThread(tid); + InitializeMainThread(); if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) Atexit(DoLeakCheck); diff --git a/libsanitizer/lsan/lsan.h b/libsanitizer/lsan/lsan.h index 9904ada4bb3..1e82ad72f00 100644 --- a/libsanitizer/lsan/lsan.h +++ b/libsanitizer/lsan/lsan.h @@ -12,6 +12,11 @@ //===----------------------------------------------------------------------===// #include "lsan_thread.h" +#if SANITIZER_POSIX +#include "lsan_posix.h" +#elif SANITIZER_FUCHSIA +#include "lsan_fuchsia.h" +#endif #include "sanitizer_common/sanitizer_flags.h" #include "sanitizer_common/sanitizer_stacktrace.h" @@ -33,6 +38,7 @@ namespace __lsan { void InitializeInterceptors(); void ReplaceSystemMalloc(); +void LsanOnDeadlySignal(int signo, void *siginfo, void *context); #define ENSURE_LSAN_INITED do { \ CHECK(!lsan_init_is_running); \ diff --git a/libsanitizer/lsan/lsan_allocator.h b/libsanitizer/lsan/lsan_allocator.h index e1397099767..bda9d8cdf74 100644 --- a/libsanitizer/lsan/lsan_allocator.h +++ b/libsanitizer/lsan/lsan_allocator.h @@ -66,7 +66,10 @@ template using PrimaryAllocatorASVT = SizeClassAllocator32>; using PrimaryAllocator = PrimaryAllocatorASVT; #elif defined(__x86_64__) || defined(__powerpc64__) -# if defined(__powerpc64__) +# if SANITIZER_FUCHSIA +const uptr kAllocatorSpace = ~(uptr)0; +const uptr kAllocatorSize = 0x40000000000ULL; // 4T. +# elif defined(__powerpc64__) const uptr kAllocatorSpace = 0xa0000000000ULL; const uptr kAllocatorSize = 0x20000000000ULL; // 2T. # else diff --git a/libsanitizer/lsan/lsan_common.cpp b/libsanitizer/lsan/lsan_common.cpp index 9ff9f4c5d1c..32ea4e88003 100644 --- a/libsanitizer/lsan/lsan_common.cpp +++ b/libsanitizer/lsan/lsan_common.cpp @@ -211,6 +211,13 @@ void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) { ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable); } +#if SANITIZER_FUCHSIA + +// Fuchsia handles all threads together with its own callback. +static void ProcessThreads(SuspendedThreadsList const &, Frontier *) {} + +#else + // Scans thread data (stacks and TLS) for heap pointers. static void ProcessThreads(SuspendedThreadsList const &suspended_threads, Frontier *frontier) { @@ -308,6 +315,8 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads, } } +#endif // SANITIZER_FUCHSIA + void ScanRootRegion(Frontier *frontier, const RootRegion &root_region, uptr region_begin, uptr region_end, bool is_readable) { uptr intersection_begin = Max(root_region.begin, region_begin); @@ -443,25 +452,23 @@ void ProcessPC(Frontier *frontier) { } // Sets the appropriate tag on each chunk. -static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) { - // Holds the flood fill frontier. - Frontier frontier; - - ForEachChunk(CollectIgnoredCb, &frontier); - ProcessGlobalRegions(&frontier); - ProcessThreads(suspended_threads, &frontier); - ProcessRootRegions(&frontier); - FloodFillTag(&frontier, kReachable); +static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads, + Frontier *frontier) { + ForEachChunk(CollectIgnoredCb, frontier); + ProcessGlobalRegions(frontier); + ProcessThreads(suspended_threads, frontier); + ProcessRootRegions(frontier); + FloodFillTag(frontier, kReachable); - CHECK_EQ(0, frontier.size()); - ProcessPC(&frontier); + CHECK_EQ(0, frontier->size()); + ProcessPC(frontier); // The check here is relatively expensive, so we do this in a separate flood // fill. That way we can skip the check for chunks that are reachable // otherwise. LOG_POINTERS("Processing platform-specific allocations.\n"); - ProcessPlatformSpecificAllocations(&frontier); - FloodFillTag(&frontier, kReachable); + ProcessPlatformSpecificAllocations(frontier); + FloodFillTag(frontier, kReachable); // Iterate over leaked chunks and mark those that are reachable from other // leaked chunks. @@ -521,11 +528,6 @@ static void PrintMatchedSuppressions() { Printf("%s\n\n", line); } -struct CheckForLeaksParam { - bool success; - LeakReport leak_report; -}; - static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) { const InternalMmapVector &suspended_threads = *(const InternalMmapVector *)arg; @@ -538,6 +540,14 @@ static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) { } } +#if SANITIZER_FUCHSIA + +// Fuchsia provides a libc interface that guarantees all threads are +// covered, and SuspendedThreadList is never really used. +static void ReportUnsuspendedThreads(const SuspendedThreadsList &) {} + +#else // !SANITIZER_FUCHSIA + static void ReportUnsuspendedThreads( const SuspendedThreadsList &suspended_threads) { InternalMmapVector threads(suspended_threads.ThreadCount()); @@ -550,13 +560,15 @@ static void ReportUnsuspendedThreads( &ReportIfNotSuspended, &threads); } +#endif // !SANITIZER_FUCHSIA + static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads, void *arg) { CheckForLeaksParam *param = reinterpret_cast(arg); CHECK(param); CHECK(!param->success); ReportUnsuspendedThreads(suspended_threads); - ClassifyAllChunks(suspended_threads); + ClassifyAllChunks(suspended_threads, ¶m->frontier); ForEachChunk(CollectLeaksCb, ¶m->leak_report); // Clean up for subsequent leak checks. This assumes we did not overwrite any // kIgnored tags. @@ -569,7 +581,6 @@ static bool CheckForLeaks() { return false; EnsureMainThreadIDIsCorrect(); CheckForLeaksParam param; - param.success = false; LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m); if (!param.success) { diff --git a/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h index d24abe31b71..6252d52c197 100644 --- a/libsanitizer/lsan/lsan_common.h +++ b/libsanitizer/lsan/lsan_common.h @@ -40,7 +40,7 @@ #elif defined(__arm__) && \ SANITIZER_LINUX && !SANITIZER_ANDROID #define CAN_SANITIZE_LEAKS 1 -#elif SANITIZER_NETBSD +#elif SANITIZER_NETBSD || SANITIZER_FUCHSIA #define CAN_SANITIZE_LEAKS 1 #else #define CAN_SANITIZE_LEAKS 0 @@ -126,12 +126,24 @@ struct RootRegion { uptr size; }; +// LockStuffAndStopTheWorld can start to use Scan* calls to collect into +// this Frontier vector before the StopTheWorldCallback actually runs. +// This is used when the OS has a unified callback API for suspending +// threads and enumerating roots. +struct CheckForLeaksParam { + Frontier frontier; + LeakReport leak_report; + bool success = false; +}; + InternalMmapVector const *GetRootRegions(); void ScanRootRegion(Frontier *frontier, RootRegion const ®ion, uptr region_begin, uptr region_end, bool is_readable); +void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg); // Run stoptheworld while holding any platform-specific locks, as well as the // allocator and thread registry locks. -void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void* argument); +void LockStuffAndStopTheWorld(StopTheWorldCallback callback, + CheckForLeaksParam* argument); void ScanRangeForPointers(uptr begin, uptr end, Frontier *frontier, @@ -211,6 +223,7 @@ ThreadRegistry *GetThreadRegistryLocked(); bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, uptr *tls_begin, uptr *tls_end, uptr *cache_begin, uptr *cache_end, DTLS **dtls); +void GetAllThreadAllocatorCachesLocked(InternalMmapVector *caches); void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, void *arg); // If called from the main thread, updates the main thread's TID in the thread diff --git a/libsanitizer/lsan/lsan_common_fuchsia.cpp b/libsanitizer/lsan/lsan_common_fuchsia.cpp new file mode 100644 index 00000000000..caedbf15596 --- /dev/null +++ b/libsanitizer/lsan/lsan_common_fuchsia.cpp @@ -0,0 +1,166 @@ +//=-- lsan_common_fuchsia.cpp --------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer. +// Implementation of common leak checking functionality. Fuchsia-specific code. +// +//===---------------------------------------------------------------------===// + +#include "lsan_common.h" +#include "sanitizer_common/sanitizer_platform.h" + +#if CAN_SANITIZE_LEAKS && SANITIZER_FUCHSIA +#include + +#include "lsan_allocator.h" +#include "sanitizer_common/sanitizer_flags.h" +#include "sanitizer_common/sanitizer_thread_registry.h" + +// Ensure that the Zircon system ABI is linked in. +#pragma comment(lib, "zircon") + +namespace __lsan { + +void InitializePlatformSpecificModules() {} + +LoadedModule *GetLinker() { return nullptr; } + +__attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter; +bool DisabledInThisThread() { return disable_counter > 0; } +void DisableInThisThread() { disable_counter++; } +void EnableInThisThread() { + if (disable_counter == 0) { + DisableCounterUnderflow(); + } + disable_counter--; +} + +// There is nothing left to do after the globals callbacks. +void ProcessGlobalRegions(Frontier *frontier) {} + +// Nothing to do here. +void ProcessPlatformSpecificAllocations(Frontier *frontier) {} + +// On Fuchsia, we can intercept _Exit gracefully, and return a failing exit +// code if required at that point. Calling Die() here is undefined +// behavior and causes rare race conditions. +void HandleLeaks() {} + +int ExitHook(int status) { + return status == 0 && HasReportedLeaks() ? common_flags()->exitcode : status; +} + +void LockStuffAndStopTheWorld(StopTheWorldCallback callback, + CheckForLeaksParam *argument) { + LockThreadRegistry(); + LockAllocator(); + + struct Params { + InternalMmapVector allocator_caches; + StopTheWorldCallback callback; + CheckForLeaksParam *argument; + } params = {{}, callback, argument}; + + // Callback from libc for globals (data/bss modulo relro), when enabled. + auto globals = +[](void *chunk, size_t size, void *data) { + auto params = static_cast(data); + uptr begin = reinterpret_cast(chunk); + uptr end = begin + size; + ScanGlobalRange(begin, end, ¶ms->argument->frontier); + }; + + // Callback from libc for thread stacks. + auto stacks = +[](void *chunk, size_t size, void *data) { + auto params = static_cast(data); + uptr begin = reinterpret_cast(chunk); + uptr end = begin + size; + ScanRangeForPointers(begin, end, ¶ms->argument->frontier, "STACK", + kReachable); + }; + + // Callback from libc for thread registers. + auto registers = +[](void *chunk, size_t size, void *data) { + auto params = static_cast(data); + uptr begin = reinterpret_cast(chunk); + uptr end = begin + size; + ScanRangeForPointers(begin, end, ¶ms->argument->frontier, "REGISTERS", + kReachable); + }; + + if (flags()->use_tls) { + // Collect the allocator cache range from each thread so these + // can all be excluded from the reported TLS ranges. + GetAllThreadAllocatorCachesLocked(¶ms.allocator_caches); + __sanitizer::Sort(params.allocator_caches.data(), + params.allocator_caches.size()); + } + + // Callback from libc for TLS regions. This includes thread_local + // variables as well as C11 tss_set and POSIX pthread_setspecific. + auto tls = +[](void *chunk, size_t size, void *data) { + auto params = static_cast(data); + uptr begin = reinterpret_cast(chunk); + uptr end = begin + size; + auto i = __sanitizer::InternalLowerBound(params->allocator_caches, 0, + params->allocator_caches.size(), + begin, CompareLess()); + if (i < params->allocator_caches.size() && + params->allocator_caches[i] >= begin && + end - params->allocator_caches[i] <= sizeof(AllocatorCache)) { + // Split the range in two and omit the allocator cache within. + ScanRangeForPointers(begin, params->allocator_caches[i], + ¶ms->argument->frontier, "TLS", kReachable); + uptr begin2 = params->allocator_caches[i] + sizeof(AllocatorCache); + ScanRangeForPointers(begin2, end, ¶ms->argument->frontier, "TLS", + kReachable); + } else { + ScanRangeForPointers(begin, end, ¶ms->argument->frontier, "TLS", + kReachable); + } + }; + + // This stops the world and then makes callbacks for various memory regions. + // The final callback is the last thing before the world starts up again. + __sanitizer_memory_snapshot( + flags()->use_globals ? globals : nullptr, + flags()->use_stacks ? stacks : nullptr, + flags()->use_registers ? registers : nullptr, + flags()->use_tls ? tls : nullptr, + [](zx_status_t, void *data) { + auto params = static_cast(data); + + // We don't use the thread registry at all for enumerating the threads + // and their stacks, registers, and TLS regions. So use it separately + // just for the allocator cache, and to call ForEachExtraStackRange, + // which ASan needs. + if (flags()->use_stacks) { + GetThreadRegistryLocked()->RunCallbackForEachThreadLocked( + [](ThreadContextBase *tctx, void *arg) { + ForEachExtraStackRange(tctx->os_id, ForEachExtraStackRangeCb, + arg); + }, + ¶ms->argument->frontier); + } + + params->callback({}, params->argument); + }, + ¶ms); + + UnlockAllocator(); + UnlockThreadRegistry(); +} + +} // namespace __lsan + +// This is declared (in extern "C") by . +// _Exit calls this directly to intercept and change the status value. +int __sanitizer_process_exit_hook(int status) { + return __lsan::ExitHook(status); +} + +#endif diff --git a/libsanitizer/lsan/lsan_common_linux.cpp b/libsanitizer/lsan/lsan_common_linux.cpp index ea1a4a2f569..c97ef31593d 100644 --- a/libsanitizer/lsan/lsan_common_linux.cpp +++ b/libsanitizer/lsan/lsan_common_linux.cpp @@ -134,7 +134,8 @@ static int LockStuffAndStopTheWorldCallback(struct dl_phdr_info *info, // while holding the libdl lock in the parent thread, we can safely reenter it // in the tracer. The solution is to run stoptheworld from a dl_iterate_phdr() // callback in the parent thread. -void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) { +void LockStuffAndStopTheWorld(StopTheWorldCallback callback, + CheckForLeaksParam *argument) { DoStopTheWorldParam param = {callback, argument}; dl_iterate_phdr(LockStuffAndStopTheWorldCallback, ¶m); } diff --git a/libsanitizer/lsan/lsan_common_mac.cpp b/libsanitizer/lsan/lsan_common_mac.cpp index c1804e93c11..8516a176eb4 100644 --- a/libsanitizer/lsan/lsan_common_mac.cpp +++ b/libsanitizer/lsan/lsan_common_mac.cpp @@ -193,7 +193,8 @@ void ProcessPlatformSpecificAllocations(Frontier *frontier) { // causes rare race conditions. void HandleLeaks() {} -void LockStuffAndStopTheWorld(StopTheWorldCallback callback, void *argument) { +void LockStuffAndStopTheWorld(StopTheWorldCallback callback, + CheckForLeaksParam *argument) { LockThreadRegistry(); LockAllocator(); StopTheWorld(callback, argument); diff --git a/libsanitizer/lsan/lsan_fuchsia.cpp b/libsanitizer/lsan/lsan_fuchsia.cpp new file mode 100644 index 00000000000..40e65c6fb72 --- /dev/null +++ b/libsanitizer/lsan/lsan_fuchsia.cpp @@ -0,0 +1,123 @@ +//=-- lsan_fuchsia.cpp ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer. +// Standalone LSan RTL code specific to Fuchsia. +// +//===---------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" + +#if SANITIZER_FUCHSIA +#include + +#include "lsan.h" +#include "lsan_allocator.h" + +using namespace __lsan; + +namespace __lsan { + +void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {} + +ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {} + +struct OnCreatedArgs { + uptr stack_begin, stack_end; +}; + +// On Fuchsia, the stack bounds of a new thread are available before +// the thread itself has started running. +void ThreadContext::OnCreated(void *arg) { + // Stack bounds passed through from __sanitizer_before_thread_create_hook + // or InitializeMainThread. + auto args = reinterpret_cast(arg); + stack_begin_ = args->stack_begin; + stack_end_ = args->stack_end; +} + +struct OnStartedArgs { + uptr cache_begin, cache_end; +}; + +void ThreadContext::OnStarted(void *arg) { + auto args = reinterpret_cast(arg); + cache_begin_ = args->cache_begin; + cache_end_ = args->cache_end; +} + +void ThreadStart(u32 tid) { + OnStartedArgs args; + GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); + CHECK_EQ(args.cache_end - args.cache_begin, sizeof(AllocatorCache)); + ThreadContextLsanBase::ThreadStart(tid, GetTid(), ThreadType::Regular, &args); +} + +void InitializeMainThread() { + OnCreatedArgs args; + __sanitizer::GetThreadStackTopAndBottom(true, &args.stack_end, + &args.stack_begin); + u32 tid = ThreadCreate(0, GetThreadSelf(), true, &args); + CHECK_EQ(tid, 0); + ThreadStart(tid); +} + +void GetAllThreadAllocatorCachesLocked(InternalMmapVector *caches) { + GetThreadRegistryLocked()->RunCallbackForEachThreadLocked( + [](ThreadContextBase *tctx, void *arg) { + auto ctx = static_cast(tctx); + static_cast(arg)->push_back(ctx->cache_begin()); + }, + caches); +} + +} // namespace __lsan + +// These are declared (in extern "C") by . +// The system runtime will call our definitions directly. + +// This is called before each thread creation is attempted. So, in +// its first call, the calling thread is the initial and sole thread. +void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached, + const char *name, void *stack_base, + size_t stack_size) { + uptr user_id = reinterpret_cast(thread); + ENSURE_LSAN_INITED; + EnsureMainThreadIDIsCorrect(); + OnCreatedArgs args; + args.stack_begin = reinterpret_cast(stack_base); + args.stack_end = args.stack_begin + stack_size; + u32 parent_tid = GetCurrentThread(); + u32 tid = ThreadCreate(parent_tid, user_id, detached, &args); + return reinterpret_cast(static_cast(tid)); +} + +// This is called after creating a new thread (in the creating thread), +// with the pointer returned by __sanitizer_before_thread_create_hook (above). +void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) { + u32 tid = static_cast(reinterpret_cast(hook)); + // On success, there is nothing to do here. + if (error != thrd_success) { + // Clean up the thread registry for the thread creation that didn't happen. + GetThreadRegistryLocked()->FinishThread(tid); + } +} + +// This is called in the newly-created thread before it runs anything else, +// with the pointer returned by __sanitizer_before_thread_create_hook (above). +void __sanitizer_thread_start_hook(void *hook, thrd_t self) { + u32 tid = static_cast(reinterpret_cast(hook)); + ThreadStart(tid); +} + +// Each thread runs this just before it exits, +// with the pointer returned by BeforeThreadCreateHook (above). +// All per-thread destructors have already been called. +void __sanitizer_thread_exit_hook(void *hook, thrd_t self) { ThreadFinish(); } + +#endif // SANITIZER_FUCHSIA diff --git a/libsanitizer/lsan/lsan_fuchsia.h b/libsanitizer/lsan/lsan_fuchsia.h new file mode 100644 index 00000000000..65d20ea2114 --- /dev/null +++ b/libsanitizer/lsan/lsan_fuchsia.h @@ -0,0 +1,35 @@ +//=-- lsan_fuchsia.h ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer. +// Standalone LSan RTL code specific to Fuchsia. +// +//===---------------------------------------------------------------------===// + +#ifndef LSAN_FUCHSIA_H +#define LSAN_FUCHSIA_H + +#include "lsan_thread.h" +#include "sanitizer_common/sanitizer_platform.h" + +#if !SANITIZER_FUCHSIA +#error "lsan_fuchsia.h is used only on Fuchsia systems (SANITIZER_FUCHSIA)" +#endif + +namespace __lsan { + +class ThreadContext : public ThreadContextLsanBase { + public: + explicit ThreadContext(int tid); + void OnCreated(void *arg) override; + void OnStarted(void *arg) override; +}; + +} // namespace __lsan + +#endif // LSAN_FUCHSIA_H diff --git a/libsanitizer/lsan/lsan_interceptors.cpp b/libsanitizer/lsan/lsan_interceptors.cpp index f642bb807bc..9ce9b78c5a5 100644 --- a/libsanitizer/lsan/lsan_interceptors.cpp +++ b/libsanitizer/lsan/lsan_interceptors.cpp @@ -22,7 +22,9 @@ #include "sanitizer_common/sanitizer_platform_interceptors.h" #include "sanitizer_common/sanitizer_platform_limits_netbsd.h" #include "sanitizer_common/sanitizer_platform_limits_posix.h" +#if SANITIZER_POSIX #include "sanitizer_common/sanitizer_posix.h" +#endif #include "sanitizer_common/sanitizer_tls_get_addr.h" #include "lsan.h" #include "lsan_allocator.h" @@ -61,6 +63,9 @@ INTERCEPTOR(void, free, void *p) { } INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { + // This hack is not required for Fuchsia because there are no dlsym calls + // involved in setting up interceptors. +#if !SANITIZER_FUCHSIA if (lsan_init_is_running) { // Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym. const uptr kCallocPoolSize = 1024; @@ -72,6 +77,7 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) { CHECK(allocated < kCallocPoolSize); return mem; } +#endif // !SANITIZER_FUCHSIA ENSURE_LSAN_INITED; GET_STACK_TRACE_MALLOC; return lsan_calloc(nmemb, size, stack); @@ -100,7 +106,7 @@ INTERCEPTOR(void*, valloc, uptr size) { GET_STACK_TRACE_MALLOC; return lsan_valloc(size, stack); } -#endif +#endif // !SANITIZER_MAC #if SANITIZER_INTERCEPT_MEMALIGN INTERCEPTOR(void*, memalign, uptr alignment, uptr size) { @@ -307,7 +313,7 @@ INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&) ///// Thread initialization and finalization. ///// -#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD +#if !SANITIZER_NETBSD && !SANITIZER_FREEBSD && !SANITIZER_FUCHSIA static unsigned g_thread_finalize_key; static void thread_finalize(void *v) { @@ -394,6 +400,8 @@ INTERCEPTOR(char *, strerror, int errnum) { #define LSAN_MAYBE_INTERCEPT_STRERROR #endif +#if SANITIZER_POSIX + struct ThreadParam { void *(*callback)(void *arg); void *param; @@ -416,7 +424,6 @@ extern "C" void *__lsan_thread_start_func(void *arg) { int tid = 0; while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0) internal_sched_yield(); - SetCurrentThread(tid); ThreadStart(tid, GetTid()); atomic_store(&p->tid, 0, memory_order_release); return callback(param); @@ -477,9 +484,13 @@ INTERCEPTOR(void, _exit, int status) { #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) #include "sanitizer_common/sanitizer_signal_interceptors.inc" +#endif // SANITIZER_POSIX + namespace __lsan { void InitializeInterceptors() { + // Fuchsia doesn't use interceptors that require any setup. +#if !SANITIZER_FUCHSIA InitializeSignalInterceptors(); INTERCEPT_FUNCTION(malloc); @@ -515,6 +526,8 @@ void InitializeInterceptors() { Die(); } #endif + +#endif // !SANITIZER_FUCHSIA } } // namespace __lsan diff --git a/libsanitizer/lsan/lsan_linux.cpp b/libsanitizer/lsan/lsan_linux.cpp index 14a42b75d2a..47c2f21b5a6 100644 --- a/libsanitizer/lsan/lsan_linux.cpp +++ b/libsanitizer/lsan/lsan_linux.cpp @@ -6,13 +6,13 @@ // //===----------------------------------------------------------------------===// // -// This file is a part of LeakSanitizer. Linux/NetBSD-specific code. +// This file is a part of LeakSanitizer. Linux/NetBSD/Fuchsia-specific code. // //===----------------------------------------------------------------------===// #include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_LINUX || SANITIZER_NETBSD +#if SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA #include "lsan_allocator.h" @@ -29,4 +29,4 @@ void ReplaceSystemMalloc() {} } // namespace __lsan -#endif // SANITIZER_LINUX || SANITIZER_NETBSD +#endif // SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA diff --git a/libsanitizer/lsan/lsan_posix.cpp b/libsanitizer/lsan/lsan_posix.cpp new file mode 100644 index 00000000000..8e05915dd1b --- /dev/null +++ b/libsanitizer/lsan/lsan_posix.cpp @@ -0,0 +1,96 @@ +//=-- lsan_posix.cpp -----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer. +// Standalone LSan RTL code common to POSIX-like systems. +// +//===---------------------------------------------------------------------===// + +#include "sanitizer_common/sanitizer_platform.h" + +#if SANITIZER_POSIX +#include "lsan.h" +#include "lsan_allocator.h" +#include "sanitizer_common/sanitizer_stacktrace.h" +#include "sanitizer_common/sanitizer_tls_get_addr.h" + +namespace __lsan { + +ThreadContext::ThreadContext(int tid) : ThreadContextLsanBase(tid) {} + +struct OnStartedArgs { + uptr stack_begin; + uptr stack_end; + uptr cache_begin; + uptr cache_end; + uptr tls_begin; + uptr tls_end; + DTLS *dtls; +}; + +void ThreadContext::OnStarted(void *arg) { + auto args = reinterpret_cast(arg); + stack_begin_ = args->stack_begin; + stack_end_ = args->stack_end; + tls_begin_ = args->tls_begin; + tls_end_ = args->tls_end; + cache_begin_ = args->cache_begin; + cache_end_ = args->cache_end; + dtls_ = args->dtls; +} + +void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) { + OnStartedArgs args; + uptr stack_size = 0; + uptr tls_size = 0; + GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size, + &args.tls_begin, &tls_size); + args.stack_end = args.stack_begin + stack_size; + args.tls_end = args.tls_begin + tls_size; + GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); + args.dtls = DTLS_Get(); + ThreadContextLsanBase::ThreadStart(tid, os_id, thread_type, &args); +} + +bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, + uptr *tls_begin, uptr *tls_end, uptr *cache_begin, + uptr *cache_end, DTLS **dtls) { + ThreadContext *context = static_cast( + GetThreadRegistryLocked()->FindThreadContextByOsIDLocked(os_id)); + if (!context) + return false; + *stack_begin = context->stack_begin(); + *stack_end = context->stack_end(); + *tls_begin = context->tls_begin(); + *tls_end = context->tls_end(); + *cache_begin = context->cache_begin(); + *cache_end = context->cache_end(); + *dtls = context->dtls(); + return true; +} + +void InitializeMainThread() { + u32 tid = ThreadCreate(0, 0, true); + CHECK_EQ(tid, 0); + ThreadStart(tid, GetTid()); +} + +static void OnStackUnwind(const SignalContext &sig, const void *, + BufferedStackTrace *stack) { + stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context, + common_flags()->fast_unwind_on_fatal); +} + +void LsanOnDeadlySignal(int signo, void *siginfo, void *context) { + HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind, + nullptr); +} + +} // namespace __lsan + +#endif // SANITIZER_POSIX diff --git a/libsanitizer/lsan/lsan_posix.h b/libsanitizer/lsan/lsan_posix.h new file mode 100644 index 00000000000..840e427c55e --- /dev/null +++ b/libsanitizer/lsan/lsan_posix.h @@ -0,0 +1,49 @@ +//=-- lsan_posix.h -----------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// This file is a part of LeakSanitizer. +// Standalone LSan RTL code common to POSIX-like systems. +// +//===---------------------------------------------------------------------===// + +#ifndef LSAN_POSIX_H +#define LSAN_POSIX_H + +#include "lsan_thread.h" +#include "sanitizer_common/sanitizer_platform.h" + +#if !SANITIZER_POSIX +#error "lsan_posix.h is used only on POSIX-like systems (SANITIZER_POSIX)" +#endif + +namespace __sanitizer { +struct DTLS; +} + +namespace __lsan { + +class ThreadContext : public ThreadContextLsanBase { + public: + explicit ThreadContext(int tid); + void OnStarted(void *arg) override; + uptr tls_begin() { return tls_begin_; } + uptr tls_end() { return tls_end_; } + DTLS *dtls() { return dtls_; } + + private: + uptr tls_begin_ = 0; + uptr tls_end_ = 0; + DTLS *dtls_ = nullptr; +}; + +void ThreadStart(u32 tid, tid_t os_id, + ThreadType thread_type = ThreadType::Regular); + +} // namespace __lsan + +#endif // LSAN_POSIX_H diff --git a/libsanitizer/lsan/lsan_thread.cpp b/libsanitizer/lsan/lsan_thread.cpp index 84e7ce61b97..40bdc254bb6 100644 --- a/libsanitizer/lsan/lsan_thread.cpp +++ b/libsanitizer/lsan/lsan_thread.cpp @@ -13,12 +13,13 @@ #include "lsan_thread.h" +#include "lsan.h" +#include "lsan_allocator.h" +#include "lsan_common.h" #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_thread_registry.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" -#include "lsan_allocator.h" -#include "lsan_common.h" namespace __lsan { @@ -26,7 +27,7 @@ static ThreadRegistry *thread_registry; static ThreadContextBase *CreateThreadContext(u32 tid) { void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext"); - return new(mem) ThreadContext(tid); + return new (mem) ThreadContext(tid); } static const uptr kMaxThreads = 1 << 13; @@ -34,59 +35,26 @@ static const uptr kThreadQuarantineSize = 64; void InitializeThreadRegistry() { static ALIGNED(64) char thread_registry_placeholder[sizeof(ThreadRegistry)]; - thread_registry = new(thread_registry_placeholder) - ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize); + thread_registry = new (thread_registry_placeholder) + ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize); } -ThreadContext::ThreadContext(int tid) - : ThreadContextBase(tid), - stack_begin_(0), - stack_end_(0), - cache_begin_(0), - cache_end_(0), - tls_begin_(0), - tls_end_(0), - dtls_(nullptr) {} - -struct OnStartedArgs { - uptr stack_begin, stack_end, - cache_begin, cache_end, - tls_begin, tls_end; - DTLS *dtls; -}; - -void ThreadContext::OnStarted(void *arg) { - OnStartedArgs *args = reinterpret_cast(arg); - stack_begin_ = args->stack_begin; - stack_end_ = args->stack_end; - tls_begin_ = args->tls_begin; - tls_end_ = args->tls_end; - cache_begin_ = args->cache_begin; - cache_end_ = args->cache_end; - dtls_ = args->dtls; -} +ThreadContextLsanBase::ThreadContextLsanBase(int tid) + : ThreadContextBase(tid) {} -void ThreadContext::OnFinished() { +void ThreadContextLsanBase::OnFinished() { AllocatorThreadFinish(); DTLS_Destroy(); } -u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) { - return thread_registry->CreateThread(user_id, detached, parent_tid, - /* arg */ nullptr); +u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached, void *arg) { + return thread_registry->CreateThread(user_id, detached, parent_tid, arg); } -void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) { - OnStartedArgs args; - uptr stack_size = 0; - uptr tls_size = 0; - GetThreadStackAndTls(tid == 0, &args.stack_begin, &stack_size, - &args.tls_begin, &tls_size); - args.stack_end = args.stack_begin + stack_size; - args.tls_end = args.tls_begin + tls_size; - GetAllocatorCacheRange(&args.cache_begin, &args.cache_end); - args.dtls = DTLS_Get(); - thread_registry->StartThread(tid, os_id, thread_type, &args); +void ThreadContextLsanBase::ThreadStart(u32 tid, tid_t os_id, + ThreadType thread_type, void *arg) { + thread_registry->StartThread(tid, os_id, thread_type, arg); + SetCurrentThread(tid); } void ThreadFinish() { @@ -95,7 +63,8 @@ void ThreadFinish() { } ThreadContext *CurrentThreadContext() { - if (!thread_registry) return nullptr; + if (!thread_registry) + return nullptr; if (GetCurrentThread() == kInvalidTid) return nullptr; // No lock needed when getting current thread. @@ -111,12 +80,12 @@ static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) { } u32 ThreadTid(uptr uid) { - return thread_registry->FindThread(FindThreadByUid, (void*)uid); + return thread_registry->FindThread(FindThreadByUid, (void *)uid); } void ThreadJoin(u32 tid) { CHECK_NE(tid, kInvalidTid); - thread_registry->JoinThread(tid, /* arg */nullptr); + thread_registry->JoinThread(tid, /* arg */ nullptr); } void EnsureMainThreadIDIsCorrect() { @@ -126,37 +95,16 @@ void EnsureMainThreadIDIsCorrect() { ///// Interface to the common LSan module. ///// -bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, - uptr *tls_begin, uptr *tls_end, uptr *cache_begin, - uptr *cache_end, DTLS **dtls) { - ThreadContext *context = static_cast( - thread_registry->FindThreadContextByOsIDLocked(os_id)); - if (!context) return false; - *stack_begin = context->stack_begin(); - *stack_end = context->stack_end(); - *tls_begin = context->tls_begin(); - *tls_end = context->tls_end(); - *cache_begin = context->cache_begin(); - *cache_end = context->cache_end(); - *dtls = context->dtls(); - return true; -} - void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, - void *arg) { -} + void *arg) {} -void LockThreadRegistry() { - thread_registry->Lock(); -} +void LockThreadRegistry() { thread_registry->Lock(); } -void UnlockThreadRegistry() { - thread_registry->Unlock(); -} +void UnlockThreadRegistry() { thread_registry->Unlock(); } ThreadRegistry *GetThreadRegistryLocked() { thread_registry->CheckLocked(); return thread_registry; } -} // namespace __lsan +} // namespace __lsan diff --git a/libsanitizer/lsan/lsan_thread.h b/libsanitizer/lsan/lsan_thread.h index b869d066d9d..0ab1582de66 100644 --- a/libsanitizer/lsan/lsan_thread.h +++ b/libsanitizer/lsan/lsan_thread.h @@ -16,38 +16,36 @@ #include "sanitizer_common/sanitizer_thread_registry.h" -namespace __sanitizer { -struct DTLS; -} - namespace __lsan { -class ThreadContext : public ThreadContextBase { +class ThreadContextLsanBase : public ThreadContextBase { public: - explicit ThreadContext(int tid); - void OnStarted(void *arg) override; + explicit ThreadContextLsanBase(int tid); void OnFinished() override; uptr stack_begin() { return stack_begin_; } uptr stack_end() { return stack_end_; } - uptr tls_begin() { return tls_begin_; } - uptr tls_end() { return tls_end_; } uptr cache_begin() { return cache_begin_; } uptr cache_end() { return cache_end_; } - DTLS *dtls() { return dtls_; } - private: - uptr stack_begin_, stack_end_, - cache_begin_, cache_end_, - tls_begin_, tls_end_; - DTLS *dtls_; + // The argument is passed on to the subclass's OnStarted member function. + static void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type, + void *onstarted_arg); + + protected: + uptr stack_begin_ = 0; + uptr stack_end_ = 0; + uptr cache_begin_ = 0; + uptr cache_end_ = 0; }; +// This subclass of ThreadContextLsanBase is declared in an OS-specific header. +class ThreadContext; + void InitializeThreadRegistry(); +void InitializeMainThread(); -void ThreadStart(u32 tid, tid_t os_id, - ThreadType thread_type = ThreadType::Regular); +u32 ThreadCreate(u32 tid, uptr uid, bool detached, void *arg = nullptr); void ThreadFinish(); -u32 ThreadCreate(u32 tid, uptr uid, bool detached); void ThreadJoin(u32 tid); u32 ThreadTid(uptr uid); @@ -55,6 +53,7 @@ u32 GetCurrentThread(); void SetCurrentThread(u32 tid); ThreadContext *CurrentThreadContext(); void EnsureMainThreadIDIsCorrect(); + } // namespace __lsan #endif // LSAN_THREAD_H diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.cpp b/libsanitizer/sanitizer_common/sanitizer_allocator.cpp index 8d07906cca0..ec77b9cbfee 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_allocator.cpp @@ -25,7 +25,7 @@ const char *PrimaryAllocatorName = "SizeClassAllocator"; const char *SecondaryAllocatorName = "LargeMmapAllocator"; // ThreadSanitizer for Go uses libc malloc/free. -#if SANITIZER_GO || defined(SANITIZER_USE_MALLOC) +#if defined(SANITIZER_USE_MALLOC) # if SANITIZER_LINUX && !SANITIZER_ANDROID extern "C" void *__libc_malloc(uptr size); # if !SANITIZER_GO @@ -213,7 +213,7 @@ void *LowLevelAllocator::Allocate(uptr size) { // Align allocation size. size = RoundUpTo(size, low_level_alloc_min_alignment); if (allocated_end_ - allocated_current_ < (sptr)size) { - uptr size_to_allocate = Max(size, GetPageSizeCached()); + uptr size_to_allocate = RoundUpTo(size, GetPageSizeCached()); allocated_current_ = (char*)MmapOrDie(size_to_allocate, __func__); allocated_end_ = allocated_current_ + size_to_allocate; diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h index 90603280e7c..1d9a29c70f3 100644 --- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h @@ -72,11 +72,15 @@ class SizeClassAllocator64 { void Init(s32 release_to_os_interval_ms) { uptr TotalSpaceSize = kSpaceSize + AdditionalSize(); if (kUsingConstantSpaceBeg) { + CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize)); CHECK_EQ(kSpaceBeg, address_range.Init(TotalSpaceSize, PrimaryAllocatorName, kSpaceBeg)); } else { - NonConstSpaceBeg = address_range.Init(TotalSpaceSize, - PrimaryAllocatorName); + // Combined allocator expects that an 2^N allocation is always aligned to + // 2^N. For this to work, the start of the space needs to be aligned as + // high as the largest size class (which also needs to be a power of 2). + NonConstSpaceBeg = address_range.InitAligned( + TotalSpaceSize, SizeClassMap::kMaxSize, PrimaryAllocatorName); CHECK_NE(NonConstSpaceBeg, ~(uptr)0); } SetReleaseToOSIntervalMs(release_to_os_interval_ms); @@ -220,7 +224,7 @@ class SizeClassAllocator64 { // Test-only. void TestOnlyUnmap() { - UnmapWithCallbackOrDie(SpaceBeg(), kSpaceSize + AdditionalSize()); + UnmapWithCallbackOrDie((uptr)address_range.base(), address_range.size()); } static void FillMemoryProfile(uptr start, uptr rss, bool file, uptr *stats, diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cpp b/libsanitizer/sanitizer_common/sanitizer_common.cpp index f5f9f49d8cf..87efda5bd37 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_common.cpp @@ -274,6 +274,7 @@ uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) { return name_len; } +#if !SANITIZER_GO void PrintCmdline() { char **argv = GetArgv(); if (!argv) return; @@ -282,6 +283,7 @@ void PrintCmdline() { Printf("%s ", argv[i]); Printf("\n\n"); } +#endif // Malloc hooks. static const int kMaxMallocFreeHooks = 5; diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h index 87b8f02b5b7..ac16e0e47ef 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common.h +++ b/libsanitizer/sanitizer_common/sanitizer_common.h @@ -143,6 +143,7 @@ void RunFreeHooks(const void *ptr); class ReservedAddressRange { public: uptr Init(uptr size, const char *name = nullptr, uptr fixed_addr = 0); + uptr InitAligned(uptr size, uptr align, const char *name = nullptr); uptr Map(uptr fixed_addr, uptr size, const char *name = nullptr); uptr MapOrDie(uptr fixed_addr, uptr size, const char *name = nullptr); void Unmap(uptr addr, uptr size); @@ -552,7 +553,7 @@ bool operator!=(const InternalMmapVectorNoCtor &lhs, template class InternalMmapVector : public InternalMmapVectorNoCtor { public: - InternalMmapVector() { InternalMmapVectorNoCtor::Initialize(1); } + InternalMmapVector() { InternalMmapVectorNoCtor::Initialize(0); } explicit InternalMmapVector(uptr cnt) { InternalMmapVectorNoCtor::Initialize(cnt); this->resize(cnt); @@ -855,7 +856,7 @@ INLINE uptr GetPthreadDestructorIterations() { #endif } -void *internal_start_thread(void(*func)(void*), void *arg); +void *internal_start_thread(void *(*func)(void*), void *arg); void internal_join_thread(void *th); void MaybeStartBackgroudThread(); diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc index 50e3558b52e..57f8b2d2944 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc @@ -79,13 +79,15 @@ #define devname __devname50 #define fgetpos __fgetpos50 #define fsetpos __fsetpos50 +#define fstatvfs __fstatvfs90 +#define fstatvfs1 __fstatvfs190 #define fts_children __fts_children60 #define fts_close __fts_close60 #define fts_open __fts_open60 #define fts_read __fts_read60 #define fts_set __fts_set60 #define getitimer __getitimer50 -#define getmntinfo __getmntinfo13 +#define getmntinfo __getmntinfo90 #define getpwent __getpwent50 #define getpwnam __getpwnam50 #define getpwnam_r __getpwnam_r50 @@ -95,6 +97,7 @@ #define getutxent __getutxent50 #define getutxid __getutxid50 #define getutxline __getutxline50 +#define getvfsstat __getvfsstat90 #define pututxline __pututxline50 #define glob __glob30 #define gmtime __gmtime50 @@ -110,12 +113,15 @@ #define setitimer __setitimer50 #define setlocale __setlocale50 #define shmctl __shmctl50 +#define sigaltstack __sigaltstack14 #define sigemptyset __sigemptyset14 #define sigfillset __sigfillset14 #define sigpending __sigpending14 #define sigprocmask __sigprocmask14 #define sigtimedwait __sigtimedwait50 #define stat __stat50 +#define statvfs __statvfs90 +#define statvfs1 __statvfs190 #define time __time50 #define times __times13 #define unvis __unvis50 @@ -128,11 +134,7 @@ extern const short *_tolower_tab_; // Platform-specific options. #if SANITIZER_MAC -namespace __sanitizer { -bool PlatformHasDifferentMemcpyAndMemmove(); -} -#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \ - (__sanitizer::PlatformHasDifferentMemcpyAndMemmove()) +#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false #elif SANITIZER_WINDOWS64 #define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false #else @@ -4177,11 +4179,27 @@ INTERCEPTOR(int, pthread_mutex_unlock, void *m) { #if SANITIZER_INTERCEPT___PTHREAD_MUTEX INTERCEPTOR(int, __pthread_mutex_lock, void *m) { - return WRAP(pthread_mutex_lock)(m); + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __pthread_mutex_lock, m); + COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m); + int res = REAL(__pthread_mutex_lock)(m); + if (res == errno_EOWNERDEAD) + COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m); + if (res == 0 || res == errno_EOWNERDEAD) + COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m); + if (res == errno_EINVAL) + COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m); + return res; } INTERCEPTOR(int, __pthread_mutex_unlock, void *m) { - return WRAP(pthread_mutex_unlock)(m); + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __pthread_mutex_unlock, m); + COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m); + int res = REAL(__pthread_mutex_unlock)(m); + if (res == errno_EINVAL) + COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m); + return res; } #define INIT___PTHREAD_MUTEX_LOCK \ @@ -6411,12 +6429,11 @@ INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags, if (srcaddr) srcaddr_sz = *addrlen; (void)srcaddr_sz; // prevent "set but not used" warning SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen); - if (res > 0) { + if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, Min((SIZE_T)res, len)); - if (srcaddr) - COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr, - Min((SIZE_T)*addrlen, srcaddr_sz)); - } + if (res >= 0 && srcaddr) + COMMON_INTERCEPTOR_INITIALIZE_RANGE(srcaddr, + Min((SIZE_T)*addrlen, srcaddr_sz)); return res; } #define INIT_RECV_RECVFROM \ @@ -9623,6 +9640,148 @@ INTERCEPTOR(int, getentropy, void *buf, SIZE_T buflen) { #define INIT_GETENTROPY #endif +#if SANITIZER_INTERCEPT_QSORT +// Glibc qsort uses a temporary buffer allocated either on stack or on heap. +// Poisoned memory from there may get copied into the comparator arguments, +// where it needs to be dealt with. But even that is not enough - the results of +// the sort may be copied into the input/output array based on the results of +// the comparator calls, but directly from the temp memory, bypassing the +// unpoisoning done in wrapped_qsort_compar. We deal with this by, again, +// unpoisoning the entire array after the sort is done. +// +// We can not check that the entire array is initialized at the beginning. IMHO, +// it's fine for parts of the sorted objects to contain uninitialized memory, +// ex. as padding in structs. +typedef int (*qsort_compar_f)(const void *, const void *); +static THREADLOCAL qsort_compar_f qsort_compar; +static THREADLOCAL SIZE_T qsort_size; +int wrapped_qsort_compar(const void *a, const void *b) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(2); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, qsort_size); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, qsort_size); + return qsort_compar(a, b); +} + +INTERCEPTOR(void, qsort, void *base, SIZE_T nmemb, SIZE_T size, + qsort_compar_f compar) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, qsort, base, nmemb, size, compar); + // Run the comparator over all array elements to detect any memory issues. + if (nmemb > 1) { + for (SIZE_T i = 0; i < nmemb - 1; ++i) { + void *p = (void *)((char *)base + i * size); + void *q = (void *)((char *)base + (i + 1) * size); + COMMON_INTERCEPTOR_UNPOISON_PARAM(2); + compar(p, q); + } + } + qsort_compar_f old_compar = qsort_compar; + qsort_compar = compar; + SIZE_T old_size = qsort_size; + qsort_size = size; + REAL(qsort)(base, nmemb, size, wrapped_qsort_compar); + qsort_compar = old_compar; + qsort_size = old_size; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size); +} +#define INIT_QSORT COMMON_INTERCEPT_FUNCTION(qsort) +#else +#define INIT_QSORT +#endif + +#if SANITIZER_INTERCEPT_QSORT_R +typedef int (*qsort_r_compar_f)(const void *, const void *, void *); +static THREADLOCAL qsort_r_compar_f qsort_r_compar; +static THREADLOCAL SIZE_T qsort_r_size; +int wrapped_qsort_r_compar(const void *a, const void *b, void *arg) { + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(a, qsort_r_size); + COMMON_INTERCEPTOR_INITIALIZE_RANGE(b, qsort_r_size); + return qsort_r_compar(a, b, arg); +} + +INTERCEPTOR(void, qsort_r, void *base, SIZE_T nmemb, SIZE_T size, + qsort_r_compar_f compar, void *arg) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, qsort_r, base, nmemb, size, compar, arg); + // Run the comparator over all array elements to detect any memory issues. + if (nmemb > 1) { + for (SIZE_T i = 0; i < nmemb - 1; ++i) { + void *p = (void *)((char *)base + i * size); + void *q = (void *)((char *)base + (i + 1) * size); + COMMON_INTERCEPTOR_UNPOISON_PARAM(3); + compar(p, q, arg); + } + } + qsort_r_compar_f old_compar = qsort_r_compar; + qsort_r_compar = compar; + SIZE_T old_size = qsort_r_size; + qsort_r_size = size; + REAL(qsort_r)(base, nmemb, size, wrapped_qsort_r_compar, arg); + qsort_r_compar = old_compar; + qsort_r_size = old_size; + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, base, nmemb * size); +} +#define INIT_QSORT_R COMMON_INTERCEPT_FUNCTION(qsort_r) +#else +#define INIT_QSORT_R +#endif + +#if SANITIZER_INTERCEPT_SIGALTSTACK +INTERCEPTOR(int, sigaltstack, void *ss, void *oss) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, sigaltstack, ss, oss); + int r = REAL(sigaltstack)(ss, oss); + if (r == 0 && oss != nullptr) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oss, struct_stack_t_sz); + } + return r; +} +#define INIT_SIGALTSTACK COMMON_INTERCEPT_FUNCTION(sigaltstack) +#else +#define INIT_SIGALTSTACK +#endif + +#if SANITIZER_INTERCEPT_UNAME +INTERCEPTOR(int, uname, struct utsname *utsname) { +#if SANITIZER_LINUX + if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) + return internal_uname(utsname); +#endif + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, uname, utsname); + int res = REAL(uname)(utsname); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname, + __sanitizer::struct_utsname_sz); + return res; +} +#define INIT_UNAME COMMON_INTERCEPT_FUNCTION(uname) +#else +#define INIT_UNAME +#endif + +#if SANITIZER_INTERCEPT___XUNAME +// FreeBSD's define uname() as +// static __inline int uname(struct utsname *name) { +// return __xuname(SYS_NMLN, (void*)name); +// } +INTERCEPTOR(int, __xuname, int size, void *utsname) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __xuname, size, utsname); + int res = REAL(__xuname)(size, utsname); + if (!res) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, utsname, + __sanitizer::struct_utsname_sz); + return res; +} +#define INIT___XUNAME COMMON_INTERCEPT_FUNCTION(__xuname) +#else +#define INIT___XUNAME +#endif + +#include "sanitizer_common_interceptors_netbsd_compat.inc" + static void InitializeCommonInterceptors() { #if SI_POSIX static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1]; @@ -9924,6 +10083,11 @@ static void InitializeCommonInterceptors() { INIT_CRYPT; INIT_CRYPT_R; INIT_GETENTROPY; + INIT_QSORT; + INIT_QSORT_R; + INIT_SIGALTSTACK; + INIT_UNAME; + INIT___XUNAME; INIT___PRINTF_CHK; } diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc new file mode 100644 index 00000000000..6aa73ec8c6a --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc @@ -0,0 +1,128 @@ +//===-- sanitizer_common_interceptors_netbsd_compat.inc ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Common function interceptors for tools like AddressSanitizer, +// ThreadSanitizer, MemorySanitizer, etc. +// +// Interceptors for NetBSD old function calls that have been versioned. +// +// NetBSD minimal version supported 9.0. +// NetBSD current version supported 9.99.26. +// +//===----------------------------------------------------------------------===// + +#if SANITIZER_NETBSD + +// First undef all mangled symbols. +// Next, define compat interceptors. +// Finally, undef INIT_ and redefine it. +// This allows to avoid preprocessor issues. + +#undef fstatvfs +#undef fstatvfs1 +#undef getmntinfo +#undef getvfsstat +#undef statvfs +#undef statvfs1 + +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://github.com/google/sanitizers/issues/321. + int res = REAL(statvfs)(path, buf); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz); + return res; +} + +INTERCEPTOR(int, fstatvfs, int fd, void *buf) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + // FIXME: under ASan the call below may write to freed memory and corrupt + // its metadata. See + // https://github.com/google/sanitizers/issues/321. + int res = REAL(fstatvfs)(fd, buf); + if (!res) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz); + if (fd >= 0) + COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + } + return res; +} + +#undef INIT_STATVFS +#define INIT_STATVFS \ + COMMON_INTERCEPT_FUNCTION(statvfs); \ + COMMON_INTERCEPT_FUNCTION(fstatvfs); \ + COMMON_INTERCEPT_FUNCTION(__statvfs90); \ + COMMON_INTERCEPT_FUNCTION(__fstatvfs90) + +INTERCEPTOR(int, __getmntinfo13, void **mntbufp, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, __getmntinfo13, mntbufp, flags); + int cnt = REAL(__getmntinfo13)(mntbufp, flags); + if (cnt > 0 && mntbufp) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mntbufp, sizeof(void *)); + if (*mntbufp) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *mntbufp, cnt * struct_statvfs90_sz); + } + return cnt; +} + +#undef INIT_GETMNTINFO +#define INIT_GETMNTINFO \ + COMMON_INTERCEPT_FUNCTION(__getmntinfo13); \ + COMMON_INTERCEPT_FUNCTION(__getmntinfo90) + +INTERCEPTOR(int, getvfsstat, void *buf, SIZE_T bufsize, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, getvfsstat, buf, bufsize, flags); + int ret = REAL(getvfsstat)(buf, bufsize, flags); + if (buf && ret > 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, ret * struct_statvfs90_sz); + return ret; +} + +#undef INIT_GETVFSSTAT +#define INIT_GETVFSSTAT \ + COMMON_INTERCEPT_FUNCTION(getvfsstat); \ + COMMON_INTERCEPT_FUNCTION(__getvfsstat90) + +INTERCEPTOR(int, statvfs1, const char *path, void *buf, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, statvfs1, path, buf, flags); + if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1); + int res = REAL(statvfs1)(path, buf, flags); + if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz); + return res; +} + +INTERCEPTOR(int, fstatvfs1, int fd, void *buf, int flags) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs1, fd, buf, flags); + COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd); + int res = REAL(fstatvfs1)(fd, buf, flags); + if (!res) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs90_sz); + if (fd >= 0) + COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd); + } + return res; +} + +#undef INIT_STATVFS1 +#define INIT_STATVFS1 \ + COMMON_INTERCEPT_FUNCTION(statvfs1); \ + COMMON_INTERCEPT_FUNCTION(fstatvfs1); \ + COMMON_INTERCEPT_FUNCTION(__statvfs190); \ + COMMON_INTERCEPT_FUNCTION(__fstatvfs190) + +#endif diff --git a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp index 27d6a177760..0c918ebb4a9 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp @@ -30,7 +30,7 @@ SANITIZER_WEAK_ATTRIBUTE StackDepotStats *StackDepotGetStats() { return nullptr; } -void BackgroundThread(void *arg) { +void *BackgroundThread(void *arg) { const uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb; const uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb; const bool heap_profile = common_flags()->heap_profile; @@ -129,6 +129,16 @@ void SetSandboxingCallback(void (*f)()) { sandboxing_callback = f; } +uptr ReservedAddressRange::InitAligned(uptr size, uptr align, + const char *name) { + CHECK(IsPowerOfTwo(align)); + if (align <= GetPageSizeCached()) + return Init(size, name); + uptr start = Init(size + align, name); + start += align - (start & (align - 1)); + return start; +} + } // namespace __sanitizer SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify, diff --git a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc index 31ff48cfd2c..532ac9ead34 100644 --- a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc +++ b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc @@ -2885,6 +2885,23 @@ POST_SYSCALL(getrandom)(long res, void *buf, uptr count, long flags) { POST_WRITE(buf, res); } } + +PRE_SYSCALL(sigaltstack)(const void *ss, void *oss) { + if (ss != nullptr) { + PRE_READ(ss, struct_stack_t_sz); + } + if (oss != nullptr) { + PRE_WRITE(oss, struct_stack_t_sz); + } +} + +POST_SYSCALL(sigaltstack)(long res, void *ss, void *oss) { + if (res == 0) { + if (oss != nullptr) { + POST_WRITE(oss, struct_stack_t_sz); + } + } +} } // extern "C" #undef PRE_SYSCALL diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp index f18cee66b84..a52db08433e 100644 --- a/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp @@ -27,15 +27,15 @@ #include "sanitizer_platform.h" #if SANITIZER_FUCHSIA +#include +#include +#include + #include "sanitizer_atomic.h" #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" #include "sanitizer_symbolizer_fuchsia.h" -#include -#include -#include - using namespace __sanitizer; namespace __sancov { @@ -82,7 +82,8 @@ class TracePcGuardController final { void TracePcGuard(u32 *guard, uptr pc) { atomic_uint32_t *guard_ptr = reinterpret_cast(guard); u32 idx = atomic_exchange(guard_ptr, 0, memory_order_relaxed); - if (idx > 0) array_[idx] = pc; + if (idx > 0) + array_[idx] = pc; } void Dump() { @@ -140,6 +141,10 @@ class TracePcGuardController final { internal_getpid()); _zx_object_set_property(vmo_, ZX_PROP_NAME, vmo_name_, internal_strlen(vmo_name_)); + uint64_t size = DataSize(); + status = _zx_object_set_property(vmo_, ZX_PROP_VMO_CONTENT_SIZE, &size, + sizeof(size)); + CHECK_EQ(status, ZX_OK); // Map the largest possible view we might need into the VMO. Later // we might need to increase the VMO's size before we can use larger @@ -172,6 +177,10 @@ class TracePcGuardController final { zx_status_t status = _zx_vmo_set_size(vmo_, DataSize()); CHECK_EQ(status, ZX_OK); + uint64_t size = DataSize(); + status = _zx_object_set_property(vmo_, ZX_PROP_VMO_CONTENT_SIZE, &size, + sizeof(size)); + CHECK_EQ(status, ZX_OK); return first_index; } @@ -204,13 +213,15 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage(const uptr *pcs, } SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *guard) { - if (!*guard) return; + if (!*guard) + return; __sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1); } SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *start, u32 *end) { - if (start == end || *start) return; + if (start == end || *start) + return; __sancov::pc_guard_controller.InitTracePcGuard(start, end); } diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc b/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc index 7beeff7e8af..d7ab0c3d98c 100644 --- a/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc +++ b/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc @@ -29,4 +29,5 @@ INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_guard_init) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_indir) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_switch) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_8bit_counters_init) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_bool_flag_init) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_pcs_init) diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp index 6a75792f926..73ebeb5fa14 100644 --- a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp @@ -207,6 +207,7 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_bool_flag_init, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {} } // extern "C" // Weak definition for code instrumented with -fsanitize-coverage=stack-depth diff --git a/libsanitizer/sanitizer_common/sanitizer_file.h b/libsanitizer/sanitizer_common/sanitizer_file.h index 4a78a0e0ac8..26681f0493d 100644 --- a/libsanitizer/sanitizer_common/sanitizer_file.h +++ b/libsanitizer/sanitizer_common/sanitizer_file.h @@ -87,8 +87,8 @@ bool IsAbsolutePath(const char *path); // The child process will close all fds after STDERR_FILENO // before passing control to a program. pid_t StartSubprocess(const char *filename, const char *const argv[], - fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd, - fd_t stderr_fd = kInvalidFd); + const char *const envp[], fd_t stdin_fd = kInvalidFd, + fd_t stdout_fd = kInvalidFd, fd_t stderr_fd = kInvalidFd); // Checks if specified process is still running bool IsProcessRunning(pid_t pid); // Waits for the process to finish and returns its exit code. diff --git a/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp b/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp index 1e2bc665261..9e274268bf2 100644 --- a/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp @@ -56,9 +56,16 @@ char *FlagParser::ll_strndup(const char *s, uptr n) { } void FlagParser::PrintFlagDescriptions() { + char buffer[128]; + buffer[sizeof(buffer) - 1] = '\0'; Printf("Available flags for %s:\n", SanitizerToolName); - for (int i = 0; i < n_flags_; ++i) - Printf("\t%s\n\t\t- %s\n", flags_[i].name, flags_[i].desc); + for (int i = 0; i < n_flags_; ++i) { + bool truncated = !(flags_[i].handler->Format(buffer, sizeof(buffer))); + CHECK_EQ(buffer[sizeof(buffer) - 1], '\0'); + const char *truncation_str = truncated ? " Truncated" : ""; + Printf("\t%s\n\t\t- %s (Current Value%s: %s)\n", flags_[i].name, + flags_[i].desc, truncation_str, buffer); + } } void FlagParser::fatal_error(const char *err) { diff --git a/libsanitizer/sanitizer_common/sanitizer_flag_parser.h b/libsanitizer/sanitizer_common/sanitizer_flag_parser.h index c24ad25626b..fac5dff3463 100644 --- a/libsanitizer/sanitizer_common/sanitizer_flag_parser.h +++ b/libsanitizer/sanitizer_common/sanitizer_flag_parser.h @@ -22,9 +22,23 @@ namespace __sanitizer { class FlagHandlerBase { public: virtual bool Parse(const char *value) { return false; } + // Write the C string representation of the current value (truncated to fit) + // into the buffer of size `size`. Returns false if truncation occurred and + // returns true otherwise. + virtual bool Format(char *buffer, uptr size) { + if (size > 0) + buffer[0] = '\0'; + return false; + } protected: ~FlagHandlerBase() {} + + inline bool FormatString(char *buffer, uptr size, const char *str_to_use) { + uptr num_symbols_should_write = + internal_snprintf(buffer, size, "%s", str_to_use); + return num_symbols_should_write < size; + } }; template @@ -34,6 +48,7 @@ class FlagHandler : public FlagHandlerBase { public: explicit FlagHandler(T *t) : t_(t) {} bool Parse(const char *value) final; + bool Format(char *buffer, uptr size) final; }; inline bool ParseBool(const char *value, bool *b) { @@ -59,6 +74,11 @@ inline bool FlagHandler::Parse(const char *value) { return false; } +template <> +inline bool FlagHandler::Format(char *buffer, uptr size) { + return FormatString(buffer, size, *t_ ? "true" : "false"); +} + template <> inline bool FlagHandler::Parse(const char *value) { bool b; @@ -75,12 +95,23 @@ inline bool FlagHandler::Parse(const char *value) { return false; } +template <> +inline bool FlagHandler::Format(char *buffer, uptr size) { + uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_); + return num_symbols_should_write < size; +} + template <> inline bool FlagHandler::Parse(const char *value) { *t_ = value; return true; } +template <> +inline bool FlagHandler::Format(char *buffer, uptr size) { + return FormatString(buffer, size, *t_); +} + template <> inline bool FlagHandler::Parse(const char *value) { const char *value_end; @@ -90,6 +121,12 @@ inline bool FlagHandler::Parse(const char *value) { return ok; } +template <> +inline bool FlagHandler::Format(char *buffer, uptr size) { + uptr num_symbols_should_write = internal_snprintf(buffer, size, "%d", *t_); + return num_symbols_should_write < size; +} + template <> inline bool FlagHandler::Parse(const char *value) { const char *value_end; @@ -99,6 +136,12 @@ inline bool FlagHandler::Parse(const char *value) { return ok; } +template <> +inline bool FlagHandler::Format(char *buffer, uptr size) { + uptr num_symbols_should_write = internal_snprintf(buffer, size, "%p", *t_); + return num_symbols_should_write < size; +} + template <> inline bool FlagHandler::Parse(const char *value) { const char *value_end; @@ -108,6 +151,12 @@ inline bool FlagHandler::Parse(const char *value) { return ok; } +template <> +inline bool FlagHandler::Format(char *buffer, uptr size) { + uptr num_symbols_should_write = internal_snprintf(buffer, size, "%lld", *t_); + return num_symbols_should_write < size; +} + class FlagParser { static const int kMaxFlags = 200; struct Flag { diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.cpp b/libsanitizer/sanitizer_common/sanitizer_flags.cpp index 66a0a5579ed..684ee1e0b99 100644 --- a/libsanitizer/sanitizer_common/sanitizer_flags.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_flags.cpp @@ -75,11 +75,13 @@ void SubstituteForFlagValue(const char *s, char *out, uptr out_size) { class FlagHandlerInclude : public FlagHandlerBase { FlagParser *parser_; bool ignore_missing_; + const char *original_path_; public: explicit FlagHandlerInclude(FlagParser *parser, bool ignore_missing) - : parser_(parser), ignore_missing_(ignore_missing) {} + : parser_(parser), ignore_missing_(ignore_missing), original_path_("") {} bool Parse(const char *value) final { + original_path_ = value; if (internal_strchr(value, '%')) { char *buf = (char *)MmapOrDie(kMaxPathLength, "FlagHandlerInclude"); SubstituteForFlagValue(value, buf, kMaxPathLength); @@ -89,6 +91,12 @@ class FlagHandlerInclude : public FlagHandlerBase { } return parser_->ParseFile(value, ignore_missing_); } + bool Format(char *buffer, uptr size) { + // Note `original_path_` isn't actually what's parsed due to `%` + // substitutions. Printing the substituted path would require holding onto + // mmap'ed memory. + return FormatString(buffer, size, original_path_); + } }; void RegisterIncludeFlags(FlagParser *parser, CommonFlags *cf) { diff --git a/libsanitizer/sanitizer_common/sanitizer_freebsd.h b/libsanitizer/sanitizer_common/sanitizer_freebsd.h index 64cb21f1c3d..82b227eab6d 100644 --- a/libsanitizer/sanitizer_common/sanitizer_freebsd.h +++ b/libsanitizer/sanitizer_common/sanitizer_freebsd.h @@ -19,11 +19,11 @@ // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in // 32-bit mode. #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) -# include -# if __FreeBSD_version <= 902001 // v9.2 -# include -# include -# include +#include +#if __FreeBSD_version <= 902001 // v9.2 +#include +#include +#include namespace __sanitizer { @@ -68,8 +68,8 @@ typedef struct __xmcontext { } xmcontext_t; typedef struct __xucontext { - sigset_t uc_sigmask; - xmcontext_t uc_mcontext; + sigset_t uc_sigmask; + xmcontext_t uc_mcontext; struct __ucontext *uc_link; stack_t uc_stack; @@ -122,15 +122,16 @@ struct xdl_phdr_info { 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*); +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))) + (((xdl_iterate_phdr_t *)dl_iterate_phdr)((callback), (param))) } // namespace __sanitizer -# endif // __FreeBSD_version <= 902001 +#endif // __FreeBSD_version <= 902001 #endif // SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) #endif // SANITIZER_FREEBSD_H diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp index 6e2c6137f0c..6d1ad794677 100644 --- a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp @@ -66,6 +66,10 @@ uptr internal_getpid() { return pid; } +int internal_dlinfo(void *handle, int request, void *p) { + UNIMPLEMENTED(); +} + uptr GetThreadSelf() { return reinterpret_cast(thrd_current()); } tid_t GetTid() { return GetThreadSelf(); } diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.h b/libsanitizer/sanitizer_common/sanitizer_fuchsia.h index 5a2ad32b411..96f9cde7ef1 100644 --- a/libsanitizer/sanitizer_common/sanitizer_fuchsia.h +++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.h @@ -18,12 +18,18 @@ #include "sanitizer_common.h" #include +#include namespace __sanitizer { extern uptr MainThreadStackBase, MainThreadStackSize; extern sanitizer_shadow_bounds_t ShadowBounds; +struct MemoryMappingLayoutData { + InternalMmapVector data; + size_t current; // Current index into the vector. +}; + } // namespace __sanitizer #endif // SANITIZER_FUCHSIA diff --git a/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc b/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc index 03ef7c1788c..576807ea3a6 100644 --- a/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc +++ b/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc @@ -24,7 +24,7 @@ struct ioctl_desc { const char *name; }; -const unsigned ioctl_table_max = 1236; +const unsigned ioctl_table_max = 1238; static ioctl_desc ioctl_table[ioctl_table_max]; static unsigned ioctl_table_size = 0; @@ -166,9 +166,6 @@ static void ioctl_table_fill() { _(FE_ENABLE_HIGH_LNB_VOLTAGE, READ, sizeof(int)); _(FE_SET_FRONTEND_TUNE_MODE, READ, sizeof(unsigned int)); _(FE_DISHNETWORK_SEND_LEGACY_CMD, READ, sizeof(unsigned long)); - /* Entries from file: dev/filemon/filemon.h */ - _(FILEMON_SET_FD, READWRITE, sizeof(int)); - _(FILEMON_SET_PID, READWRITE, sizeof(int)); /* Entries from file: dev/hdaudio/hdaudioio.h */ _(HDAUDIO_FGRP_INFO, READWRITE, struct_plistref_sz); _(HDAUDIO_FGRP_GETCONFIG, READWRITE, struct_plistref_sz); @@ -449,9 +446,6 @@ static void ioctl_table_fill() { _(STICIO_STOPQ, NONE, 0); /* Entries from file: dev/usb/ukyopon.h */ _(UKYOPON_IDENTIFY, WRITE, struct_ukyopon_identify_sz); - /* Entries from file: dev/usb/urio.h */ - _(URIO_SEND_COMMAND, READWRITE, struct_urio_command_sz); - _(URIO_RECV_COMMAND, READWRITE, struct_urio_command_sz); /* Entries from file: dev/usb/usb.h */ _(USB_REQUEST, READWRITE, struct_usb_ctl_request_sz); _(USB_SETDEBUG, READ, sizeof(int)); @@ -653,6 +647,7 @@ static void ioctl_table_fill() { _(NVMM_IOC_MACHINE_CONFIGURE, READ, struct_nvmm_ioc_machine_configure_sz); _(NVMM_IOC_VCPU_CREATE, READ, struct_nvmm_ioc_vcpu_create_sz); _(NVMM_IOC_VCPU_DESTROY, READ, struct_nvmm_ioc_vcpu_destroy_sz); + _(NVMM_IOC_VCPU_CONFIGURE, READ, struct_nvmm_ioc_vcpu_configure_sz); _(NVMM_IOC_VCPU_SETSTATE, READ, struct_nvmm_ioc_vcpu_setstate_sz); _(NVMM_IOC_VCPU_GETSTATE, READ, struct_nvmm_ioc_vcpu_getstate_sz); _(NVMM_IOC_VCPU_INJECT, READ, struct_nvmm_ioc_vcpu_inject_sz); @@ -735,6 +730,7 @@ static void ioctl_table_fill() { _(IOC_NPF_SAVE, WRITE, struct_nvlist_ref_sz); _(IOC_NPF_RULE, READWRITE, struct_nvlist_ref_sz); _(IOC_NPF_CONN_LOOKUP, READWRITE, struct_nvlist_ref_sz); + _(IOC_NPF_TABLE_REPLACE, READWRITE, struct_nvlist_ref_sz); /* Entries from file: net/if_pppoe.h */ _(PPPOESETPARMS, READ, struct_pppoediscparms_sz); _(PPPOEGETPARMS, READWRITE, struct_pppoediscparms_sz); @@ -1403,8 +1399,14 @@ static void ioctl_table_fill() { _(SNDCTL_DSP_SETRECVOL, READ, sizeof(unsigned int)); _(SNDCTL_DSP_SKIP, NONE, 0); _(SNDCTL_DSP_SILENCE, NONE, 0); + /* Entries from file: dev/filemon/filemon.h (compat <= 9.99.26) */ + _(FILEMON_SET_FD, READWRITE, sizeof(int)); + _(FILEMON_SET_PID, READWRITE, sizeof(int)); + /* Entries from file: dev/usb/urio.h (compat <= 9.99.43) */ + _(URIO_SEND_COMMAND, READWRITE, struct_urio_command_sz); + _(URIO_RECV_COMMAND, READWRITE, struct_urio_command_sz); #undef _ -} // NOLINT +} // NOLINT static bool ioctl_initialized = false; diff --git a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h index c110eff130f..be8023e9e16 100644 --- a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h +++ b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h @@ -109,8 +109,10 @@ extern "C" { __sanitizer::u32*); SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void __sanitizer_cov_8bit_counters_init(); - SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE - void __sanitizer_cov_pcs_init(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void + __sanitizer_cov_bool_flag_init(); + SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void + __sanitizer_cov_pcs_init(); } // extern "C" #endif // SANITIZER_INTERFACE_INTERNAL_H diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h index 00226305e07..d0ffc79b061 100644 --- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h +++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h @@ -105,7 +105,7 @@ // FIXME: do we have anything like this on Mac? #ifndef SANITIZER_CAN_USE_PREINIT_ARRAY #if ((SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_OPENBSD || \ - SANITIZER_FUCHSIA) && !defined(PIC) + SANITIZER_FUCHSIA || SANITIZER_NETBSD) && !defined(PIC) #define SANITIZER_CAN_USE_PREINIT_ARRAY 1 // Before Solaris 11.4, .preinit_array is fully supported only with GNU ld. // FIXME: Check for those conditions. diff --git a/libsanitizer/sanitizer_common/sanitizer_libc.h b/libsanitizer/sanitizer_common/sanitizer_libc.h index 3d5db35d68b..ec0a6ded009 100644 --- a/libsanitizer/sanitizer_common/sanitizer_libc.h +++ b/libsanitizer/sanitizer_common/sanitizer_libc.h @@ -72,6 +72,8 @@ unsigned int internal_sleep(unsigned int seconds); uptr internal_getpid(); uptr internal_getppid(); +int internal_dlinfo(void *handle, int request, void *p); + // Threading uptr internal_sched_yield(); diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_linux.cpp index 3807a79b1cd..2168301fd69 100644 --- a/libsanitizer/sanitizer_common/sanitizer_linux.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_linux.cpp @@ -26,7 +26,7 @@ #include "sanitizer_placement_new.h" #include "sanitizer_procmaps.h" -#if SANITIZER_LINUX +#if SANITIZER_LINUX && !SANITIZER_GO #include #endif @@ -166,7 +166,7 @@ namespace __sanitizer { #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD #if !SANITIZER_S390 && !SANITIZER_OPENBSD uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, - OFF_T offset) { + u64 offset) { #if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd, offset); @@ -552,13 +552,14 @@ const char *GetEnv(const char *name) { #endif } -#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_OPENBSD +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_OPENBSD && \ + !SANITIZER_GO extern "C" { SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end; } #endif -#if !SANITIZER_GO && !SANITIZER_FREEBSD && !SANITIZER_NETBSD && \ +#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && \ !SANITIZER_OPENBSD static void ReadNullSepFileToArray(const char *path, char ***arr, int arr_size) { @@ -604,16 +605,21 @@ static void GetArgsAndEnv(char ***argv, char ***envp) { #else // SANITIZER_FREEBSD #if !SANITIZER_GO if (&__libc_stack_end) { -#endif // !SANITIZER_GO uptr* stack_end = (uptr*)__libc_stack_end; - int argc = *stack_end; + // Normally argc can be obtained from *stack_end, however, on ARM glibc's + // _start clobbers it: + // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/arm/start.S;hb=refs/heads/release/2.31/master#l75 + // Do not special-case ARM and infer argc from argv everywhere. + int argc = 0; + while (stack_end[argc + 1]) argc++; *argv = (char**)(stack_end + 1); *envp = (char**)(stack_end + argc + 2); -#if !SANITIZER_GO } else { +#endif // !SANITIZER_GO static const int kMaxArgv = 2000, kMaxEnvp = 2000; ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv); ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp); +#if !SANITIZER_GO } #endif // !SANITIZER_GO #endif // SANITIZER_FREEBSD @@ -735,6 +741,14 @@ uptr internal_getppid() { return internal_syscall(SYSCALL(getppid)); } +int internal_dlinfo(void *handle, int request, void *p) { +#if SANITIZER_FREEBSD + return dlinfo(handle, request, p); +#else + UNIMPLEMENTED(); +#endif +} + uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { #if SANITIZER_FREEBSD return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL); @@ -1006,9 +1020,8 @@ static uptr GetKernelAreaSize() { // is modified (e.g. under schroot) so check this as well. struct utsname uname_info; int pers = personality(0xffffffffUL); - if (!(pers & PER_MASK) - && uname(&uname_info) == 0 - && internal_strstr(uname_info.machine, "64")) + if (!(pers & PER_MASK) && internal_uname(&uname_info) == 0 && + internal_strstr(uname_info.machine, "64")) return 0; #endif // SANITIZER_ANDROID @@ -1063,7 +1076,8 @@ uptr GetMaxUserVirtualAddress() { #if !SANITIZER_ANDROID uptr GetPageSize() { -#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) +#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) && \ + defined(EXEC_PAGESIZE) return EXEC_PAGESIZE; #elif SANITIZER_FREEBSD || SANITIZER_NETBSD // Use sysctl as sysconf can trigger interceptors internally. @@ -1619,6 +1633,12 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, } #endif // defined(__x86_64__) && SANITIZER_LINUX +#if SANITIZER_LINUX +int internal_uname(struct utsname *buf) { + return internal_syscall(SYSCALL(uname), buf); +} +#endif + #if SANITIZER_ANDROID #if __ANDROID_API__ < 21 extern "C" __attribute__((weak)) int dl_iterate_phdr( @@ -1701,7 +1721,7 @@ HandleSignalMode GetHandleSignalMode(int signum) { } #if !SANITIZER_GO -void *internal_start_thread(void(*func)(void *arg), void *arg) { +void *internal_start_thread(void *(*func)(void *arg), void *arg) { // Start the thread with signals blocked, otherwise it can steal user signals. __sanitizer_sigset_t set, old; internal_sigfillset(&set); @@ -1712,7 +1732,7 @@ void *internal_start_thread(void(*func)(void *arg), void *arg) { #endif internal_sigprocmask(SIG_SETMASK, &set, &old); void *th; - real_pthread_create(&th, nullptr, (void*(*)(void *arg))func, arg); + real_pthread_create(&th, nullptr, func, arg); internal_sigprocmask(SIG_SETMASK, &old, nullptr); return th; } @@ -1721,7 +1741,7 @@ void internal_join_thread(void *th) { real_pthread_join(th, nullptr); } #else -void *internal_start_thread(void (*func)(void *), void *arg) { return 0; } +void *internal_start_thread(void *(*func)(void *), void *arg) { return 0; } void internal_join_thread(void *th) {} #endif @@ -1846,6 +1866,105 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag() const { #endif u32 instr = *(u32 *)pc; return (instr >> 21) & 1 ? WRITE: READ; +#elif defined(__riscv) + unsigned long pc = ucontext->uc_mcontext.__gregs[REG_PC]; + unsigned faulty_instruction = *(uint16_t *)pc; + +#if defined(__riscv_compressed) + if ((faulty_instruction & 0x3) != 0x3) { // it's a compressed instruction + // set op_bits to the instruction bits [1, 0, 15, 14, 13] + unsigned op_bits = + ((faulty_instruction & 0x3) << 3) | (faulty_instruction >> 13); + unsigned rd = faulty_instruction & 0xF80; // bits 7-11, inclusive + switch (op_bits) { + case 0b10'010: // c.lwsp (rd != x0) +#if __riscv_xlen == 64 + case 0b10'011: // c.ldsp (rd != x0) +#endif + return rd ? SignalContext::READ : SignalContext::UNKNOWN; + case 0b00'010: // c.lw +#if __riscv_flen >= 32 && __riscv_xlen == 32 + case 0b10'011: // c.flwsp +#endif +#if __riscv_flen >= 32 || __riscv_xlen == 64 + case 0b00'011: // c.flw / c.ld +#endif +#if __riscv_flen == 64 + case 0b00'001: // c.fld + case 0b10'001: // c.fldsp +#endif + return SignalContext::READ; + case 0b00'110: // c.sw + case 0b10'110: // c.swsp +#if __riscv_flen >= 32 || __riscv_xlen == 64 + case 0b00'111: // c.fsw / c.sd + case 0b10'111: // c.fswsp / c.sdsp +#endif +#if __riscv_flen == 64 + case 0b00'101: // c.fsd + case 0b10'101: // c.fsdsp +#endif + return SignalContext::WRITE; + default: + return SignalContext::UNKNOWN; + } + } +#endif + + unsigned opcode = faulty_instruction & 0x7f; // lower 7 bits + unsigned funct3 = (faulty_instruction >> 12) & 0x7; // bits 12-14, inclusive + switch (opcode) { + case 0b0000011: // loads + switch (funct3) { + case 0b000: // lb + case 0b001: // lh + case 0b010: // lw +#if __riscv_xlen == 64 + case 0b011: // ld +#endif + case 0b100: // lbu + case 0b101: // lhu + return SignalContext::READ; + default: + return SignalContext::UNKNOWN; + } + case 0b0100011: // stores + switch (funct3) { + case 0b000: // sb + case 0b001: // sh + case 0b010: // sw +#if __riscv_xlen == 64 + case 0b011: // sd +#endif + return SignalContext::WRITE; + default: + return SignalContext::UNKNOWN; + } +#if __riscv_flen >= 32 + case 0b0000111: // floating-point loads + switch (funct3) { + case 0b010: // flw +#if __riscv_flen == 64 + case 0b011: // fld +#endif + return SignalContext::READ; + default: + return SignalContext::UNKNOWN; + } + case 0b0100111: // floating-point stores + switch (funct3) { + case 0b010: // fsw +#if __riscv_flen == 64 + case 0b011: // fsd +#endif + return SignalContext::WRITE; + default: + return SignalContext::UNKNOWN; + } +#endif + default: + return SignalContext::UNKNOWN; + } #else (void)ucontext; return UNKNOWN; // FIXME: Implement. @@ -2011,7 +2130,9 @@ void CheckASLR() { } if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_ASLR)) { - Printf("This sanitizer is not compatible with enabled ASLR\n"); + Printf("This sanitizer is not compatible with enabled ASLR.\n" + "To disable ASLR, please run \"paxctl +a %s\" and try again.\n", + GetArgv()[0]); Die(); } #elif SANITIZER_PPC64V2 diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h b/libsanitizer/sanitizer_common/sanitizer_linux.h index c28347ad963..c162d1ca5d2 100644 --- a/libsanitizer/sanitizer_common/sanitizer_linux.h +++ b/libsanitizer/sanitizer_common/sanitizer_linux.h @@ -25,6 +25,7 @@ #include "sanitizer_posix.h" struct link_map; // Opaque type returned by dlopen(). +struct utsname; namespace __sanitizer { // Dirent structure for getdents(). Note that this structure is different from @@ -65,6 +66,7 @@ void internal_sigdelset(__sanitizer_sigset_t *set, int signum); uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg, int *parent_tidptr, void *newtls, int *child_tidptr); #endif +int internal_uname(struct utsname *buf); #elif SANITIZER_FREEBSD void internal_sigdelset(__sanitizer_sigset_t *set, int signum); #elif SANITIZER_NETBSD diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp index e09d568d802..4d17c9686e4 100644 --- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp @@ -35,6 +35,10 @@ #include #include +#if !defined(ElfW) +#define ElfW(type) Elf_##type +#endif + #if SANITIZER_FREEBSD #include #include @@ -50,6 +54,7 @@ #if SANITIZER_NETBSD #include #include +#include #endif #if SANITIZER_SOLARIS @@ -399,13 +404,7 @@ uptr ThreadSelf() { #if SANITIZER_NETBSD static struct tls_tcb * ThreadSelfTlsTcb() { - struct tls_tcb * tcb; -# ifdef __HAVE___LWP_GETTCB_FAST - tcb = (struct tls_tcb *)__lwp_gettcb_fast(); -# elif defined(__HAVE___LWP_GETPRIVATE_FAST) - tcb = (struct tls_tcb *)__lwp_getprivate_fast(); -# endif - return tcb; + return (struct tls_tcb *)_lwp_getprivate(); } uptr ThreadSelf() { @@ -698,13 +697,9 @@ u32 GetNumberOfCPUs() { #elif SANITIZER_SOLARIS return sysconf(_SC_NPROCESSORS_ONLN); #else -#if defined(CPU_COUNT) cpu_set_t CPUs; CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0); return CPU_COUNT(&CPUs); -#else - return 1; -#endif #endif } diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp index 41e187eaf8d..bb2f5b5f9f7 100644 --- a/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp @@ -15,19 +15,20 @@ #if SANITIZER_LINUX && SANITIZER_S390 -#include "sanitizer_libc.h" -#include "sanitizer_linux.h" - +#include #include #include #include #include +#include "sanitizer_libc.h" +#include "sanitizer_linux.h" + namespace __sanitizer { // --------------- sanitizer_libc.h uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, - OFF_T offset) { + u64 offset) { struct s390_mmap_params { unsigned long addr; unsigned long length; @@ -123,7 +124,7 @@ static bool FixedCVE_2016_2143() { struct utsname buf; unsigned int major, minor, patch = 0; // This should never fail, but just in case... - if (uname(&buf)) + if (internal_uname(&buf)) return false; const char *ptr = buf.release; major = internal_simple_strtoll(ptr, &ptr, 10); diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_mac.cpp index b971ad058e9..7550545ea6f 100644 --- a/libsanitizer/sanitizer_common/sanitizer_mac.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_mac.cpp @@ -30,6 +30,7 @@ #include "sanitizer_placement_new.h" #include "sanitizer_platform_limits_posix.h" #include "sanitizer_procmaps.h" +#include "sanitizer_ptrauth.h" #if !SANITIZER_IOS #include // for _NSGetEnviron @@ -37,7 +38,7 @@ extern char **environ; #endif -#if defined(__has_include) && __has_include() && defined(__BLOCKS__) +#if defined(__has_include) && __has_include() #define SANITIZER_OS_TRACE 1 #include #else @@ -208,6 +209,10 @@ uptr internal_getpid() { return getpid(); } +int internal_dlinfo(void *handle, int request, void *p) { + UNIMPLEMENTED(); +} + int internal_sigaction(int signum, const void *act, void *oldact) { return sigaction(signum, (const struct sigaction *)act, (struct sigaction *)oldact); @@ -242,7 +247,8 @@ int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp, (size_t)newlen); } -static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) { +static fd_t internal_spawn_impl(const char *argv[], const char *envp[], + pid_t *pid) { fd_t master_fd = kInvalidFd; fd_t slave_fd = kInvalidFd; @@ -298,8 +304,8 @@ static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) { // posix_spawn char **argv_casted = const_cast(argv); - char **env = GetEnviron(); - res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, env); + char **envp_casted = const_cast(envp); + res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, envp_casted); if (res != 0) return kInvalidFd; // Disable echo in the new terminal, disable CR. @@ -316,7 +322,7 @@ static fd_t internal_spawn_impl(const char *argv[], pid_t *pid) { return fd; } -fd_t internal_spawn(const char *argv[], pid_t *pid) { +fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid) { // The client program may close its stdin and/or stdout and/or stderr thus // allowing open/posix_openpt to reuse file descriptors 0, 1 or 2. In this // case the communication is broken if either the parent or the child tries to @@ -331,7 +337,7 @@ fd_t internal_spawn(const char *argv[], pid_t *pid) { break; } - fd_t fd = internal_spawn_impl(argv, pid); + fd_t fd = internal_spawn_impl(argv, envp, pid); for (; count > 0; count--) { internal_close(low_fds[count]); @@ -623,19 +629,13 @@ MacosVersion GetMacosVersionInternal() { if (*p != '.') return MACOS_VERSION_UNKNOWN; switch (major) { - case 9: return MACOS_VERSION_LEOPARD; - case 10: return MACOS_VERSION_SNOW_LEOPARD; case 11: return MACOS_VERSION_LION; case 12: return MACOS_VERSION_MOUNTAIN_LION; case 13: return MACOS_VERSION_MAVERICKS; case 14: return MACOS_VERSION_YOSEMITE; case 15: return MACOS_VERSION_EL_CAPITAN; case 16: return MACOS_VERSION_SIERRA; - case 17: - // Not a typo, 17.5 Darwin Kernel Version maps to High Sierra 10.13.4. - if (minor >= 5) - return MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4; - return MACOS_VERSION_HIGH_SIERRA; + case 17: return MACOS_VERSION_HIGH_SIERRA; case 18: return MACOS_VERSION_MOJAVE; case 19: return MACOS_VERSION_CATALINA; default: @@ -656,13 +656,21 @@ MacosVersion GetMacosVersion() { return result; } -bool PlatformHasDifferentMemcpyAndMemmove() { - // On OS X 10.7 memcpy() and memmove() are both resolved - // into memmove$VARIANT$sse42. - // See also https://github.com/google/sanitizers/issues/34. - // TODO(glider): need to check dynamically that memcpy() and memmove() are - // actually the same function. - return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD; +DarwinKernelVersion GetDarwinKernelVersion() { + char buf[100]; + size_t len = sizeof(buf); + int res = internal_sysctlbyname("kern.osrelease", buf, &len, nullptr, 0); + CHECK_EQ(res, 0); + + // Format: ..\0 + CHECK_GE(len, 6); + const char *p = buf; + u16 major = internal_simple_strtoll(p, &p, /*base=*/10); + CHECK_EQ(*p, '.'); + p += 1; + u16 minor = internal_simple_strtoll(p, &p, /*base=*/10); + + return DarwinKernelVersion(major, minor); } uptr GetRSS() { @@ -677,13 +685,13 @@ uptr GetRSS() { return info.resident_size; } -void *internal_start_thread(void(*func)(void *arg), void *arg) { +void *internal_start_thread(void *(*func)(void *arg), void *arg) { // Start the thread with signals blocked, otherwise it can steal user signals. __sanitizer_sigset_t set, old; internal_sigfillset(&set); internal_sigprocmask(SIG_SETMASK, &set, &old); pthread_t th; - pthread_create(&th, 0, (void*(*)(void *arg))func, arg); + pthread_create(&th, 0, func, arg); internal_sigprocmask(SIG_SETMASK, &old, 0); return th; } @@ -760,16 +768,24 @@ bool SignalContext::IsTrueFaultingAddress() const { return si->si_signo == SIGSEGV && si->si_code != 0; } +#if defined(__aarch64__) && defined(arm_thread_state64_get_sp) + #define AARCH64_GET_REG(r) \ + (uptr)ptrauth_strip( \ + (void *)arm_thread_state64_get_##r(ucontext->uc_mcontext->__ss), 0) +#else + #define AARCH64_GET_REG(r) ucontext->uc_mcontext->__ss.__##r +#endif + static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { ucontext_t *ucontext = (ucontext_t*)context; # if defined(__aarch64__) - *pc = ucontext->uc_mcontext->__ss.__pc; + *pc = AARCH64_GET_REG(pc); # if defined(__IPHONE_8_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0 - *bp = ucontext->uc_mcontext->__ss.__fp; + *bp = AARCH64_GET_REG(fp); # else - *bp = ucontext->uc_mcontext->__ss.__lr; + *bp = AARCH64_GET_REG(lr); # endif - *sp = ucontext->uc_mcontext->__ss.__sp; + *sp = AARCH64_GET_REG(sp); # elif defined(__x86_64__) *pc = ucontext->uc_mcontext->__ss.__rip; *bp = ucontext->uc_mcontext->__ss.__rbp; @@ -787,13 +803,16 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { # endif } -void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); } +void SignalContext::InitPcSpBp() { + addr = (uptr)ptrauth_strip((void *)addr, 0); + GetPcSpBp(context, &pc, &sp, &bp); +} void InitializePlatformEarly() { - // Only use xnu_fast_mmap when on x86_64 and the OS supports it. + // Only use xnu_fast_mmap when on x86_64 and the kernel supports it. use_xnu_fast_mmap = #if defined(__x86_64__) - GetMacosVersion() >= MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4; + GetDarwinKernelVersion() >= DarwinKernelVersion(17, 5); #else false; #endif @@ -1123,6 +1142,8 @@ void SignalContext::DumpAllRegisters(void *context) { ucontext_t *ucontext = (ucontext_t*)context; # define DUMPREG64(r) \ Printf("%s = 0x%016llx ", #r, ucontext->uc_mcontext->__ss.__ ## r); +# define DUMPREGA64(r) \ + Printf(" %s = 0x%016llx ", #r, AARCH64_GET_REG(r)); # define DUMPREG32(r) \ Printf("%s = 0x%08x ", #r, ucontext->uc_mcontext->__ss.__ ## r); # define DUMPREG_(r) Printf(" "); DUMPREG(r); @@ -1148,7 +1169,7 @@ void SignalContext::DumpAllRegisters(void *context) { DUMPREG(x[16]); DUMPREG(x[17]); DUMPREG(x[18]); DUMPREG(x[19]); Printf("\n"); DUMPREG(x[20]); DUMPREG(x[21]); DUMPREG(x[22]); DUMPREG(x[23]); Printf("\n"); DUMPREG(x[24]); DUMPREG(x[25]); DUMPREG(x[26]); DUMPREG(x[27]); Printf("\n"); - DUMPREG(x[28]); DUMPREG___(fp); DUMPREG___(lr); DUMPREG___(sp); Printf("\n"); + DUMPREG(x[28]); DUMPREGA64(fp); DUMPREGA64(lr); DUMPREGA64(sp); Printf("\n"); # elif defined(__arm__) # define DUMPREG(r) DUMPREG32(r) DUMPREG_(r[0]); DUMPREG_(r[1]); DUMPREG_(r[2]); DUMPREG_(r[3]); Printf("\n"); diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_mac.h index 2257883084e..34dc2c05dcf 100644 --- a/libsanitizer/sanitizer_common/sanitizer_mac.h +++ b/libsanitizer/sanitizer_common/sanitizer_mac.h @@ -33,22 +33,35 @@ struct MemoryMappingLayoutData { enum MacosVersion { MACOS_VERSION_UNINITIALIZED = 0, MACOS_VERSION_UNKNOWN, - MACOS_VERSION_LEOPARD, - MACOS_VERSION_SNOW_LEOPARD, - MACOS_VERSION_LION, + MACOS_VERSION_LION, // macOS 10.7; oldest currently supported MACOS_VERSION_MOUNTAIN_LION, MACOS_VERSION_MAVERICKS, MACOS_VERSION_YOSEMITE, MACOS_VERSION_EL_CAPITAN, MACOS_VERSION_SIERRA, MACOS_VERSION_HIGH_SIERRA, - MACOS_VERSION_HIGH_SIERRA_DOT_RELEASE_4, MACOS_VERSION_MOJAVE, MACOS_VERSION_CATALINA, MACOS_VERSION_UNKNOWN_NEWER }; +struct DarwinKernelVersion { + u16 major; + u16 minor; + + DarwinKernelVersion(u16 major, u16 minor) : major(major), minor(minor) {} + + bool operator==(const DarwinKernelVersion &other) const { + return major == other.major && minor == other.minor; + } + bool operator>=(const DarwinKernelVersion &other) const { + return major >= other.major || + (major == other.major && minor >= other.minor); + } +}; + MacosVersion GetMacosVersion(); +DarwinKernelVersion GetDarwinKernelVersion(); char **GetEnviron(); diff --git a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc index 11adbe5c25b..647bcdfe105 100644 --- a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc +++ b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc @@ -61,12 +61,10 @@ INTERCEPTOR(malloc_zone_t *, malloc_create_zone, malloc_zone_t *new_zone = (malloc_zone_t *)p; internal_memcpy(new_zone, &sanitizer_zone, sizeof(sanitizer_zone)); new_zone->zone_name = NULL; // The name will be changed anyway. - if (GetMacosVersion() >= MACOS_VERSION_LION) { - // Prevent the client app from overwriting the zone contents. - // Library functions that need to modify the zone will set PROT_WRITE on it. - // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher. - mprotect(new_zone, allocated_size, PROT_READ); - } + // Prevent the client app from overwriting the zone contents. + // Library functions that need to modify the zone will set PROT_WRITE on it. + // This matches the behavior of malloc_create_zone() on OSX 10.7 and higher. + mprotect(new_zone, allocated_size, PROT_READ); // We're explicitly *NOT* registering the zone. return new_zone; } @@ -75,11 +73,9 @@ INTERCEPTOR(void, malloc_destroy_zone, malloc_zone_t *zone) { COMMON_MALLOC_ENTER(); // We don't need to do anything here. We're not registering new zones, so we // don't to unregister. Just un-mprotect and free() the zone. - if (GetMacosVersion() >= MACOS_VERSION_LION) { - uptr page_size = GetPageSizeCached(); - uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size); - mprotect(zone, allocated_size, PROT_READ | PROT_WRITE); - } + uptr page_size = GetPageSizeCached(); + uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size); + mprotect(zone, allocated_size, PROT_READ | PROT_WRITE); if (zone->zone_name) { COMMON_MALLOC_FREE((void *)zone->zone_name); } diff --git a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp index 4e74f6a3b51..d9aff51d8ae 100644 --- a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp @@ -95,7 +95,7 @@ static void *GetRealLibcAddress(const char *symbol) { // --------------- sanitizer_libc.h uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, - OFF_T offset) { + u64 offset) { CHECK(&__mmap); return (uptr)__mmap(addr, length, prot, flags, fd, 0, offset); } @@ -265,6 +265,11 @@ uptr internal_getppid() { return _REAL(getppid); } +int internal_dlinfo(void *handle, int request, void *p) { + DEFINE__REAL(int, dlinfo, void *a, int b, void *c); + return _REAL(dlinfo, handle, request, p); +} + uptr internal_getdents(fd_t fd, void *dirp, unsigned int count) { DEFINE__REAL(int, __getdents30, int a, void *b, size_t c); return _REAL(__getdents30, fd, dirp, count); diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h index 61a6b82ef81..9dd6d285f59 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h @@ -90,6 +90,24 @@ # define SI_IOS 0 #endif +#if SANITIZER_IOSSIM +# define SI_IOSSIM 1 +#else +# define SI_IOSSIM 0 +#endif + +#if SANITIZER_WATCHOS +# define SI_WATCHOS 1 +#else +# define SI_WATCHOS 0 +#endif + +#if SANITIZER_TVOS +# define SI_TVOS 1 +#else +# define SI_TVOS 0 +#endif + #if SANITIZER_FUCHSIA # define SI_NOT_FUCHSIA 0 #else @@ -575,5 +593,11 @@ #define SANITIZER_INTERCEPT_ATEXIT SI_NETBSD #define SANITIZER_INTERCEPT_PTHREAD_ATFORK SI_NETBSD #define SANITIZER_INTERCEPT_GETENTROPY SI_FREEBSD +#define SANITIZER_INTERCEPT_QSORT \ + (SI_POSIX && !SI_IOSSIM && !SI_WATCHOS && !SI_TVOS && !SI_ANDROID) +#define SANITIZER_INTERCEPT_QSORT_R (SI_LINUX && !SI_ANDROID) +#define SANITIZER_INTERCEPT_SIGALTSTACK SI_POSIX +#define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD) +#define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp index 2d1bb1a12da..dcc6c71c07d 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp @@ -15,342 +15,348 @@ #if SANITIZER_FREEBSD +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include +#include +#include +#include +#include +#include +#include +#include +// #include -#include +#include #include +#include +#include #include +#include #include -#include -#include #include #include #include #include +#include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include +#include +#include +#include #include -#include #include +#include +#include #define _KERNEL // to declare 'shminfo' structure -# include +#include #undef _KERNEL #undef INLINE // to avoid clashes with sanitizers' definitions #undef IOC_DIRMASK -# include -# include -# include - -#include -#include -#include - // Include these after system headers to avoid name clashes and ambiguities. #include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" #include "sanitizer_platform_limits_freebsd.h" namespace __sanitizer { - unsigned struct_cap_rights_sz = sizeof(cap_rights_t); - unsigned struct_utsname_sz = sizeof(struct utsname); - unsigned struct_stat_sz = sizeof(struct stat); - unsigned struct_rusage_sz = sizeof(struct rusage); - unsigned struct_tm_sz = sizeof(struct tm); - unsigned struct_passwd_sz = sizeof(struct passwd); - unsigned struct_group_sz = sizeof(struct group); - unsigned siginfo_t_sz = sizeof(siginfo_t); - unsigned struct_sigaction_sz = sizeof(struct sigaction); - unsigned struct_itimerval_sz = sizeof(struct itimerval); - unsigned pthread_t_sz = sizeof(pthread_t); - unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); - unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); - unsigned pid_t_sz = sizeof(pid_t); - unsigned timeval_sz = sizeof(timeval); - unsigned uid_t_sz = sizeof(uid_t); - unsigned gid_t_sz = sizeof(gid_t); - unsigned fpos_t_sz = sizeof(fpos_t); - unsigned mbstate_t_sz = sizeof(mbstate_t); - unsigned sigset_t_sz = sizeof(sigset_t); - unsigned struct_timezone_sz = sizeof(struct timezone); - 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); - unsigned struct_sockaddr_sz = sizeof(struct sockaddr); - unsigned ucontext_t_sz = sizeof(ucontext_t); - unsigned struct_rlimit_sz = sizeof(struct rlimit); - unsigned struct_timespec_sz = sizeof(struct timespec); - unsigned struct_utimbuf_sz = sizeof(struct utimbuf); - unsigned struct_itimerspec_sz = sizeof(struct itimerspec); - unsigned struct_timeb_sz = sizeof(struct timeb); - unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); - unsigned struct_mq_attr_sz = sizeof(struct mq_attr); - unsigned struct_statvfs_sz = sizeof(struct statvfs); - unsigned struct_shminfo_sz = sizeof(struct shminfo); - unsigned struct_shm_info_sz = sizeof(struct shm_info); - unsigned struct_regmatch_sz = sizeof(regmatch_t); - unsigned struct_regex_sz = sizeof(regex_t); - unsigned struct_fstab_sz = sizeof(struct fstab); - unsigned struct_FTS_sz = sizeof(FTS); - unsigned struct_FTSENT_sz = sizeof(FTSENT); - unsigned struct_StringList_sz = sizeof(StringList); - - const uptr sig_ign = (uptr)SIG_IGN; - const uptr sig_dfl = (uptr)SIG_DFL; - const uptr sig_err = (uptr)SIG_ERR; - const uptr sa_siginfo = (uptr)SA_SIGINFO; - - int shmctl_ipc_stat = (int)IPC_STAT; - int shmctl_ipc_info = (int)IPC_INFO; - int shmctl_shm_info = (int)SHM_INFO; - int shmctl_shm_stat = (int)SHM_STAT; - unsigned struct_utmpx_sz = sizeof(struct utmpx); - - int map_fixed = MAP_FIXED; - - int af_inet = (int)AF_INET; - int af_inet6 = (int)AF_INET6; - - uptr __sanitizer_in_addr_sz(int af) { - if (af == AF_INET) - return sizeof(struct in_addr); - else if (af == AF_INET6) - return sizeof(struct in6_addr); - else - return 0; - } - - unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); - int glob_nomatch = GLOB_NOMATCH; - int glob_altdirfunc = GLOB_ALTDIRFUNC; - - unsigned path_max = PATH_MAX; - - // ioctl arguments - unsigned struct_ifreq_sz = sizeof(struct ifreq); - unsigned struct_termios_sz = sizeof(struct termios); - unsigned struct_winsize_sz = sizeof(struct winsize); +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle) { + void *p = nullptr; + return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p : nullptr; +} + +unsigned struct_cap_rights_sz = sizeof(cap_rights_t); +unsigned struct_utsname_sz = sizeof(struct utsname); +unsigned struct_stat_sz = sizeof(struct stat); +unsigned struct_rusage_sz = sizeof(struct rusage); +unsigned struct_tm_sz = sizeof(struct tm); +unsigned struct_passwd_sz = sizeof(struct passwd); +unsigned struct_group_sz = sizeof(struct group); +unsigned siginfo_t_sz = sizeof(siginfo_t); +unsigned struct_sigaction_sz = sizeof(struct sigaction); +unsigned struct_stack_t_sz = sizeof(stack_t); +unsigned struct_itimerval_sz = sizeof(struct itimerval); +unsigned pthread_t_sz = sizeof(pthread_t); +unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); +unsigned pthread_cond_t_sz = sizeof(pthread_cond_t); +unsigned pid_t_sz = sizeof(pid_t); +unsigned timeval_sz = sizeof(timeval); +unsigned uid_t_sz = sizeof(uid_t); +unsigned gid_t_sz = sizeof(gid_t); +unsigned fpos_t_sz = sizeof(fpos_t); +unsigned mbstate_t_sz = sizeof(mbstate_t); +unsigned sigset_t_sz = sizeof(sigset_t); +unsigned struct_timezone_sz = sizeof(struct timezone); +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); +unsigned struct_sockaddr_sz = sizeof(struct sockaddr); +unsigned ucontext_t_sz = sizeof(ucontext_t); +unsigned struct_rlimit_sz = sizeof(struct rlimit); +unsigned struct_timespec_sz = sizeof(struct timespec); +unsigned struct_utimbuf_sz = sizeof(struct utimbuf); +unsigned struct_itimerspec_sz = sizeof(struct itimerspec); +unsigned struct_timeb_sz = sizeof(struct timeb); +unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds); +unsigned struct_mq_attr_sz = sizeof(struct mq_attr); +unsigned struct_statvfs_sz = sizeof(struct statvfs); +unsigned struct_shminfo_sz = sizeof(struct shminfo); +unsigned struct_shm_info_sz = sizeof(struct shm_info); +unsigned struct_regmatch_sz = sizeof(regmatch_t); +unsigned struct_regex_sz = sizeof(regex_t); +unsigned struct_fstab_sz = sizeof(struct fstab); +unsigned struct_FTS_sz = sizeof(FTS); +unsigned struct_FTSENT_sz = sizeof(FTSENT); +unsigned struct_StringList_sz = sizeof(StringList); + +const uptr sig_ign = (uptr)SIG_IGN; +const uptr sig_dfl = (uptr)SIG_DFL; +const uptr sig_err = (uptr)SIG_ERR; +const uptr sa_siginfo = (uptr)SA_SIGINFO; + +int shmctl_ipc_stat = (int)IPC_STAT; +int shmctl_ipc_info = (int)IPC_INFO; +int shmctl_shm_info = (int)SHM_INFO; +int shmctl_shm_stat = (int)SHM_STAT; +unsigned struct_utmpx_sz = sizeof(struct utmpx); + +int map_fixed = MAP_FIXED; + +int af_inet = (int)AF_INET; +int af_inet6 = (int)AF_INET6; + +uptr __sanitizer_in_addr_sz(int af) { + if (af == AF_INET) + return sizeof(struct in_addr); + else if (af == AF_INET6) + return sizeof(struct in6_addr); + else + return 0; +} + +unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); +int glob_nomatch = GLOB_NOMATCH; +int glob_altdirfunc = GLOB_ALTDIRFUNC; + +unsigned path_max = PATH_MAX; + +// ioctl arguments +unsigned struct_ifreq_sz = sizeof(struct ifreq); +unsigned struct_termios_sz = sizeof(struct termios); +unsigned struct_winsize_sz = sizeof(struct winsize); #if SOUND_VERSION >= 0x040000 - unsigned struct_copr_buffer_sz = 0; - unsigned struct_copr_debug_buf_sz = 0; - unsigned struct_copr_msg_sz = 0; +unsigned struct_copr_buffer_sz = 0; +unsigned struct_copr_debug_buf_sz = 0; +unsigned struct_copr_msg_sz = 0; #else - unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer); - unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf); - unsigned struct_copr_msg_sz = sizeof(struct copr_msg); +unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer); +unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf); +unsigned struct_copr_msg_sz = sizeof(struct copr_msg); #endif - unsigned struct_midi_info_sz = sizeof(struct midi_info); - unsigned struct_mtget_sz = sizeof(struct mtget); - unsigned struct_mtop_sz = sizeof(struct mtop); - unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument); - unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec); - unsigned struct_synth_info_sz = sizeof(struct synth_info); - unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); - unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); - unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); - unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); - const unsigned long __sanitizer_bufsiz = BUFSIZ; - - const unsigned IOCTL_NOT_PRESENT = 0; - - unsigned IOCTL_FIOASYNC = FIOASYNC; - unsigned IOCTL_FIOCLEX = FIOCLEX; - unsigned IOCTL_FIOGETOWN = FIOGETOWN; - unsigned IOCTL_FIONBIO = FIONBIO; - unsigned IOCTL_FIONCLEX = FIONCLEX; - unsigned IOCTL_FIOSETOWN = FIOSETOWN; - unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; - unsigned IOCTL_SIOCATMARK = SIOCATMARK; - unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; - unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; - unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; - unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; - unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; - unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; - unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; - unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; - unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; - unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; - unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; - unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; - unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; - unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; - unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; - unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; - unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; - unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; - unsigned IOCTL_TIOCCONS = TIOCCONS; - unsigned IOCTL_TIOCEXCL = TIOCEXCL; - unsigned IOCTL_TIOCGETD = TIOCGETD; - unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; - unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; - unsigned IOCTL_TIOCMBIC = TIOCMBIC; - unsigned IOCTL_TIOCMBIS = TIOCMBIS; - unsigned IOCTL_TIOCMGET = TIOCMGET; - unsigned IOCTL_TIOCMSET = TIOCMSET; - unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; - unsigned IOCTL_TIOCNXCL = TIOCNXCL; - unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; - unsigned IOCTL_TIOCPKT = TIOCPKT; - unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; - unsigned IOCTL_TIOCSETD = TIOCSETD; - unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; - unsigned IOCTL_TIOCSTI = TIOCSTI; - unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; - unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; - unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; - unsigned IOCTL_MTIOCGET = MTIOCGET; - unsigned IOCTL_MTIOCTOP = MTIOCTOP; - unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; - unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; - unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; - unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; - unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; - unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; - unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; - unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; - unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; - unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; - unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; - unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE; - unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR; - unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO; - unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME; - unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE; - unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT; - unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT; - unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS; - unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS; - unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND; - unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC; - unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE; - unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET; - unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES; - unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC; - unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI; - unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD; - unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO; - unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL; - unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE; - unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME; - unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT; - unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE; - unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START; - unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP; - unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO; - unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE; - unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM; - unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS; - unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS; - unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD; - unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK; - unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE; - unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN; - unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX; - unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE; - unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1; - unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2; - unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3; - unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD; - unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC; - unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE; - unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN; - unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM; - unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV; - unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK; - unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC; - unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER; - unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS; - unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH; - unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE; - unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME; - unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM; - unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS; - unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD; - unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE; - unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN; - unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX; - unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE; - unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1; - unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2; - unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3; - unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD; - unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC; - unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE; - unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN; - unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM; - unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV; - unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC; - unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER; - unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH; - unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE; - unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME; - unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; - unsigned IOCTL_VT_GETMODE = VT_GETMODE; - unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; - unsigned IOCTL_VT_RELDISP = VT_RELDISP; - unsigned IOCTL_VT_SETMODE = VT_SETMODE; - unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; - unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP; - unsigned IOCTL_KDDISABIO = KDDISABIO; - unsigned IOCTL_KDENABIO = KDENABIO; - unsigned IOCTL_KDGETLED = KDGETLED; - unsigned IOCTL_KDGETMODE = KDGETMODE; - unsigned IOCTL_KDGKBMODE = KDGKBMODE; - unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; - unsigned IOCTL_KDMKTONE = KDMKTONE; - unsigned IOCTL_KDSETLED = KDSETLED; - unsigned IOCTL_KDSETMODE = KDSETMODE; - unsigned IOCTL_KDSKBMODE = KDSKBMODE; - unsigned IOCTL_KIOCSOUND = KIOCSOUND; - unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP; - unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; - - const int si_SEGV_MAPERR = SEGV_MAPERR; - const int si_SEGV_ACCERR = SEGV_ACCERR; - const int unvis_valid = UNVIS_VALID; - const int unvis_validpush = UNVIS_VALIDPUSH; -} // namespace __sanitizer +unsigned struct_midi_info_sz = sizeof(struct midi_info); +unsigned struct_mtget_sz = sizeof(struct mtget); +unsigned struct_mtop_sz = sizeof(struct mtop); +unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument); +unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec); +unsigned struct_synth_info_sz = sizeof(struct synth_info); +unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info); +unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); +unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); +unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); +const unsigned long __sanitizer_bufsiz = BUFSIZ; + +const unsigned IOCTL_NOT_PRESENT = 0; + +unsigned IOCTL_FIOASYNC = FIOASYNC; +unsigned IOCTL_FIOCLEX = FIOCLEX; +unsigned IOCTL_FIOGETOWN = FIOGETOWN; +unsigned IOCTL_FIONBIO = FIONBIO; +unsigned IOCTL_FIONCLEX = FIONCLEX; +unsigned IOCTL_FIOSETOWN = FIOSETOWN; +unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI; +unsigned IOCTL_SIOCATMARK = SIOCATMARK; +unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI; +unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR; +unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR; +unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF; +unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR; +unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS; +unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC; +unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU; +unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK; +unsigned IOCTL_SIOCGPGRP = SIOCGPGRP; +unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR; +unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR; +unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR; +unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS; +unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC; +unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU; +unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK; +unsigned IOCTL_SIOCSPGRP = SIOCSPGRP; +unsigned IOCTL_TIOCCONS = TIOCCONS; +unsigned IOCTL_TIOCEXCL = TIOCEXCL; +unsigned IOCTL_TIOCGETD = TIOCGETD; +unsigned IOCTL_TIOCGPGRP = TIOCGPGRP; +unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ; +unsigned IOCTL_TIOCMBIC = TIOCMBIC; +unsigned IOCTL_TIOCMBIS = TIOCMBIS; +unsigned IOCTL_TIOCMGET = TIOCMGET; +unsigned IOCTL_TIOCMSET = TIOCMSET; +unsigned IOCTL_TIOCNOTTY = TIOCNOTTY; +unsigned IOCTL_TIOCNXCL = TIOCNXCL; +unsigned IOCTL_TIOCOUTQ = TIOCOUTQ; +unsigned IOCTL_TIOCPKT = TIOCPKT; +unsigned IOCTL_TIOCSCTTY = TIOCSCTTY; +unsigned IOCTL_TIOCSETD = TIOCSETD; +unsigned IOCTL_TIOCSPGRP = TIOCSPGRP; +unsigned IOCTL_TIOCSTI = TIOCSTI; +unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ; +unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; +unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; +unsigned IOCTL_MTIOCGET = MTIOCGET; +unsigned IOCTL_MTIOCTOP = MTIOCTOP; +unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE; +unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS; +unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK; +unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST; +unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET; +unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT; +unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT; +unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED; +unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO; +unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE; +unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC; +unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE; +unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR; +unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO; +unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME; +unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE; +unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT; +unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT; +unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS; +unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS; +unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND; +unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC; +unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE; +unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET; +unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES; +unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC; +unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI; +unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD; +unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO; +unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL; +unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE; +unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME; +unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT; +unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE; +unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START; +unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP; +unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO; +unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE; +unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM; +unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS; +unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS; +unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD; +unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK; +unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE; +unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN; +unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX; +unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE; +unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1; +unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2; +unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3; +unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD; +unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC; +unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE; +unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN; +unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM; +unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV; +unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK; +unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC; +unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER; +unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS; +unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH; +unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE; +unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME; +unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM; +unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS; +unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD; +unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE; +unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN; +unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX; +unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE; +unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1; +unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2; +unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3; +unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD; +unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC; +unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE; +unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN; +unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM; +unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV; +unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC; +unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER; +unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH; +unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE; +unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME; +unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE; +unsigned IOCTL_VT_GETMODE = VT_GETMODE; +unsigned IOCTL_VT_OPENQRY = VT_OPENQRY; +unsigned IOCTL_VT_RELDISP = VT_RELDISP; +unsigned IOCTL_VT_SETMODE = VT_SETMODE; +unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE; +unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP; +unsigned IOCTL_KDDISABIO = KDDISABIO; +unsigned IOCTL_KDENABIO = KDENABIO; +unsigned IOCTL_KDGETLED = KDGETLED; +unsigned IOCTL_KDGETMODE = KDGETMODE; +unsigned IOCTL_KDGKBMODE = KDGKBMODE; +unsigned IOCTL_KDGKBTYPE = KDGKBTYPE; +unsigned IOCTL_KDMKTONE = KDMKTONE; +unsigned IOCTL_KDSETLED = KDSETLED; +unsigned IOCTL_KDSETMODE = KDSETMODE; +unsigned IOCTL_KDSKBMODE = KDSKBMODE; +unsigned IOCTL_KIOCSOUND = KIOCSOUND; +unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP; +unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE; + +const int si_SEGV_MAPERR = SEGV_MAPERR; +const int si_SEGV_ACCERR = SEGV_ACCERR; +const int unvis_valid = UNVIS_VALID; +const int unvis_validpush = UNVIS_VALIDPUSH; +} // namespace __sanitizer using namespace __sanitizer; diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h index 71cf5b9c357..5e0ca9c7d78 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h @@ -18,18 +18,17 @@ #include "sanitizer_internal_defs.h" #include "sanitizer_platform.h" - #include "sanitizer_platform_limits_posix.h" -// FreeBSD's dlopen() returns a pointer to an Obj_Entry structure that -// incorporates the map structure. -# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ - ((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 560))) // Get sys/_types.h, because that tells us whether 64-bit inodes are // used in struct dirent below. #include namespace __sanitizer { +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle); +#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ + (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle) + extern unsigned struct_utsname_sz; extern unsigned struct_stat_sz; #if defined(__powerpc64__) @@ -53,6 +52,7 @@ extern unsigned struct_timezone_sz; extern unsigned struct_tms_sz; extern unsigned struct_itimerspec_sz; extern unsigned struct_sigevent_sz; +extern unsigned struct_stack_t_sz; extern unsigned struct_sched_param_sz; extern unsigned struct_statfs64_sz; extern unsigned struct_statfs_sz; @@ -147,7 +147,7 @@ struct __sanitizer_ifaddrs { unsigned int ifa_flags; void *ifa_addr; // (struct sockaddr *) void *ifa_netmask; // (struct sockaddr *) -# undef ifa_dstaddr +#undef ifa_dstaddr void *ifa_dstaddr; // (struct sockaddr *) void *ifa_data; }; @@ -630,27 +630,27 @@ extern unsigned struct_cap_rights_sz; extern unsigned struct_fstab_sz; extern unsigned struct_StringList_sz; -} // namespace __sanitizer +} // namespace __sanitizer #define CHECK_TYPE_SIZE(TYPE) \ COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE)) -#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ - COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *) NULL)->MEMBER) == \ - sizeof(((CLASS *) NULL)->MEMBER)); \ - COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ +#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \ offsetof(CLASS, MEMBER)) // For sigaction, which is a function and struct at the same time, // and thus requires explicit "struct" in sizeof() expression. -#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ - COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *) NULL)->MEMBER) == \ - sizeof(((struct CLASS *) NULL)->MEMBER)); \ - COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ +#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \ + COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \ + sizeof(((struct CLASS *)NULL)->MEMBER)); \ + COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \ offsetof(struct CLASS, MEMBER)) #define SIGACTION_SYMNAME sigaction #endif -#endif // SANITIZER_FREEBSD +#endif // SANITIZER_FREEBSD diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp index f22f5039128..c51327e1269 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp @@ -26,12 +26,9 @@ // With old kernels (and even new kernels on powerpc) asm/stat.h uses types that // are not defined anywhere in userspace headers. Fake them. This seems to work -// fine with newer headers, too. Beware that with , struct stat -// takes the form of struct stat64 on 32-bit platforms if _FILE_OFFSET_BITS=64. -// Also, for some platforms (e.g. mips) there are additional members in the -// struct stat:s. +// fine with newer headers, too. #include -#if defined(__x86_64__) +#if defined(__x86_64__) || defined(__mips__) #include #else #define ino_t __kernel_ino_t diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp index f01de6c995e..25da334b63f 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp @@ -17,6 +17,7 @@ #define _KMEMUSER #define RAY_DO_SIGLEV +#define __LEGACY_PT_LWPINFO // clang-format off #include @@ -71,6 +72,15 @@ #include #include #include + +// Compat for NetBSD < 9.99.30. +#ifndef PT_LWPSTATUS +#define PT_LWPSTATUS 24 +#endif +#ifndef PT_LWPNEXT +#define PT_LWPNEXT 25 +#endif + #include #include #include @@ -109,7 +119,12 @@ #include #include #include +#if !__NetBSD_Prereq__(9, 99, 26) #include +#else +#define FILEMON_SET_FD _IOWR('S', 1, int) +#define FILEMON_SET_PID _IOWR('S', 2, pid_t) +#endif #include #include #include @@ -146,12 +161,121 @@ #include #include #include +#if __has_include() #include #include #include +#else +/* Fallback for MKIPFILTER=no */ + +typedef struct ap_control { + char apc_label[16]; + char apc_config[16]; + unsigned char apc_p; + unsigned long apc_cmd; + unsigned long apc_arg; + void *apc_data; + size_t apc_dsize; +} ap_ctl_t; + +typedef struct ipftq { + ipfmutex_t ifq_lock; + unsigned int ifq_ttl; + void *ifq_head; + void **ifq_tail; + void *ifq_next; + void **ifq_pnext; + int ifq_ref; + unsigned int ifq_flags; +} ipftq_t; + +typedef struct ipfobj { + uint32_t ipfo_rev; + uint32_t ipfo_size; + void *ipfo_ptr; + int ipfo_type; + int ipfo_offset; + int ipfo_retval; + unsigned char ipfo_xxxpad[28]; +} ipfobj_t; + +#define SIOCADNAT _IOW('r', 60, struct ipfobj) +#define SIOCRMNAT _IOW('r', 61, struct ipfobj) +#define SIOCGNATS _IOWR('r', 62, struct ipfobj) +#define SIOCGNATL _IOWR('r', 63, struct ipfobj) +#define SIOCPURGENAT _IOWR('r', 100, struct ipfobj) +#endif #include #include +#if !__NetBSD_Prereq__(9, 99, 51) #include +#else +struct smbioc_flags { + int ioc_level; + int ioc_mask; + int ioc_flags; +}; +struct smbioc_oshare { + int ioc_opt; + int ioc_stype; + char ioc_share[129]; + char ioc_password[129]; + uid_t ioc_owner; + gid_t ioc_group; + mode_t ioc_mode; + mode_t ioc_rights; +}; +struct smbioc_ossn { + int ioc_opt; + uint32_t ioc_svlen; + struct sockaddr *ioc_server; + uint32_t ioc_lolen; + struct sockaddr *ioc_local; + char ioc_srvname[16]; + int ioc_timeout; + int ioc_retrycount; + char ioc_localcs[16]; + char ioc_servercs[16]; + char ioc_user[129]; + char ioc_workgroup[129]; + char ioc_password[129]; + uid_t ioc_owner; + gid_t ioc_group; + mode_t ioc_mode; + mode_t ioc_rights; +}; +struct smbioc_lookup { + int ioc_level; + int ioc_flags; + struct smbioc_ossn ioc_ssn; + struct smbioc_oshare ioc_sh; +}; +struct smbioc_rq { + u_char ioc_cmd; + u_char ioc_twc; + void *ioc_twords; + u_short ioc_tbc; + void *ioc_tbytes; + int ioc_rpbufsz; + char *ioc_rpbuf; + u_char ioc_rwc; + u_short ioc_rbc; +}; +struct smbioc_rw { + u_int16_t ioc_fh; + char *ioc_base; + off_t ioc_offset; + int ioc_cnt; +}; +#define SMBIOC_OPENSESSION _IOW('n', 100, struct smbioc_ossn) +#define SMBIOC_OPENSHARE _IOW('n', 101, struct smbioc_oshare) +#define SMBIOC_REQUEST _IOWR('n', 102, struct smbioc_rq) +#define SMBIOC_T2RQ _IOWR('n', 103, struct smbioc_t2rq) +#define SMBIOC_SETFLAGS _IOW('n', 104, struct smbioc_flags) +#define SMBIOC_LOOKUP _IOW('n', 106, struct smbioc_lookup) +#define SMBIOC_READ _IOWR('n', 107, struct smbioc_rw) +#define SMBIOC_WRITE _IOWR('n', 108, struct smbioc_rw) +#endif #include #include #include @@ -175,7 +299,21 @@ #include #include #include +#if !__NetBSD_Prereq__(9, 99, 44) #include +#else +struct urio_command { + unsigned short length; + int request; + int requesttype; + int value; + int index; + void *buffer; + int timeout; +}; +#define URIO_SEND_COMMAND _IOWR('U', 200, struct urio_command) +#define URIO_RECV_COMMAND _IOWR('U', 201, struct urio_command) +#endif #include #include #include @@ -184,6 +322,7 @@ #include #include #include +#include #include #include #include @@ -229,9 +368,15 @@ // Include these after system headers to avoid name clashes and ambiguities. #include "sanitizer_internal_defs.h" +#include "sanitizer_libc.h" #include "sanitizer_platform_limits_netbsd.h" namespace __sanitizer { +void *__sanitizer_get_link_map_by_dlopen_handle(void* handle) { + void *p = nullptr; + return internal_dlinfo(handle, RTLD_DI_LINKMAP, &p) == 0 ? p : nullptr; +} + unsigned struct_utsname_sz = sizeof(struct utsname); unsigned struct_stat_sz = sizeof(struct stat); unsigned struct_rusage_sz = sizeof(struct rusage); @@ -240,6 +385,7 @@ unsigned struct_passwd_sz = sizeof(struct passwd); unsigned struct_group_sz = sizeof(struct group); unsigned siginfo_t_sz = sizeof(siginfo_t); unsigned struct_sigaction_sz = sizeof(struct sigaction); +unsigned struct_stack_t_sz = sizeof(stack_t); unsigned struct_itimerval_sz = sizeof(struct itimerval); unsigned pthread_t_sz = sizeof(pthread_t); unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); @@ -287,6 +433,8 @@ int ptrace_pt_get_event_mask = PT_GET_EVENT_MASK; int ptrace_pt_get_process_state = PT_GET_PROCESS_STATE; int ptrace_pt_set_siginfo = PT_SET_SIGINFO; int ptrace_pt_get_siginfo = PT_GET_SIGINFO; +int ptrace_pt_lwpstatus = PT_LWPSTATUS; +int ptrace_pt_lwpnext = PT_LWPNEXT; int ptrace_piod_read_d = PIOD_READ_D; int ptrace_piod_write_d = PIOD_WRITE_D; int ptrace_piod_read_i = PIOD_READ_I; @@ -319,6 +467,8 @@ int ptrace_pt_getdbregs = -1; unsigned struct_ptrace_ptrace_io_desc_struct_sz = sizeof(struct ptrace_io_desc); unsigned struct_ptrace_ptrace_lwpinfo_struct_sz = sizeof(struct ptrace_lwpinfo); +unsigned struct_ptrace_ptrace_lwpstatus_struct_sz = + sizeof(struct __sanitizer_ptrace_lwpstatus); unsigned struct_ptrace_ptrace_event_struct_sz = sizeof(ptrace_event_t); unsigned struct_ptrace_ptrace_siginfo_struct_sz = sizeof(ptrace_siginfo_t); @@ -698,6 +848,7 @@ unsigned struct_nvmm_ioc_machine_configure_sz = sizeof(nvmm_ioc_machine_configure); unsigned struct_nvmm_ioc_vcpu_create_sz = sizeof(nvmm_ioc_vcpu_create); unsigned struct_nvmm_ioc_vcpu_destroy_sz = sizeof(nvmm_ioc_vcpu_destroy); +unsigned struct_nvmm_ioc_vcpu_configure_sz = sizeof(nvmm_ioc_vcpu_configure); unsigned struct_nvmm_ioc_vcpu_setstate_sz = sizeof(nvmm_ioc_vcpu_destroy); unsigned struct_nvmm_ioc_vcpu_getstate_sz = sizeof(nvmm_ioc_vcpu_getstate); unsigned struct_nvmm_ioc_vcpu_inject_sz = sizeof(nvmm_ioc_vcpu_inject); @@ -1458,6 +1609,7 @@ unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY = NVMM_IOC_MACHINE_DESTROY; unsigned IOCTL_NVMM_IOC_MACHINE_CONFIGURE = NVMM_IOC_MACHINE_CONFIGURE; unsigned IOCTL_NVMM_IOC_VCPU_CREATE = NVMM_IOC_VCPU_CREATE; unsigned IOCTL_NVMM_IOC_VCPU_DESTROY = NVMM_IOC_VCPU_DESTROY; +unsigned IOCTL_NVMM_IOC_VCPU_CONFIGURE = NVMM_IOC_VCPU_CONFIGURE; unsigned IOCTL_NVMM_IOC_VCPU_SETSTATE = NVMM_IOC_VCPU_SETSTATE; unsigned IOCTL_NVMM_IOC_VCPU_GETSTATE = NVMM_IOC_VCPU_GETSTATE; unsigned IOCTL_NVMM_IOC_VCPU_INJECT = NVMM_IOC_VCPU_INJECT; @@ -1534,6 +1686,7 @@ unsigned IOCTL_IOC_NPF_STATS = IOC_NPF_STATS; unsigned IOCTL_IOC_NPF_SAVE = IOC_NPF_SAVE; unsigned IOCTL_IOC_NPF_RULE = IOC_NPF_RULE; unsigned IOCTL_IOC_NPF_CONN_LOOKUP = IOC_NPF_CONN_LOOKUP; +unsigned IOCTL_IOC_NPF_TABLE_REPLACE = IOC_NPF_TABLE_REPLACE; unsigned IOCTL_PPPOESETPARMS = PPPOESETPARMS; unsigned IOCTL_PPPOEGETPARMS = PPPOEGETPARMS; unsigned IOCTL_PPPOEGETSESSION = PPPOEGETSESSION; @@ -2392,4 +2545,42 @@ CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_flags); CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_props); CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_propslen); +// Compat with 9.0 +struct statvfs90 { + unsigned long f_flag; + unsigned long f_bsize; + unsigned long f_frsize; + unsigned long f_iosize; + + u64 f_blocks; + u64 f_bfree; + u64 f_bavail; + u64 f_bresvd; + + u64 f_files; + u64 f_ffree; + u64 f_favail; + u64 f_fresvd; + + u64 f_syncreads; + u64 f_syncwrites; + + u64 f_asyncreads; + u64 f_asyncwrites; + + struct { + s32 __fsid_val[2]; + } f_fsidx; + unsigned long f_fsid; + unsigned long f_namemax; + u32 f_owner; + + u32 f_spare[4]; + + char f_fstypename[32]; + char f_mntonname[32]; + char f_mntfromname[32]; +}; +unsigned struct_statvfs90_sz = sizeof(struct statvfs90); + #endif // SANITIZER_NETBSD diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h index 419d830c69e..d80280d9bf8 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h @@ -19,18 +19,11 @@ #include "sanitizer_internal_defs.h" #include "sanitizer_platform.h" -#define _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, shift) \ - ((link_map *)((handle) == nullptr ? nullptr : ((char *)(handle) + (shift)))) - -#if defined(__x86_64__) -#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ - _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 264) -#elif defined(__i386__) -#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ - _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 136) -#endif - namespace __sanitizer { +void *__sanitizer_get_link_map_by_dlopen_handle(void *handle); +# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \ + (link_map *)__sanitizer_get_link_map_by_dlopen_handle(handle) + extern unsigned struct_utsname_sz; extern unsigned struct_stat_sz; extern unsigned struct_rusage_sz; @@ -48,6 +41,7 @@ extern unsigned struct_timezone_sz; extern unsigned struct_tms_sz; extern unsigned struct_itimerspec_sz; extern unsigned struct_sigevent_sz; +extern unsigned struct_stack_t_sz; extern unsigned struct_sched_param_sz; extern unsigned struct_statfs_sz; extern unsigned struct_sockaddr_sz; @@ -412,6 +406,8 @@ extern int ptrace_pt_get_event_mask; extern int ptrace_pt_get_process_state; extern int ptrace_pt_set_siginfo; extern int ptrace_pt_get_siginfo; +extern int ptrace_pt_lwpstatus; +extern int ptrace_pt_lwpnext; extern int ptrace_piod_read_d; extern int ptrace_piod_write_d; extern int ptrace_piod_read_i; @@ -436,8 +432,17 @@ struct __sanitizer_ptrace_lwpinfo { int pl_event; }; +struct __sanitizer_ptrace_lwpstatus { + __sanitizer_lwpid_t pl_lwpid; + __sanitizer_sigset_t pl_sigpend; + __sanitizer_sigset_t pl_sigmask; + char pl_name[20]; + void *pl_private; +}; + extern unsigned struct_ptrace_ptrace_io_desc_struct_sz; extern unsigned struct_ptrace_ptrace_lwpinfo_struct_sz; +extern unsigned struct_ptrace_ptrace_lwpstatus_struct_sz; extern unsigned struct_ptrace_ptrace_event_struct_sz; extern unsigned struct_ptrace_ptrace_siginfo_struct_sz; @@ -862,6 +867,7 @@ extern unsigned struct_nvmm_ioc_machine_destroy_sz; extern unsigned struct_nvmm_ioc_machine_configure_sz; extern unsigned struct_nvmm_ioc_vcpu_create_sz; extern unsigned struct_nvmm_ioc_vcpu_destroy_sz; +extern unsigned struct_nvmm_ioc_vcpu_configure_sz; extern unsigned struct_nvmm_ioc_vcpu_setstate_sz; extern unsigned struct_nvmm_ioc_vcpu_getstate_sz; extern unsigned struct_nvmm_ioc_vcpu_inject_sz; @@ -1611,6 +1617,7 @@ extern unsigned IOCTL_NVMM_IOC_MACHINE_DESTROY; extern unsigned IOCTL_NVMM_IOC_MACHINE_CONFIGURE; extern unsigned IOCTL_NVMM_IOC_VCPU_CREATE; extern unsigned IOCTL_NVMM_IOC_VCPU_DESTROY; +extern unsigned IOCTL_NVMM_IOC_VCPU_CONFIGURE; extern unsigned IOCTL_NVMM_IOC_VCPU_SETSTATE; extern unsigned IOCTL_NVMM_IOC_VCPU_GETSTATE; extern unsigned IOCTL_NVMM_IOC_VCPU_INJECT; @@ -1685,6 +1692,7 @@ extern unsigned IOCTL_IOC_NPF_STATS; extern unsigned IOCTL_IOC_NPF_SAVE; extern unsigned IOCTL_IOC_NPF_RULE; extern unsigned IOCTL_IOC_NPF_CONN_LOOKUP; +extern unsigned IOCTL_IOC_NPF_TABLE_REPLACE; extern unsigned IOCTL_PPPOESETPARMS; extern unsigned IOCTL_PPPOEGETPARMS; extern unsigned IOCTL_PPPOEGETSESSION; @@ -2406,6 +2414,9 @@ struct __sanitizer_cdbw { #define SIGACTION_SYMNAME __sigaction14 +// Compat with 9.0 +extern unsigned struct_statvfs90_sz; + #endif // SANITIZER_NETBSD #endif diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp index 12515626ce5..1420ecbfa56 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp @@ -72,6 +72,7 @@ unsigned struct_passwd_sz = sizeof(struct passwd); unsigned struct_group_sz = sizeof(struct group); unsigned siginfo_t_sz = sizeof(siginfo_t); unsigned struct_sigaction_sz = sizeof(struct sigaction); +unsigned struct_stack_t_sz = sizeof(stack_t); unsigned struct_itimerval_sz = sizeof(struct itimerval); unsigned pthread_t_sz = sizeof(pthread_t); unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h index 6d8b062716b..8a194872360 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h @@ -50,6 +50,7 @@ extern unsigned struct_timezone_sz; extern unsigned struct_tms_sz; extern unsigned struct_itimerspec_sz; extern unsigned struct_sigevent_sz; +extern unsigned struct_stack_t_sz; extern unsigned struct_statfs_sz; extern unsigned struct_sockaddr_sz; diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp index aa845df4dde..e71515f12e9 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp @@ -179,6 +179,7 @@ namespace __sanitizer { unsigned struct_group_sz = sizeof(struct group); unsigned siginfo_t_sz = sizeof(siginfo_t); unsigned struct_sigaction_sz = sizeof(struct sigaction); + unsigned struct_stack_t_sz = sizeof(stack_t); unsigned struct_itimerval_sz = sizeof(struct itimerval); unsigned pthread_t_sz = sizeof(pthread_t); unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h index d82fd5e4005..f6c8a1450a9 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h @@ -47,6 +47,7 @@ extern unsigned struct_timezone_sz; extern unsigned struct_tms_sz; extern unsigned struct_itimerspec_sz; extern unsigned struct_sigevent_sz; +extern unsigned struct_stack_t_sz; extern unsigned struct_sched_param_sz; extern unsigned struct_statfs64_sz; extern unsigned struct_regex_sz; @@ -82,7 +83,7 @@ const unsigned struct_kernel_stat64_sz = 104; #elif defined(__mips__) const unsigned struct_kernel_stat_sz = SANITIZER_ANDROID ? FIRST_32_SECOND_64(104, 128) - : FIRST_32_SECOND_64(144, 216); + : FIRST_32_SECOND_64(160, 216); const unsigned struct_kernel_stat64_sz = 104; #elif defined(__s390__) && !defined(__s390x__) const unsigned struct_kernel_stat_sz = 64; diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp index 9717d98ebf1..6ec1a1bdd11 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp @@ -72,6 +72,7 @@ namespace __sanitizer { unsigned struct_group_sz = sizeof(struct group); unsigned siginfo_t_sz = sizeof(siginfo_t); unsigned struct_sigaction_sz = sizeof(struct sigaction); + unsigned struct_stack_t_sz = sizeof(stack_t); unsigned struct_itimerval_sz = sizeof(struct itimerval); unsigned pthread_t_sz = sizeof(pthread_t); unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t); diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h index 77ae6e6a44d..85995e79792 100644 --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h @@ -38,6 +38,7 @@ extern unsigned struct_timezone_sz; extern unsigned struct_tms_sz; extern unsigned struct_itimerspec_sz; extern unsigned struct_sigevent_sz; +extern unsigned struct_stack_t_sz; extern unsigned struct_sched_param_sz; extern unsigned struct_statfs64_sz; extern unsigned struct_statfs_sz; diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_posix.cpp index d890a3a3177..e21661b42f8 100644 --- a/libsanitizer/sanitizer_common/sanitizer_posix.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_posix.cpp @@ -347,9 +347,17 @@ int GetNamedMappingFd(const char *name, uptr size, int *flags) { CHECK(internal_strlen(name) < sizeof(shmname) - 10); internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu [%s]", internal_getpid(), name); + int o_cloexec = 0; +#if defined(O_CLOEXEC) + o_cloexec = O_CLOEXEC; +#endif int fd = ReserveStandardFds( - internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, S_IRWXU)); + internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | o_cloexec, S_IRWXU)); CHECK_GE(fd, 0); + if (!o_cloexec) { + int res = fcntl(fd, F_SETFD, FD_CLOEXEC); + CHECK_EQ(0, res); + } int res = internal_ftruncate(fd, size); CHECK_EQ(0, res); res = internal_unlink(shmname); diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.h b/libsanitizer/sanitizer_common/sanitizer_posix.h index 05fb0f63020..a1b49702da2 100644 --- a/libsanitizer/sanitizer_common/sanitizer_posix.h +++ b/libsanitizer/sanitizer_common/sanitizer_posix.h @@ -39,7 +39,7 @@ uptr internal_write(fd_t fd, const void *buf, uptr count); // Memory uptr internal_mmap(void *addr, uptr length, int prot, int flags, - int fd, OFF_T offset); + int fd, u64 offset); uptr internal_munmap(void *addr, uptr length); int internal_mprotect(void *addr, uptr length, int prot); @@ -63,7 +63,7 @@ uptr internal_ptrace(int request, int pid, void *addr, void *data); uptr internal_waitpid(int pid, int *status, int options); int internal_fork(); -fd_t internal_spawn(const char *argv[], pid_t *pid); +fd_t internal_spawn(const char *argv[], const char *envp[], pid_t *pid); int internal_sysctl(const int *name, unsigned int namelen, void *oldp, uptr *oldlenp, const void *newp, uptr newlen); diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp index 304b3a01a08..f920172c06d 100644 --- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -426,7 +426,8 @@ void AdjustStackSize(void *attr_) { #endif // !SANITIZER_GO pid_t StartSubprocess(const char *program, const char *const argv[], - fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { + const char *const envp[], fd_t stdin_fd, fd_t stdout_fd, + fd_t stderr_fd) { auto file_closer = at_scope_exit([&] { if (stdin_fd != kInvalidFd) { internal_close(stdin_fd); @@ -469,7 +470,8 @@ pid_t StartSubprocess(const char *program, const char *const argv[], for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd); - execv(program, const_cast(&argv[0])); + internal_execve(program, const_cast(&argv[0]), + const_cast(envp)); internal__exit(1); } diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps.h b/libsanitizer/sanitizer_common/sanitizer_procmaps.h index d0e5245f84d..665ed45fa93 100644 --- a/libsanitizer/sanitizer_common/sanitizer_procmaps.h +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps.h @@ -15,18 +15,19 @@ #include "sanitizer_platform.h" -#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_MAC || SANITIZER_SOLARIS +#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ + SANITIZER_OPENBSD || SANITIZER_MAC || SANITIZER_SOLARIS || \ + SANITIZER_FUCHSIA #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" +#include "sanitizer_fuchsia.h" #include "sanitizer_linux.h" #include "sanitizer_mac.h" #include "sanitizer_mutex.h" namespace __sanitizer { - // Memory protection masks. static const uptr kProtectionRead = 1; static const uptr kProtectionWrite = 2; diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp new file mode 100644 index 00000000000..cc3e9be0645 --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp @@ -0,0 +1,80 @@ +//===-- sanitizer_procmaps_fuchsia.cpp +//----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Information about the process mappings (Fuchsia-specific parts). +//===----------------------------------------------------------------------===// + +#include "sanitizer_platform.h" +#if SANITIZER_FUCHSIA +#include +#include + +#include "sanitizer_common.h" +#include "sanitizer_procmaps.h" + +namespace __sanitizer { + +// The cache flag is ignored on Fuchsia because a process can always get this +// information via its process-self handle. +MemoryMappingLayout::MemoryMappingLayout(bool) { Reset(); } + +void MemoryMappingLayout::Reset() { + data_.data.clear(); + data_.current = 0; + + size_t count; + zx_status_t status = _zx_object_get_info( + _zx_process_self(), ZX_INFO_PROCESS_MAPS, nullptr, 0, nullptr, &count); + if (status != ZX_OK) { + return; + } + + size_t filled; + do { + data_.data.resize(count); + status = _zx_object_get_info( + _zx_process_self(), ZX_INFO_PROCESS_MAPS, data_.data.data(), + count * sizeof(zx_info_maps_t), &filled, &count); + if (status != ZX_OK) { + data_.data.clear(); + return; + } + } while (filled < count); +} + +MemoryMappingLayout::~MemoryMappingLayout() {} + +bool MemoryMappingLayout::Error() const { return data_.data.empty(); } + +bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) { + while (data_.current < data_.data.size()) { + const auto &entry = data_.data[data_.current++]; + if (entry.type == ZX_INFO_MAPS_TYPE_MAPPING) { + segment->start = entry.base; + segment->end = entry.base + entry.size; + segment->offset = entry.u.mapping.vmo_offset; + const auto flags = entry.u.mapping.mmu_flags; + segment->protection = + ((flags & ZX_VM_PERM_READ) ? kProtectionRead : 0) | + ((flags & ZX_VM_PERM_WRITE) ? kProtectionWrite : 0) | + ((flags & ZX_VM_PERM_EXECUTE) ? kProtectionExecute : 0); + if (segment->filename && segment->filename_size > 0) { + uptr len = Min(sizeof(entry.name), segment->filename_size) - 1; + internal_strncpy(segment->filename, entry.name, len); + segment->filename[len] = 0; + } + return true; + } + } + return false; +} + +} // namespace __sanitizer + +#endif // SANITIZER_FUCHSIA diff --git a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h new file mode 100644 index 00000000000..4d0d96a64f6 --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h @@ -0,0 +1,21 @@ +//===-- sanitizer_ptrauth.h -------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef SANITIZER_PTRAUTH_H +#define SANITIZER_PTRAUTH_H + +#if __has_feature(ptrauth_calls) +#include +#else +// Copied from +#define ptrauth_strip(__value, __key) __value +#define ptrauth_auth_data(__value, __old_key, __old_data) __value +#define ptrauth_string_discriminator(__string) ((int)0) +#endif + +#endif // SANITIZER_PTRAUTH_H diff --git a/libsanitizer/sanitizer_common/sanitizer_rtems.cpp b/libsanitizer/sanitizer_common/sanitizer_rtems.cpp index 0d2576c00ab..29bcfcfa6f1 100644 --- a/libsanitizer/sanitizer_common/sanitizer_rtems.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_rtems.cpp @@ -49,6 +49,10 @@ uptr internal_getpid() { return getpid(); } +int internal_dlinfo(void *handle, int request, void *p) { + UNIMPLEMENTED(); +} + bool FileExists(const char *filename) { struct stat st; if (stat(filename, &st)) diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp index ce75cbe5d26..ef14fb704ee 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp @@ -60,8 +60,8 @@ static inline uhwptr *GetCanonicFrame(uptr bp, // Nope, this does not look right either. This means the frame after next does // not have a valid frame pointer, but we can still extract the caller PC. // Unfortunately, there is no way to decide between GCC and LLVM frame - // layouts. Assume GCC. - return bp_prev - 1; + // layouts. Assume LLVM. + return bp_prev; #else return (uhwptr*)bp; #endif @@ -84,21 +84,14 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top, IsAligned((uptr)frame, sizeof(*frame)) && size < max_depth) { #ifdef __powerpc__ - // PowerPC ABIs specify that the return address is saved on the - // *caller's* stack frame. Thus we must dereference the back chain - // to find the caller frame before extracting it. + // PowerPC ABIs specify that the return address is saved at offset + // 16 of the *caller's* stack frame. Thus we must dereference the + // back chain to find the caller frame before extracting it. uhwptr *caller_frame = (uhwptr*)frame[0]; if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) || !IsAligned((uptr)caller_frame, sizeof(uhwptr))) break; - // For most ABIs the offset where the return address is saved is two - // register sizes. The exception is the SVR4 ABI, which uses an - // offset of only one register size. -#ifdef _CALL_SYSV - uhwptr pc1 = caller_frame[1]; -#else uhwptr pc1 = caller_frame[2]; -#endif #elif defined(__s390__) uhwptr pc1 = frame[14]; #else diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp new file mode 100644 index 00000000000..3a246443ed9 --- /dev/null +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp @@ -0,0 +1,42 @@ +//===-- sanitizer_stoptheworld_fuchsia.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +// +// See sanitizer_stoptheworld.h for details. +// +//===---------------------------------------------------------------------===// + +#include "sanitizer_platform.h" + +#if SANITIZER_FUCHSIA + +#include + +#include "sanitizer_stoptheworld.h" + +namespace __sanitizer { + +// The Fuchsia implementation stops the world but doesn't offer a real +// SuspendedThreadsList argument. This is enough for ASan's use case, +// and LSan does not use this API on Fuchsia. +void StopTheWorld(StopTheWorldCallback callback, void *argument) { + struct Params { + StopTheWorldCallback callback; + void *argument; + } params = {callback, argument}; + __sanitizer_memory_snapshot( + nullptr, nullptr, nullptr, nullptr, + [](zx_status_t, void *data) { + auto params = reinterpret_cast(data); + params->callback({}, params->argument); + }, + ¶ms); +} + +} // namespace __sanitizer + +#endif // SANITIZER_FUCHSIA diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp index 9dffd21ecb7..6c577426ad5 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp @@ -50,7 +50,7 @@ struct RunThreadArgs { void *argument; }; -void RunThread(void *arg) { +void *RunThread(void *arg) { struct RunThreadArgs *run_args = (struct RunThreadArgs *)arg; SuspendedThreadsListMac suspended_threads_list; @@ -59,7 +59,7 @@ void RunThread(void *arg) { kern_return_t err = task_threads(mach_task_self(), &threads, &num_threads); if (err != KERN_SUCCESS) { VReport(1, "Failed to get threads for task (errno %d).\n", err); - return; + return nullptr; } thread_t thread_self = mach_thread_self(); @@ -76,6 +76,7 @@ void RunThread(void *arg) { for (unsigned int i = 0; i < num_suspended; ++i) { thread_resume(suspended_threads_list.GetThread(i)); } + return nullptr; } void StopTheWorld(StopTheWorldCallback callback, void *argument) { @@ -159,7 +160,11 @@ PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP( } internal_memcpy(buffer, ®s, sizeof(regs)); +#if defined(__aarch64__) && defined(arm_thread_state64_get_sp) + *sp = arm_thread_state64_get_sp(regs); +#else *sp = regs.SP_REG; +#endif // On x86_64 and aarch64, we must account for the stack redzone, which is 128 // bytes. diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp index 5690d75097f..1ed21343254 100644 --- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp @@ -120,10 +120,18 @@ bool ThreadSuspender::SuspendAllThreads() { VReport(2, "Attached to process %d.\n", pid_); +#ifdef PT_LWPNEXT + struct ptrace_lwpstatus pl; + int op = PT_LWPNEXT; +#else struct ptrace_lwpinfo pl; - int val; + int op = PT_LWPINFO; +#endif + pl.pl_lwpid = 0; - while ((val = ptrace(PT_LWPINFO, pid_, (void *)&pl, sizeof(pl))) != -1 && + + int val; + while ((val = ptrace(op, pid_, (void *)&pl, sizeof(pl))) != -1 && pl.pl_lwpid != 0) { suspended_threads_list_.Append(pl.pl_lwpid); VReport(2, "Appended thread %d in process %d.\n", pl.pl_lwpid, pid_); diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp index ce2ece5f4d5..0c4b84c767a 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp @@ -126,4 +126,10 @@ Symbolizer::SymbolizerScope::~SymbolizerScope() { sym_->end_hook_(); } +void Symbolizer::LateInitializeTools() { + for (auto &tool : tools_) { + tool.LateInitialize(); + } +} + } // namespace __sanitizer diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h index 51648e2d0e8..2476b0ea7bf 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h @@ -209,6 +209,9 @@ class Symbolizer final { private: const Symbolizer *sym_; }; + + // Calls `LateInitialize()` on all items in `tools_`. + void LateInitializeTools(); }; #ifdef SANITIZER_WINDOWS diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h index c04797dd61b..e4c351e667b 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h @@ -69,6 +69,11 @@ class SymbolizerTool { virtual const char *Demangle(const char *name) { return nullptr; } + + // Called during the LateInitialize phase of Sanitizer initialization. + // Usually this is a safe place to call code that might need to use user + // memory allocators. + virtual void LateInitialize() {} }; // SymbolizerProcess encapsulates communication between the tool and @@ -86,6 +91,8 @@ class SymbolizerProcess { // Customizable by subclasses. virtual bool StartSymbolizerSubprocess(); virtual bool ReadFromSymbolizer(char *buffer, uptr max_length); + // Return the environment to run the symbolizer in. + virtual char **GetEnvP() { return GetEnviron(); } private: virtual bool ReachedEndOfOutput(const char *buffer, uptr length) const { diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp index 3b19a6836ec..490c6fe89be 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp @@ -39,9 +39,9 @@ const char *ExtractToken(const char *str, const char *delims, char **result) { } const char *ExtractInt(const char *str, const char *delims, int *result) { - char *buff; + char *buff = nullptr; const char *ret = ExtractToken(str, delims, &buff); - if (buff != 0) { + if (buff) { *result = (int)internal_atoll(buff); } InternalFree(buff); @@ -49,9 +49,9 @@ const char *ExtractInt(const char *str, const char *delims, int *result) { } const char *ExtractUptr(const char *str, const char *delims, uptr *result) { - char *buff; + char *buff = nullptr; const char *ret = ExtractToken(str, delims, &buff); - if (buff != 0) { + if (buff) { *result = (uptr)internal_atoll(buff); } InternalFree(buff); @@ -59,9 +59,9 @@ const char *ExtractUptr(const char *str, const char *delims, uptr *result) { } const char *ExtractSptr(const char *str, const char *delims, sptr *result) { - char *buff; + char *buff = nullptr; const char *ret = ExtractToken(str, delims, &buff); - if (buff != 0) { + if (buff) { *result = (sptr)internal_atoll(buff); } InternalFree(buff); @@ -83,7 +83,7 @@ const char *ExtractTokenUpToDelimiter(const char *str, const char *delimiter, SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) { BlockingMutexLock l(&mu_); - const char *module_name; + const char *module_name = nullptr; uptr module_offset; ModuleArch arch; SymbolizedStack *res = SymbolizedStack::New(addr); @@ -103,7 +103,7 @@ SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) { bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { BlockingMutexLock l(&mu_); - const char *module_name; + const char *module_name = nullptr; uptr module_offset; ModuleArch arch; if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset, @@ -124,7 +124,7 @@ bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) { bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { BlockingMutexLock l(&mu_); - const char *module_name; + const char *module_name = nullptr; if (!FindModuleNameAndOffsetForAddress( addr, &module_name, &info->module_offset, &info->module_arch)) return false; @@ -175,7 +175,7 @@ bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address, uptr *module_offset, ModuleArch *module_arch) { const LoadedModule *module = FindModuleForAddress(address); - if (module == nullptr) + if (!module) return false; *module_name = module->full_name(); *module_offset = address - module->base_address(); @@ -292,7 +292,7 @@ LLVMSymbolizer::LLVMSymbolizer(const char *path, LowLevelAllocator *allocator) // Windows, so extract tokens from the right hand side first. The column info is // also optional. static const char *ParseFileLineInfo(AddressInfo *info, const char *str) { - char *file_line_info = 0; + char *file_line_info = nullptr; str = ExtractToken(str, "\n", &file_line_info); CHECK(file_line_info); @@ -323,7 +323,7 @@ void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) { bool top_frame = true; SymbolizedStack *last = res; while (true) { - char *function_name = 0; + char *function_name = nullptr; str = ExtractToken(str, "\n", &function_name); CHECK(function_name); if (function_name[0] == '\0') { @@ -402,32 +402,29 @@ bool LLVMSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { AddressInfo *info = &stack->info; const char *buf = FormatAndSendCommand( "CODE", info->module, info->module_offset, info->module_arch); - if (buf) { - ParseSymbolizePCOutput(buf, stack); - return true; - } - return false; + if (!buf) + return false; + ParseSymbolizePCOutput(buf, stack); + return true; } bool LLVMSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { const char *buf = FormatAndSendCommand( "DATA", info->module, info->module_offset, info->module_arch); - if (buf) { - ParseSymbolizeDataOutput(buf, info); - info->start += (addr - info->module_offset); // Add the base address. - return true; - } - return false; + if (!buf) + return false; + ParseSymbolizeDataOutput(buf, info); + info->start += (addr - info->module_offset); // Add the base address. + return true; } bool LLVMSymbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { const char *buf = FormatAndSendCommand( "FRAME", info->module, info->module_offset, info->module_arch); - if (buf) { - ParseSymbolizeFrameOutput(buf, &info->locals); - return true; - } - return false; + if (!buf) + return false; + ParseSymbolizeFrameOutput(buf, &info->locals); + return true; } const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix, @@ -435,21 +432,21 @@ const char *LLVMSymbolizer::FormatAndSendCommand(const char *command_prefix, uptr module_offset, ModuleArch arch) { CHECK(module_name); - if (arch == kModuleArchUnknown) { - if (internal_snprintf(buffer_, kBufferSize, "%s \"%s\" 0x%zx\n", - command_prefix, module_name, - module_offset) >= static_cast(kBufferSize)) { - Report("WARNING: Command buffer too small"); - return nullptr; - } - } else { - if (internal_snprintf(buffer_, kBufferSize, "%s \"%s:%s\" 0x%zx\n", - command_prefix, module_name, ModuleArchToString(arch), - module_offset) >= static_cast(kBufferSize)) { - Report("WARNING: Command buffer too small"); - return nullptr; - } + int size_needed = 0; + if (arch == kModuleArchUnknown) + size_needed = internal_snprintf(buffer_, kBufferSize, "%s \"%s\" 0x%zx\n", + command_prefix, module_name, module_offset); + else + size_needed = internal_snprintf(buffer_, kBufferSize, + "%s \"%s:%s\" 0x%zx\n", command_prefix, + module_name, ModuleArchToString(arch), + module_offset); + + if (size_needed >= static_cast(kBufferSize)) { + Report("WARNING: Command buffer too small"); + return nullptr; } + return symbolizer_process_->SendCommand(buffer_); } @@ -492,16 +489,16 @@ const char *SymbolizerProcess::SendCommand(const char *command) { Report("WARNING: Failed to use and restart external symbolizer!\n"); failed_to_start_ = true; } - return 0; + return nullptr; } const char *SymbolizerProcess::SendCommandImpl(const char *command) { if (input_fd_ == kInvalidFd || output_fd_ == kInvalidFd) - return 0; + return nullptr; if (!WriteToSymbolizer(command, internal_strlen(command))) - return 0; + return nullptr; if (!ReadFromSymbolizer(buffer_, kBufferSize)) - return 0; + return nullptr; return buffer_; } diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp index a619ed092f0..cc233408d0c 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -31,6 +32,9 @@ bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { Dl_info info; int result = dladdr((const void *)addr, &info); if (!result) return false; + + CHECK(addr >= reinterpret_cast(info.dli_saddr)); + stack->info.function_offset = addr - reinterpret_cast(info.dli_saddr); const char *demangled = DemangleSwiftAndCXX(info.dli_sname); if (!demangled) return false; stack->info.function = internal_strdup(demangled); @@ -47,18 +51,65 @@ bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) { return true; } +#define K_ATOS_ENV_VAR "__check_mach_ports_lookup" + +// This cannot live in `AtosSymbolizerProcess` because instances of that object +// are allocated by the internal allocator which under ASan is poisoned with +// kAsanInternalHeapMagic. +static char kAtosMachPortEnvEntry[] = K_ATOS_ENV_VAR "=000000000000000"; + class AtosSymbolizerProcess : public SymbolizerProcess { public: - explicit AtosSymbolizerProcess(const char *path, pid_t parent_pid) + explicit AtosSymbolizerProcess(const char *path) : SymbolizerProcess(path, /*use_posix_spawn*/ true) { - // Put the string command line argument in the object so that it outlives - // the call to GetArgV. - internal_snprintf(pid_str_, sizeof(pid_str_), "%d", parent_pid); + pid_str_[0] = '\0'; + } + + void LateInitialize() { + if (SANITIZER_IOSSIM) { + // `putenv()` may call malloc/realloc so it is only safe to do this + // during LateInitialize() or later (i.e. we can't do this in the + // constructor). We also can't do this in `StartSymbolizerSubprocess()` + // because in TSan we switch allocators when we're symbolizing. + // We use `putenv()` rather than `setenv()` so that we can later directly + // write into the storage without LibC getting involved to change what the + // variable is set to + int result = putenv(kAtosMachPortEnvEntry); + CHECK_EQ(result, 0); + } } private: bool StartSymbolizerSubprocess() override { // Configure sandbox before starting atos process. + + // Put the string command line argument in the object so that it outlives + // the call to GetArgV. + internal_snprintf(pid_str_, sizeof(pid_str_), "%d", internal_getpid()); + + if (SANITIZER_IOSSIM) { + // `atos` in the simulator is restricted in its ability to retrieve the + // task port for the target process (us) so we need to do extra work + // to pass our task port to it. + mach_port_t ports[]{mach_task_self()}; + kern_return_t ret = + mach_ports_register(mach_task_self(), ports, /*count=*/1); + CHECK_EQ(ret, KERN_SUCCESS); + + // Set environment variable that signals to `atos` that it should look + // for our task port. We can't call `setenv()` here because it might call + // malloc/realloc. To avoid that we instead update the + // `mach_port_env_var_entry_` variable with our current PID. + uptr count = internal_snprintf(kAtosMachPortEnvEntry, + sizeof(kAtosMachPortEnvEntry), + K_ATOS_ENV_VAR "=%s", pid_str_); + CHECK_GE(count, sizeof(K_ATOS_ENV_VAR) + internal_strlen(pid_str_)); + // Document our assumption but without calling `getenv()` in normal + // builds. + DCHECK(getenv(K_ATOS_ENV_VAR)); + DCHECK_EQ(internal_strcmp(getenv(K_ATOS_ENV_VAR), pid_str_), 0); + } + return SymbolizerProcess::StartSymbolizerSubprocess(); } @@ -82,8 +133,14 @@ class AtosSymbolizerProcess : public SymbolizerProcess { } char pid_str_[16]; + // Space for `\0` in `K_ATOS_ENV_VAR` is reused for `=`. + static_assert(sizeof(kAtosMachPortEnvEntry) == + (sizeof(K_ATOS_ENV_VAR) + sizeof(pid_str_)), + "sizes should match"); }; +#undef K_ATOS_ENV_VAR + static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, char **out_module, char **out_file, uptr *line, uptr *start_address) { @@ -135,7 +192,7 @@ static bool ParseCommandOutput(const char *str, uptr addr, char **out_name, } AtosSymbolizer::AtosSymbolizer(const char *path, LowLevelAllocator *allocator) - : process_(new(*allocator) AtosSymbolizerProcess(path, getpid())) {} + : process_(new (*allocator) AtosSymbolizerProcess(path)) {} bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { if (!process_) return false; @@ -145,12 +202,29 @@ bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) { const char *buf = process_->SendCommand(command); if (!buf) return false; uptr line; + uptr start_address = AddressInfo::kUnknown; if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module, - &stack->info.file, &line, nullptr)) { + &stack->info.file, &line, &start_address)) { process_ = nullptr; return false; } stack->info.line = (int)line; + + if (start_address == AddressInfo::kUnknown) { + // Fallback to dladdr() to get function start address if atos doesn't report + // it. + Dl_info info; + int result = dladdr((const void *)addr, &info); + if (result) + start_address = reinterpret_cast(info.dli_saddr); + } + + // Only assig to `function_offset` if we were able to get the function's + // start address. + if (start_address != AddressInfo::kUnknown) { + CHECK(addr >= start_address); + stack->info.function_offset = addr - start_address; + } return true; } @@ -168,6 +242,8 @@ bool AtosSymbolizer::SymbolizeData(uptr addr, DataInfo *info) { return true; } +void AtosSymbolizer::LateInitialize() { process_->LateInitialize(); } + } // namespace __sanitizer #endif // SANITIZER_MAC diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h index 68521375e64..8996131fc13 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h @@ -35,6 +35,7 @@ class AtosSymbolizer : public SymbolizerTool { bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; bool SymbolizeData(uptr addr, DataInfo *info) override; + void LateInitialize() override; private: AtosSymbolizerProcess *process_; diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp index 57b4d0c9d96..2963af95360 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp @@ -94,7 +94,9 @@ Symbolizer *Symbolizer::PlatformInit() { return new (symbolizer_allocator_) Symbolizer({}); } -void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); } +void Symbolizer::LateInitialize() { + Symbolizer::GetOrInit()->LateInitializeTools(); +} void StartReportDeadlySignal() {} void ReportDeadlySignal(const SignalContext &sig, u32 tid, diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp index c123ecb1120..d7b931bc237 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp @@ -151,9 +151,19 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() { GetArgV(path_, argv); pid_t pid; + // Report how symbolizer is being launched for debugging purposes. + if (Verbosity() >= 3) { + // Only use `Report` for first line so subsequent prints don't get prefixed + // with current PID. + Report("Launching Symbolizer process: "); + for (unsigned index = 0; index < kArgVMax && argv[index]; ++index) + Printf("%s ", argv[index]); + Printf("\n"); + } + if (use_posix_spawn_) { #if SANITIZER_MAC - fd_t fd = internal_spawn(argv, &pid); + fd_t fd = internal_spawn(argv, const_cast(GetEnvP()), &pid); if (fd == kInvalidFd) { Report("WARNING: failed to spawn external symbolizer (errno: %d)\n", errno); @@ -173,7 +183,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() { return false; } - pid = StartSubprocess(path_, argv, /* stdin */ outfd[0], + pid = StartSubprocess(path_, argv, GetEnvP(), /* stdin */ outfd[0], /* stdout */ infd[1]); if (pid < 0) { internal_close(infd[0]); @@ -478,7 +488,7 @@ Symbolizer *Symbolizer::PlatformInit() { } void Symbolizer::LateInitialize() { - Symbolizer::GetOrInit(); + Symbolizer::GetOrInit()->LateInitializeTools(); InitializeSwiftDemangler(); } diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp index 2808779156e..373437e7ee2 100644 --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp @@ -310,7 +310,7 @@ Symbolizer *Symbolizer::PlatformInit() { } void Symbolizer::LateInitialize() { - Symbolizer::GetOrInit(); + Symbolizer::GetOrInit()->LateInitializeTools(); } } // namespace __sanitizer diff --git a/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc b/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc index 69e59871874..02b7e11b167 100644 --- a/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc +++ b/libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc @@ -42,7 +42,7 @@ // DO NOT EDIT! THIS FILE HAS BEEN GENERATED! // // Generated with: generate_netbsd_syscalls.awk -// Generated date: 2019-11-01 +// Generated date: 2019-12-24 // Generated from: syscalls.master,v 1.296 2019/09/22 22:59:39 christos Exp // //===----------------------------------------------------------------------===// @@ -323,6 +323,16 @@ PRE_SYSCALL(ptrace) PRE_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz); } else if (req_ == ptrace_pt_get_siginfo) { PRE_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz); + } else if (req_ == ptrace_pt_lwpstatus) { + struct __sanitizer_ptrace_lwpstatus *addr = + (struct __sanitizer_ptrace_lwpstatus *)addr_; + PRE_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); + PRE_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz); + } else if (req_ == ptrace_pt_lwpnext) { + struct __sanitizer_ptrace_lwpstatus *addr = + (struct __sanitizer_ptrace_lwpstatus *)addr_; + PRE_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); + PRE_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz); } else if (req_ == ptrace_pt_setregs) { PRE_READ(addr_, struct_ptrace_reg_struct_sz); } else if (req_ == ptrace_pt_getregs) { @@ -366,6 +376,16 @@ POST_SYSCALL(ptrace) POST_READ(addr_, struct_ptrace_ptrace_siginfo_struct_sz); } else if (req_ == ptrace_pt_get_siginfo) { POST_WRITE(addr_, struct_ptrace_ptrace_siginfo_struct_sz); + } else if (req_ == ptrace_pt_lwpstatus) { + struct __sanitizer_ptrace_lwpstatus *addr = + (struct __sanitizer_ptrace_lwpstatus *)addr_; + POST_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); + POST_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz); + } else if (req_ == ptrace_pt_lwpnext) { + struct __sanitizer_ptrace_lwpstatus *addr = + (struct __sanitizer_ptrace_lwpstatus *)addr_; + POST_READ(&addr->pl_lwpid, sizeof(__sanitizer_lwpid_t)); + POST_WRITE(addr, struct_ptrace_ptrace_lwpstatus_struct_sz); } else if (req_ == ptrace_pt_setregs) { POST_READ(addr_, struct_ptrace_reg_struct_sz); } else if (req_ == ptrace_pt_getregs) { diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_win.cpp index 36dde49d870..fca15beb616 100644 --- a/libsanitizer/sanitizer_common/sanitizer_win.cpp +++ b/libsanitizer/sanitizer_common/sanitizer_win.cpp @@ -94,6 +94,10 @@ uptr internal_getpid() { return GetProcessId(GetCurrentProcess()); } +int internal_dlinfo(void *handle, int request, void *p) { + UNIMPLEMENTED(); +} + // In contrast to POSIX, on Windows GetCurrentThreadId() // returns a system-unique identifier. tid_t GetTid() { @@ -787,7 +791,7 @@ uptr GetRSS() { return counters.WorkingSetSize; } -void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; } +void *internal_start_thread(void *(*func)(void *arg), void *arg) { return 0; } void internal_join_thread(void *th) { } // ---------------------- BlockingMutex ---------------- {{{1 @@ -1060,7 +1064,8 @@ char **GetEnviron() { } pid_t StartSubprocess(const char *program, const char *const argv[], - fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) { + const char *const envp[], fd_t stdin_fd, fd_t stdout_fd, + fd_t stderr_fd) { // FIXME: implement on this platform // Should be implemented based on // SymbolizerProcess::StarAtSymbolizerSubprocess diff --git a/libsanitizer/tsan/tsan_clock.cpp b/libsanitizer/tsan/tsan_clock.cpp index 4b7aa0653da..c91b29cb22b 100644 --- a/libsanitizer/tsan/tsan_clock.cpp +++ b/libsanitizer/tsan/tsan_clock.cpp @@ -30,6 +30,14 @@ // dst->clock[i] = max(dst->clock[i], clock[i]); // } // +// void ThreadClock::releaseStoreAcquire(SyncClock *sc) const { +// for (int i = 0; i < kMaxThreads; i++) { +// tmp = clock[i]; +// clock[i] = max(clock[i], sc->clock[i]); +// sc->clock[i] = tmp; +// } +// } +// // void ThreadClock::ReleaseStore(SyncClock *dst) const { // for (int i = 0; i < kMaxThreads; i++) // dst->clock[i] = clock[i]; @@ -107,13 +115,14 @@ static void UnrefClockBlock(ClockCache *c, u32 idx, uptr blocks) { ThreadClock::ThreadClock(unsigned tid, unsigned reused) : tid_(tid) , reused_(reused + 1) // 0 has special meaning + , last_acquire_() + , global_acquire_() , cached_idx_() , cached_size_() , cached_blocks_() { CHECK_LT(tid, kMaxTidInClock); CHECK_EQ(reused_, ((u64)reused_ << kClkBits) >> kClkBits); nclk_ = tid_ + 1; - last_acquire_ = 0; internal_memset(clk_, 0, sizeof(clk_)); } @@ -177,6 +186,49 @@ void ThreadClock::acquire(ClockCache *c, SyncClock *src) { } } +void ThreadClock::releaseStoreAcquire(ClockCache *c, SyncClock *sc) { + DCHECK_LE(nclk_, kMaxTid); + DCHECK_LE(sc->size_, kMaxTid); + + if (sc->size_ == 0) { + // ReleaseStore will correctly set release_store_tid_, + // which can be important for future operations. + ReleaseStore(c, sc); + return; + } + + nclk_ = max(nclk_, (uptr) sc->size_); + + // Check if we need to resize sc. + if (sc->size_ < nclk_) + sc->Resize(c, nclk_); + + bool acquired = false; + + sc->Unshare(c); + // Update sc->clk_. + sc->FlushDirty(); + uptr i = 0; + for (ClockElem &ce : *sc) { + u64 tmp = clk_[i]; + if (clk_[i] < ce.epoch) { + clk_[i] = ce.epoch; + acquired = true; + } + ce.epoch = tmp; + ce.reused = 0; + i++; + } + sc->release_store_tid_ = kInvalidTid; + sc->release_store_reused_ = 0; + + if (acquired) { + CPP_STAT_INC(StatClockAcquiredSomething); + last_acquire_ = clk_[tid_]; + ResetCached(c); + } +} + void ThreadClock::release(ClockCache *c, SyncClock *dst) { DCHECK_LE(nclk_, kMaxTid); DCHECK_LE(dst->size_, kMaxTid); @@ -196,7 +248,7 @@ void ThreadClock::release(ClockCache *c, SyncClock *dst) { // Check if we had not acquired anything from other threads // since the last release on dst. If so, we need to update // only dst->elem(tid_). - if (dst->elem(tid_).epoch > last_acquire_) { + if (!HasAcquiredAfterRelease(dst)) { UpdateCurrentThread(c, dst); if (dst->release_store_tid_ != tid_ || dst->release_store_reused_ != reused_) @@ -222,8 +274,6 @@ void ThreadClock::release(ClockCache *c, SyncClock *dst) { // Clear 'acquired' flag in the remaining elements. if (nclk_ < dst->size_) CPP_STAT_INC(StatClockReleaseClearTail); - for (uptr i = nclk_; i < dst->size_; i++) - dst->elem(i).reused = 0; dst->release_store_tid_ = kInvalidTid; dst->release_store_reused_ = 0; // If we've acquired dst, remember this fact, @@ -269,7 +319,7 @@ void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) { if (dst->release_store_tid_ == tid_ && dst->release_store_reused_ == reused_ && - dst->elem(tid_).epoch > last_acquire_) { + !HasAcquiredAfterRelease(dst)) { CPP_STAT_INC(StatClockStoreFast); UpdateCurrentThread(c, dst); return; @@ -351,6 +401,14 @@ bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const { return true; } +// Checks whether the current thread has acquired anything +// from other clocks after releasing to dst (directly or indirectly). +bool ThreadClock::HasAcquiredAfterRelease(const SyncClock *dst) const { + const u64 my_epoch = dst->elem(tid_).epoch; + return my_epoch <= last_acquire_ || + my_epoch <= atomic_load_relaxed(&global_acquire_); +} + // Sets a single element in the vector clock. // This function is called only from weird places like AcquireGlobal. void ThreadClock::set(ClockCache *c, unsigned tid, u64 v) { diff --git a/libsanitizer/tsan/tsan_clock.h b/libsanitizer/tsan/tsan_clock.h index 6a1d15a2a16..736cdae06ba 100644 --- a/libsanitizer/tsan/tsan_clock.h +++ b/libsanitizer/tsan/tsan_clock.h @@ -134,10 +134,12 @@ class ThreadClock { uptr size() const; void acquire(ClockCache *c, SyncClock *src); + void releaseStoreAcquire(ClockCache *c, SyncClock *src); void release(ClockCache *c, SyncClock *dst); void acq_rel(ClockCache *c, SyncClock *dst); void ReleaseStore(ClockCache *c, SyncClock *dst); void ResetCached(ClockCache *c); + void NoteGlobalAcquire(u64 v); void DebugReset(); void DebugDump(int(*printf)(const char *s, ...)); @@ -150,6 +152,53 @@ class ThreadClock { // Current thread time when it acquired something from other threads. u64 last_acquire_; + // Last time another thread has done a global acquire of this thread's clock. + // It helps to avoid problem described in: + // https://github.com/golang/go/issues/39186 + // See test/tsan/java_finalizer2.cpp for a regression test. + // Note the failuire is _extremely_ hard to hit, so if you are trying + // to reproduce it, you may want to run something like: + // $ go get golang.org/x/tools/cmd/stress + // $ stress -p=64 ./a.out + // + // The crux of the problem is roughly as follows. + // A number of O(1) optimizations in the clocks algorithm assume proper + // transitive cumulative propagation of clock values. The AcquireGlobal + // operation may produce an inconsistent non-linearazable view of + // thread clocks. Namely, it may acquire a later value from a thread + // with a higher ID, but fail to acquire an earlier value from a thread + // with a lower ID. If a thread that executed AcquireGlobal then releases + // to a sync clock, it will spoil the sync clock with the inconsistent + // values. If another thread later releases to the sync clock, the optimized + // algorithm may break. + // + // The exact sequence of events that leads to the failure. + // - thread 1 executes AcquireGlobal + // - thread 1 acquires value 1 for thread 2 + // - thread 2 increments clock to 2 + // - thread 2 releases to sync object 1 + // - thread 3 at time 1 + // - thread 3 acquires from sync object 1 + // - thread 3 increments clock to 2 + // - thread 1 acquires value 2 for thread 3 + // - thread 1 releases to sync object 2 + // - sync object 2 clock has 1 for thread 2 and 2 for thread 3 + // - thread 3 releases to sync object 2 + // - thread 3 sees value 2 in the clock for itself + // and decides that it has already released to the clock + // and did not acquire anything from other threads after that + // (the last_acquire_ check in release operation) + // - thread 3 does not update the value for thread 2 in the clock from 1 to 2 + // - thread 4 acquires from sync object 2 + // - thread 4 detects a false race with thread 2 + // as it should have been synchronized with thread 2 up to time 2, + // but because of the broken clock it is now synchronized only up to time 1 + // + // The global_acquire_ value helps to prevent this scenario. + // Namely, thread 3 will not trust any own clock values up to global_acquire_ + // for the purposes of the last_acquire_ optimization. + atomic_uint64_t global_acquire_; + // Cached SyncClock (without dirty entries and release_store_tid_). // We reuse it for subsequent store-release operations without intervening // acquire operations. Since it is shared (and thus constant), clock value @@ -164,6 +213,7 @@ class ThreadClock { u64 clk_[kMaxTidInClock]; // Fixed size vector clock. bool IsAlreadyAcquired(const SyncClock *src) const; + bool HasAcquiredAfterRelease(const SyncClock *dst) const; void UpdateCurrentThread(ClockCache *c, SyncClock *dst) const; }; @@ -185,6 +235,14 @@ ALWAYS_INLINE uptr ThreadClock::size() const { return nclk_; } +ALWAYS_INLINE void ThreadClock::NoteGlobalAcquire(u64 v) { + // Here we rely on the fact that AcquireGlobal is protected by + // ThreadRegistryLock, thus only one thread at a time executes it + // and values passed to this function should not go backwards. + CHECK_LE(atomic_load_relaxed(&global_acquire_), v); + atomic_store_relaxed(&global_acquire_, v); +} + ALWAYS_INLINE SyncClock::Iter SyncClock::begin() { return Iter(this); } diff --git a/libsanitizer/tsan/tsan_interceptors_posix.cpp b/libsanitizer/tsan/tsan_interceptors_posix.cpp index 8aea1e4ec05..718957c3703 100644 --- a/libsanitizer/tsan/tsan_interceptors_posix.cpp +++ b/libsanitizer/tsan/tsan_interceptors_posix.cpp @@ -891,13 +891,16 @@ void DestroyThreadState() { ThreadFinish(thr); ProcUnwire(proc, thr); ProcDestroy(proc); + DTLS_Destroy(); + cur_thread_finalize(); +} + +void PlatformCleanUpThreadState(ThreadState *thr) { ThreadSignalContext *sctx = thr->signal_ctx; if (sctx) { thr->signal_ctx = 0; UnmapOrDie(sctx, sizeof(*sctx)); } - DTLS_Destroy(); - cur_thread_finalize(); } } // namespace __tsan @@ -1016,7 +1019,7 @@ TSAN_INTERCEPTOR(int, pthread_create, TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) { SCOPED_INTERCEPTOR_RAW(pthread_join, th, ret); - int tid = ThreadTid(thr, pc, (uptr)th); + int tid = ThreadConsumeTid(thr, pc, (uptr)th); ThreadIgnoreBegin(thr, pc); int res = BLOCK_REAL(pthread_join)(th, ret); ThreadIgnoreEnd(thr, pc); @@ -1029,8 +1032,8 @@ TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) { DEFINE_REAL_PTHREAD_FUNCTIONS TSAN_INTERCEPTOR(int, pthread_detach, void *th) { - SCOPED_TSAN_INTERCEPTOR(pthread_detach, th); - int tid = ThreadTid(thr, pc, (uptr)th); + SCOPED_INTERCEPTOR_RAW(pthread_detach, th); + int tid = ThreadConsumeTid(thr, pc, (uptr)th); int res = REAL(pthread_detach)(th); if (res == 0) { ThreadDetach(thr, pc, tid); @@ -1050,8 +1053,8 @@ TSAN_INTERCEPTOR(void, pthread_exit, void *retval) { #if SANITIZER_LINUX TSAN_INTERCEPTOR(int, pthread_tryjoin_np, void *th, void **ret) { - SCOPED_TSAN_INTERCEPTOR(pthread_tryjoin_np, th, ret); - int tid = ThreadTid(thr, pc, (uptr)th); + SCOPED_INTERCEPTOR_RAW(pthread_tryjoin_np, th, ret); + int tid = ThreadConsumeTid(thr, pc, (uptr)th); ThreadIgnoreBegin(thr, pc); int res = REAL(pthread_tryjoin_np)(th, ret); ThreadIgnoreEnd(thr, pc); @@ -1064,8 +1067,8 @@ TSAN_INTERCEPTOR(int, pthread_tryjoin_np, void *th, void **ret) { TSAN_INTERCEPTOR(int, pthread_timedjoin_np, void *th, void **ret, const struct timespec *abstime) { - SCOPED_TSAN_INTERCEPTOR(pthread_timedjoin_np, th, ret, abstime); - int tid = ThreadTid(thr, pc, (uptr)th); + SCOPED_INTERCEPTOR_RAW(pthread_timedjoin_np, th, ret, abstime); + int tid = ThreadConsumeTid(thr, pc, (uptr)th); ThreadIgnoreBegin(thr, pc); int res = BLOCK_REAL(pthread_timedjoin_np)(th, ret, abstime); ThreadIgnoreEnd(thr, pc); diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h index 63eb14fcd34..7256d64e507 100644 --- a/libsanitizer/tsan/tsan_platform.h +++ b/libsanitizer/tsan/tsan_platform.h @@ -1021,6 +1021,7 @@ int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m, void(*cleanup)(void *arg), void *arg); void DestroyThreadState(); +void PlatformCleanUpThreadState(ThreadState *thr); } // namespace __tsan diff --git a/libsanitizer/tsan/tsan_platform_mac.cpp b/libsanitizer/tsan/tsan_platform_mac.cpp index 326ca8532e5..f92ecc5e40f 100644 --- a/libsanitizer/tsan/tsan_platform_mac.cpp +++ b/libsanitizer/tsan/tsan_platform_mac.cpp @@ -19,6 +19,7 @@ #include "sanitizer_common/sanitizer_libc.h" #include "sanitizer_common/sanitizer_posix.h" #include "sanitizer_common/sanitizer_procmaps.h" +#include "sanitizer_common/sanitizer_ptrauth.h" #include "sanitizer_common/sanitizer_stackdepot.h" #include "tsan_platform.h" #include "tsan_rtl.h" @@ -75,9 +76,14 @@ static uptr main_thread_identity = 0; ALIGNED(64) static char main_thread_state[sizeof(ThreadState)]; static ThreadState *main_thread_state_loc = (ThreadState *)main_thread_state; +// We cannot use pthread_self() before libpthread has been initialized. Our +// current heuristic for guarding this is checking `main_thread_identity` which +// is only assigned in `__tsan::InitializePlatform`. static ThreadState **cur_thread_location() { + if (main_thread_identity == 0) + return &main_thread_state_loc; uptr thread_identity = (uptr)pthread_self(); - if (thread_identity == main_thread_identity || main_thread_identity == 0) + if (thread_identity == main_thread_identity) return &main_thread_state_loc; return (ThreadState **)MemToShadow(thread_identity); } @@ -269,6 +275,8 @@ void InitializePlatform() { uptr ExtractLongJmpSp(uptr *env) { uptr mangled_sp = env[LONG_JMP_SP_ENV_SLOT]; uptr sp = mangled_sp ^ longjmp_xor_key; + sp = (uptr)ptrauth_auth_data((void *)sp, ptrauth_key_asdb, + ptrauth_string_discriminator("sp")); return sp; } diff --git a/libsanitizer/tsan/tsan_rtl.cpp b/libsanitizer/tsan/tsan_rtl.cpp index 3f3c0cce119..13c9b770f50 100644 --- a/libsanitizer/tsan/tsan_rtl.cpp +++ b/libsanitizer/tsan/tsan_rtl.cpp @@ -144,7 +144,7 @@ static void MemoryProfiler(Context *ctx, fd_t fd, int i) { WriteToFile(fd, buf.data(), internal_strlen(buf.data())); } -static void BackgroundThread(void *arg) { +static void *BackgroundThread(void *arg) { // This is a non-initialized non-user thread, nothing to see here. // We don't use ScopedIgnoreInterceptors, because we want ignores to be // enabled even when the thread function exits (e.g. during pthread thread @@ -220,6 +220,7 @@ static void BackgroundThread(void *arg) { } } } + return nullptr; } static void StartBackgroundThread() { @@ -494,14 +495,23 @@ int Finalize(ThreadState *thr) { void ForkBefore(ThreadState *thr, uptr pc) { ctx->thread_registry->Lock(); ctx->report_mtx.Lock(); + // Ignore memory accesses in the pthread_atfork callbacks. + // If any of them triggers a data race we will deadlock + // on the report_mtx. + // We could ignore interceptors and sync operations as well, + // but so far it's unclear if it will do more good or harm. + // Unnecessarily ignoring things can lead to false positives later. + ThreadIgnoreBegin(thr, pc); } void ForkParentAfter(ThreadState *thr, uptr pc) { + ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore. ctx->report_mtx.Unlock(); ctx->thread_registry->Unlock(); } void ForkChildAfter(ThreadState *thr, uptr pc) { + ThreadIgnoreEnd(thr, pc); // Begin is in ForkBefore. ctx->report_mtx.Unlock(); ctx->thread_registry->Unlock(); diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h index c38fc43a9f8..d3bb61ff87d 100644 --- a/libsanitizer/tsan/tsan_rtl.h +++ b/libsanitizer/tsan/tsan_rtl.h @@ -775,7 +775,7 @@ int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached); void ThreadStart(ThreadState *thr, int tid, tid_t os_id, ThreadType thread_type); void ThreadFinish(ThreadState *thr); -int ThreadTid(ThreadState *thr, uptr pc, uptr uid); +int ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid); void ThreadJoin(ThreadState *thr, uptr pc, int tid); void ThreadDetach(ThreadState *thr, uptr pc, int tid); void ThreadFinalize(ThreadState *thr); @@ -813,10 +813,12 @@ void Acquire(ThreadState *thr, uptr pc, uptr addr); // approximation of the actual required synchronization. void AcquireGlobal(ThreadState *thr, uptr pc); void Release(ThreadState *thr, uptr pc, uptr addr); +void ReleaseStoreAcquire(ThreadState *thr, uptr pc, uptr addr); void ReleaseStore(ThreadState *thr, uptr pc, uptr addr); void AfterSleep(ThreadState *thr, uptr pc); void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c); void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c); +void ReleaseStoreAcquireImpl(ThreadState *thr, uptr pc, SyncClock *c); void ReleaseStoreImpl(ThreadState *thr, uptr pc, SyncClock *c); void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c); diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cpp b/libsanitizer/tsan/tsan_rtl_mutex.cpp index ce6e7cb2c4e..ebd0d722181 100644 --- a/libsanitizer/tsan/tsan_rtl_mutex.cpp +++ b/libsanitizer/tsan/tsan_rtl_mutex.cpp @@ -415,8 +415,10 @@ static void UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) { ThreadState *thr = reinterpret_cast(arg); ThreadContext *tctx = static_cast(tctx_base); u64 epoch = tctx->epoch1; - if (tctx->status == ThreadStatusRunning) + if (tctx->status == ThreadStatusRunning) { epoch = tctx->thr->fast_state.epoch(); + tctx->thr->clock.NoteGlobalAcquire(epoch); + } thr->clock.set(&thr->proc()->clock_cache, tctx->tid, epoch); } @@ -429,6 +431,18 @@ void AcquireGlobal(ThreadState *thr, uptr pc) { UpdateClockCallback, thr); } +void ReleaseStoreAcquire(ThreadState *thr, uptr pc, uptr addr) { + DPrintf("#%d: ReleaseStoreAcquire %zx\n", thr->tid, addr); + if (thr->ignore_sync) + return; + SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true); + thr->fast_state.IncrementEpoch(); + // Can't increment epoch w/o writing to the trace as well. + TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0); + ReleaseStoreAcquireImpl(thr, pc, &s->clock); + s->mtx.Unlock(); +} + void Release(ThreadState *thr, uptr pc, uptr addr) { DPrintf("#%d: Release %zx\n", thr->tid, addr); if (thr->ignore_sync) @@ -482,6 +496,15 @@ void AcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) { StatInc(thr, StatSyncAcquire); } +void ReleaseStoreAcquireImpl(ThreadState *thr, uptr pc, SyncClock *c) { + if (thr->ignore_sync) + return; + thr->clock.set(thr->fast_state.epoch()); + thr->fast_synch_epoch = thr->fast_state.epoch(); + thr->clock.releaseStoreAcquire(&thr->proc()->clock_cache, c); + StatInc(thr, StatSyncReleaseStoreAcquire); +} + void ReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) { if (thr->ignore_sync) return; diff --git a/libsanitizer/tsan/tsan_rtl_ppc64.S b/libsanitizer/tsan/tsan_rtl_ppc64.S index 9e533a71a9c..8285e21aa1e 100644 --- a/libsanitizer/tsan/tsan_rtl_ppc64.S +++ b/libsanitizer/tsan/tsan_rtl_ppc64.S @@ -1,6 +1,5 @@ #include "tsan_ppc_regs.h" - .machine altivec .section .text .hidden __tsan_setjmp .globl _setjmp diff --git a/libsanitizer/tsan/tsan_rtl_thread.cpp b/libsanitizer/tsan/tsan_rtl_thread.cpp index 0ac1ee99c47..d80146735ea 100644 --- a/libsanitizer/tsan/tsan_rtl_thread.cpp +++ b/libsanitizer/tsan/tsan_rtl_thread.cpp @@ -144,6 +144,9 @@ void ThreadContext::OnFinished() { thr->clock.ResetCached(&thr->proc()->clock_cache); #if !SANITIZER_GO thr->last_sleep_clock.ResetCached(&thr->proc()->clock_cache); +#endif +#if !SANITIZER_GO + PlatformCleanUpThreadState(thr); #endif thr->~ThreadState(); #if TSAN_COLLECT_STATS @@ -285,19 +288,34 @@ void ThreadFinish(ThreadState *thr) { ctx->thread_registry->FinishThread(thr->tid); } -static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) { - uptr uid = (uptr)arg; - if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) { +struct ConsumeThreadContext { + uptr uid; + ThreadContextBase *tctx; +}; + +static bool ConsumeThreadByUid(ThreadContextBase *tctx, void *arg) { + ConsumeThreadContext *findCtx = (ConsumeThreadContext *)arg; + if (tctx->user_id == findCtx->uid && tctx->status != ThreadStatusInvalid) { + if (findCtx->tctx) { + // Ensure that user_id is unique. If it's not the case we are screwed. + // Something went wrong before, but now there is no way to recover. + // Returning a wrong thread is not an option, it may lead to very hard + // to debug false positives (e.g. if we join a wrong thread). + Report("ThreadSanitizer: dup thread with used id 0x%zx\n", findCtx->uid); + Die(); + } + findCtx->tctx = tctx; tctx->user_id = 0; - return true; } return false; } -int ThreadTid(ThreadState *thr, uptr pc, uptr uid) { - int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid); - DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res); - return res; +int ThreadConsumeTid(ThreadState *thr, uptr pc, uptr uid) { + ConsumeThreadContext findCtx = {uid, nullptr}; + ctx->thread_registry->FindThread(ConsumeThreadByUid, &findCtx); + int tid = findCtx.tctx ? findCtx.tctx->tid : ThreadRegistry::kUnknownTid; + DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, tid); + return tid; } void ThreadJoin(ThreadState *thr, uptr pc, int tid) { diff --git a/libsanitizer/tsan/tsan_stat.h b/libsanitizer/tsan/tsan_stat.h index 94e18bc66df..8b26a59bb2e 100644 --- a/libsanitizer/tsan/tsan_stat.h +++ b/libsanitizer/tsan/tsan_stat.h @@ -68,6 +68,7 @@ enum StatType { StatSyncDestroyed, StatSyncAcquire, StatSyncRelease, + StatSyncReleaseStoreAcquire, // Clocks - acquire. StatClockAcquire, diff --git a/libsanitizer/ubsan/ubsan_checks.inc b/libsanitizer/ubsan/ubsan_checks.inc index 33a8dfcde02..2c1529a7d92 100644 --- a/libsanitizer/ubsan/ubsan_checks.inc +++ b/libsanitizer/ubsan/ubsan_checks.inc @@ -18,6 +18,8 @@ UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined") UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null") +UBSAN_CHECK(NullPointerUseWithNullability, "null-pointer-use", + "nullability-assign") UBSAN_CHECK(NullptrWithOffset, "nullptr-with-offset", "pointer-overflow") UBSAN_CHECK(NullptrWithNonZeroOffset, "nullptr-with-nonzero-offset", "pointer-overflow") @@ -59,6 +61,10 @@ UBSAN_CHECK(InvalidEnumLoad, "invalid-enum-load", "enum") UBSAN_CHECK(FunctionTypeMismatch, "function-type-mismatch", "function") UBSAN_CHECK(InvalidNullReturn, "invalid-null-return", "returns-nonnull-attribute") +UBSAN_CHECK(InvalidNullReturnWithNullability, "invalid-null-return", + "nullability-return") UBSAN_CHECK(InvalidNullArgument, "invalid-null-argument", "nonnull-attribute") +UBSAN_CHECK(InvalidNullArgumentWithNullability, "invalid-null-argument", + "nullability-arg") UBSAN_CHECK(DynamicTypeMismatch, "dynamic-type-mismatch", "vptr") UBSAN_CHECK(CFIBadType, "cfi-bad-type", "cfi") diff --git a/libsanitizer/ubsan/ubsan_flags.cpp b/libsanitizer/ubsan/ubsan_flags.cpp index 80de2a6d101..721c2273f13 100644 --- a/libsanitizer/ubsan/ubsan_flags.cpp +++ b/libsanitizer/ubsan/ubsan_flags.cpp @@ -54,7 +54,6 @@ void InitializeFlags() { { CommonFlags cf; cf.CopyFrom(*common_flags()); - cf.print_summary = false; cf.external_symbolizer_path = GetFlag("UBSAN_SYMBOLIZER_PATH"); OverrideCommonFlags(cf); } diff --git a/libsanitizer/ubsan/ubsan_handlers.cpp b/libsanitizer/ubsan/ubsan_handlers.cpp index 0ddbb50c26c..7f6a46fb6cf 100644 --- a/libsanitizer/ubsan/ubsan_handlers.cpp +++ b/libsanitizer/ubsan/ubsan_handlers.cpp @@ -36,6 +36,45 @@ bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) { return SLoc.isDisabled() || IsPCSuppressed(ET, Opts.pc, SLoc.getFilename()); } +/// Situations in which we might emit a check for the suitability of a +/// pointer or glvalue. Needs to be kept in sync with CodeGenFunction.h in +/// clang. +enum TypeCheckKind { + /// Checking the operand of a load. Must be suitably sized and aligned. + TCK_Load, + /// Checking the destination of a store. Must be suitably sized and aligned. + TCK_Store, + /// Checking the bound value in a reference binding. Must be suitably sized + /// and aligned, but is not required to refer to an object (until the + /// reference is used), per core issue 453. + TCK_ReferenceBinding, + /// Checking the object expression in a non-static data member access. Must + /// be an object within its lifetime. + TCK_MemberAccess, + /// Checking the 'this' pointer for a call to a non-static member function. + /// Must be an object within its lifetime. + TCK_MemberCall, + /// Checking the 'this' pointer for a constructor call. + TCK_ConstructorCall, + /// Checking the operand of a static_cast to a derived pointer type. Must be + /// null or an object within its lifetime. + TCK_DowncastPointer, + /// Checking the operand of a static_cast to a derived reference type. Must + /// be an object within its lifetime. + TCK_DowncastReference, + /// Checking the operand of a cast to a base object. Must be suitably sized + /// and aligned. + TCK_Upcast, + /// Checking the operand of a cast to a virtual base object. Must be an + /// object within its lifetime. + TCK_UpcastToVirtualBase, + /// Checking the value assigned to a _Nonnull pointer. Must not be null. + TCK_NonnullAssign, + /// Checking the operand of a dynamic_cast or a typeid expression. Must be + /// null or an object within its lifetime. + TCK_DynamicOperation +}; + const char *TypeCheckKinds[] = { "load of", "store to", "reference binding to", "member access within", "member call on", "constructor call on", "downcast of", "downcast of", @@ -50,7 +89,9 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer, uptr Alignment = (uptr)1 << Data->LogAlignment; ErrorType ET; if (!Pointer) - ET = ErrorType::NullPointerUse; + ET = (Data->TypeCheckKind == TCK_NonnullAssign) + ? ErrorType::NullPointerUseWithNullability + : ErrorType::NullPointerUse; else if (Pointer & (Alignment - 1)) ET = ErrorType::MisalignedPointerUse; else @@ -71,6 +112,7 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer, switch (ET) { case ErrorType::NullPointerUse: + case ErrorType::NullPointerUseWithNullability: Diag(Loc, DL_Error, ET, "%0 null pointer of type %1") << TypeCheckKinds[Data->TypeCheckKind] << Data->Type; break; @@ -604,7 +646,8 @@ static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr, UNREACHABLE("source location pointer is null!"); SourceLocation Loc = LocPtr->acquire(); - ErrorType ET = ErrorType::InvalidNullReturn; + ErrorType ET = IsAttr ? ErrorType::InvalidNullReturn + : ErrorType::InvalidNullReturnWithNullability; if (ignoreReport(Loc, Opts, ET)) return; @@ -648,7 +691,8 @@ void __ubsan::__ubsan_handle_nullability_return_v1_abort( static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts, bool IsAttr) { SourceLocation Loc = Data->Loc.acquire(); - ErrorType ET = ErrorType::InvalidNullArgument; + ErrorType ET = IsAttr ? ErrorType::InvalidNullArgument + : ErrorType::InvalidNullArgumentWithNullability; if (ignoreReport(Loc, Opts, ET)) return; @@ -819,21 +863,6 @@ void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, } // namespace __ubsan -void __ubsan::__ubsan_handle_cfi_bad_icall(CFIBadIcallData *CallData, - ValueHandle Function) { - GET_REPORT_OPTIONS(false); - CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type}; - handleCFIBadIcall(&Data, Function, Opts); -} - -void __ubsan::__ubsan_handle_cfi_bad_icall_abort(CFIBadIcallData *CallData, - ValueHandle Function) { - GET_REPORT_OPTIONS(true); - CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type}; - handleCFIBadIcall(&Data, Function, Opts); - Die(); -} - void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data, ValueHandle Value, uptr ValidVtable) { diff --git a/libsanitizer/ubsan/ubsan_handlers.h b/libsanitizer/ubsan/ubsan_handlers.h index eba1cf918fc..22ca9642238 100644 --- a/libsanitizer/ubsan/ubsan_handlers.h +++ b/libsanitizer/ubsan/ubsan_handlers.h @@ -207,20 +207,12 @@ enum CFITypeCheckKind : unsigned char { CFITCK_VMFCall, }; -struct CFIBadIcallData { - SourceLocation Loc; - const TypeDescriptor &Type; -}; - struct CFICheckFailData { CFITypeCheckKind CheckKind; SourceLocation Loc; const TypeDescriptor &Type; }; -/// \brief Handle control flow integrity failure for indirect function calls. -RECOVERABLE(cfi_bad_icall, CFIBadIcallData *Data, ValueHandle Function) - /// \brief Handle control flow integrity failures. RECOVERABLE(cfi_check_fail, CFICheckFailData *Data, ValueHandle Function, uptr VtableIsValid) diff --git a/libsanitizer/ubsan/ubsan_init.cpp b/libsanitizer/ubsan/ubsan_init.cpp index 1a3b7d37267..e0be5a72ec4 100644 --- a/libsanitizer/ubsan/ubsan_init.cpp +++ b/libsanitizer/ubsan/ubsan_init.cpp @@ -37,10 +37,12 @@ static void CommonStandaloneInit() { SanitizerToolName = GetSanititizerToolName(); CacheBinaryName(); InitializeFlags(); + __sanitizer::InitializePlatformEarly(); __sanitizer_set_report_path(common_flags()->log_path); AndroidLogInit(); InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir); CommonInit(); + Symbolizer::LateInitialize(); } void __ubsan::InitAsStandalone() { diff --git a/libsanitizer/ubsan/ubsan_platform.h b/libsanitizer/ubsan/ubsan_platform.h index 58aabbe67b5..71d7fb18c9b 100644 --- a/libsanitizer/ubsan/ubsan_platform.h +++ b/libsanitizer/ubsan/ubsan_platform.h @@ -12,7 +12,6 @@ #ifndef UBSAN_PLATFORM_H #define UBSAN_PLATFORM_H -#ifndef CAN_SANITIZE_UB // Other platforms should be easy to add, and probably work as-is. #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ defined(__NetBSD__) || defined(__OpenBSD__) || \ @@ -22,6 +21,5 @@ #else # define CAN_SANITIZE_UB 0 #endif -#endif //CAN_SANITIZE_UB #endif diff --git a/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp b/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp index 97846d4dd43..4f1708ba190 100644 --- a/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp +++ b/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp @@ -16,6 +16,7 @@ #include "ubsan_type_hash.h" #include "sanitizer_common/sanitizer_common.h" +#include "sanitizer_common/sanitizer_ptrauth.h" // The following are intended to be binary compatible with the definitions // given in the Itanium ABI. We make no attempt to be ODR-compatible with @@ -194,6 +195,7 @@ struct VtablePrefix { std::type_info *TypeInfo; }; VtablePrefix *getVtablePrefix(void *Vtable) { + Vtable = ptrauth_auth_data(Vtable, ptrauth_key_cxx_vtable_pointer, 0); VtablePrefix *Vptr = reinterpret_cast(Vtable); VtablePrefix *Prefix = Vptr - 1; if (!IsAccessibleMemoryRange((uptr)Prefix, sizeof(VtablePrefix))) -- 2.30.2