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