Libsanitizer: merge from master.
authorMartin Liska <mliska@suse.cz>
Mon, 1 Jun 2020 19:15:18 +0000 (21:15 +0200)
committerMartin Liska <mliska@suse.cz>
Tue, 2 Jun 2020 06:02:07 +0000 (08:02 +0200)
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.

107 files changed:
libsanitizer/MERGE
libsanitizer/asan/asan_globals.cpp
libsanitizer/asan/asan_interceptors.h
libsanitizer/asan/asan_mapping.h
libsanitizer/asan/asan_report.cpp
libsanitizer/asan/asan_thread.cpp
libsanitizer/include/sanitizer/linux_syscall_hooks.h
libsanitizer/include/sanitizer/netbsd_syscall_hooks.h
libsanitizer/include/sanitizer/tsan_interface.h
libsanitizer/lsan/lsan.cpp
libsanitizer/lsan/lsan.h
libsanitizer/lsan/lsan_allocator.h
libsanitizer/lsan/lsan_common.cpp
libsanitizer/lsan/lsan_common.h
libsanitizer/lsan/lsan_common_fuchsia.cpp [new file with mode: 0644]
libsanitizer/lsan/lsan_common_linux.cpp
libsanitizer/lsan/lsan_common_mac.cpp
libsanitizer/lsan/lsan_fuchsia.cpp [new file with mode: 0644]
libsanitizer/lsan/lsan_fuchsia.h [new file with mode: 0644]
libsanitizer/lsan/lsan_interceptors.cpp
libsanitizer/lsan/lsan_linux.cpp
libsanitizer/lsan/lsan_posix.cpp [new file with mode: 0644]
libsanitizer/lsan/lsan_posix.h [new file with mode: 0644]
libsanitizer/lsan/lsan_thread.cpp
libsanitizer/lsan/lsan_thread.h
libsanitizer/sanitizer_common/sanitizer_allocator.cpp
libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
libsanitizer/sanitizer_common/sanitizer_common.cpp
libsanitizer/sanitizer_common/sanitizer_common.h
libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
libsanitizer/sanitizer_common/sanitizer_common_interceptors_netbsd_compat.inc [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp
libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc
libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
libsanitizer/sanitizer_common/sanitizer_file.h
libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp
libsanitizer/sanitizer_common/sanitizer_flag_parser.h
libsanitizer/sanitizer_common/sanitizer_flags.cpp
libsanitizer/sanitizer_common/sanitizer_freebsd.h
libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
libsanitizer/sanitizer_common/sanitizer_fuchsia.h
libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
libsanitizer/sanitizer_common/sanitizer_interface_internal.h
libsanitizer/sanitizer_common/sanitizer_internal_defs.h
libsanitizer/sanitizer_common/sanitizer_libc.h
libsanitizer/sanitizer_common/sanitizer_linux.cpp
libsanitizer/sanitizer_common/sanitizer_linux.h
libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp
libsanitizer/sanitizer_common/sanitizer_mac.cpp
libsanitizer/sanitizer_common/sanitizer_mac.h
libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h
libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h
libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp
libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h
libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.cpp
libsanitizer/sanitizer_common/sanitizer_platform_limits_solaris.h
libsanitizer/sanitizer_common/sanitizer_posix.cpp
libsanitizer/sanitizer_common/sanitizer_posix.h
libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
libsanitizer/sanitizer_common/sanitizer_procmaps.h
libsanitizer/sanitizer_common/sanitizer_procmaps_fuchsia.cpp [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_ptrauth.h [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_rtems.cpp
libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
libsanitizer/sanitizer_common/sanitizer_stoptheworld_fuchsia.cpp [new file with mode: 0644]
libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cpp
libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
libsanitizer/sanitizer_common/sanitizer_symbolizer.cpp
libsanitizer/sanitizer_common/sanitizer_symbolizer.h
libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.h
libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
libsanitizer/sanitizer_common/sanitizer_syscalls_netbsd.inc
libsanitizer/sanitizer_common/sanitizer_win.cpp
libsanitizer/tsan/tsan_clock.cpp
libsanitizer/tsan/tsan_clock.h
libsanitizer/tsan/tsan_interceptors_posix.cpp
libsanitizer/tsan/tsan_platform.h
libsanitizer/tsan/tsan_platform_mac.cpp
libsanitizer/tsan/tsan_rtl.cpp
libsanitizer/tsan/tsan_rtl.h
libsanitizer/tsan/tsan_rtl_mutex.cpp
libsanitizer/tsan/tsan_rtl_ppc64.S
libsanitizer/tsan/tsan_rtl_thread.cpp
libsanitizer/tsan/tsan_stat.h
libsanitizer/ubsan/ubsan_checks.inc
libsanitizer/ubsan/ubsan_flags.cpp
libsanitizer/ubsan/ubsan_handlers.cpp
libsanitizer/ubsan/ubsan_handlers.h
libsanitizer/ubsan/ubsan_init.cpp
libsanitizer/ubsan/ubsan_platform.h
libsanitizer/ubsan/ubsan_type_hash_itanium.cpp

index 49ee2c3bab80107f1245f2a86c4663f3e5c12e53..e14e830ea7de88d38d915f9b9472499c4d0a5522 100644 (file)
@@ -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.
index e045c31cd1c38ec4258a1857ced145934b2aa90c..9d7dbc6f264cea7b80a71a91da37cfa0cfbbd0db 100644 (file)
@@ -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);
index b7a85fedbdfd4d69a1abf0d5cb0a4ced2d183079..344a64bd83d330553bca41f066b004092b6632df 100644 (file)
@@ -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
index 09be904270cedbb1bed9736dd3a616463180c83b..41fb49ee46d460774a487c638b2c58531b8ac8d0 100644 (file)
@@ -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
index 2e6ce436d03061f7c3054d9c0f2474c7f309dfc4..99e8678aa78575adc11e4dcc80fc0331799de609 100644 (file)
@@ -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());
index 6734d9a1668c7ccbd7f6f75ccea394bc755d95e9..f0df8bd4b374dd3bac528af5b121f14b2bdf5d33 100644 (file)
@@ -480,6 +480,8 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
   return true;
 }
 
+void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {}
+
 void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
                             void *arg) {
   __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
index a1794b71af503168a408b79acdf5cfdaae2143cf..56eae3d40f968f6bd5f07e34c25856d9d0be3767 100644 (file)
 #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(...)
 #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(...)
 #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
index 174b4bf06de6ca71171d0ec4ed32e2a61f626712..370da0ea72ed8b927371ee73c40bfc21d2c79540 100644 (file)
@@ -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
 //
 //===----------------------------------------------------------------------===//
index 011b23350cac39f16d77d9e9d60047a33ae95ddb..96b8ad58541cbb1c050dbf4f85dadbb3b44a98fe 100644 (file)
@@ -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"
index 4ce03046ffb7fbe550da6f3d274ae80fa54d135b..80a6e2fa70169d26dfc1ed5899732656a5c037c9 100644 (file)
@@ -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);
index 9904ada4bb3bd93e50bc1801324b756671684241..1e82ad72f0058b2d2e73248b580c8d1b49c3945e 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #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);   \
index e1397099767284f28376214ac9284a610cac46d2..bda9d8cdf746dd46a643e1ea97873ee9a1a2c89e 100644 (file)
@@ -66,7 +66,10 @@ template <typename AddressSpaceView>
 using PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView>>;
 using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
 #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
index 9ff9f4c5d1c977d32b7ce668e7a810691bae3215..32ea4e88003877c72fed5c19231303550cc1cf58 100644 (file)
@@ -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<tid_t> &suspended_threads =
       *(const InternalMmapVector<tid_t> *)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<tid_t> 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<CheckForLeaksParam *>(arg);
   CHECK(param);
   CHECK(!param->success);
   ReportUnsuspendedThreads(suspended_threads);
-  ClassifyAllChunks(suspended_threads);
+  ClassifyAllChunks(suspended_threads, &param->frontier);
   ForEachChunk(CollectLeaksCb, &param->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, &param);
 
   if (!param.success) {
index d24abe31b71b524e3f545410e772ce6744170ba8..6252d52c19781ca01635a2c3678de786c6e26ad6 100644 (file)
@@ -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<RootRegion> const *GetRootRegions();
 void ScanRootRegion(Frontier *frontier, RootRegion const &region,
                     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<uptr> *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 (file)
index 0000000..caedbf1
--- /dev/null
@@ -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 <zircon/sanitizer.h>
+
+#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<uptr> 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<const Params *>(data);
+    uptr begin = reinterpret_cast<uptr>(chunk);
+    uptr end = begin + size;
+    ScanGlobalRange(begin, end, &params->argument->frontier);
+  };
+
+  // Callback from libc for thread stacks.
+  auto stacks = +[](void *chunk, size_t size, void *data) {
+    auto params = static_cast<const Params *>(data);
+    uptr begin = reinterpret_cast<uptr>(chunk);
+    uptr end = begin + size;
+    ScanRangeForPointers(begin, end, &params->argument->frontier, "STACK",
+                         kReachable);
+  };
+
+  // Callback from libc for thread registers.
+  auto registers = +[](void *chunk, size_t size, void *data) {
+    auto params = static_cast<const Params *>(data);
+    uptr begin = reinterpret_cast<uptr>(chunk);
+    uptr end = begin + size;
+    ScanRangeForPointers(begin, end, &params->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(&params.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<const Params *>(data);
+    uptr begin = reinterpret_cast<uptr>(chunk);
+    uptr end = begin + size;
+    auto i = __sanitizer::InternalLowerBound(params->allocator_caches, 0,
+                                             params->allocator_caches.size(),
+                                             begin, CompareLess<uptr>());
+    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],
+                           &params->argument->frontier, "TLS", kReachable);
+      uptr begin2 = params->allocator_caches[i] + sizeof(AllocatorCache);
+      ScanRangeForPointers(begin2, end, &params->argument->frontier, "TLS",
+                           kReachable);
+    } else {
+      ScanRangeForPointers(begin, end, &params->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<const Params *>(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);
+              },
+              &params->argument->frontier);
+        }
+
+        params->callback({}, params->argument);
+      },
+      &params);
+
+  UnlockAllocator();
+  UnlockThreadRegistry();
+}
+
+}  // namespace __lsan
+
+// This is declared (in extern "C") by <zircon/sanitizer.h>.
+// _Exit calls this directly to intercept and change the status value.
+int __sanitizer_process_exit_hook(int status) {
+  return __lsan::ExitHook(status);
+}
+
+#endif
index ea1a4a2f569d0648a06b3b25d6e73a865dbab14d..c97ef31593dfa8eaf287ae215849e8cad5f7302c 100644 (file)
@@ -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, &param);
 }
index c1804e93c11db7ce667102bbe925300815d9891b..8516a176eb467ef53095ce75921d26838b4113ad 100644 (file)
@@ -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 (file)
index 0000000..40e65c6
--- /dev/null
@@ -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 <zircon/sanitizer.h>
+
+#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<const OnCreatedArgs *>(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<const OnStartedArgs *>(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<uptr> *caches) {
+  GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+      [](ThreadContextBase *tctx, void *arg) {
+        auto ctx = static_cast<ThreadContext *>(tctx);
+        static_cast<decltype(caches)>(arg)->push_back(ctx->cache_begin());
+      },
+      caches);
+}
+
+}  // namespace __lsan
+
+// These are declared (in extern "C") by <zircon/sanitizer.h>.
+// 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<uptr>(thread);
+  ENSURE_LSAN_INITED;
+  EnsureMainThreadIDIsCorrect();
+  OnCreatedArgs args;
+  args.stack_begin = reinterpret_cast<uptr>(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<void *>(static_cast<uptr>(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<u32>(reinterpret_cast<uptr>(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<u32>(reinterpret_cast<uptr>(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 (file)
index 0000000..65d20ea
--- /dev/null
@@ -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
index f642bb807bc88ff6f14bb13cfbd7640ebbd4c050..9ce9b78c5a5ff6c59cfdbfb84166f47e5dfab25c 100644 (file)
@@ -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
index 14a42b75d2af337e862c96081e670e920cebdada..47c2f21b5a6bc3e69c7bb1cfee34a4c7bff0edc9 100644 (file)
@@ -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 (file)
index 0000000..8e05915
--- /dev/null
@@ -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<const OnStartedArgs *>(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<ThreadContext *>(
+      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 (file)
index 0000000..840e427
--- /dev/null
@@ -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
index 84e7ce61b975659324d0a7280a18a5740cbc73c1..40bdc254bb62251510ec656e0b4bd0250b14389b 100644 (file)
 
 #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<OnStartedArgs *>(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<ThreadContext *>(
-      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
index b869d066d9d8bdbf48c96c593b663cb75c1f0531..0ab1582de662513eb128e9513bf8be1623a81e1d 100644 (file)
 
 #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
index 8d07906cca0348d25702c5cd255fa16ee171886f..ec77b9cbfee8c896c98811ca4150347a66f65e83 100644 (file)
@@ -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;
index 90603280e7c9558050675185bc8b157bb9281e56..1d9a29c70f308b4d589880d6d652b1066b39188d 100644 (file)
@@ -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,
index f5f9f49d8cffc4168bd50240ed0bf077436634f8..87efda5bd372153e04ebd2667859216d9b3ff7c3 100644 (file)
@@ -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;
index 87b8f02b5b730158f61569fb5d9b8dfceb898ec5..ac16e0e47efc5c159c8011a73e417dcda9733063 100644 (file)
@@ -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<T> &lhs,
 template<typename T>
 class InternalMmapVector : public InternalMmapVectorNoCtor<T> {
  public:
-  InternalMmapVector() { InternalMmapVectorNoCtor<T>::Initialize(1); }
+  InternalMmapVector() { InternalMmapVectorNoCtor<T>::Initialize(0); }
   explicit InternalMmapVector(uptr cnt) {
     InternalMmapVectorNoCtor<T>::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();
 
index 50e3558b52e87275987a6ba4522a0ea66e02e382..57f8b2d29442ca86f2e1f816e123ba390c70279c 100644 (file)
 #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
 #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 <sys/utsname.h> 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 (file)
index 0000000..6aa73ec
--- /dev/null
@@ -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
index 27d6a177760e4dfc29cff823e86c582e0f835e98..0c918ebb4a9d651692d66b1ea88f4e07b536cb2c 100644 (file)
@@ -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,
index 31ff48cfd2cfccef973402f8613568e32afb205f..532ac9ead3498954a409767ee475edea0e50b469 100644 (file)
@@ -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
index f18cee66b84318705f0fb87a7d460706926c50c0..a52db08433e3b4de99c29062ef86770c45e1bc02 100644 (file)
 
 #include "sanitizer_platform.h"
 #if SANITIZER_FUCHSIA
+#include <zircon/process.h>
+#include <zircon/sanitizer.h>
+#include <zircon/syscalls.h>
+
 #include "sanitizer_atomic.h"
 #include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_symbolizer_fuchsia.h"
 
-#include <zircon/process.h>
-#include <zircon/sanitizer.h>
-#include <zircon/syscalls.h>
-
 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<atomic_uint32_t *>(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);
 }
 
index 7beeff7e8af80b96e398709a362e68039ad95c31..d7ab0c3d98c15b5f56ac7b3eaa6615dad8e67eff 100644 (file)
@@ -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)
index 6a75792f92624d29b16932c8c649c0c32c4fd0ee..73ebeb5fa14add217a92fd83af3f25e54a7385bb 100644 (file)
@@ -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
index 4a78a0e0ac88102546a4154b455154da2f3e54ab..26681f0493d736258ed7db99867a14c0ed562bd0 100644 (file)
@@ -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.
index 1e2bc6652617965a6043fbf7a0cac4ae6753268a..9e274268bf2a613c40589820d939d99adc00dc7e 100644 (file)
@@ -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) {
index c24ad25626badc4e84a3e74c7996f0457d41701b..fac5dff3463337732626ba0d7c77db460cdb4dbc 100644 (file)
@@ -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 <typename T>
@@ -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<bool>::Parse(const char *value) {
   return false;
 }
 
+template <>
+inline bool FlagHandler<bool>::Format(char *buffer, uptr size) {
+  return FormatString(buffer, size, *t_ ? "true" : "false");
+}
+
 template <>
 inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) {
   bool b;
@@ -75,12 +95,23 @@ inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) {
   return false;
 }
 
+template <>
+inline bool FlagHandler<HandleSignalMode>::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<const char *>::Parse(const char *value) {
   *t_ = value;
   return true;
 }
 
+template <>
+inline bool FlagHandler<const char *>::Format(char *buffer, uptr size) {
+  return FormatString(buffer, size, *t_);
+}
+
 template <>
 inline bool FlagHandler<int>::Parse(const char *value) {
   const char *value_end;
@@ -90,6 +121,12 @@ inline bool FlagHandler<int>::Parse(const char *value) {
   return ok;
 }
 
+template <>
+inline bool FlagHandler<int>::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<uptr>::Parse(const char *value) {
   const char *value_end;
@@ -99,6 +136,12 @@ inline bool FlagHandler<uptr>::Parse(const char *value) {
   return ok;
 }
 
+template <>
+inline bool FlagHandler<uptr>::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<s64>::Parse(const char *value) {
   const char *value_end;
@@ -108,6 +151,12 @@ inline bool FlagHandler<s64>::Parse(const char *value) {
   return ok;
 }
 
+template <>
+inline bool FlagHandler<s64>::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 {
index 66a0a5579ed386bc8104c3162c74fbd22a6d5d25..684ee1e0b9995633ca91aa85f8df3ddcd4c77c65 100644 (file)
@@ -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) {
index 64cb21f1c3d2bc46537ae5bad367a9d064053965..82b227eab6dab73dbce734891a4a138dcb94da99 100644 (file)
 // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
 // 32-bit mode.
 #if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
-# include <osreldate.h>
-# if __FreeBSD_version <= 902001  // v9.2
-#  include <link.h>
-#  include <sys/param.h>
-#  include <ucontext.h>
+#include <osreldate.h>
+#if __FreeBSD_version <= 902001  // v9.2
+#include <link.h>
+#include <sys/param.h>
+#include <ucontext.h>
 
 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
index 6e2c6137f0ce7fa25d2b07fee67ce6bf46161248..6d1ad794677062b94d08f7ca69543a090d03254f 100644 (file)
@@ -66,6 +66,10 @@ uptr internal_getpid() {
   return pid;
 }
 
+int internal_dlinfo(void *handle, int request, void *p) {
+  UNIMPLEMENTED();
+}
+
 uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); }
 
 tid_t GetTid() { return GetThreadSelf(); }
index 5a2ad32b4113b92dac27cf5c8c8c342b3a714c51..96f9cde7ef1919c955477f31c69362011c962ec8 100644 (file)
 #include "sanitizer_common.h"
 
 #include <zircon/sanitizer.h>
+#include <zircon/syscalls/object.h>
 
 namespace __sanitizer {
 
 extern uptr MainThreadStackBase, MainThreadStackSize;
 extern sanitizer_shadow_bounds_t ShadowBounds;
 
+struct MemoryMappingLayoutData {
+  InternalMmapVector<zx_info_maps_t> data;
+  size_t current;  // Current index into the vector.
+};
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_FUCHSIA
index 03ef7c1788cdb1658adfb99be9c6fe1a59849d09..576807ea3a6a1f4f0b409eaecfdb6fe3d4fd8c37 100644 (file)
@@ -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;
 
index c110eff130f24f53391086c6df3ad9b6af66ad13..be8023e9e16ce86bf856ae5b9ffe297348a4f6d0 100644 (file)
@@ -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
index 00226305e07cef5be10e682c30d1e80ae75bc0a6..d0ffc79b06107d72315a0bb4c1f1a9c7cfcb75c3 100644 (file)
 // 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.
index 3d5db35d68ba560d8de46b82746fe4d867423b2c..ec0a6ded009b0773d66d492375ed0831c9058b4c 100644 (file)
@@ -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();
 
index 3807a79b1cdb9f1922af9386380132ed9167ca40..2168301fd69d2261ea95a0a9497b417201cec7bf 100644 (file)
@@ -26,7 +26,7 @@
 #include "sanitizer_placement_new.h"
 #include "sanitizer_procmaps.h"
 
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX && !SANITIZER_GO
 #include <asm/param.h>
 #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
index c28347ad963a7e1482e3aa06bd433670f76cd7d4..c162d1ca5d2851fabf422d593523ab43de321250 100644 (file)
@@ -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
index e09d568d8024863f7d97861cb2d9e246740083a5..4d17c9686e4ed25bc8cd6771f5087d14f7be82dd 100644 (file)
 #include <sys/resource.h>
 #include <syslog.h>
 
+#if !defined(ElfW)
+#define ElfW(type) Elf_##type
+#endif
+
 #if SANITIZER_FREEBSD
 #include <pthread_np.h>
 #include <osreldate.h>
@@ -50,6 +54,7 @@
 #if SANITIZER_NETBSD
 #include <sys/sysctl.h>
 #include <sys/tls.h>
+#include <lwp.h>
 #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
 }
 
index 41e187eaf8daea9f28ad91e1baf61f39ebfdb567..bb2f5b5f9f7df1309a9519c25ed0c86d76ed8c7a 100644 (file)
 
 #if SANITIZER_LINUX && SANITIZER_S390
 
-#include "sanitizer_libc.h"
-#include "sanitizer_linux.h"
-
+#include <dlfcn.h>
 #include <errno.h>
 #include <sys/syscall.h>
 #include <sys/utsname.h>
 #include <unistd.h>
 
+#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);
index b971ad058e9f6d8cf78defe7eb130f6b9cf66273..7550545ea6fa2fccac96b16f20f63577292c1278 100644 (file)
@@ -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 <crt_externs.h>  // for _NSGetEnviron
@@ -37,7 +38,7 @@
 extern char **environ;
 #endif
 
-#if defined(__has_include) && __has_include(<os/trace.h>) && defined(__BLOCKS__)
+#if defined(__has_include) && __has_include(<os/trace.h>)
 #define SANITIZER_OS_TRACE 1
 #include <os/trace.h>
 #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<char **>(argv);
-  char **env = GetEnviron();
-  res = posix_spawn(pid, argv[0], &acts, &attrs, argv_casted, env);
+  char **envp_casted = const_cast<char **>(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: <major>.<minor>.<patch>\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");
index 2257883084ea9a769c7279f2d7ce66375bc513c5..34dc2c05dcf4b7cae1b544d507ba2103681a663b 100644 (file)
@@ -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();
 
index 11adbe5c25b4b26e8db77568ad0a500517231ce2..647bcdfe105e66633aed488b20b54904d1dd01b7 100644 (file)
@@ -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);
   }
index 4e74f6a3b5161cf704202d9a931b318790467c49..d9aff51d8ae793a9a50ef38b2baff802da62b2bb 100644 (file)
@@ -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);
index 61a6b82ef8184b98833ca482b6040cc6a9d3f198..9dd6d285f594034d44d78a325ea7a24279f0d5df 100644 (file)
 # 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
 #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
index 2d1bb1a12da6e40458c6adf639284bf01c202a39..dcc6c71c07d8ae7873c7903761d8537e4bfe7d11 100644 (file)
 
 #if SANITIZER_FREEBSD
 
+#include <sys/capsicum.h>
+#include <sys/consio.h>
+#include <sys/filio.h>
+#include <sys/ipc.h>
+#include <sys/kbio.h>
+#include <sys/link_elf.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/mqueue.h>
+#include <sys/msg.h>
+#include <sys/mtio.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/soundcard.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/times.h>
+#include <sys/timespec.h>
+#include <sys/types.h>
+#include <sys/ucontext.h>
+#include <sys/utsname.h>
+//
 #include <arpa/inet.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/ppp_defs.h>
+#include <net/route.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/ip_mroute.h>
+//
 #include <dirent.h>
-#include <fts.h>
+#include <dlfcn.h>
 #include <fstab.h>
+#include <fts.h>
+#include <glob.h>
 #include <grp.h>
+#include <ifaddrs.h>
 #include <limits.h>
-#include <net/if.h>
-#include <netdb.h>
 #include <poll.h>
 #include <pthread.h>
 #include <pwd.h>
 #include <regex.h>
+#include <semaphore.h>
 #include <signal.h>
 #include <stddef.h>
-#include <sys/mman.h>
-#include <sys/capsicum.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/times.h>
-#include <sys/types.h>
-#include <sys/utsname.h>
-#include <termios.h>
-#include <time.h>
-
-#include <net/route.h>
-#include <sys/mount.h>
-#include <sys/sockio.h>
-#include <sys/socket.h>
-#include <sys/filio.h>
-#include <sys/signal.h>
-#include <sys/timespec.h>
-#include <sys/timeb.h>
-#include <sys/mqueue.h>
-#include <sys/msg.h>
-#include <sys/ipc.h>
-#include <sys/msg.h>
-#include <sys/statvfs.h>
-#include <sys/soundcard.h>
-#include <sys/mtio.h>
-#include <sys/consio.h>
-#include <sys/kbio.h>
-#include <sys/link_elf.h>
-#include <netinet/ip_mroute.h>
-#include <netinet/in.h>
-#include <net/ethernet.h>
-#include <net/ppp_defs.h>
-#include <glob.h>
 #include <stdio.h>
 #include <stringlist.h>
 #include <term.h>
+#include <termios.h>
+#include <time.h>
+#include <utime.h>
 #include <utmpx.h>
-#include <wchar.h>
 #include <vis.h>
+#include <wchar.h>
+#include <wordexp.h>
 
 #define _KERNEL  // to declare 'shminfo' structure
-# include <sys/shm.h>
+#include <sys/shm.h>
 #undef _KERNEL
 
 #undef INLINE  // to avoid clashes with sanitizers' definitions
 
 #undef IOC_DIRMASK
 
-# include <utime.h>
-# include <sys/ptrace.h>
-# include <semaphore.h>
-
-#include <ifaddrs.h>
-#include <sys/ucontext.h>
-#include <wordexp.h>
-
 // 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;
 
index 71cf5b9c35715c85a26018d3824212a5689305db..5e0ca9c7d78236821e41226edf33a4b551f3ee5d 100644 (file)
 
 #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 <sys/_types.h>
 
 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
index f22f50391286b484a17c19b2b7efe17995fd858b..c51327e1269e081cb0e231b75cbce71b62601e88 100644 (file)
 
 // 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 <sys/stat.h>, 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
-// <sys/stat.h> struct stat:s.
+// fine with newer headers, too.
 #include <linux/posix_types.h>
-#if defined(__x86_64__)
+#if defined(__x86_64__) ||  defined(__mips__)
 #include <sys/stat.h>
 #else
 #define ino_t __kernel_ino_t
index f01de6c995e60e09f9875bb04e6270d7411e6fc0..25da334b63f098b47d43d5cdd6f1cec58f2a0de9 100644 (file)
@@ -17,6 +17,7 @@
 
 #define _KMEMUSER
 #define RAY_DO_SIGLEV
+#define __LEGACY_PT_LWPINFO
 
 // clang-format off
 #include <sys/param.h>
 #include <sys/msg.h>
 #include <sys/mtio.h>
 #include <sys/ptrace.h>
+
+// Compat for NetBSD < 9.99.30.
+#ifndef PT_LWPSTATUS
+#define PT_LWPSTATUS 24
+#endif
+#ifndef PT_LWPNEXT
+#define PT_LWPNEXT 25
+#endif
+
 #include <sys/resource.h>
 #include <sys/sem.h>
 #include <sys/sha1.h>
 #include <dev/dmover/dmover_io.h>
 #include <dev/dtv/dtvio_demux.h>
 #include <dev/dtv/dtvio_frontend.h>
+#if !__NetBSD_Prereq__(9, 99, 26)
 #include <dev/filemon/filemon.h>
+#else
+#define FILEMON_SET_FD          _IOWR('S', 1, int)
+#define FILEMON_SET_PID         _IOWR('S', 2, pid_t)
+#endif
 #include <dev/hdaudio/hdaudioio.h>
 #include <dev/hdmicec/hdmicecio.h>
 #include <dev/hpc/hpcfbio.h>
 #include <net/slip.h>
 #include <netbt/hci.h>
 #include <netinet/ip_compat.h>
+#if __has_include(<netinet/ip_fil.h>)
 #include <netinet/ip_fil.h>
 #include <netinet/ip_nat.h>
 #include <netinet/ip_proxy.h>
+#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 <netinet6/in6_var.h>
 #include <netinet6/nd6.h>
+#if !__NetBSD_Prereq__(9, 99, 51)
 #include <netsmb/smb_dev.h>
+#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 <dev/biovar.h>
 #include <dev/bluetooth/btdev.h>
 #include <dev/bluetooth/btsco.h>
 #include <dev/sun/vuid_event.h>
 #include <dev/tc/sticio.h>
 #include <dev/usb/ukyopon.h>
+#if !__NetBSD_Prereq__(9, 99, 44)
 #include <dev/usb/urio.h>
+#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 <dev/usb/usb.h>
 #include <dev/usb/utoppy.h>
 #include <dev/vme/xio.h>
 #include <dev/wscons/wsdisplay_usl_io.h>
 #include <fs/autofs/autofs_ioctl.h>
 #include <dirent.h>
+#include <dlfcn.h>
 #include <glob.h>
 #include <grp.h>
 #include <ifaddrs.h>
 
 // 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
index 419d830c69efe70039b59f50b212fe21bb792371..d80280d9bf8c837635435463e80b01354f391f9b 100644 (file)
 #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
index 12515626ce5342ec816f38ad991da47a3e05dbdd..1420ecbfa568479b17a7aac28ffe27b036add125 100644 (file)
@@ -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);
index 6d8b062716b7839593cbd0e3fb2d56f7d1b3a201..8a1948723605e3f8548364b5cdf96e9daaeb0c38 100644 (file)
@@ -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;
 
index aa845df4dde481ead5c80ef0fac5e361a84c5c39..e71515f12e94e6fb8ac06b53c83c49dee84f3720 100644 (file)
@@ -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);
index d82fd5e400587a46c23ba66d27d9568582c37952..f6c8a1450a9323e2725146cfc4e83b2f2faf88f8 100644 (file)
@@ -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;
index 9717d98ebf1aa6f23a7fd09217661564b0c0e59c..6ec1a1bdd114cf32a37b8d73be433d8997c35122 100644 (file)
@@ -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);
index 77ae6e6a44dbd96dd00feaac6925ee1555579637..85995e79792d211910676a2cd04337e20125a487 100644 (file)
@@ -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;
index d890a3a317737cdeddb31ddf35c429c53454e1d7..e21661b42f8d2725ab1005bb5d93b023ffbf60bc 100644 (file)
@@ -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);
index 05fb0f630207c5951e8c8a7f18fa24c6752f3931..a1b49702da23b7ec5fa9f0e4cb18ccec727509c2 100644 (file)
@@ -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);
index 304b3a01a08b6ac06e8dae266e5c4bc116cf8be6..f920172c06d634963b4d20a1748fc913f22d3e25 100644 (file)
@@ -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<char **>(&argv[0]));
+    internal_execve(program, const_cast<char **>(&argv[0]),
+                    const_cast<char *const *>(envp));
     internal__exit(1);
   }
 
index d0e5245f84dab815a6d1ee31f08a77a15df6cfe4..665ed45fa93e1c45566c6609294a56dadfd29774 100644 (file)
 
 #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 (file)
index 0000000..cc3e9be
--- /dev/null
@@ -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 <zircon/process.h>
+#include <zircon/syscalls.h>
+
+#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 (file)
index 0000000..4d0d96a
--- /dev/null
@@ -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 <ptrauth.h>
+#else
+// Copied from <ptrauth.h>
+#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
index 0d2576c00ab3c8d34c0f3ac8eb8984e5b49b586d..29bcfcfa6f1581a456e9a5183e8de51a14d1c834 100644 (file)
@@ -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))
index ce75cbe5d265094329e3f770e5f0ed19b9a455f4..ef14fb704eed394acf0be36505eaae5f952fa6d2 100644 (file)
@@ -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 (file)
index 0000000..3a24644
--- /dev/null
@@ -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 <zircon/sanitizer.h>
+
+#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<Params *>(data);
+        params->callback({}, params->argument);
+      },
+      &params);
+}
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_FUCHSIA
index 9dffd21ecb7cc52668b4c860c70eebc92c6a2bb3..6c577426ad566af339d1b634b4ec3aa37f974cfa 100644 (file)
@@ -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, &regs, 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.
index 5690d75097f94bfb9caf318fa7f9052ec6533457..1ed21343254d5fa0f4a372d5e7eee5ba8ecc88a0 100644 (file)
@@ -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_);
index ce2ece5f4d51236aed44b500ce5fb116139da8ed..0c4b84c767aa153f87674462da96e99377997cab 100644 (file)
@@ -126,4 +126,10 @@ Symbolizer::SymbolizerScope::~SymbolizerScope() {
     sym_->end_hook_();
 }
 
+void Symbolizer::LateInitializeTools() {
+  for (auto &tool : tools_) {
+    tool.LateInitialize();
+  }
+}
+
 }  // namespace __sanitizer
index 51648e2d0e8d7d31150343b8d057c4b3d2b65c93..2476b0ea7bf7d858e99269433fc1625f1973c9e1 100644 (file)
@@ -209,6 +209,9 @@ class Symbolizer final {
    private:
     const Symbolizer *sym_;
   };
+
+  // Calls `LateInitialize()` on all items in `tools_`.
+  void LateInitializeTools();
 };
 
 #ifdef SANITIZER_WINDOWS
index c04797dd61b8b6d250046860125d41b66faba526..e4c351e667b4d3d630ec5587903da12e9badf30e 100644 (file)
@@ -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 {
index 3b19a6836ec53da3d2c4f71123e1e81cc6ffdecf..490c6fe89beb5bfc2681aeb6dbd679e0c2c475b8 100644 (file)
@@ -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<int>(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<int>(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<int>(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_;
 }
 
index a619ed092f0bce054c6b7d2c28724fb65d3f8eb3..cc233408d0cebfc19a17f40803a80b09c2b8f157 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <dlfcn.h>
 #include <errno.h>
+#include <mach/mach.h>
 #include <stdlib.h>
 #include <sys/wait.h>
 #include <unistd.h>
@@ -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<uptr>(info.dli_saddr));
+  stack->info.function_offset = addr - reinterpret_cast<uptr>(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<uptr>(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
index 68521375e64c44e7842307488a68216acab26532..8996131fc138508cb9074fd8d69d8df4ef05a5bc 100644 (file)
@@ -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_;
index 57b4d0c9d9613bdc69240e17e3592b0bc3e90492..2963af953609e3e18c28db1e7393261076150f6f 100644 (file)
@@ -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,
index c123ecb11206cca14d1b78683e40aa45edc8d201..d7b931bc23795deabbef0febaba039903a07ad27 100644 (file)
@@ -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<const char **>(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();
 }
 
index 2808779156edd2142a434236ae39d06c40118bd7..373437e7ee2ad2d3b357ac519bfb105d5b59a25f 100644 (file)
@@ -310,7 +310,7 @@ Symbolizer *Symbolizer::PlatformInit() {
 }
 
 void Symbolizer::LateInitialize() {
-  Symbolizer::GetOrInit();
+  Symbolizer::GetOrInit()->LateInitializeTools();
 }
 
 }  // namespace __sanitizer
index 69e59871874133a33420165c9062be2b78217c0a..02b7e11b1677f49e9f371d97d1905849a8c4a796 100644 (file)
@@ -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) {
index 36dde49d8708343337fe5b965b5408cec8c50d19..fca15beb61612dfb5d301ce6a9b430602a687689 100644 (file)
@@ -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
index 4b7aa0653da6bbeae2db384dc5e0149a2f1e2df3..c91b29cb22b4786af5e66c32b4b28a469dacc5c3 100644 (file)
 //       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) {
index 6a1d15a2a16de331f3a63818a8d77bdca772f976..736cdae06ba21fdcd6c5f350f112b3e8fdcbc119 100644 (file)
@@ -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);
 }
index 8aea1e4ec0513bbddc55bd55e307fa456e26d03e..718957c370315c13e5f280dd0f77b9f910dd2398 100644 (file)
@@ -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);
index 63eb14fcd3402abb8426ecfc30f2a62c4e32c9a7..7256d64e50795c9e038bec5755aace9bb554fb21 100644 (file)
@@ -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
 
index 326ca8532e5222af8296657d3a7e1a3e275fc0a5..f92ecc5e40f6dc04d54062857fa90b1c9a6cf4a3 100644 (file)
@@ -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;
 }
 
index 3f3c0cce119c13ff665599eeff14d8b564ea9e22..13c9b770f50a3ccece2b906fe492de72df596773 100644 (file)
@@ -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();
 
index c38fc43a9f848726ae40562b3de465d0a0a1d4bf..d3bb61ff87d3f8ba1a3f953da4eeb67f9dc216d2 100644 (file)
@@ -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);
 
index ce6e7cb2c4ef09520eb95b9199873dd959436c51..ebd0d722181885d3b19670d8fc9a9983d25d77d1 100644 (file)
@@ -415,8 +415,10 @@ static void UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) {
   ThreadState *thr = reinterpret_cast<ThreadState*>(arg);
   ThreadContext *tctx = static_cast<ThreadContext*>(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;
index 9e533a71a9c477ecae59f09ab431b2664554d998..8285e21aa1ec7a797dfcf4840ee5a7851106b497 100644 (file)
@@ -1,6 +1,5 @@
 #include "tsan_ppc_regs.h"
 
-        .machine altivec
         .section .text
         .hidden __tsan_setjmp
         .globl _setjmp
index 0ac1ee99c470141176d39a8cbb06e6d1caeb35c4..d80146735ea794b098596645d63f39a993cfe168 100644 (file)
@@ -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) {
index 94e18bc66df940489381ab0c2763ba8a4fec2c6a..8b26a59bb2ed77f14b592de7c4f6321cebc2519f 100644 (file)
@@ -68,6 +68,7 @@ enum StatType {
   StatSyncDestroyed,
   StatSyncAcquire,
   StatSyncRelease,
+  StatSyncReleaseStoreAcquire,
 
   // Clocks - acquire.
   StatClockAcquire,
index 33a8dfcde0269a013f57e2a6b25b47f5ade7fd5b..2c1529a7d92c5ee821fcf9e1affe140b3ff392a5 100644 (file)
@@ -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")
index 80de2a6d10169c2f58bc855ef11918bca3f58981..721c2273f133a3b4f7158b7e7297d7e9078eaffa 100644 (file)
@@ -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);
   }
index 0ddbb50c26cc3da00980867be7811ab5e3f41a1b..7f6a46fb6cf08531142f7a5b36734f46a08cde48 100644 (file)
@@ -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) {
index eba1cf918fc34796fdaaf0d458984e197758e43c..22ca96422381c104798588f64c5ae370f3ef2f07 100644 (file)
@@ -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)
index 1a3b7d3726743e61ce3129f6021527a23b8c166c..e0be5a72ec42fbabd7f6f5dce31d8a3f56bc18cc 100644 (file)
@@ -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() {
index 58aabbe67b5c25e0b47b03a848182691de2252a7..71d7fb18c9b3a5e94039e3843113050f31fa1c9f 100644 (file)
@@ -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
index 97846d4dd434b1bdc2b5bafd8052dc99a2232422..4f1708ba1901f2b53c24852e1eb63061eb707f99 100644 (file)
@@ -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<VtablePrefix*>(Vtable);
   VtablePrefix *Prefix = Vptr - 1;
   if (!IsAccessibleMemoryRange((uptr)Prefix, sizeof(VtablePrefix)))