public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Hongtao Liu <crazylht@gmail.com>
To: "Martin Liška" <mliska@suse.cz>
Cc: GCC Patches <gcc-patches@gcc.gnu.org>
Subject: Re: [PATCH] libsanitizer: merge from master
Date: Fri, 4 Jun 2021 15:53:38 +0800	[thread overview]
Message-ID: <CAMZc-bw6SjbrRCLYCeq1RN0e5qc5wsFK-qo1zE0cO5VnSSqeqQ@mail.gmail.com> (raw)
In-Reply-To: <17ffdd85-54bd-d90a-ed53-8944e003fe3d@suse.cz>

On Fri, Jun 4, 2021 at 3:36 PM Martin Liška <mliska@suse.cz> wrote:
>
> On 6/4/21 9:32 AM, Hongtao Liu wrote:
> > Hi:
> >    I'm currently working on support hwasan with Intel LAM, i found
>
> Nice!
>
> > there's gap between gcc libsanitizer and corresponding llvm
> > compiler-rt, so could you help to sync from llvm to gcc libsanitizer.
> > Or is there's any instructions i can follow to sync it myself?
>
> Yes, please follow instructions mentioned in here:
> libsanitizer/HOWTO_MERGE
>
Great, that's what i need, thanks.
> Martin
>
> >
> > On Thu, May 13, 2021 at 3:50 PM Martin Liška <mliska@suse.cz> wrote:
> >>
> >> I'm planning to do merge from master twice a year.
> >> This merge was tested on x86_64-linux-gnu and ppc64le-linux-gnu
> >> and survives regression tests.
> >>
> >> Pushed to master.
> >> Thanks,
> >> Martin
> >>
> >> Merged revision: f58e0513dd95944b81ce7a6e7b49ba656de7d75f
> >> ---
> >>    libsanitizer/MERGE                            |   2 +-
> >>    libsanitizer/asan/asan_allocator.cpp          |  32 +-
> >>    libsanitizer/asan/asan_descriptions.cpp       |  19 +-
> >>    libsanitizer/asan/asan_descriptions.h         |  13 +-
> >>    libsanitizer/asan/asan_errors.cpp             |   7 +-
> >>    libsanitizer/asan/asan_fake_stack.cpp         |   2 +-
> >>    libsanitizer/asan/asan_fuchsia.cpp            |   2 +-
> >>    libsanitizer/asan/asan_globals.cpp            |  19 +
> >>    libsanitizer/asan/asan_interceptors.cpp       |  41 +-
> >>    libsanitizer/asan/asan_interceptors.h         |  21 +-
> >>    libsanitizer/asan/asan_linux.cpp              |   3 +-
> >>    libsanitizer/asan/asan_mapping.h              |  25 +-
> >>    libsanitizer/asan/asan_new_delete.cpp         |   2 +-
> >>    libsanitizer/asan/asan_poisoning.cpp          |   2 +-
> >>    libsanitizer/asan/asan_posix.cpp              |   2 +-
> >>    libsanitizer/asan/asan_rtl.cpp                |  20 +-
> >>    libsanitizer/asan/asan_stack.h                |   9 -
> >>    libsanitizer/asan/asan_thread.cpp             |  51 +-
> >>    libsanitizer/asan/asan_thread.h               |   6 +-
> >>    libsanitizer/asan/asan_win.cpp                |   2 +-
> >>    libsanitizer/builtins/assembly.h              |  98 +++-
> >>    libsanitizer/hwasan/hwasan.cpp                |  19 +-
> >>    libsanitizer/hwasan/hwasan.h                  |  41 +-
> >>    libsanitizer/hwasan/hwasan_allocator.cpp      |  28 +-
> >>    libsanitizer/hwasan/hwasan_allocator.h        |  19 +-
> >>    libsanitizer/hwasan/hwasan_checks.h           |   5 +-
> >>    libsanitizer/hwasan/hwasan_dynamic_shadow.cpp |  16 +-
> >>    libsanitizer/hwasan/hwasan_flags.h            |   2 +
> >>    libsanitizer/hwasan/hwasan_flags.inc          |   9 +
> >>    libsanitizer/hwasan/hwasan_interceptors.cpp   |   3 +-
> >>    .../hwasan/hwasan_interceptors_vfork.S        |   3 +
> >>    .../hwasan/hwasan_interface_internal.h        |   3 +
> >>    libsanitizer/hwasan/hwasan_linux.cpp          |  41 +-
> >>    libsanitizer/hwasan/hwasan_mapping.h          |   2 +
> >>    libsanitizer/hwasan/hwasan_memintrinsics.cpp  |   4 +-
> >>    libsanitizer/hwasan/hwasan_new_delete.cpp     |  39 ++
> >>    libsanitizer/hwasan/hwasan_report.cpp         |  26 +-
> >>    libsanitizer/hwasan/hwasan_setjmp.S           |   6 +
> >>    .../hwasan/hwasan_tag_mismatch_aarch64.S      |   6 +
> >>    libsanitizer/hwasan/hwasan_thread.cpp         |  15 +-
> >>    libsanitizer/hwasan/hwasan_thread.h           |   4 +-
> >>    libsanitizer/hwasan/hwasan_thread_list.h      |  90 ++--
> >>    .../include/sanitizer/common_interface_defs.h |   3 +
> >>    .../include/sanitizer/dfsan_interface.h       |  16 +
> >>    .../include/sanitizer/hwasan_interface.h      |   3 +
> >>    .../include/sanitizer/memprof_interface.h     |   5 +
> >>    .../include/sanitizer/tsan_interface.h        |  17 +-
> >>    .../include/sanitizer/tsan_interface_atomic.h |   2 +-
> >>    .../interception/interception_linux.cpp       |   6 +-
> >>    .../interception/interception_linux.h         |   6 +-
> >>    .../interception/interception_win.cpp         |   6 +-
> >>    libsanitizer/lsan/lsan_allocator.cpp          |  26 +-
> >>    libsanitizer/lsan/lsan_allocator.h            |   2 +-
> >>    libsanitizer/lsan/lsan_common.cpp             | 234 ++++++---
> >>    libsanitizer/lsan/lsan_common.h               |   9 +-
> >>    libsanitizer/lsan/lsan_common_fuchsia.cpp     |   4 +-
> >>    libsanitizer/lsan/lsan_fuchsia.h              |   2 +-
> >>    libsanitizer/lsan/lsan_interceptors.cpp       |   2 +-
> >>    libsanitizer/lsan/lsan_posix.cpp              |   6 +-
> >>    libsanitizer/lsan/lsan_thread.cpp             |   2 +-
> >>    .../sanitizer_allocator_combined.h            |   4 +-
> >>    .../sanitizer_allocator_primary32.h           |   3 +-
> >>    .../sanitizer_allocator_primary64.h           |  93 +++-
> >>    .../sanitizer_allocator_size_class_map.h      |   2 +-
> >>    .../sanitizer_atomic_clang_mips.h             |   8 +-
> >>    .../sanitizer_chained_origin_depot.cpp        | 108 +++++
> >>    .../sanitizer_chained_origin_depot.h          |  88 ++++
> >>    .../sanitizer_common/sanitizer_common.cpp     |  10 +-
> >>    .../sanitizer_common/sanitizer_common.h       |  82 +++-
> >>    .../sanitizer_common_interceptors.inc         |  19 +-
> >>    .../sanitizer_common_interceptors_ioctl.inc   |   6 +-
> >>    ...er_common_interceptors_vfork_aarch64.inc.S |   5 +
> >>    .../sanitizer_common_interface.inc            |   1 +
> >>    .../sanitizer_common_libcdep.cpp              |   7 +-
> >>    .../sanitizer_common/sanitizer_file.cpp       |  13 +
> >>    .../sanitizer_common/sanitizer_file.h         |   1 +
> >>    .../sanitizer_common/sanitizer_flags.cpp      |   7 +
> >>    .../sanitizer_common/sanitizer_flags.inc      |   2 +
> >>    .../sanitizer_common/sanitizer_fuchsia.cpp    |  72 +--
> >>    .../sanitizer_interface_internal.h            |   4 +
> >>    .../sanitizer_internal_defs.h                 |   3 +
> >>    .../sanitizer_common/sanitizer_libignore.cpp  |   2 +-
> >>    .../sanitizer_common/sanitizer_linux.cpp      |  72 +--
> >>    .../sanitizer_common/sanitizer_linux.h        |   3 +-
> >>    .../sanitizer_linux_libcdep.cpp               | 447 ++++++++++--------
> >>    .../sanitizer_local_address_space_view.h      |   2 +-
> >>    .../sanitizer_common/sanitizer_mac.cpp        | 141 +++++-
> >>    libsanitizer/sanitizer_common/sanitizer_mac.h |  37 --
> >>    .../sanitizer_common/sanitizer_malloc_mac.inc |   6 +-
> >>    .../sanitizer_common/sanitizer_netbsd.cpp     |   6 +
> >>    .../sanitizer_common/sanitizer_platform.h     |  27 +-
> >>    .../sanitizer_platform_interceptors.h         | 113 +++--
> >>    .../sanitizer_platform_limits_freebsd.cpp     |   3 +
> >>    .../sanitizer_platform_limits_linux.cpp       |   7 +-
> >>    .../sanitizer_platform_limits_posix.cpp       |  85 ++--
> >>    .../sanitizer_platform_limits_posix.h         |   4 +-
> >>    .../sanitizer_common/sanitizer_posix.cpp      |   4 +-
> >>    .../sanitizer_common/sanitizer_posix.h        |   4 +
> >>    .../sanitizer_posix_libcdep.cpp               |   2 +-
> >>    .../sanitizer_common/sanitizer_printf.cpp     |  57 ++-
> >>    .../sanitizer_procmaps_common.cpp             |   2 +-
> >>    .../sanitizer_procmaps_mac.cpp                |   4 +-
> >>    .../sanitizer_procmaps_solaris.cpp            |   4 +-
> >>    .../sanitizer_common/sanitizer_ptrauth.h      |  20 +-
> >>    .../sanitizer_common/sanitizer_stackdepot.cpp |   3 +-
> >>    .../sanitizer_common/sanitizer_stacktrace.cpp |  20 +-
> >>    .../sanitizer_common/sanitizer_stacktrace.h   |   2 -
> >>    .../sanitizer_stacktrace_libcdep.cpp          |   8 +-
> >>    .../sanitizer_stoptheworld_linux_libcdep.cpp  |   5 +
> >>    .../sanitizer_suppressions.cpp                |   4 +-
> >>    .../sanitizer_symbolizer_libcdep.cpp          |   2 +-
> >>    .../sanitizer_symbolizer_markup.cpp           |   4 +
> >>    .../sanitizer_symbolizer_posix_libcdep.cpp    |  11 +-
> >>    .../sanitizer_symbolizer_report.cpp           |   6 +-
> >>    .../sanitizer_symbolizer_win.cpp              |  18 +-
> >>    .../sanitizer_termination.cpp                 |  33 +-
> >>    .../sanitizer_thread_registry.cpp             |  14 +-
> >>    .../sanitizer_thread_registry.h               |   7 +-
> >>    .../sanitizer_tls_get_addr.cpp                |  79 ++--
> >>    .../sanitizer_common/sanitizer_tls_get_addr.h |  21 +-
> >>    .../sanitizer_common/sanitizer_unwind_win.cpp |   7 +
> >>    .../sanitizer_common/sanitizer_win.cpp        |  84 ++--
> >>    libsanitizer/tsan/tsan_clock.cpp              |  37 +-
> >>    libsanitizer/tsan/tsan_clock.h                |  16 +-
> >>    libsanitizer/tsan/tsan_defs.h                 |   2 -
> >>    libsanitizer/tsan/tsan_dense_alloc.h          |  32 +-
> >>    libsanitizer/tsan/tsan_external.cpp           |   4 +-
> >>    libsanitizer/tsan/tsan_interceptors_mac.cpp   |   1 +
> >>    libsanitizer/tsan/tsan_interceptors_posix.cpp | 149 ++++--
> >>    libsanitizer/tsan/tsan_interface.cpp          |   8 +-
> >>    libsanitizer/tsan/tsan_interface.h            |   9 +-
> >>    libsanitizer/tsan/tsan_interface_inl.h        |  22 +-
> >>    libsanitizer/tsan/tsan_mman.cpp               |   2 +-
> >>    libsanitizer/tsan/tsan_platform.h             | 121 ++++-
> >>    libsanitizer/tsan/tsan_platform_linux.cpp     |  23 +-
> >>    libsanitizer/tsan/tsan_platform_mac.cpp       |   9 +-
> >>    libsanitizer/tsan/tsan_platform_posix.cpp     |   2 +-
> >>    libsanitizer/tsan/tsan_report.cpp             |  14 +-
> >>    libsanitizer/tsan/tsan_rtl.cpp                | 129 +++--
> >>    libsanitizer/tsan/tsan_rtl.h                  |  11 +-
> >>    libsanitizer/tsan/tsan_rtl_mutex.cpp          |  25 +-
> >>    libsanitizer/tsan/tsan_rtl_ppc64.S            |   1 -
> >>    libsanitizer/tsan/tsan_rtl_report.cpp         |  56 ++-
> >>    libsanitizer/tsan/tsan_rtl_thread.cpp         |  13 +-
> >>    libsanitizer/tsan/tsan_sync.cpp               |   4 +-
> >>    libsanitizer/tsan/tsan_sync.h                 |   8 +-
> >>    libsanitizer/ubsan/ubsan_diag.cpp             |   8 +-
> >>    libsanitizer/ubsan/ubsan_flags.cpp            |   1 -
> >>    libsanitizer/ubsan/ubsan_handlers.cpp         |  15 -
> >>    libsanitizer/ubsan/ubsan_handlers.h           |   8 -
> >>    libsanitizer/ubsan/ubsan_init.cpp             |   9 +
> >>    libsanitizer/ubsan/ubsan_monitor.cpp          |   6 +-
> >>    libsanitizer/ubsan/ubsan_platform.h           |   4 +-
> >>    153 files changed, 2538 insertions(+), 1239 deletions(-)
> >>    create mode 100644 libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
> >>    create mode 100644 libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
> >>
> >> diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE
> >> index 0fb64a9567c..c4731d0866c 100644
> >> --- a/libsanitizer/MERGE
> >> +++ b/libsanitizer/MERGE
> >> @@ -1,4 +1,4 @@
> >> -6e7dd1e3e1170080b76b5dcc5716bdd974343233
> >> +f58e0513dd95944b81ce7a6e7b49ba656de7d75f
> >>
> >>    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_allocator.cpp b/libsanitizer/asan/asan_allocator.cpp
> >> index 58b496a3ca4..7c8bb504332 100644
> >> --- a/libsanitizer/asan/asan_allocator.cpp
> >> +++ b/libsanitizer/asan/asan_allocator.cpp
> >> @@ -476,7 +476,7 @@ struct Allocator {
> >>          return false;
> >>        if (m->Beg() != addr) return false;
> >>        AsanThread *t = GetCurrentThread();
> >> -    m->SetAllocContext(t ? t->tid() : 0, StackDepotPut(*stack));
> >> +    m->SetAllocContext(t ? t->tid() : kMainTid, StackDepotPut(*stack));
> >>        return true;
> >>      }
> >>
> >> @@ -570,7 +570,7 @@ struct Allocator {
> >>        m->SetUsedSize(size);
> >>        m->user_requested_alignment_log = user_requested_alignment_log;
> >>
> >> -    m->SetAllocContext(t ? t->tid() : 0, StackDepotPut(*stack));
> >> +    m->SetAllocContext(t ? t->tid() : kMainTid, StackDepotPut(*stack));
> >>
> >>        uptr size_rounded_down_to_granularity =
> >>            RoundDownTo(size, SHADOW_GRANULARITY);
> >> @@ -1183,6 +1183,34 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
> >>      m->lsan_tag = __lsan::kIgnored;
> >>      return kIgnoreObjectSuccess;
> >>    }
> >> +
> >> +void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
> >> +  // Look for the arg pointer of threads that have been created or are running.
> >> +  // This is necessary to prevent false positive leaks due to the AsanThread
> >> +  // holding the only live reference to a heap object.  This can happen because
> >> +  // the `pthread_create()` interceptor doesn't wait for the child thread to
> >> +  // start before returning and thus loosing the the only live reference to the
> >> +  // heap object on the stack.
> >> +
> >> +  __asan::AsanThreadContext *atctx =
> >> +      reinterpret_cast<__asan::AsanThreadContext *>(tctx);
> >> +  __asan::AsanThread *asan_thread = atctx->thread;
> >> +
> >> +  // Note ThreadStatusRunning is required because there is a small window where
> >> +  // the thread status switches to `ThreadStatusRunning` but the `arg` pointer
> >> +  // still isn't on the stack yet.
> >> +  if (atctx->status != ThreadStatusCreated &&
> >> +      atctx->status != ThreadStatusRunning)
> >> +    return;
> >> +
> >> +  uptr thread_arg = reinterpret_cast<uptr>(asan_thread->get_arg());
> >> +  if (!thread_arg)
> >> +    return;
> >> +
> >> +  auto ptrsVec = reinterpret_cast<InternalMmapVector<uptr> *>(ptrs);
> >> +  ptrsVec->push_back(thread_arg);
> >> +}
> >> +
> >>    }  // namespace __lsan
> >>
> >>    // ---------------------- Interface ---------------- {{{1
> >> diff --git a/libsanitizer/asan/asan_descriptions.cpp b/libsanitizer/asan/asan_descriptions.cpp
> >> index 153c874a4e7..2ba8a02f841 100644
> >> --- a/libsanitizer/asan/asan_descriptions.cpp
> >> +++ b/libsanitizer/asan/asan_descriptions.cpp
> >> @@ -44,11 +44,11 @@ void DescribeThread(AsanThreadContext *context) {
> >>      CHECK(context);
> >>      asanThreadRegistry().CheckLocked();
> >>      // No need to announce the main thread.
> >> -  if (context->tid == 0 || context->announced) {
> >> +  if (context->tid == kMainTid || context->announced) {
> >>        return;
> >>      }
> >>      context->announced = true;
> >> -  InternalScopedString str(1024);
> >> +  InternalScopedString str;
> >>      str.append("Thread %s", AsanThreadIdAndName(context).c_str());
> >>      if (context->parent_tid == kInvalidTid) {
> >>        str.append(" created by unknown thread\n");
> >> @@ -77,7 +77,6 @@ static bool GetShadowKind(uptr addr, ShadowKind *shadow_kind) {
> >>      } else if (AddrIsInLowShadow(addr)) {
> >>        *shadow_kind = kShadowKindLow;
> >>      } else {
> >> -    CHECK(0 && "Address is not in memory and not in shadow?");
> >>        return false;
> >>      }
> >>      return true;
> >> @@ -126,7 +125,7 @@ static void GetAccessToHeapChunkInformation(ChunkAccess *descr,
> >>
> >>    static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) {
> >>      Decorator d;
> >> -  InternalScopedString str(4096);
> >> +  InternalScopedString str;
> >>      str.append("%s", d.Location());
> >>      switch (descr.access_type) {
> >>        case kAccessTypeLeft:
> >> @@ -243,7 +242,7 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
> >>        else if (addr >= prev_var_end && addr - prev_var_end >= var.beg - addr_end)
> >>          pos_descr = "underflows";
> >>      }
> >> -  InternalScopedString str(1024);
> >> +  InternalScopedString str;
> >>      str.append("    [%zd, %zd)", var.beg, var_end);
> >>      // Render variable name.
> >>      str.append(" '");
> >> @@ -276,7 +275,7 @@ bool DescribeAddressIfStack(uptr addr, uptr access_size) {
> >>    // Global descriptions
> >>    static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
> >>                                                const __asan_global &g) {
> >> -  InternalScopedString str(4096);
> >> +  InternalScopedString str;
> >>      Decorator d;
> >>      str.append("%s", d.Location());
> >>      if (addr < g.beg) {
> >> @@ -464,7 +463,13 @@ AddressDescription::AddressDescription(uptr addr, uptr access_size,
> >>        return;
> >>      }
> >>      data.kind = kAddressKindWild;
> >> -  addr = 0;
> >> +  data.wild.addr = addr;
> >> +  data.wild.access_size = access_size;
> >> +}
> >> +
> >> +void WildAddressDescription::Print() const {
> >> +  Printf("Address %p is a wild pointer inside of access range of size %p.\n",
> >> +         addr, access_size);
> >>    }
> >>
> >>    void PrintAddressDescription(uptr addr, uptr access_size,
> >> diff --git a/libsanitizer/asan/asan_descriptions.h b/libsanitizer/asan/asan_descriptions.h
> >> index ee0e2061559..650e2eb9173 100644
> >> --- a/libsanitizer/asan/asan_descriptions.h
> >> +++ b/libsanitizer/asan/asan_descriptions.h
> >> @@ -146,6 +146,13 @@ struct StackAddressDescription {
> >>    bool GetStackAddressInformation(uptr addr, uptr access_size,
> >>                                    StackAddressDescription *descr);
> >>
> >> +struct WildAddressDescription {
> >> +  uptr addr;
> >> +  uptr access_size;
> >> +
> >> +  void Print() const;
> >> +};
> >> +
> >>    struct GlobalAddressDescription {
> >>      uptr addr;
> >>      // Assume address is close to at most four globals.
> >> @@ -193,7 +200,7 @@ class AddressDescription {
> >>          HeapAddressDescription heap;
> >>          StackAddressDescription stack;
> >>          GlobalAddressDescription global;
> >> -      uptr addr;
> >> +      WildAddressDescription wild;
> >>        };
> >>      };
> >>
> >> @@ -211,7 +218,7 @@ class AddressDescription {
> >>      uptr Address() const {
> >>        switch (data.kind) {
> >>          case kAddressKindWild:
> >> -        return data.addr;
> >> +        return data.wild.addr;
> >>          case kAddressKindShadow:
> >>            return data.shadow.addr;
> >>          case kAddressKindHeap:
> >> @@ -226,7 +233,7 @@ class AddressDescription {
> >>      void Print(const char *bug_descr = nullptr) const {
> >>        switch (data.kind) {
> >>          case kAddressKindWild:
> >> -        Printf("Address %p is a wild pointer.\n", data.addr);
> >> +        data.wild.Print();
> >>            return;
> >>          case kAddressKindShadow:
> >>            return data.shadow.Print();
> >> diff --git a/libsanitizer/asan/asan_errors.cpp b/libsanitizer/asan/asan_errors.cpp
> >> index 541c6e0353b..e68e6971f96 100644
> >> --- a/libsanitizer/asan/asan_errors.cpp
> >> +++ b/libsanitizer/asan/asan_errors.cpp
> >> @@ -343,7 +343,8 @@ void ErrorODRViolation::Print() {
> >>      Report("ERROR: AddressSanitizer: %s (%p):\n", scariness.GetDescription(),
> >>             global1.beg);
> >>      Printf("%s", d.Default());
> >> -  InternalScopedString g1_loc(256), g2_loc(256);
> >> +  InternalScopedString g1_loc;
> >> +  InternalScopedString g2_loc;
> >>      PrintGlobalLocation(&g1_loc, global1);
> >>      PrintGlobalLocation(&g2_loc, global2);
> >>      Printf("  [1] size=%zd '%s' %s\n", global1.size,
> >> @@ -360,7 +361,7 @@ void ErrorODRViolation::Print() {
> >>      Report(
> >>          "HINT: if you don't care about these errors you may set "
> >>          "ASAN_OPTIONS=detect_odr_violation=0\n");
> >> -  InternalScopedString error_msg(256);
> >> +  InternalScopedString error_msg;
> >>      error_msg.append("%s: global '%s' at %s", scariness.GetDescription(),
> >>                       MaybeDemangleGlobalName(global1.name), g1_loc.data());
> >>      ReportErrorSummary(error_msg.data());
> >> @@ -554,7 +555,7 @@ static void PrintShadowMemoryForAddress(uptr addr) {
> >>      uptr shadow_addr = MemToShadow(addr);
> >>      const uptr n_bytes_per_row = 16;
> >>      uptr aligned_shadow = shadow_addr & ~(n_bytes_per_row - 1);
> >> -  InternalScopedString str(4096 * 8);
> >> +  InternalScopedString str;
> >>      str.append("Shadow bytes around the buggy address:\n");
> >>      for (int i = -5; i <= 5; i++) {
> >>        uptr row_shadow_addr = aligned_shadow + i * n_bytes_per_row;
> >> diff --git a/libsanitizer/asan/asan_fake_stack.cpp b/libsanitizer/asan/asan_fake_stack.cpp
> >> index 295e6debc96..1f873fec7d7 100644
> >> --- a/libsanitizer/asan/asan_fake_stack.cpp
> >> +++ b/libsanitizer/asan/asan_fake_stack.cpp
> >> @@ -65,7 +65,7 @@ FakeStack *FakeStack::Create(uptr stack_size_log) {
> >>    void FakeStack::Destroy(int tid) {
> >>      PoisonAll(0);
> >>      if (Verbosity() >= 2) {
> >> -    InternalScopedString str(kNumberOfSizeClasses * 50);
> >> +    InternalScopedString str;
> >>        for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++)
> >>          str.append("%zd: %zd/%zd; ", class_id, hint_position_[class_id],
> >>                     NumberOfFrames(stack_size_log(), class_id));
> >> diff --git a/libsanitizer/asan/asan_fuchsia.cpp b/libsanitizer/asan/asan_fuchsia.cpp
> >> index 6c61344f87c..b0c7255144a 100644
> >> --- a/libsanitizer/asan/asan_fuchsia.cpp
> >> +++ b/libsanitizer/asan/asan_fuchsia.cpp
> >> @@ -81,7 +81,7 @@ void AsanTSDInit(void (*destructor)(void *tsd)) {
> >>    void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); }
> >>
> >>    static inline size_t AsanThreadMmapSize() {
> >> -  return RoundUpTo(sizeof(AsanThread), PAGE_SIZE);
> >> +  return RoundUpTo(sizeof(AsanThread), _zx_system_get_page_size());
> >>    }
> >>
> >>    struct AsanThread::InitOptions {
> >> 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.cpp b/libsanitizer/asan/asan_interceptors.cpp
> >> index 4e68b3b0b47..9db7db89fa1 100644
> >> --- a/libsanitizer/asan/asan_interceptors.cpp
> >> +++ b/libsanitizer/asan/asan_interceptors.cpp
> >> @@ -191,20 +191,11 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
> >>    #include "sanitizer_common/sanitizer_common_syscalls.inc"
> >>    #include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
> >>
> >> -struct ThreadStartParam {
> >> -  atomic_uintptr_t t;
> >> -  atomic_uintptr_t is_registered;
> >> -};
> >> -
> >>    #if ASAN_INTERCEPT_PTHREAD_CREATE
> >>    static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
> >> -  ThreadStartParam *param = reinterpret_cast<ThreadStartParam *>(arg);
> >> -  AsanThread *t = nullptr;
> >> -  while ((t = reinterpret_cast<AsanThread *>(
> >> -              atomic_load(&param->t, memory_order_acquire))) == nullptr)
> >> -    internal_sched_yield();
> >> +  AsanThread *t = (AsanThread *)arg;
> >>      SetCurrentThread(t);
> >> -  return t->ThreadStart(GetTid(), &param->is_registered);
> >> +  return t->ThreadStart(GetTid());
> >>    }
> >>
> >>    INTERCEPTOR(int, pthread_create, void *thread,
> >> @@ -217,9 +208,11 @@ INTERCEPTOR(int, pthread_create, void *thread,
> >>      int detached = 0;
> >>      if (attr)
> >>        REAL(pthread_attr_getdetachstate)(attr, &detached);
> >> -  ThreadStartParam param;
> >> -  atomic_store(&param.t, 0, memory_order_relaxed);
> >> -  atomic_store(&param.is_registered, 0, memory_order_relaxed);
> >> +
> >> +  u32 current_tid = GetCurrentTidOrInvalid();
> >> +  AsanThread *t =
> >> +      AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
> >> +
> >>      int result;
> >>      {
> >>        // Ignore all allocations made by pthread_create: thread stack/TLS may be
> >> @@ -229,21 +222,13 @@ INTERCEPTOR(int, pthread_create, void *thread,
> >>    #if CAN_SANITIZE_LEAKS
> >>        __lsan::ScopedInterceptorDisabler disabler;
> >>    #endif
> >> -    result = REAL(pthread_create)(thread, attr, asan_thread_start, &param);
> >> +    result = REAL(pthread_create)(thread, attr, asan_thread_start, t);
> >>      }
> >> -  if (result == 0) {
> >> -    u32 current_tid = GetCurrentTidOrInvalid();
> >> -    AsanThread *t =
> >> -        AsanThread::Create(start_routine, arg, current_tid, &stack, detached);
> >> -    atomic_store(&param.t, reinterpret_cast<uptr>(t), memory_order_release);
> >> -    // Wait until the AsanThread object is initialized and the ThreadRegistry
> >> -    // entry is in "started" state. One reason for this is that after this
> >> -    // interceptor exits, the child thread's stack may be the only thing holding
> >> -    // the |arg| pointer. This may cause LSan to report a leak if leak checking
> >> -    // happens at a point when the interceptor has already exited, but the stack
> >> -    // range for the child thread is not yet known.
> >> -    while (atomic_load(&param.is_registered, memory_order_acquire) == 0)
> >> -      internal_sched_yield();
> >> +  if (result != 0) {
> >> +    // If the thread didn't start delete the AsanThread to avoid leaking it.
> >> +    // Note AsanThreadContexts never get destroyed so the AsanThreadContext
> >> +    // that was just created for the AsanThread is wasted.
> >> +    t->Destroy();
> >>      }
> >>      return result;
> >>    }
> >> diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h
> >> index 56dc34b7d93..e8c58c2dc6b 100644
> >> --- a/libsanitizer/asan/asan_interceptors.h
> >> +++ b/libsanitizer/asan/asan_interceptors.h
> >> @@ -60,7 +60,7 @@ void InitializePlatformInterceptors();
> >>    # define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
> >>    #endif
> >>
> >> -#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_SOLARIS
> >> +#if SANITIZER_GLIBC || SANITIZER_SOLARIS
> >>    # define ASAN_INTERCEPT_SWAPCONTEXT 1
> >>    #else
> >>    # define ASAN_INTERCEPT_SWAPCONTEXT 0
> >> @@ -72,7 +72,7 @@ void InitializePlatformInterceptors();
> >>    # define ASAN_INTERCEPT_SIGLONGJMP 0
> >>    #endif
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC
> >>    # define ASAN_INTERCEPT___LONGJMP_CHK 1
> >>    #else
> >>    # define ASAN_INTERCEPT___LONGJMP_CHK 0
> >> @@ -81,12 +81,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
> >> @@ -111,7 +106,7 @@ void InitializePlatformInterceptors();
> >>    # define ASAN_INTERCEPT_ATEXIT 0
> >>    #endif
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC
> >>    # define ASAN_INTERCEPT___STRDUP 1
> >>    #else
> >>    # define ASAN_INTERCEPT___STRDUP 0
> >> @@ -139,10 +134,10 @@ DECLARE_REAL(uptr, strnlen, const char *s, uptr maxlen)
> >>    DECLARE_REAL(char*, strstr, const char *s1, const char *s2)
> >>
> >>    #if !SANITIZER_MAC
> >> -#define ASAN_INTERCEPT_FUNC(name)                                         \
> >> -  do {                                                                    \
> >> -    if (!INTERCEPT_FUNCTION(name))                                        \
> >> -      VReport(1, "AddressSanitizer: failed to intercept '%s'\n'", #name); \
> >> +#define ASAN_INTERCEPT_FUNC(name)                                        \
> >> +  do {                                                                   \
> >> +    if (!INTERCEPT_FUNCTION(name))                                       \
> >> +      VReport(1, "AddressSanitizer: failed to intercept '%s'\n", #name); \
> >>      } while (0)
> >>    #define ASAN_INTERCEPT_FUNC_VER(name, ver)                                  \
> >>      do {                                                                      \
> >> diff --git a/libsanitizer/asan/asan_linux.cpp b/libsanitizer/asan/asan_linux.cpp
> >> index fb1a442b3d4..4bcbe5d02e3 100644
> >> --- a/libsanitizer/asan/asan_linux.cpp
> >> +++ b/libsanitizer/asan/asan_linux.cpp
> >> @@ -55,6 +55,7 @@ extern Elf_Dyn _DYNAMIC;
> >>    #else
> >>    #include <sys/ucontext.h>
> >>    #include <link.h>
> >> +extern ElfW(Dyn) _DYNAMIC[];
> >>    #endif
> >>
> >>    // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
> >> @@ -84,7 +85,7 @@ bool IsSystemHeapAddress (uptr addr) { return false; }
> >>
> >>    void *AsanDoesNotSupportStaticLinkage() {
> >>      // This will fail to link with -static.
> >> -  return &_DYNAMIC;  // defined in link.h
> >> +  return &_DYNAMIC;
> >>    }
> >>
> >>    #if ASAN_PREMAP_SHADOW
> >> diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h
> >> index a7136de60d2..455e2364cd0 100644
> >> --- a/libsanitizer/asan/asan_mapping.h
> >> +++ b/libsanitizer/asan/asan_mapping.h
> >> @@ -72,6 +72,13 @@
> >>    // || `[0x2000000000, 0x23ffffffff]` || LowShadow  ||
> >>    // || `[0x0000000000, 0x1fffffffff]` || LowMem     ||
> >>    //
> >> +// Default Linux/RISCV64 Sv39 mapping:
> >> +// || `[0x1555550000, 0x3fffffffff]` || HighMem    ||
> >> +// || `[0x0fffffa000, 0x1555555fff]` || HighShadow ||
> >> +// || `[0x0effffa000, 0x0fffff9fff]` || ShadowGap  ||
> >> +// || `[0x0d55550000, 0x0effff9fff]` || LowShadow  ||
> >> +// || `[0x0000000000, 0x0d5554ffff]` || LowMem     ||
> >> +//
> >>    // Default Linux/AArch64 (39-bit VMA) mapping:
> >>    // || `[0x2000000000, 0x7fffffffff]` || highmem    ||
> >>    // || `[0x1400000000, 0x1fffffffff]` || highshadow ||
> >> @@ -79,20 +86,6 @@
> >>    // || `[0x1000000000, 0x11ffffffff]` || lowshadow  ||
> >>    // || `[0x0000000000, 0x0fffffffff]` || lowmem     ||
> >>    //
> >> -// RISC-V has only 38 bits for task size
> >> -// Low mem size is set with kRiscv64_ShadowOffset64 in
> >> -// compiler-rt/lib/asan/asan_allocator.h and in
> >> -// llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp with
> >> -// kRiscv64_ShadowOffset64, High mem top border is set with
> >> -// GetMaxVirtualAddress() in
> >> -// compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp
> >> -// Default Linux/RISCV64 Sv39/Sv48 mapping:
> >> -// || `[0x000820000000, 0x003fffffffff]` || HighMem    ||
> >> -// || `[0x000124000000, 0x00081fffffff]` || HighShadow ||
> >> -// || `[0x000024000000, 0x000123ffffff]` || ShadowGap  ||
> >> -// || `[0x000020000000, 0x000023ffffff]` || LowShadow  ||
> >> -// || `[0x000000000000, 0x00001fffffff]` || LowMem     ||
> >> -//
> >>    // Default Linux/AArch64 (42-bit VMA) mapping:
> >>    // || `[0x10000000000, 0x3ffffffffff]` || highmem    ||
> >>    // || `[0x0a000000000, 0x0ffffffffff]` || highshadow ||
> >> @@ -175,10 +168,10 @@ static const u64 kDefaultShadowOffset64 = 1ULL << 44;
> >>    static const u64 kDefaultShort64bitShadowOffset =
> >>        0x7FFFFFFF & (~0xFFFULL << kDefaultShadowScale);  // < 2G.
> >>    static const u64 kAArch64_ShadowOffset64 = 1ULL << 36;
> >> -static const u64 kRiscv64_ShadowOffset64 = 0x20000000;
> >> +static const u64 kRiscv64_ShadowOffset64 = 0xd55550000;
> >>    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_new_delete.cpp b/libsanitizer/asan/asan_new_delete.cpp
> >> index 5dfcc00fd5d..92a8648452b 100644
> >> --- a/libsanitizer/asan/asan_new_delete.cpp
> >> +++ b/libsanitizer/asan/asan_new_delete.cpp
> >> @@ -45,7 +45,7 @@ COMMENT_EXPORT("??_V@YAXPAX@Z")                   // operator delete[]
> >>    #endif
> >>    #undef COMMENT_EXPORT
> >>    #else
> >> -#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
> >> +#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
> >>    #endif
> >>
> >>    using namespace __asan;
> >> diff --git a/libsanitizer/asan/asan_poisoning.cpp b/libsanitizer/asan/asan_poisoning.cpp
> >> index 44f872ef619..fa149ecfde6 100644
> >> --- a/libsanitizer/asan/asan_poisoning.cpp
> >> +++ b/libsanitizer/asan/asan_poisoning.cpp
> >> @@ -364,7 +364,7 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p,
> >>                                                     &stack);
> >>      }
> >>      CHECK_LE(end - beg,
> >> -           FIRST_32_SECOND_64(1UL << 30, 1ULL << 34)); // Sanity check.
> >> +           FIRST_32_SECOND_64(1UL << 30, 1ULL << 40)); // Sanity check.
> >>
> >>      uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
> >>      uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
> >> diff --git a/libsanitizer/asan/asan_posix.cpp b/libsanitizer/asan/asan_posix.cpp
> >> index d7f19d84654..63ad735f8bb 100644
> >> --- a/libsanitizer/asan/asan_posix.cpp
> >> +++ b/libsanitizer/asan/asan_posix.cpp
> >> @@ -56,7 +56,7 @@ bool PlatformUnpoisonStacks() {
> >>      if (signal_stack.ss_flags != SS_ONSTACK)
> >>        return false;
> >>
> >> -  // Since we're on the signal altnerate stack, we cannot find the DEFAULT
> >> +  // Since we're on the signal alternate stack, we cannot find the DEFAULT
> >>      // stack bottom using a local variable.
> >>      uptr default_bottom, tls_addr, tls_size, stack_size;
> >>      GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr,
> >> diff --git a/libsanitizer/asan/asan_rtl.cpp b/libsanitizer/asan/asan_rtl.cpp
> >> index 7b5a929963c..e715d774228 100644
> >> --- a/libsanitizer/asan/asan_rtl.cpp
> >> +++ b/libsanitizer/asan/asan_rtl.cpp
> >> @@ -62,19 +62,9 @@ static void AsanDie() {
> >>      }
> >>    }
> >>
> >> -static void AsanCheckFailed(const char *file, int line, const char *cond,
> >> -                            u64 v1, u64 v2) {
> >> -  Report("AddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
> >> -         line, cond, (uptr)v1, (uptr)v2);
> >> -
> >> -  // Print a stack trace the first time we come here. Otherwise, we probably
> >> -  // failed a CHECK during symbolization.
> >> -  static atomic_uint32_t num_calls;
> >> -  if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) == 0) {
> >> -    PRINT_CURRENT_STACK_CHECK();
> >> -  }
> >> -
> >> -  Die();
> >> +static void CheckUnwind() {
> >> +  GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check);
> >> +  stack.Print();
> >>    }
> >>
> >>    // -------------------------- Globals --------------------- {{{1
> >> @@ -432,7 +422,7 @@ static void AsanInitInternal() {
> >>
> >>      // Install tool-specific callbacks in sanitizer_common.
> >>      AddDieCallback(AsanDie);
> >> -  SetCheckFailedCallback(AsanCheckFailed);
> >> +  SetCheckUnwindCallback(CheckUnwind);
> >>      SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
> >>
> >>      __sanitizer_set_report_path(common_flags()->log_path);
> >> @@ -568,7 +558,7 @@ void UnpoisonStack(uptr bottom, uptr top, const char *type) {
> >>            type, top, bottom, top - bottom, top - bottom);
> >>        return;
> >>      }
> >> -  PoisonShadow(bottom, top - bottom, 0);
> >> +  PoisonShadow(bottom, RoundUpTo(top - bottom, SHADOW_GRANULARITY), 0);
> >>    }
> >>
> >>    static void UnpoisonDefaultStack() {
> >> diff --git a/libsanitizer/asan/asan_stack.h b/libsanitizer/asan/asan_stack.h
> >> index 47ca85a1644..b9575d2f427 100644
> >> --- a/libsanitizer/asan/asan_stack.h
> >> +++ b/libsanitizer/asan/asan_stack.h
> >> @@ -54,9 +54,6 @@ u32 GetMallocContextSize();
> >>    #define GET_STACK_TRACE_FATAL_HERE                                \
> >>      GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
> >>
> >> -#define GET_STACK_TRACE_CHECK_HERE                                \
> >> -  GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_check)
> >> -
> >>    #define GET_STACK_TRACE_THREAD                                    \
> >>      GET_STACK_TRACE(kStackTraceMax, true)
> >>
> >> @@ -71,10 +68,4 @@ u32 GetMallocContextSize();
> >>        stack.Print();              \
> >>      }
> >>
> >> -#define PRINT_CURRENT_STACK_CHECK() \
> >> -  {                                 \
> >> -    GET_STACK_TRACE_CHECK_HERE;     \
> >> -    stack.Print();                  \
> >> -  }
> >> -
> >>    #endif // ASAN_STACK_H
> >> diff --git a/libsanitizer/asan/asan_thread.cpp b/libsanitizer/asan/asan_thread.cpp
> >> index fb09af0ecca..9c3c86f5735 100644
> >> --- a/libsanitizer/asan/asan_thread.cpp
> >> +++ b/libsanitizer/asan/asan_thread.cpp
> >> @@ -100,18 +100,27 @@ void AsanThread::Destroy() {
> >>      int tid = this->tid();
> >>      VReport(1, "T%d exited\n", tid);
> >>
> >> -  malloc_storage().CommitBack();
> >> -  if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack();
> >> -  asanThreadRegistry().FinishThread(tid);
> >> -  FlushToDeadThreadStats(&stats_);
> >> -  // We also clear the shadow on thread destruction because
> >> -  // some code may still be executing in later TSD destructors
> >> -  // and we don't want it to have any poisoned stack.
> >> -  ClearShadowForThreadStackAndTLS();
> >> -  DeleteFakeStack(tid);
> >> +  bool was_running =
> >> +      (asanThreadRegistry().FinishThread(tid) == ThreadStatusRunning);
> >> +  if (was_running) {
> >> +    if (AsanThread *thread = GetCurrentThread())
> >> +      CHECK_EQ(this, thread);
> >> +    malloc_storage().CommitBack();
> >> +    if (common_flags()->use_sigaltstack)
> >> +      UnsetAlternateSignalStack();
> >> +    FlushToDeadThreadStats(&stats_);
> >> +    // We also clear the shadow on thread destruction because
> >> +    // some code may still be executing in later TSD destructors
> >> +    // and we don't want it to have any poisoned stack.
> >> +    ClearShadowForThreadStackAndTLS();
> >> +    DeleteFakeStack(tid);
> >> +  } else {
> >> +    CHECK_NE(this, GetCurrentThread());
> >> +  }
> >>      uptr size = RoundUpTo(sizeof(AsanThread), GetPageSizeCached());
> >>      UnmapOrDie(this, size);
> >> -  DTLS_Destroy();
> >> +  if (was_running)
> >> +    DTLS_Destroy();
> >>    }
> >>
> >>    void AsanThread::StartSwitchFiber(FakeStack **fake_stack_save, uptr bottom,
> >> @@ -219,7 +228,7 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
> >>    }
> >>
> >>    void AsanThread::Init(const InitOptions *options) {
> >> -  DCHECK_NE(tid(), ThreadRegistry::kUnknownTid);
> >> +  DCHECK_NE(tid(), kInvalidTid);
> >>      next_stack_top_ = next_stack_bottom_ = 0;
> >>      atomic_store(&stack_switching_, false, memory_order_release);
> >>      CHECK_EQ(this->stack_size(), 0U);
> >> @@ -253,12 +262,9 @@ void AsanThread::Init(const InitOptions *options) {
> >>    // SetThreadStackAndTls.
> >>    #if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS
> >>
> >> -thread_return_t AsanThread::ThreadStart(
> >> -    tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) {
> >> +thread_return_t AsanThread::ThreadStart(tid_t os_id) {
> >>      Init();
> >>      asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr);
> >> -  if (signal_thread_is_registered)
> >> -    atomic_store(signal_thread_is_registered, 1, memory_order_release);
> >>
> >>      if (common_flags()->use_sigaltstack) SetAlternateSignalStack();
> >>
> >> @@ -285,11 +291,10 @@ thread_return_t AsanThread::ThreadStart(
> >>
> >>    AsanThread *CreateMainThread() {
> >>      AsanThread *main_thread = AsanThread::Create(
> >> -      /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
> >> +      /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ kMainTid,
> >>          /* stack */ nullptr, /* detached */ true);
> >>      SetCurrentThread(main_thread);
> >> -  main_thread->ThreadStart(internal_getpid(),
> >> -                           /* signal_thread_is_registered */ nullptr);
> >> +  main_thread->ThreadStart(internal_getpid());
> >>      return main_thread;
> >>    }
> >>
> >> @@ -300,9 +305,9 @@ void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
> >>      DCHECK_EQ(options, nullptr);
> >>      uptr tls_size = 0;
> >>      uptr stack_size = 0;
> >> -  GetThreadStackAndTls(tid() == 0, &stack_bottom_, &stack_size, &tls_begin_,
> >> -                       &tls_size);
> >> -  stack_top_ = stack_bottom_ + stack_size;
> >> +  GetThreadStackAndTls(tid() == kMainTid, &stack_bottom_, &stack_size,
> >> +                       &tls_begin_, &tls_size);
> >> +  stack_top_ = RoundDownTo(stack_bottom_ + stack_size, SHADOW_GRANULARITY);
> >>      tls_end_ = tls_begin_ + tls_size;
> >>      dtls_ = DTLS_Get();
> >>
> >> @@ -426,7 +431,7 @@ AsanThread *GetCurrentThread() {
> >>          // address. We are not entirely sure that we have correct main thread
> >>          // limits, so only do this magic on Android, and only if the found thread
> >>          // is the main thread.
> >> -      AsanThreadContext *tctx = GetThreadContextByTidLocked(0);
> >> +      AsanThreadContext *tctx = GetThreadContextByTidLocked(kMainTid);
> >>          if (tctx && ThreadStackContainsAddress(tctx, &context)) {
> >>            SetCurrentThread(tctx->thread);
> >>            return tctx->thread;
> >> @@ -463,7 +468,7 @@ AsanThread *FindThreadByStackAddress(uptr addr) {
> >>    void EnsureMainThreadIDIsCorrect() {
> >>      AsanThreadContext *context =
> >>          reinterpret_cast<AsanThreadContext *>(AsanTSDGet());
> >> -  if (context && (context->tid == 0))
> >> +  if (context && (context->tid == kMainTid))
> >>        context->os_id = GetTid();
> >>    }
> >>
> >> diff --git a/libsanitizer/asan/asan_thread.h b/libsanitizer/asan/asan_thread.h
> >> index ea58de4216a..200069ce0dd 100644
> >> --- a/libsanitizer/asan/asan_thread.h
> >> +++ b/libsanitizer/asan/asan_thread.h
> >> @@ -28,7 +28,6 @@ struct DTLS;
> >>
> >>    namespace __asan {
> >>
> >> -const u32 kInvalidTid = 0xffffff;  // Must fit into 24 bits.
> >>    const u32 kMaxNumberOfThreads = (1 << 22);  // 4M
> >>
> >>    class AsanThread;
> >> @@ -69,8 +68,7 @@ class AsanThread {
> >>      struct InitOptions;
> >>      void Init(const InitOptions *options = nullptr);
> >>
> >> -  thread_return_t ThreadStart(tid_t os_id,
> >> -                              atomic_uintptr_t *signal_thread_is_registered);
> >> +  thread_return_t ThreadStart(tid_t os_id);
> >>
> >>      uptr stack_top();
> >>      uptr stack_bottom();
> >> @@ -132,6 +130,8 @@ class AsanThread {
> >>
> >>      void *extra_spill_area() { return &extra_spill_area_; }
> >>
> >> +  void *get_arg() { return arg_; }
> >> +
> >>     private:
> >>      // NOTE: There is no AsanThread constructor. It is allocated
> >>      // via mmap() and *must* be valid in zero-initialized state.
> >> diff --git a/libsanitizer/asan/asan_win.cpp b/libsanitizer/asan/asan_win.cpp
> >> index 8044ae16ff9..1577c83cf99 100644
> >> --- a/libsanitizer/asan/asan_win.cpp
> >> +++ b/libsanitizer/asan/asan_win.cpp
> >> @@ -134,7 +134,7 @@ INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
> >>    static thread_return_t THREAD_CALLING_CONV asan_thread_start(void *arg) {
> >>      AsanThread *t = (AsanThread *)arg;
> >>      SetCurrentThread(t);
> >> -  return t->ThreadStart(GetTid(), /* signal_thread_is_registered */ nullptr);
> >> +  return t->ThreadStart(GetTid());
> >>    }
> >>
> >>    INTERCEPTOR_WINAPI(HANDLE, CreateThread, LPSECURITY_ATTRIBUTES security,
> >> diff --git a/libsanitizer/builtins/assembly.h b/libsanitizer/builtins/assembly.h
> >> index f437cb87f60..9c015059af5 100644
> >> --- a/libsanitizer/builtins/assembly.h
> >> +++ b/libsanitizer/builtins/assembly.h
> >> @@ -14,8 +14,8 @@
> >>    #ifndef COMPILERRT_ASSEMBLY_H
> >>    #define COMPILERRT_ASSEMBLY_H
> >>
> >> -#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
> >> -#define SEPARATOR @
> >> +#if defined(__APPLE__) && defined(__aarch64__)
> >> +#define SEPARATOR %%
> >>    #else
> >>    #define SEPARATOR ;
> >>    #endif
> >> @@ -35,14 +35,14 @@
> >>    #define HIDDEN(name) .hidden name
> >>    #define LOCAL_LABEL(name) .L_##name
> >>    #define FILE_LEVEL_DIRECTIVE
> >> -#if defined(__arm__)
> >> +#if defined(__arm__) || defined(__aarch64__)
> >>    #define SYMBOL_IS_FUNC(name) .type name,%function
> >>    #else
> >>    #define SYMBOL_IS_FUNC(name) .type name,@function
> >>    #endif
> >>    #define CONST_SECTION .section .rodata
> >>
> >> -#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
> >> +#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) ||        \
> >>        defined(__linux__)
> >>    #define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits
> >>    #else
> >> @@ -65,6 +65,68 @@
> >>
> >>    #endif
> >>
> >> +#if defined(__arm__) || defined(__aarch64__)
> >> +#define FUNC_ALIGN                                                             \
> >> +  .text SEPARATOR                                                              \
> >> +  .balign 16 SEPARATOR
> >> +#else
> >> +#define FUNC_ALIGN
> >> +#endif
> >> +
> >> +// BTI and PAC gnu property note
> >> +#define NT_GNU_PROPERTY_TYPE_0 5
> >> +#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
> >> +#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI 1
> >> +#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 2
> >> +
> >> +#if defined(__ARM_FEATURE_BTI_DEFAULT)
> >> +#define BTI_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_BTI
> >> +#else
> >> +#define BTI_FLAG 0
> >> +#endif
> >> +
> >> +#if __ARM_FEATURE_PAC_DEFAULT & 3
> >> +#define PAC_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_PAC
> >> +#else
> >> +#define PAC_FLAG 0
> >> +#endif
> >> +
> >> +#define GNU_PROPERTY(type, value)                                              \
> >> +  .pushsection .note.gnu.property, "a" SEPARATOR                               \
> >> +  .p2align 3 SEPARATOR                                                         \
> >> +  .word 4 SEPARATOR                                                            \
> >> +  .word 16 SEPARATOR                                                           \
> >> +  .word NT_GNU_PROPERTY_TYPE_0 SEPARATOR                                       \
> >> +  .asciz "GNU" SEPARATOR                                                       \
> >> +  .word type SEPARATOR                                                         \
> >> +  .word 4 SEPARATOR                                                            \
> >> +  .word value SEPARATOR                                                        \
> >> +  .word 0 SEPARATOR                                                            \
> >> +  .popsection
> >> +
> >> +#if BTI_FLAG != 0
> >> +#define BTI_C hint #34
> >> +#define BTI_J hint #36
> >> +#else
> >> +#define BTI_C
> >> +#define BTI_J
> >> +#endif
> >> +
> >> +#if (BTI_FLAG | PAC_FLAG) != 0
> >> +#define GNU_PROPERTY_BTI_PAC                                                   \
> >> +  GNU_PROPERTY(GNU_PROPERTY_AARCH64_FEATURE_1_AND, BTI_FLAG | PAC_FLAG)
> >> +#else
> >> +#define GNU_PROPERTY_BTI_PAC
> >> +#endif
> >> +
> >> +#if defined(__clang__) || defined(__GCC_HAVE_DWARF2_CFI_ASM)
> >> +#define CFI_START .cfi_startproc
> >> +#define CFI_END .cfi_endproc
> >> +#else
> >> +#define CFI_START
> >> +#define CFI_END
> >> +#endif
> >> +
> >>    #if defined(__arm__)
> >>
> >>    // Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros:
> >> @@ -131,15 +193,24 @@
> >>    #define DEFINE_CODE_STATE
> >>    #endif
> >>
> >> -#define GLUE2(a, b) a##b
> >> -#define GLUE(a, b) GLUE2(a, b)
> >> +#define GLUE2_(a, b) a##b
> >> +#define GLUE(a, b) GLUE2_(a, b)
> >> +#define GLUE2(a, b) GLUE2_(a, b)
> >> +#define GLUE3_(a, b, c) a##b##c
> >> +#define GLUE3(a, b, c) GLUE3_(a, b, c)
> >> +#define GLUE4_(a, b, c, d) a##b##c##d
> >> +#define GLUE4(a, b, c, d) GLUE4_(a, b, c, d)
> >> +
> >>    #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
> >>
> >>    #ifdef VISIBILITY_HIDDEN
> >>    #define DECLARE_SYMBOL_VISIBILITY(name)                                        \
> >>      HIDDEN(SYMBOL_NAME(name)) SEPARATOR
> >> +#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) \
> >> +  HIDDEN(name) SEPARATOR
> >>    #else
> >>    #define DECLARE_SYMBOL_VISIBILITY(name)
> >> +#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name)
> >>    #endif
> >>
> >>    #define DEFINE_COMPILERRT_FUNCTION(name)                                       \
> >> @@ -177,6 +248,16 @@
> >>      DECLARE_FUNC_ENCODING                                                        \
> >>      name:
> >>
> >> +#define DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(name)                     \
> >> +  DEFINE_CODE_STATE                                                            \
> >> +  FUNC_ALIGN                                                                   \
> >> +  .globl name SEPARATOR                                                        \
> >> +  SYMBOL_IS_FUNC(name) SEPARATOR                                               \
> >> +  DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) SEPARATOR                          \
> >> +  CFI_START SEPARATOR                                                          \
> >> +  DECLARE_FUNC_ENCODING                                                        \
> >> +  name: SEPARATOR BTI_C
> >> +
> >>    #define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target)                         \
> >>      .globl SYMBOL_NAME(name) SEPARATOR                                           \
> >>      SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR                                  \
> >> @@ -193,8 +274,13 @@
> >>    #ifdef __ELF__
> >>    #define END_COMPILERRT_FUNCTION(name)                                          \
> >>      .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
> >> +#define END_COMPILERRT_OUTLINE_FUNCTION(name)                                  \
> >> +  CFI_END SEPARATOR                                                            \
> >> +  .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
> >>    #else
> >>    #define END_COMPILERRT_FUNCTION(name)
> >> +#define END_COMPILERRT_OUTLINE_FUNCTION(name)                                  \
> >> +  CFI_END
> >>    #endif
> >>
> >>    #endif // COMPILERRT_ASSEMBLY_H
> >> diff --git a/libsanitizer/hwasan/hwasan.cpp b/libsanitizer/hwasan/hwasan.cpp
> >> index c5322110cb6..8d6c25261b8 100644
> >> --- a/libsanitizer/hwasan/hwasan.cpp
> >> +++ b/libsanitizer/hwasan/hwasan.cpp
> >> @@ -128,16 +128,11 @@ static void InitializeFlags() {
> >>      if (common_flags()->help) parser.PrintFlagDescriptions();
> >>    }
> >>
> >> -static void HWAsanCheckFailed(const char *file, int line, const char *cond,
> >> -                              u64 v1, u64 v2) {
> >> -  Report("HWAddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
> >> -         line, cond, (uptr)v1, (uptr)v2);
> >> -  PRINT_CURRENT_STACK_CHECK();
> >> -  Die();
> >> +static void CheckUnwind() {
> >> +  GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME());
> >> +  stack.Print();
> >>    }
> >>
> >> -static constexpr uptr kMemoryUsageBufferSize = 4096;
> >> -
> >>    static void HwasanFormatMemoryUsage(InternalScopedString &s) {
> >>      HwasanThreadList &thread_list = hwasanThreadList();
> >>      auto thread_stats = thread_list.GetThreadStats();
> >> @@ -155,6 +150,8 @@ static void HwasanFormatMemoryUsage(InternalScopedString &s) {
> >>    }
> >>
> >>    #if SANITIZER_ANDROID
> >> +static constexpr uptr kMemoryUsageBufferSize = 4096;
> >> +
> >>    static char *memory_usage_buffer = nullptr;
> >>
> >>    static void InitMemoryUsage() {
> >> @@ -171,7 +168,7 @@ void UpdateMemoryUsage() {
> >>        return;
> >>      if (!memory_usage_buffer)
> >>        InitMemoryUsage();
> >> -  InternalScopedString s(kMemoryUsageBufferSize);
> >> +  InternalScopedString s;
> >>      HwasanFormatMemoryUsage(s);
> >>      internal_strncpy(memory_usage_buffer, s.data(), kMemoryUsageBufferSize - 1);
> >>      memory_usage_buffer[kMemoryUsageBufferSize - 1] = '\0';
> >> @@ -271,7 +268,7 @@ void __hwasan_init() {
> >>      InitializeFlags();
> >>
> >>      // Install tool-specific callbacks in sanitizer_common.
> >> -  SetCheckFailedCallback(HWAsanCheckFailed);
> >> +  SetCheckUnwindCallback(CheckUnwind);
> >>
> >>      __sanitizer_set_report_path(common_flags()->log_path);
> >>
> >> @@ -493,7 +490,7 @@ extern "C" void *__hwasan_extra_spill_area() {
> >>    }
> >>
> >>    void __hwasan_print_memory_usage() {
> >> -  InternalScopedString s(kMemoryUsageBufferSize);
> >> +  InternalScopedString s;
> >>      HwasanFormatMemoryUsage(s);
> >>      Printf("%s\n", s.data());
> >>    }
> >> diff --git a/libsanitizer/hwasan/hwasan.h b/libsanitizer/hwasan/hwasan.h
> >> index d4521efd089..8515df559f3 100644
> >> --- a/libsanitizer/hwasan/hwasan.h
> >> +++ b/libsanitizer/hwasan/hwasan.h
> >> @@ -14,11 +14,12 @@
> >>    #ifndef HWASAN_H
> >>    #define HWASAN_H
> >>
> >> +#include "hwasan_flags.h"
> >> +#include "hwasan_interface_internal.h"
> >> +#include "sanitizer_common/sanitizer_common.h"
> >>    #include "sanitizer_common/sanitizer_flags.h"
> >>    #include "sanitizer_common/sanitizer_internal_defs.h"
> >>    #include "sanitizer_common/sanitizer_stacktrace.h"
> >> -#include "hwasan_interface_internal.h"
> >> -#include "hwasan_flags.h"
> >>    #include "ubsan/ubsan_platform.h"
> >>
> >>    #ifndef HWASAN_CONTAINS_UBSAN
> >> @@ -35,10 +36,31 @@
> >>
> >>    typedef u8 tag_t;
> >>
> >> +#if defined(__x86_64__)
> >> +// Tags are done in middle bits using userspace aliasing.
> >> +constexpr unsigned kAddressTagShift = 39;
> >> +constexpr unsigned kTagBits = 3;
> >> +
> >> +// The alias region is placed next to the shadow so the upper bits of all
> >> +// taggable addresses matches the upper bits of the shadow base.  This shift
> >> +// value determines which upper bits must match.  It has a floor of 44 since the
> >> +// shadow is always 8TB.
> >> +// TODO(morehouse): In alias mode we can shrink the shadow and use a
> >> +// simpler/faster shadow calculation.
> >> +constexpr unsigned kTaggableRegionCheckShift =
> >> +    __sanitizer::Max(kAddressTagShift + kTagBits + 1U, 44U);
> >> +#else
> >>    // TBI (Top Byte Ignore) feature of AArch64: bits [63:56] are ignored in address
> >>    // translation and can be used to store a tag.
> >> -const unsigned kAddressTagShift = 56;
> >> -const uptr kAddressTagMask = 0xFFUL << kAddressTagShift;
> >> +constexpr unsigned kAddressTagShift = 56;
> >> +constexpr unsigned kTagBits = 8;
> >> +#endif  // defined(__x86_64__)
> >> +
> >> +// Mask for extracting tag bits from the lower 8 bits.
> >> +constexpr uptr kTagMask = (1UL << kTagBits) - 1;
> >> +
> >> +// Mask for extracting tag bits from full pointers.
> >> +constexpr uptr kAddressTagMask = kTagMask << kAddressTagShift;
> >>
> >>    // Minimal alignment of the shadow base address. Determines the space available
> >>    // for threads and stack histories. This is an ABI constant.
> >> @@ -50,7 +72,7 @@ const unsigned kRecordFPLShift = 4;
> >>    const unsigned kRecordFPModulus = 1 << (64 - kRecordFPShift + kRecordFPLShift);
> >>
> >>    static inline tag_t GetTagFromPointer(uptr p) {
> >> -  return p >> kAddressTagShift;
> >> +  return (p >> kAddressTagShift) & kTagMask;
> >>    }
> >>
> >>    static inline uptr UntagAddr(uptr tagged_addr) {
> >> @@ -105,15 +127,6 @@ void InstallAtExitHandler();
> >>      if (hwasan_inited)                                     \
> >>        stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal)
> >>
> >> -#define GET_FATAL_STACK_TRACE_HERE \
> >> -  GET_FATAL_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME())
> >> -
> >> -#define PRINT_CURRENT_STACK_CHECK() \
> >> -  {                                 \
> >> -    GET_FATAL_STACK_TRACE_HERE;     \
> >> -    stack.Print();                  \
> >> -  }
> >> -
> >>    void HwasanTSDInit();
> >>    void HwasanTSDThreadInit();
> >>
> >> diff --git a/libsanitizer/hwasan/hwasan_allocator.cpp b/libsanitizer/hwasan/hwasan_allocator.cpp
> >> index 0b6b7347892..a6fc794082a 100644
> >> --- a/libsanitizer/hwasan/hwasan_allocator.cpp
> >> +++ b/libsanitizer/hwasan/hwasan_allocator.cpp
> >> @@ -29,8 +29,8 @@ static AllocatorCache fallback_allocator_cache;
> >>    static SpinMutex fallback_mutex;
> >>    static atomic_uint8_t hwasan_allocator_tagging_enabled;
> >>
> >> -static const tag_t kFallbackAllocTag = 0xBB;
> >> -static const tag_t kFallbackFreeTag = 0xBC;
> >> +static constexpr tag_t kFallbackAllocTag = 0xBB & kTagMask;
> >> +static constexpr tag_t kFallbackFreeTag = 0xBC;
> >>
> >>    enum RightAlignMode {
> >>      kRightAlignNever,
> >> @@ -84,7 +84,8 @@ void HwasanAllocatorInit() {
> >>      atomic_store_relaxed(&hwasan_allocator_tagging_enabled,
> >>                           !flags()->disable_allocator_tagging);
> >>      SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
> >> -  allocator.Init(common_flags()->allocator_release_to_os_interval_ms);
> >> +  allocator.Init(common_flags()->allocator_release_to_os_interval_ms,
> >> +                 kAliasRegionStart);
> >>      for (uptr i = 0; i < sizeof(tail_magic); i++)
> >>        tail_magic[i] = GetCurrentThread()->GenerateRandomTag();
> >>    }
> >> @@ -148,7 +149,8 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
> >>      // Tagging can only be skipped when both tag_in_malloc and tag_in_free are
> >>      // false. When tag_in_malloc = false and tag_in_free = true malloc needs to
> >>      // retag to 0.
> >> -  if ((flags()->tag_in_malloc || flags()->tag_in_free) &&
> >> +  if (InTaggableRegion(reinterpret_cast<uptr>(user_ptr)) &&
> >> +      (flags()->tag_in_malloc || flags()->tag_in_free) &&
> >>          atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) {
> >>        if (flags()->tag_in_malloc && malloc_bisect(stack, orig_size)) {
> >>          tag_t tag = t ? t->GenerateRandomTag() : kFallbackAllocTag;
> >> @@ -175,6 +177,8 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
> >>    static bool PointerAndMemoryTagsMatch(void *tagged_ptr) {
> >>      CHECK(tagged_ptr);
> >>      uptr tagged_uptr = reinterpret_cast<uptr>(tagged_ptr);
> >> +  if (!InTaggableRegion(tagged_uptr))
> >> +    return true;
> >>      tag_t mem_tag = *reinterpret_cast<tag_t *>(
> >>          MemToShadow(reinterpret_cast<uptr>(UntagPtr(tagged_ptr))));
> >>      return PossiblyShortTagMatches(mem_tag, tagged_uptr, 1);
> >> @@ -187,7 +191,9 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
> >>      if (!PointerAndMemoryTagsMatch(tagged_ptr))
> >>        ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr));
> >>
> >> -  void *untagged_ptr = UntagPtr(tagged_ptr);
> >> +  void *untagged_ptr = InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr))
> >> +                           ? UntagPtr(tagged_ptr)
> >> +                           : tagged_ptr;
> >>      void *aligned_ptr = reinterpret_cast<void *>(
> >>          RoundDownTo(reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment));
> >>      Metadata *meta =
> >> @@ -219,10 +225,14 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
> >>            Min(TaggedSize(orig_size), (uptr)flags()->max_free_fill_size);
> >>        internal_memset(aligned_ptr, flags()->free_fill_byte, fill_size);
> >>      }
> >> -  if (flags()->tag_in_free && malloc_bisect(stack, 0) &&
> >> -      atomic_load_relaxed(&hwasan_allocator_tagging_enabled))
> >> +  if (InTaggableRegion(reinterpret_cast<uptr>(tagged_ptr)) &&
> >> +      flags()->tag_in_free && malloc_bisect(stack, 0) &&
> >> +      atomic_load_relaxed(&hwasan_allocator_tagging_enabled)) {
> >> +    // Always store full 8-bit tags on free to maximize UAF detection.
> >> +    tag_t tag = t ? t->GenerateRandomTag(/*num_bits=*/8) : kFallbackFreeTag;
> >>        TagMemoryAligned(reinterpret_cast<uptr>(aligned_ptr), TaggedSize(orig_size),
> >> -                     t ? t->GenerateRandomTag() : kFallbackFreeTag);
> >> +                     tag);
> >> +  }
> >>      if (t) {
> >>        allocator.Deallocate(t->allocator_cache(), aligned_ptr);
> >>        if (auto *ha = t->heap_allocations())
> >> @@ -365,7 +375,7 @@ int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
> >>        // OOM error is already taken care of by HwasanAllocate.
> >>        return errno_ENOMEM;
> >>      CHECK(IsAligned((uptr)ptr, alignment));
> >> -  *(void **)UntagPtr(memptr) = ptr;
> >> +  *memptr = ptr;
> >>      return 0;
> >>    }
> >>
> >> diff --git a/libsanitizer/hwasan/hwasan_allocator.h b/libsanitizer/hwasan/hwasan_allocator.h
> >> index 43670a6a3fb..03bbcff3f0f 100644
> >> --- a/libsanitizer/hwasan/hwasan_allocator.h
> >> +++ b/libsanitizer/hwasan/hwasan_allocator.h
> >> @@ -13,13 +13,15 @@
> >>    #ifndef HWASAN_ALLOCATOR_H
> >>    #define HWASAN_ALLOCATOR_H
> >>
> >> +#include "hwasan.h"
> >> +#include "hwasan_interface_internal.h"
> >> +#include "hwasan_poisoning.h"
> >>    #include "sanitizer_common/sanitizer_allocator.h"
> >>    #include "sanitizer_common/sanitizer_allocator_checks.h"
> >>    #include "sanitizer_common/sanitizer_allocator_interface.h"
> >>    #include "sanitizer_common/sanitizer_allocator_report.h"
> >>    #include "sanitizer_common/sanitizer_common.h"
> >>    #include "sanitizer_common/sanitizer_ring_buffer.h"
> >> -#include "hwasan_poisoning.h"
> >>
> >>    #if !defined(__aarch64__) && !defined(__x86_64__)
> >>    #error Unsupported platform
> >> @@ -55,7 +57,12 @@ static const uptr kMaxAllowedMallocSize = 1UL << 40;  // 1T
> >>
> >>    struct AP64 {
> >>      static const uptr kSpaceBeg = ~0ULL;
> >> +
> >> +#if defined(__x86_64__)
> >> +  static const uptr kSpaceSize = 1ULL << kAddressTagShift;
> >> +#else
> >>      static const uptr kSpaceSize = 0x2000000000ULL;
> >> +#endif
> >>      static const uptr kMetadataSize = sizeof(Metadata);
> >>      typedef __sanitizer::VeryDenseSizeClassMap SizeClassMap;
> >>      using AddressSpaceView = LocalAddressSpaceView;
> >> @@ -102,6 +109,16 @@ typedef RingBuffer<HeapAllocationRecord> HeapAllocationsRingBuffer;
> >>
> >>    void GetAllocatorStats(AllocatorStatCounters s);
> >>
> >> +inline bool InTaggableRegion(uptr addr) {
> >> +#if defined(__x86_64__)
> >> +  // Aliases are mapped next to shadow so that the upper bits match the shadow
> >> +  // base.
> >> +  return (addr >> kTaggableRegionCheckShift) ==
> >> +         (__hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
> >> +#endif
> >> +  return true;
> >> +}
> >> +
> >>    } // namespace __hwasan
> >>
> >>    #endif // HWASAN_ALLOCATOR_H
> >> diff --git a/libsanitizer/hwasan/hwasan_checks.h b/libsanitizer/hwasan/hwasan_checks.h
> >> index a8de0fef20f..ab543ea88be 100644
> >> --- a/libsanitizer/hwasan/hwasan_checks.h
> >> +++ b/libsanitizer/hwasan/hwasan_checks.h
> >> @@ -13,6 +13,7 @@
> >>    #ifndef HWASAN_CHECKS_H
> >>    #define HWASAN_CHECKS_H
> >>
> >> +#include "hwasan_allocator.h"
> >>    #include "hwasan_mapping.h"
> >>    #include "sanitizer_common/sanitizer_common.h"
> >>
> >> @@ -81,6 +82,8 @@ enum class AccessType { Load, Store };
> >>
> >>    template <ErrorAction EA, AccessType AT, unsigned LogSize>
> >>    __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
> >> +  if (!InTaggableRegion(p))
> >> +    return;
> >>      uptr ptr_raw = p & ~kAddressTagMask;
> >>      tag_t mem_tag = *(tag_t *)MemToShadow(ptr_raw);
> >>      if (UNLIKELY(!PossiblyShortTagMatches(mem_tag, p, 1 << LogSize))) {
> >> @@ -94,7 +97,7 @@ __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
> >>    template <ErrorAction EA, AccessType AT>
> >>    __attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
> >>                                                                          uptr sz) {
> >> -  if (sz == 0)
> >> +  if (sz == 0 || !InTaggableRegion(p))
> >>        return;
> >>      tag_t ptr_tag = GetTagFromPointer(p);
> >>      uptr ptr_raw = p & ~kAddressTagMask;
> >> diff --git a/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp b/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
> >> index 12730b29bae..f53276e330d 100644
> >> --- a/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
> >> +++ b/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
> >> @@ -12,15 +12,17 @@
> >>    ///
> >>    //===----------------------------------------------------------------------===//
> >>
> >> -#include "hwasan.h"
> >>    #include "hwasan_dynamic_shadow.h"
> >> -#include "hwasan_mapping.h"
> >> -#include "sanitizer_common/sanitizer_common.h"
> >> -#include "sanitizer_common/sanitizer_posix.h"
> >>
> >>    #include <elf.h>
> >>    #include <link.h>
> >>
> >> +#include "hwasan.h"
> >> +#include "hwasan_mapping.h"
> >> +#include "hwasan_thread_list.h"
> >> +#include "sanitizer_common/sanitizer_common.h"
> >> +#include "sanitizer_common/sanitizer_posix.h"
> >> +
> >>    // The code in this file needs to run in an unrelocated binary. It should not
> >>    // access any external symbol, including its own non-hidden globals.
> >>
> >> @@ -117,6 +119,12 @@ namespace __hwasan {
> >>    void InitShadowGOT() {}
> >>
> >>    uptr FindDynamicShadowStart(uptr shadow_size_bytes) {
> >> +#if defined(__x86_64__)
> >> +  constexpr uptr kAliasSize = 1ULL << kAddressTagShift;
> >> +  constexpr uptr kNumAliases = 1ULL << kTagBits;
> >> +  return MapDynamicShadowAndAliases(shadow_size_bytes, kAliasSize, kNumAliases,
> >> +                                    RingBufferSize());
> >> +#endif
> >>      return MapDynamicShadow(shadow_size_bytes, kShadowScale, kShadowBaseAlignment,
> >>                              kHighMemEnd);
> >>    }
> >> diff --git a/libsanitizer/hwasan/hwasan_flags.h b/libsanitizer/hwasan/hwasan_flags.h
> >> index 0a6998f675d..b17750158d0 100644
> >> --- a/libsanitizer/hwasan/hwasan_flags.h
> >> +++ b/libsanitizer/hwasan/hwasan_flags.h
> >> @@ -12,6 +12,8 @@
> >>    #ifndef HWASAN_FLAGS_H
> >>    #define HWASAN_FLAGS_H
> >>
> >> +#include "sanitizer_common/sanitizer_internal_defs.h"
> >> +
> >>    namespace __hwasan {
> >>
> >>    struct Flags {
> >> diff --git a/libsanitizer/hwasan/hwasan_flags.inc b/libsanitizer/hwasan/hwasan_flags.inc
> >> index 8e431d9c4ff..18ea47f981b 100644
> >> --- a/libsanitizer/hwasan/hwasan_flags.inc
> >> +++ b/libsanitizer/hwasan/hwasan_flags.inc
> >> @@ -72,3 +72,12 @@ HWASAN_FLAG(uptr, malloc_bisect_right, 0,
> >>    HWASAN_FLAG(bool, malloc_bisect_dump, false,
> >>                "Print all allocations within [malloc_bisect_left, "
> >>                "malloc_bisect_right] range ")
> >> +
> >> +
> >> +// Exit if we fail to enable the AArch64 kernel ABI relaxation which allows
> >> +// tagged pointers in syscalls.  This is the default, but being able to disable
> >> +// that behaviour is useful for running the testsuite on more platforms (the
> >> +// testsuite can run since we manually ensure any pointer arguments to syscalls
> >> +// are untagged before the call.
> >> +HWASAN_FLAG(bool, fail_without_syscall_abi, true,
> >> +            "Exit if fail to request relaxed syscall ABI.")
> >> diff --git a/libsanitizer/hwasan/hwasan_interceptors.cpp b/libsanitizer/hwasan/hwasan_interceptors.cpp
> >> index 44e569ee6d7..ad67e2787d3 100644
> >> --- a/libsanitizer/hwasan/hwasan_interceptors.cpp
> >> +++ b/libsanitizer/hwasan/hwasan_interceptors.cpp
> >> @@ -221,8 +221,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
> >>      ThreadStartArg *A = reinterpret_cast<ThreadStartArg *> (MmapOrDie(
> >>          GetPageSizeCached(), "pthread_create"));
> >>      *A = {callback, param};
> >> -  int res = REAL(pthread_create)(UntagPtr(th), UntagPtr(attr),
> >> -                                 &HwasanThreadStartFunc, A);
> >> +  int res = REAL(pthread_create)(th, attr, &HwasanThreadStartFunc, A);
> >>      return res;
> >>    }
> >>
> >> diff --git a/libsanitizer/hwasan/hwasan_interceptors_vfork.S b/libsanitizer/hwasan/hwasan_interceptors_vfork.S
> >> index 23d565936d8..fd20825e3da 100644
> >> --- a/libsanitizer/hwasan/hwasan_interceptors_vfork.S
> >> +++ b/libsanitizer/hwasan/hwasan_interceptors_vfork.S
> >> @@ -1,4 +1,5 @@
> >>    #include "sanitizer_common/sanitizer_asm.h"
> >> +#include "builtins/assembly.h"
> >>
> >>    #if defined(__linux__) && HWASAN_WITH_INTERCEPTORS
> >>    #define COMMON_INTERCEPTOR_SPILL_AREA __hwasan_extra_spill_area
> >> @@ -9,3 +10,5 @@
> >>    #endif
> >>
> >>    NO_EXEC_STACK_DIRECTIVE
> >> +
> >> +GNU_PROPERTY_BTI_PAC
> >> diff --git a/libsanitizer/hwasan/hwasan_interface_internal.h b/libsanitizer/hwasan/hwasan_interface_internal.h
> >> index aedda317497..25c0f94fe51 100644
> >> --- a/libsanitizer/hwasan/hwasan_interface_internal.h
> >> +++ b/libsanitizer/hwasan/hwasan_interface_internal.h
> >> @@ -222,6 +222,9 @@ SANITIZER_INTERFACE_ATTRIBUTE
> >>    void *__hwasan_memset(void *s, int c, uptr n);
> >>    SANITIZER_INTERFACE_ATTRIBUTE
> >>    void *__hwasan_memmove(void *dest, const void *src, uptr n);
> >> +
> >> +SANITIZER_INTERFACE_ATTRIBUTE
> >> +void __hwasan_set_error_report_callback(void (*callback)(const char *));
> >>    }  // extern "C"
> >>
> >>    #endif  // HWASAN_INTERFACE_INTERNAL_H
> >> diff --git a/libsanitizer/hwasan/hwasan_linux.cpp b/libsanitizer/hwasan/hwasan_linux.cpp
> >> index e99926d355c..8ce0ff7da95 100644
> >> --- a/libsanitizer/hwasan/hwasan_linux.cpp
> >> +++ b/libsanitizer/hwasan/hwasan_linux.cpp
> >> @@ -76,6 +76,8 @@ uptr kHighShadowEnd;
> >>    uptr kHighMemStart;
> >>    uptr kHighMemEnd;
> >>
> >> +uptr kAliasRegionStart;  // Always 0 on non-x86.
> >> +
> >>    static void PrintRange(uptr start, uptr end, const char *name) {
> >>      Printf("|| [%p, %p] || %.*s ||\n", (void *)start, (void *)end, 10, name);
> >>    }
> >> @@ -119,9 +121,11 @@ void InitPrctl() {
> >>    #define PR_GET_TAGGED_ADDR_CTRL 56
> >>    #define PR_TAGGED_ADDR_ENABLE (1UL << 0)
> >>      // Check we're running on a kernel that can use the tagged address ABI.
> >> -  if (internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0) == (uptr)-1 &&
> >> -      errno == EINVAL) {
> >> -#if SANITIZER_ANDROID
> >> +  int local_errno = 0;
> >> +  if (internal_iserror(internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0),
> >> +                       &local_errno) &&
> >> +      local_errno == EINVAL) {
> >> +#if SANITIZER_ANDROID || defined(__x86_64__)
> >>        // Some older Android kernels have the tagged pointer ABI on
> >>        // unconditionally, and hence don't have the tagged-addr prctl while still
> >>        // allow the ABI.
> >> @@ -129,17 +133,20 @@ void InitPrctl() {
> >>        // case.
> >>        return;
> >>    #else
> >> -    Printf(
> >> -        "FATAL: "
> >> -        "HWAddressSanitizer requires a kernel with tagged address ABI.\n");
> >> -    Die();
> >> +    if (flags()->fail_without_syscall_abi) {
> >> +      Printf(
> >> +          "FATAL: "
> >> +          "HWAddressSanitizer requires a kernel with tagged address ABI.\n");
> >> +      Die();
> >> +    }
> >>    #endif
> >>      }
> >>
> >>      // Turn on the tagged address ABI.
> >> -  if (internal_prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE, 0, 0, 0) ==
> >> -          (uptr)-1 ||
> >> -      !internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0)) {
> >> +  if ((internal_iserror(internal_prctl(PR_SET_TAGGED_ADDR_CTRL,
> >> +                                       PR_TAGGED_ADDR_ENABLE, 0, 0, 0)) ||
> >> +       !internal_prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0)) &&
> >> +      flags()->fail_without_syscall_abi) {
> >>        Printf(
> >>            "FATAL: HWAddressSanitizer failed to enable tagged address syscall "
> >>            "ABI.\nSuggest check `sysctl abi.tagged_addr_disabled` "
> >> @@ -174,6 +181,18 @@ bool InitShadow() {
> >>      // High memory starts where allocated shadow allows.
> >>      kHighMemStart = ShadowToMem(kHighShadowStart);
> >>
> >> +#if defined(__x86_64__)
> >> +  constexpr uptr kAliasRegionOffset = 1ULL << (kTaggableRegionCheckShift - 1);
> >> +  kAliasRegionStart =
> >> +      __hwasan_shadow_memory_dynamic_address + kAliasRegionOffset;
> >> +
> >> +  CHECK_EQ(kAliasRegionStart >> kTaggableRegionCheckShift,
> >> +           __hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
> >> +  CHECK_EQ(
> >> +      (kAliasRegionStart + kAliasRegionOffset - 1) >> kTaggableRegionCheckShift,
> >> +      __hwasan_shadow_memory_dynamic_address >> kTaggableRegionCheckShift);
> >> +#endif
> >> +
> >>      // Check the sanity of the defined memory ranges (there might be gaps).
> >>      CHECK_EQ(kHighMemStart % GetMmapGranularity(), 0);
> >>      CHECK_GT(kHighMemStart, kHighShadowEnd);
> >> @@ -217,7 +236,9 @@ void InitThreads() {
> >>    }
> >>
> >>    bool MemIsApp(uptr p) {
> >> +#if !defined(__x86_64__)  // Memory outside the alias range has non-zero tags.
> >>      CHECK(GetTagFromPointer(p) == 0);
> >> +#endif
> >>      return p >= kHighMemStart || (p >= kLowMemStart && p <= kLowMemEnd);
> >>    }
> >>
> >> diff --git a/libsanitizer/hwasan/hwasan_mapping.h b/libsanitizer/hwasan/hwasan_mapping.h
> >> index c149687bdfa..8243d1ec7ed 100644
> >> --- a/libsanitizer/hwasan/hwasan_mapping.h
> >> +++ b/libsanitizer/hwasan/hwasan_mapping.h
> >> @@ -48,6 +48,8 @@ extern uptr kHighShadowEnd;
> >>    extern uptr kHighMemStart;
> >>    extern uptr kHighMemEnd;
> >>
> >> +extern uptr kAliasRegionStart;
> >> +
> >>    inline uptr MemToShadow(uptr untagged_addr) {
> >>      return (untagged_addr >> kShadowScale) +
> >>             __hwasan_shadow_memory_dynamic_address;
> >> diff --git a/libsanitizer/hwasan/hwasan_memintrinsics.cpp b/libsanitizer/hwasan/hwasan_memintrinsics.cpp
> >> index e82d77a1bc1..fab017aae60 100644
> >> --- a/libsanitizer/hwasan/hwasan_memintrinsics.cpp
> >> +++ b/libsanitizer/hwasan/hwasan_memintrinsics.cpp
> >> @@ -24,7 +24,7 @@ using namespace __hwasan;
> >>    void *__hwasan_memset(void *block, int c, uptr size) {
> >>      CheckAddressSized<ErrorAction::Recover, AccessType::Store>(
> >>          reinterpret_cast<uptr>(block), size);
> >> -  return memset(UntagPtr(block), c, size);
> >> +  return memset(block, c, size);
> >>    }
> >>
> >>    void *__hwasan_memcpy(void *to, const void *from, uptr size) {
> >> @@ -32,7 +32,7 @@ void *__hwasan_memcpy(void *to, const void *from, uptr size) {
> >>          reinterpret_cast<uptr>(to), size);
> >>      CheckAddressSized<ErrorAction::Recover, AccessType::Load>(
> >>          reinterpret_cast<uptr>(from), size);
> >> -  return memcpy(UntagPtr(to), UntagPtr(from), size);
> >> +  return memcpy(to, from, size);
> >>    }
> >>
> >>    void *__hwasan_memmove(void *to, const void *from, uptr size) {
> >> diff --git a/libsanitizer/hwasan/hwasan_new_delete.cpp b/libsanitizer/hwasan/hwasan_new_delete.cpp
> >> index 8d01d3944f2..69cddda736e 100644
> >> --- a/libsanitizer/hwasan/hwasan_new_delete.cpp
> >> +++ b/libsanitizer/hwasan/hwasan_new_delete.cpp
> >> @@ -27,6 +27,12 @@
> >>      void *res = hwasan_malloc(size, &stack);\
> >>      if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
> >>      return res
> >> +#define OPERATOR_NEW_ALIGN_BODY(nothrow)                                    \
> >> +  GET_MALLOC_STACK_TRACE;                                                   \
> >> +  void *res = hwasan_aligned_alloc(static_cast<uptr>(align), size, &stack); \
> >> +  if (!nothrow && UNLIKELY(!res))                                           \
> >> +    ReportOutOfMemory(size, &stack);                                        \
> >> +  return res
> >>
> >>    #define OPERATOR_DELETE_BODY \
> >>      GET_MALLOC_STACK_TRACE; \
> >> @@ -50,6 +56,7 @@ using namespace __hwasan;
> >>    // Fake std::nothrow_t to avoid including <new>.
> >>    namespace std {
> >>      struct nothrow_t {};
> >> +  enum class align_val_t : size_t {};
> >>    }  // namespace std
> >>
> >>
> >> @@ -66,6 +73,22 @@ INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
> >>    void *operator new[](size_t size, std::nothrow_t const&) {
> >>      OPERATOR_NEW_BODY(true /*nothrow*/);
> >>    }
> >> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(
> >> +    size_t size, std::align_val_t align) {
> >> +  OPERATOR_NEW_ALIGN_BODY(false /*nothrow*/);
> >> +}
> >> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
> >> +    size_t size, std::align_val_t align) {
> >> +  OPERATOR_NEW_ALIGN_BODY(false /*nothrow*/);
> >> +}
> >> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new(
> >> +    size_t size, std::align_val_t align, std::nothrow_t const &) {
> >> +  OPERATOR_NEW_ALIGN_BODY(true /*nothrow*/);
> >> +}
> >> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void *operator new[](
> >> +    size_t size, std::align_val_t align, std::nothrow_t const &) {
> >> +  OPERATOR_NEW_ALIGN_BODY(true /*nothrow*/);
> >> +}
> >>
> >>    INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
> >>    void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
> >> @@ -77,5 +100,21 @@ INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
> >>    void operator delete[](void *ptr, std::nothrow_t const&) {
> >>      OPERATOR_DELETE_BODY;
> >>    }
> >> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
> >> +    void *ptr, std::align_val_t align) NOEXCEPT {
> >> +  OPERATOR_DELETE_BODY;
> >> +}
> >> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
> >> +    void *ptr, std::align_val_t) NOEXCEPT {
> >> +  OPERATOR_DELETE_BODY;
> >> +}
> >> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
> >> +    void *ptr, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
> >> +  OPERATOR_DELETE_BODY;
> >> +}
> >> +INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
> >> +    void *ptr, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
> >> +  OPERATOR_DELETE_BODY;
> >> +}
> >>
> >>    #endif // OPERATOR_NEW_BODY
> >> diff --git a/libsanitizer/hwasan/hwasan_report.cpp b/libsanitizer/hwasan/hwasan_report.cpp
> >> index 894a149775f..c0217799391 100644
> >> --- a/libsanitizer/hwasan/hwasan_report.cpp
> >> +++ b/libsanitizer/hwasan/hwasan_report.cpp
> >> @@ -43,12 +43,16 @@ class ScopedReport {
> >>      }
> >>
> >>      ~ScopedReport() {
> >> +    void (*report_cb)(const char *);
> >>        {
> >>          BlockingMutexLock lock(&error_message_lock_);
> >> -      if (fatal)
> >> -        SetAbortMessage(error_message_.data());
> >> +      report_cb = error_report_callback_;
> >>          error_message_ptr_ = nullptr;
> >>        }
> >> +    if (report_cb)
> >> +      report_cb(error_message_.data());
> >> +    if (fatal)
> >> +      SetAbortMessage(error_message_.data());
> >>        if (common_flags()->print_module_map >= 2 ||
> >>            (fatal && common_flags()->print_module_map))
> >>          DumpProcessMap();
> >> @@ -66,6 +70,12 @@ class ScopedReport {
> >>        // overwrite old trailing '\0', keep new trailing '\0' untouched.
> >>        internal_memcpy(&(*error_message_ptr_)[old_size - 1], msg, len);
> >>      }
> >> +
> >> +  static void SetErrorReportCallback(void (*callback)(const char *)) {
> >> +    BlockingMutexLock lock(&error_message_lock_);
> >> +    error_report_callback_ = callback;
> >> +  }
> >> +
> >>     private:
> >>      ScopedErrorReportLock error_report_lock_;
> >>      InternalMmapVector<char> error_message_;
> >> @@ -73,10 +83,12 @@ class ScopedReport {
> >>
> >>      static InternalMmapVector<char> *error_message_ptr_;
> >>      static BlockingMutex error_message_lock_;
> >> +  static void (*error_report_callback_)(const char *);
> >>    };
> >>
> >>    InternalMmapVector<char> *ScopedReport::error_message_ptr_;
> >>    BlockingMutex ScopedReport::error_message_lock_;
> >> +void (*ScopedReport::error_report_callback_)(const char *);
> >>
> >>    // If there is an active ScopedReport, append to its error message.
> >>    void AppendToErrorMessageBuffer(const char *buffer) {
> >> @@ -212,7 +224,7 @@ static void PrintStackAllocations(StackAllocationsRingBuffer *sa,
> >>
> >>      // We didn't find any locals. Most likely we don't have symbols, so dump
> >>      // the information that we have for offline analysis.
> >> -  InternalScopedString frame_desc(GetPageSizeCached() * 2);
> >> +  InternalScopedString frame_desc;
> >>      Printf("Previously allocated frames:\n");
> >>      for (uptr i = 0; i < frames; i++) {
> >>        const uptr *record_addr = &(*sa)[i];
> >> @@ -447,7 +459,7 @@ static void PrintTagInfoAroundAddr(tag_t *tag_ptr, uptr num_rows,
> >>          RoundDownTo(reinterpret_cast<uptr>(tag_ptr), row_len));
> >>      tag_t *beg_row = center_row_beg - row_len * (num_rows / 2);
> >>      tag_t *end_row = center_row_beg + row_len * ((num_rows + 1) / 2);
> >> -  InternalScopedString s(GetPageSizeCached() * 8);
> >> +  InternalScopedString s;
> >>      for (tag_t *row = beg_row; row < end_row; row += row_len) {
> >>        s.append("%s", row == center_row_beg ? "=>" : "  ");
> >>        s.append("%p:", row);
> >> @@ -535,7 +547,7 @@ void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size,
> >>        GetStackTraceFromId(chunk.GetAllocStackId()).Print();
> >>      }
> >>
> >> -  InternalScopedString s(GetPageSizeCached() * 8);
> >> +  InternalScopedString s;
> >>      CHECK_GT(tail_size, 0U);
> >>      CHECK_LT(tail_size, kShadowAlignment);
> >>      u8 *tail = reinterpret_cast<u8*>(untagged_addr + orig_size);
> >> @@ -650,3 +662,7 @@ void ReportRegisters(uptr *frame, uptr pc) {
> >>    }
> >>
> >>    }  // namespace __hwasan
> >> +
> >> +void __hwasan_set_error_report_callback(void (*callback)(const char *)) {
> >> +  __hwasan::ScopedReport::SetErrorReportCallback(callback);
> >> +}
> >> diff --git a/libsanitizer/hwasan/hwasan_setjmp.S b/libsanitizer/hwasan/hwasan_setjmp.S
> >> index 0c135433194..381af63363c 100644
> >> --- a/libsanitizer/hwasan/hwasan_setjmp.S
> >> +++ b/libsanitizer/hwasan/hwasan_setjmp.S
> >> @@ -12,6 +12,7 @@
> >>    //===----------------------------------------------------------------------===//
> >>
> >>    #include "sanitizer_common/sanitizer_asm.h"
> >> +#include "builtins/assembly.h"
> >>
> >>    #if HWASAN_WITH_INTERCEPTORS && defined(__aarch64__)
> >>    #include "sanitizer_common/sanitizer_platform.h"
> >> @@ -34,6 +35,7 @@
> >>    ASM_TYPE_FUNCTION(__interceptor_setjmp)
> >>    __interceptor_setjmp:
> >>      CFI_STARTPROC
> >> +  BTI_C
> >>      mov x1, #0
> >>      b   __interceptor_sigsetjmp
> >>      CFI_ENDPROC
> >> @@ -46,6 +48,7 @@ ASM_SIZE(__interceptor_setjmp)
> >>    ASM_TYPE_FUNCTION(__interceptor_setjmp_bionic)
> >>    __interceptor_setjmp_bionic:
> >>      CFI_STARTPROC
> >> +  BTI_C
> >>      mov x1, #1
> >>      b   __interceptor_sigsetjmp
> >>      CFI_ENDPROC
> >> @@ -56,6 +59,7 @@ ASM_SIZE(__interceptor_setjmp_bionic)
> >>    ASM_TYPE_FUNCTION(__interceptor_sigsetjmp)
> >>    __interceptor_sigsetjmp:
> >>      CFI_STARTPROC
> >> +  BTI_C
> >>      stp x19, x20, [x0, #0<<3]
> >>      stp x21, x22, [x0, #2<<3]
> >>      stp x23, x24, [x0, #4<<3]
> >> @@ -98,3 +102,5 @@ ALIAS __interceptor_setjmp, _setjmp
> >>
> >>    // We do not need executable stack.
> >>    NO_EXEC_STACK_DIRECTIVE
> >> +
> >> +GNU_PROPERTY_BTI_PAC
> >> diff --git a/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S b/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S
> >> index 08df12736bb..bcb0df42019 100644
> >> --- a/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S
> >> +++ b/libsanitizer/hwasan/hwasan_tag_mismatch_aarch64.S
> >> @@ -1,4 +1,5 @@
> >>    #include "sanitizer_common/sanitizer_asm.h"
> >> +#include "builtins/assembly.h"
> >>
> >>    // The content of this file is AArch64-only:
> >>    #if defined(__aarch64__)
> >> @@ -74,6 +75,8 @@
> >>    .global __hwasan_tag_mismatch
> >>    .type __hwasan_tag_mismatch, %function
> >>    __hwasan_tag_mismatch:
> >> +  BTI_J
> >> +
> >>      // Compute the granule position one past the end of the access.
> >>      mov x16, #1
> >>      and x17, x1, #0xf
> >> @@ -106,6 +109,7 @@ __hwasan_tag_mismatch:
> >>    .type __hwasan_tag_mismatch_v2, %function
> >>    __hwasan_tag_mismatch_v2:
> >>      CFI_STARTPROC
> >> +  BTI_J
> >>
> >>      // Set the CFA to be the return address for caller of __hwasan_check_*. Note
> >>      // that we do not emit CFI predicates to describe the contents of this stack
> >> @@ -150,3 +154,5 @@ __hwasan_tag_mismatch_v2:
> >>
> >>    // We do not need executable stack.
> >>    NO_EXEC_STACK_DIRECTIVE
> >> +
> >> +GNU_PROPERTY_BTI_PAC
> >> diff --git a/libsanitizer/hwasan/hwasan_thread.cpp b/libsanitizer/hwasan/hwasan_thread.cpp
> >> index b81a6350c05..bb4d56abed0 100644
> >> --- a/libsanitizer/hwasan/hwasan_thread.cpp
> >> +++ b/libsanitizer/hwasan/hwasan_thread.cpp
> >> @@ -35,6 +35,10 @@ void Thread::InitRandomState() {
> >>    }
> >>
> >>    void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size) {
> >> +  CHECK_EQ(0, unique_id_);  // try to catch bad stack reuse
> >> +  CHECK_EQ(0, stack_top_);
> >> +  CHECK_EQ(0, stack_bottom_);
> >> +
> >>      static u64 unique_id;
> >>      unique_id_ = unique_id++;
> >>      if (auto sz = flags()->heap_history_size)
> >> @@ -113,18 +117,21 @@ static u32 xorshift(u32 state) {
> >>    }
> >>
> >>    // Generate a (pseudo-)random non-zero tag.
> >> -tag_t Thread::GenerateRandomTag() {
> >> +tag_t Thread::GenerateRandomTag(uptr num_bits) {
> >> +  DCHECK_GT(num_bits, 0);
> >>      if (tagging_disabled_) return 0;
> >>      tag_t tag;
> >> +  const uptr tag_mask = (1ULL << num_bits) - 1;
> >>      do {
> >>        if (flags()->random_tags) {
> >>          if (!random_buffer_)
> >>            random_buffer_ = random_state_ = xorshift(random_state_);
> >>          CHECK(random_buffer_);
> >> -      tag = random_buffer_ & 0xFF;
> >> -      random_buffer_ >>= 8;
> >> +      tag = random_buffer_ & tag_mask;
> >> +      random_buffer_ >>= num_bits;
> >>        } else {
> >> -      tag = random_state_ = (random_state_ + 1) & 0xFF;
> >> +      random_state_ += 1;
> >> +      tag = random_state_ & tag_mask;
> >>        }
> >>      } while (!tag);
> >>      return tag;
> >> diff --git a/libsanitizer/hwasan/hwasan_thread.h b/libsanitizer/hwasan/hwasan_thread.h
> >> index ebcdb791fb3..1c71cab41c4 100644
> >> --- a/libsanitizer/hwasan/hwasan_thread.h
> >> +++ b/libsanitizer/hwasan/hwasan_thread.h
> >> @@ -42,7 +42,7 @@ class Thread {
> >>      HeapAllocationsRingBuffer *heap_allocations() { return heap_allocations_; }
> >>      StackAllocationsRingBuffer *stack_allocations() { return stack_allocations_; }
> >>
> >> -  tag_t GenerateRandomTag();
> >> +  tag_t GenerateRandomTag(uptr num_bits = kTagBits);
> >>
> >>      void DisableTagging() { tagging_disabled_++; }
> >>      void EnableTagging() { tagging_disabled_--; }
> >> @@ -74,8 +74,6 @@ class Thread {
> >>      HeapAllocationsRingBuffer *heap_allocations_;
> >>      StackAllocationsRingBuffer *stack_allocations_;
> >>
> >> -  Thread *next_;  // All live threads form a linked list.
> >> -
> >>      u64 unique_id_;  // counting from zero.
> >>
> >>      u32 tagging_disabled_;  // if non-zero, malloc uses zero tag in this thread.
> >> diff --git a/libsanitizer/hwasan/hwasan_thread_list.h b/libsanitizer/hwasan/hwasan_thread_list.h
> >> index 914b632d977..11c586314ce 100644
> >> --- a/libsanitizer/hwasan/hwasan_thread_list.h
> >> +++ b/libsanitizer/hwasan/hwasan_thread_list.h
> >> @@ -66,40 +66,6 @@ static uptr RingBufferSize() {
> >>      return 0;
> >>    }
> >>
> >> -struct ThreadListHead {
> >> -  Thread *list_;
> >> -
> >> -  ThreadListHead() : list_(nullptr) {}
> >> -
> >> -  void Push(Thread *t) {
> >> -    t->next_ = list_;
> >> -    list_ = t;
> >> -  }
> >> -
> >> -  Thread *Pop() {
> >> -    Thread *t = list_;
> >> -    if (t)
> >> -      list_ = t->next_;
> >> -    return t;
> >> -  }
> >> -
> >> -  void Remove(Thread *t) {
> >> -    Thread **cur = &list_;
> >> -    while (*cur != t) cur = &(*cur)->next_;
> >> -    CHECK(*cur && "thread not found");
> >> -    *cur = (*cur)->next_;
> >> -  }
> >> -
> >> -  template <class CB>
> >> -  void ForEach(CB cb) {
> >> -    Thread *t = list_;
> >> -    while (t) {
> >> -      cb(t);
> >> -      t = t->next_;
> >> -    }
> >> -  }
> >> -};
> >> -
> >>    struct ThreadStats {
> >>      uptr n_live_threads;
> >>      uptr total_stack_size;
> >> @@ -120,17 +86,23 @@ class HwasanThreadList {
> >>      }
> >>
> >>      Thread *CreateCurrentThread() {
> >> -    Thread *t;
> >> +    Thread *t = nullptr;
> >>        {
> >> -      SpinMutexLock l(&list_mutex_);
> >> -      t = free_list_.Pop();
> >> -      if (t) {
> >> -        uptr start = (uptr)t - ring_buffer_size_;
> >> -        internal_memset((void *)start, 0, ring_buffer_size_ + sizeof(Thread));
> >> -      } else {
> >> -        t = AllocThread();
> >> +      SpinMutexLock l(&free_list_mutex_);
> >> +      if (!free_list_.empty()) {
> >> +        t = free_list_.back();
> >> +        free_list_.pop_back();
> >>          }
> >> -      live_list_.Push(t);
> >> +    }
> >> +    if (t) {
> >> +      uptr start = (uptr)t - ring_buffer_size_;
> >> +      internal_memset((void *)start, 0, ring_buffer_size_ + sizeof(Thread));
> >> +    } else {
> >> +      t = AllocThread();
> >> +    }
> >> +    {
> >> +      SpinMutexLock l(&live_list_mutex_);
> >> +      live_list_.push_back(t);
> >>        }
> >>        t->Init((uptr)t - ring_buffer_size_, ring_buffer_size_);
> >>        AddThreadStats(t);
> >> @@ -142,13 +114,26 @@ class HwasanThreadList {
> >>        ReleaseMemoryPagesToOS(start, start + thread_alloc_size_);
> >>      }
> >>
> >> +  void RemoveThreadFromLiveList(Thread *t) {
> >> +    SpinMutexLock l(&live_list_mutex_);
> >> +    for (Thread *&t2 : live_list_)
> >> +      if (t2 == t) {
> >> +        // To remove t2, copy the last element of the list in t2's position, and
> >> +        // pop_back(). This works even if t2 is itself the last element.
> >> +        t2 = live_list_.back();
> >> +        live_list_.pop_back();
> >> +        return;
> >> +      }
> >> +    CHECK(0 && "thread not found in live list");
> >> +  }
> >> +
> >>      void ReleaseThread(Thread *t) {
> >>        RemoveThreadStats(t);
> >>        t->Destroy();
> >> -    SpinMutexLock l(&list_mutex_);
> >> -    live_list_.Remove(t);
> >> -    free_list_.Push(t);
> >>        DontNeedThread(t);
> >> +    RemoveThreadFromLiveList(t);
> >> +    SpinMutexLock l(&free_list_mutex_);
> >> +    free_list_.push_back(t);
> >>      }
> >>
> >>      Thread *GetThreadByBufferAddress(uptr p) {
> >> @@ -165,8 +150,8 @@ class HwasanThreadList {
> >>
> >>      template <class CB>
> >>      void VisitAllLiveThreads(CB cb) {
> >> -    SpinMutexLock l(&list_mutex_);
> >> -    live_list_.ForEach(cb);
> >> +    SpinMutexLock l(&live_list_mutex_);
> >> +    for (Thread *t : live_list_) cb(t);
> >>      }
> >>
> >>      void AddThreadStats(Thread *t) {
> >> @@ -188,6 +173,7 @@ class HwasanThreadList {
> >>
> >>     private:
> >>      Thread *AllocThread() {
> >> +    SpinMutexLock l(&free_space_mutex_);
> >>        uptr align = ring_buffer_size_ * 2;
> >>        CHECK(IsAligned(free_space_, align));
> >>        Thread *t = (Thread *)(free_space_ + ring_buffer_size_);
> >> @@ -196,14 +182,16 @@ class HwasanThreadList {
> >>        return t;
> >>      }
> >>
> >> +  SpinMutex free_space_mutex_;
> >>      uptr free_space_;
> >>      uptr free_space_end_;
> >>      uptr ring_buffer_size_;
> >>      uptr thread_alloc_size_;
> >>
> >> -  ThreadListHead free_list_;
> >> -  ThreadListHead live_list_;
> >> -  SpinMutex list_mutex_;
> >> +  SpinMutex free_list_mutex_;
> >> +  InternalMmapVector<Thread *> free_list_;
> >> +  SpinMutex live_list_mutex_;
> >> +  InternalMmapVector<Thread *> live_list_;
> >>
> >>      ThreadStats stats_;
> >>      SpinMutex stats_mutex_;
> >> diff --git a/libsanitizer/include/sanitizer/common_interface_defs.h b/libsanitizer/include/sanitizer/common_interface_defs.h
> >> index b4f977bf557..cd69285b8d4 100644
> >> --- a/libsanitizer/include/sanitizer/common_interface_defs.h
> >> +++ b/libsanitizer/include/sanitizer/common_interface_defs.h
> >> @@ -43,6 +43,9 @@ void __sanitizer_set_report_path(const char *path);
> >>    // Tell the tools to write their reports to the provided file descriptor
> >>    // (casted to void *).
> >>    void __sanitizer_set_report_fd(void *fd);
> >> +// Get the current full report file path, if a path was specified by
> >> +// an earlier call to __sanitizer_set_report_path. Returns null otherwise.
> >> +const char *__sanitizer_get_report_path();
> >>
> >>    // Notify the tools that the sandbox is going to be turned on. The reserved
> >>    // parameter will be used in the future to hold a structure with functions
> >> diff --git a/libsanitizer/include/sanitizer/dfsan_interface.h b/libsanitizer/include/sanitizer/dfsan_interface.h
> >> index 18b2c81a602..40f9379b557 100644
> >> --- a/libsanitizer/include/sanitizer/dfsan_interface.h
> >> +++ b/libsanitizer/include/sanitizer/dfsan_interface.h
> >> @@ -22,6 +22,7 @@ extern "C" {
> >>    #endif
> >>
> >>    typedef uint16_t dfsan_label;
> >> +typedef uint32_t dfsan_origin;
> >>
> >>    /// Stores information associated with a specific label identifier.  A label
> >>    /// may be a base label created using dfsan_create_label, with associated
> >> @@ -63,6 +64,12 @@ void dfsan_add_label(dfsan_label label, void *addr, size_t size);
> >>    /// value.
> >>    dfsan_label dfsan_get_label(long data);
> >>
> >> +/// Retrieves the immediate origin associated with the given data. The returned
> >> +/// origin may point to another origin.
> >> +///
> >> +/// The type of 'data' is arbitrary.
> >> +dfsan_origin dfsan_get_origin(long data);
> >> +
> >>    /// Retrieves the label associated with the data at the given address.
> >>    dfsan_label dfsan_read_label(const void *addr, size_t size);
> >>
> >> @@ -110,6 +117,15 @@ void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2,
> >>    void dfsan_weak_hook_strncmp(void *caller_pc, const char *s1, const char *s2,
> >>                                 size_t n, dfsan_label s1_label,
> >>                                 dfsan_label s2_label, dfsan_label n_label);
> >> +
> >> +/// Prints the origin trace of the label at the address addr to stderr. It also
> >> +/// prints description at the beginning of the trace. If origin tracking is not
> >> +/// on, or the address is not labeled, it prints nothing.
> >> +void dfsan_print_origin_trace(const void *addr, const char *description);
> >> +
> >> +/// Retrieves the very first origin associated with the data at the given
> >> +/// address.
> >> +dfsan_origin dfsan_get_init_origin(const void *addr);
> >>    #ifdef __cplusplus
> >>    }  // extern "C"
> >>
> >> diff --git a/libsanitizer/include/sanitizer/hwasan_interface.h b/libsanitizer/include/sanitizer/hwasan_interface.h
> >> index 4c9ad13aa0c..14035c05c63 100644
> >> --- a/libsanitizer/include/sanitizer/hwasan_interface.h
> >> +++ b/libsanitizer/include/sanitizer/hwasan_interface.h
> >> @@ -73,6 +73,9 @@ extern "C" {
> >>       * accessed through the pointer in x, or -1 if the whole range is good. */
> >>      intptr_t __hwasan_test_shadow(const volatile void *x, size_t size);
> >>
> >> +  /* Sets the callback function to be called during HWASan error reporting. */
> >> +  void __hwasan_set_error_report_callback(void (*callback)(const char *));
> >> +
> >>      int __sanitizer_posix_memalign(void **memptr, size_t alignment, size_t size);
> >>      void * __sanitizer_memalign(size_t alignment, size_t size);
> >>      void * __sanitizer_aligned_alloc(size_t alignment, size_t size);
> >> diff --git a/libsanitizer/include/sanitizer/memprof_interface.h b/libsanitizer/include/sanitizer/memprof_interface.h
> >> index a7212605100..76031de4014 100644
> >> --- a/libsanitizer/include/sanitizer/memprof_interface.h
> >> +++ b/libsanitizer/include/sanitizer/memprof_interface.h
> >> @@ -53,6 +53,11 @@ void __memprof_print_accumulated_stats(void);
> >>    /// \returns Default options string.
> >>    const char *__memprof_default_options(void);
> >>
> >> +/// Prints the memory profile to the current profile file.
> >> +///
> >> +/// \returns 0 on success.
> >> +int __memprof_profile_dump(void);
> >> +
> >>    #ifdef __cplusplus
> >>    } // extern "C"
> >>    #endif
> >> diff --git a/libsanitizer/include/sanitizer/tsan_interface.h b/libsanitizer/include/sanitizer/tsan_interface.h
> >> index 96b8ad58541..565aa391a9f 100644
> >> --- a/libsanitizer/include/sanitizer/tsan_interface.h
> >> +++ b/libsanitizer/include/sanitizer/tsan_interface.h
> >> @@ -67,6 +67,12 @@ static const unsigned __tsan_mutex_recursive_lock   = 1 << 6;
> >>    // the corresponding __tsan_mutex_post_lock annotation.
> >>    static const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
> >>
> >> +// Convenient composed constants.
> >> +static const unsigned __tsan_mutex_try_read_lock =
> >> +    __tsan_mutex_read_lock | __tsan_mutex_try_lock;
> >> +static const unsigned __tsan_mutex_try_read_lock_failed =
> >> +    __tsan_mutex_try_read_lock | __tsan_mutex_try_lock_failed;
> >> +
> >>    // Annotate creation of a mutex.
> >>    // Supported flags: mutex creation flags.
> >>    void __tsan_mutex_create(void *addr, unsigned flags);
> >> @@ -141,7 +147,7 @@ void __tsan_external_write(void *addr, void *caller_pc, void *tag);
> >>    //     and freed by __tsan_destroy_fiber.
> >>    //   - TSAN context of current fiber or thread can be obtained
> >>    //     by calling __tsan_get_current_fiber.
> >> -//   - __tsan_switch_to_fiber should be called immediatly before switch
> >> +//   - __tsan_switch_to_fiber should be called immediately before switch
> >>    //     to fiber, such as call of swapcontext.
> >>    //   - Fiber name can be set by __tsan_set_fiber_name.
> >>    void *__tsan_get_current_fiber(void);
> >> @@ -154,6 +160,15 @@ void __tsan_set_fiber_name(void *fiber, const char *name);
> >>    // Do not establish a happens-before relation between fibers
> >>    static const unsigned __tsan_switch_to_fiber_no_sync = 1 << 0;
> >>
> >> +// User-provided callback invoked on TSan initialization.
> >> +void __tsan_on_initialize();
> >> +
> >> +// User-provided callback invoked on TSan shutdown.
> >> +// `failed` - Nonzero if TSan did detect issues, zero otherwise.
> >> +// Return `0` if TSan should exit as if no issues were detected.  Return nonzero
> >> +// if TSan should exit as if issues were detected.
> >> +int __tsan_on_finalize(int failed);
> >> +
> >>    #ifdef __cplusplus
> >>    }  // extern "C"
> >>    #endif
> >> diff --git a/libsanitizer/include/sanitizer/tsan_interface_atomic.h b/libsanitizer/include/sanitizer/tsan_interface_atomic.h
> >> index 8052bc1d56b..5e41e2256c3 100644
> >> --- a/libsanitizer/include/sanitizer/tsan_interface_atomic.h
> >> +++ b/libsanitizer/include/sanitizer/tsan_interface_atomic.h
> >> @@ -30,7 +30,7 @@ __extension__ typedef __int128 __tsan_atomic128;
> >>    #endif
> >>
> >>    // Part of ABI, do not change.
> >> -// https://github.com/llvm/llvm-project/blob/master/libcxx/include/atomic
> >> +// https://github.com/llvm/llvm-project/blob/main/libcxx/include/atomic
> >>    typedef enum {
> >>      __tsan_memory_order_relaxed,
> >>      __tsan_memory_order_consume,
> >> diff --git a/libsanitizer/interception/interception_linux.cpp b/libsanitizer/interception/interception_linux.cpp
> >> index 6883608d44f..5111a87f0a6 100644
> >> --- a/libsanitizer/interception/interception_linux.cpp
> >> +++ b/libsanitizer/interception/interception_linux.cpp
> >> @@ -63,8 +63,8 @@ bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
> >>      return addr && (func == wrapper);
> >>    }
> >>
> >> -// Android and Solaris do not have dlvsym
> >> -#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS
> >> +// dlvsym is a GNU extension supported by some other platforms.
> >> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
> >>    static void *GetFuncAddr(const char *name, const char *ver) {
> >>      return dlvsym(RTLD_NEXT, name, ver);
> >>    }
> >> @@ -75,7 +75,7 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
> >>      *ptr_to_real = (uptr)addr;
> >>      return addr && (func == wrapper);
> >>    }
> >> -#endif  // !SANITIZER_ANDROID
> >> +#endif  // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
> >>
> >>    }  // namespace __interception
> >>
> >> diff --git a/libsanitizer/interception/interception_linux.h b/libsanitizer/interception/interception_linux.h
> >> index 097375fd1c1..a08f8cb98c4 100644
> >> --- a/libsanitizer/interception/interception_linux.h
> >> +++ b/libsanitizer/interception/interception_linux.h
> >> @@ -35,8 +35,8 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
> >>          (::__interception::uptr) & (func),          \
> >>          (::__interception::uptr) & WRAP(func))
> >>
> >> -// Android and Solaris do not have dlvsym
> >> -#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS
> >> +// dlvsym is a GNU extension supported by some other platforms.
> >> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
> >>    #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
> >>      ::__interception::InterceptFunction(                        \
> >>          #func, symver,                                          \
> >> @@ -46,7 +46,7 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
> >>    #else
> >>    #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
> >>      INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
> >> -#endif  // !SANITIZER_ANDROID && !SANITIZER_SOLARIS
> >> +#endif  // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
> >>
> >>    #endif  // INTERCEPTION_LINUX_H
> >>    #endif  // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
> >> diff --git a/libsanitizer/interception/interception_win.cpp b/libsanitizer/interception/interception_win.cpp
> >> index 1a1c327e612..98bc756ae53 100644
> >> --- a/libsanitizer/interception/interception_win.cpp
> >> +++ b/libsanitizer/interception/interception_win.cpp
> >> @@ -136,7 +136,7 @@ namespace __interception {
> >>    static const int kAddressLength = FIRST_32_SECOND_64(4, 8);
> >>    static const int kJumpInstructionLength = 5;
> >>    static const int kShortJumpInstructionLength = 2;
> >> -static const int kIndirectJumpInstructionLength = 6;
> >> +UNUSED static const int kIndirectJumpInstructionLength = 6;
> >>    static const int kBranchLength =
> >>        FIRST_32_SECOND_64(kJumpInstructionLength, kIndirectJumpInstructionLength);
> >>    static const int kDirectBranchLength = kBranchLength + kAddressLength;
> >> @@ -165,7 +165,7 @@ static uptr GetMmapGranularity() {
> >>      return si.dwAllocationGranularity;
> >>    }
> >>
> >> -static uptr RoundUpTo(uptr size, uptr boundary) {
> >> +UNUSED static uptr RoundUpTo(uptr size, uptr boundary) {
> >>      return (size + boundary - 1) & ~(boundary - 1);
> >>    }
> >>
> >> @@ -309,7 +309,7 @@ struct TrampolineMemoryRegion {
> >>      uptr max_size;
> >>    };
> >>
> >> -static const uptr kTrampolineScanLimitRange = 1 << 31;  // 2 gig
> >> +UNUSED static const uptr kTrampolineScanLimitRange = 1 << 31;  // 2 gig
> >>    static const int kMaxTrampolineRegion = 1024;
> >>    static TrampolineMemoryRegion TrampolineRegions[kMaxTrampolineRegion];
> >>
> >> diff --git a/libsanitizer/lsan/lsan_allocator.cpp b/libsanitizer/lsan/lsan_allocator.cpp
> >> index d86c3921395..91e34ebb321 100644
> >> --- a/libsanitizer/lsan/lsan_allocator.cpp
> >> +++ b/libsanitizer/lsan/lsan_allocator.cpp
> >> @@ -123,14 +123,18 @@ void Deallocate(void *p) {
> >>
> >>    void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
> >>                     uptr alignment) {
> >> -  RegisterDeallocation(p);
> >>      if (new_size > max_malloc_size) {
> >> -    allocator.Deallocate(GetAllocatorCache(), p);
> >> -    return ReportAllocationSizeTooBig(new_size, stack);
> >> +    ReportAllocationSizeTooBig(new_size, stack);
> >> +    return nullptr;
> >>      }
> >> -  p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment);
> >> -  RegisterAllocation(stack, p, new_size);
> >> -  return p;
> >> +  RegisterDeallocation(p);
> >> +  void *new_p =
> >> +      allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment);
> >> +  if (new_p)
> >> +    RegisterAllocation(stack, new_p, new_size);
> >> +  else if (new_size != 0)
> >> +    RegisterAllocation(stack, p, new_size);
> >> +  return new_p;
> >>    }
> >>
> >>    void GetAllocatorCacheRange(uptr *begin, uptr *end) {
> >> @@ -309,6 +313,16 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
> >>        return kIgnoreObjectInvalid;
> >>      }
> >>    }
> >> +
> >> +void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
> >> +  // This function can be used to treat memory reachable from `tctx` as live.
> >> +  // This is useful for threads that have been created but not yet started.
> >> +
> >> +  // This is currently a no-op because the LSan `pthread_create()` interceptor
> >> +  // blocks until the child thread starts which keeps the thread's `arg` pointer
> >> +  // live.
> >> +}
> >> +
> >>    } // namespace __lsan
> >>
> >>    using namespace __lsan;
> >> diff --git a/libsanitizer/lsan/lsan_allocator.h b/libsanitizer/lsan/lsan_allocator.h
> >> index 17e13cd014b..9d763789154 100644
> >> --- a/libsanitizer/lsan/lsan_allocator.h
> >> +++ b/libsanitizer/lsan/lsan_allocator.h
> >> @@ -50,7 +50,7 @@ struct ChunkMetadata {
> >>    };
> >>
> >>    #if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \
> >> -    defined(__arm__)
> >> +    defined(__arm__) || SANITIZER_RISCV64
> >>    template <typename AddressSpaceViewTy>
> >>    struct AP32 {
> >>      static const uptr kSpaceBeg = 0;
> >> diff --git a/libsanitizer/lsan/lsan_common.cpp b/libsanitizer/lsan/lsan_common.cpp
> >> index 9e23aa9997a..74400d2e842 100644
> >> --- a/libsanitizer/lsan/lsan_common.cpp
> >> +++ b/libsanitizer/lsan/lsan_common.cpp
> >> @@ -65,8 +65,34 @@ void RegisterLsanFlags(FlagParser *parser, Flags *f) {
> >>        if (flags()->log_threads) Report(__VA_ARGS__); \
> >>      } while (0)
> >>
> >> -ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
> >> -static SuppressionContext *suppression_ctx = nullptr;
> >> +class LeakSuppressionContext {
> >> +  bool parsed = false;
> >> +  SuppressionContext context;
> >> +  bool suppressed_stacks_sorted = true;
> >> +  InternalMmapVector<u32> suppressed_stacks;
> >> +
> >> +  Suppression *GetSuppressionForAddr(uptr addr);
> >> +  void LazyInit();
> >> +
> >> + public:
> >> +  LeakSuppressionContext(const char *supprression_types[],
> >> +                         int suppression_types_num)
> >> +      : context(supprression_types, suppression_types_num) {}
> >> +
> >> +  Suppression *GetSuppressionForStack(u32 stack_trace_id);
> >> +
> >> +  const InternalMmapVector<u32> &GetSortedSuppressedStacks() {
> >> +    if (!suppressed_stacks_sorted) {
> >> +      suppressed_stacks_sorted = true;
> >> +      SortAndDedup(suppressed_stacks);
> >> +    }
> >> +    return suppressed_stacks;
> >> +  }
> >> +  void PrintMatchedSuppressions();
> >> +};
> >> +
> >> +ALIGNED(64) static char suppression_placeholder[sizeof(LeakSuppressionContext)];
> >> +static LeakSuppressionContext *suppression_ctx = nullptr;
> >>    static const char kSuppressionLeak[] = "leak";
> >>    static const char *kSuppressionTypes[] = { kSuppressionLeak };
> >>    static const char kStdSuppressions[] =
> >> @@ -86,14 +112,20 @@ static const char kStdSuppressions[] =
> >>    void InitializeSuppressions() {
> >>      CHECK_EQ(nullptr, suppression_ctx);
> >>      suppression_ctx = new (suppression_placeholder)
> >> -      SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
> >> -  suppression_ctx->ParseFromFile(flags()->suppressions);
> >> -  if (&__lsan_default_suppressions)
> >> -    suppression_ctx->Parse(__lsan_default_suppressions());
> >> -  suppression_ctx->Parse(kStdSuppressions);
> >> +      LeakSuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
> >> +}
> >> +
> >> +void LeakSuppressionContext::LazyInit() {
> >> +  if (!parsed) {
> >> +    parsed = true;
> >> +    context.ParseFromFile(flags()->suppressions);
> >> +    if (&__lsan_default_suppressions)
> >> +      context.Parse(__lsan_default_suppressions());
> >> +    context.Parse(kStdSuppressions);
> >> +  }
> >>    }
> >>
> >> -static SuppressionContext *GetSuppressionContext() {
> >> +static LeakSuppressionContext *GetSuppressionContext() {
> >>      CHECK(suppression_ctx);
> >>      return suppression_ctx;
> >>    }
> >> @@ -221,6 +253,27 @@ extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_iterate_dynamic_tls(
> >>        pid_t, void (*cb)(void *, void *, uptr, void *), void *);
> >>    #endif
> >>
> >> +static void ProcessThreadRegistry(Frontier *frontier) {
> >> +  InternalMmapVector<uptr> ptrs;
> >> +  GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
> >> +      GetAdditionalThreadContextPtrs, &ptrs);
> >> +
> >> +  for (uptr i = 0; i < ptrs.size(); ++i) {
> >> +    void *ptr = reinterpret_cast<void *>(ptrs[i]);
> >> +    uptr chunk = PointsIntoChunk(ptr);
> >> +    if (!chunk)
> >> +      continue;
> >> +    LsanMetadata m(chunk);
> >> +    if (!m.allocated())
> >> +      continue;
> >> +
> >> +    // Mark as reachable and add to frontier.
> >> +    LOG_POINTERS("Treating pointer %p from ThreadContext as reachable\n", ptr);
> >> +    m.set_tag(kReachable);
> >> +    frontier->push_back(chunk);
> >> +  }
> >> +}
> >> +
> >>    // Scans thread data (stacks and TLS) for heap pointers.
> >>    static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
> >>                               Frontier *frontier) {
> >> @@ -315,15 +368,15 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
> >>          __libc_iterate_dynamic_tls(os_id, cb, frontier);
> >>    #else
> >>          if (dtls && !DTLSInDestruction(dtls)) {
> >> -        for (uptr j = 0; j < dtls->dtv_size; ++j) {
> >> -          uptr dtls_beg = dtls->dtv[j].beg;
> >> -          uptr dtls_end = dtls_beg + dtls->dtv[j].size;
> >> +        ForEachDVT(dtls, [&](const DTLS::DTV &dtv, int id) {
> >> +          uptr dtls_beg = dtv.beg;
> >> +          uptr dtls_end = dtls_beg + dtv.size;
> >>              if (dtls_beg < dtls_end) {
> >> -            LOG_THREADS("DTLS %zu at %p-%p.\n", j, dtls_beg, dtls_end);
> >> +            LOG_THREADS("DTLS %zu at %p-%p.\n", id, dtls_beg, dtls_end);
> >>                ScanRangeForPointers(dtls_beg, dtls_end, frontier, "DTLS",
> >>                                     kReachable);
> >>              }
> >> -        }
> >> +        });
> >>          } else {
> >>            // We are handling a thread with DTLS under destruction. Log about
> >>            // this and continue.
> >> @@ -332,6 +385,9 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
> >>    #endif
> >>        }
> >>      }
> >> +
> >> +  // Add pointers reachable from ThreadContexts
> >> +  ProcessThreadRegistry(frontier);
> >>    }
> >>
> >>    #endif  // SANITIZER_FUCHSIA
> >> @@ -390,6 +446,24 @@ static void MarkIndirectlyLeakedCb(uptr chunk, void *arg) {
> >>      }
> >>    }
> >>
> >> +static void IgnoredSuppressedCb(uptr chunk, void *arg) {
> >> +  CHECK(arg);
> >> +  chunk = GetUserBegin(chunk);
> >> +  LsanMetadata m(chunk);
> >> +  if (!m.allocated() || m.tag() == kIgnored)
> >> +    return;
> >> +
> >> +  const InternalMmapVector<u32> &suppressed =
> >> +      *static_cast<const InternalMmapVector<u32> *>(arg);
> >> +  uptr idx = InternalLowerBound(suppressed, m.stack_trace_id());
> >> +  if (idx >= suppressed.size() || m.stack_trace_id() != suppressed[idx])
> >> +    return;
> >> +
> >> +  LOG_POINTERS("Suppressed: chunk %p-%p of size %zu.\n", chunk,
> >> +               chunk + m.requested_size(), m.requested_size());
> >> +  m.set_tag(kIgnored);
> >> +}
> >> +
> >>    // ForEachChunk callback. If chunk is marked as ignored, adds its address to
> >>    // frontier.
> >>    static void CollectIgnoredCb(uptr chunk, void *arg) {
> >> @@ -473,6 +547,12 @@ void ProcessPC(Frontier *frontier) {
> >>    // Sets the appropriate tag on each chunk.
> >>    static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads,
> >>                                  Frontier *frontier) {
> >> +  const InternalMmapVector<u32> &suppressed_stacks =
> >> +      GetSuppressionContext()->GetSortedSuppressedStacks();
> >> +  if (!suppressed_stacks.empty()) {
> >> +    ForEachChunk(IgnoredSuppressedCb,
> >> +                 const_cast<InternalMmapVector<u32> *>(&suppressed_stacks));
> >> +  }
> >>      ForEachChunk(CollectIgnoredCb, frontier);
> >>      ProcessGlobalRegions(frontier);
> >>      ProcessThreads(suspended_threads, frontier);
> >> @@ -532,18 +612,20 @@ static void CollectLeaksCb(uptr chunk, void *arg) {
> >>      }
> >>    }
> >>
> >> -static void PrintMatchedSuppressions() {
> >> +void LeakSuppressionContext::PrintMatchedSuppressions() {
> >>      InternalMmapVector<Suppression *> matched;
> >> -  GetSuppressionContext()->GetMatched(&matched);
> >> +  context.GetMatched(&matched);
> >>      if (!matched.size())
> >>        return;
> >>      const char *line = "-----------------------------------------------------";
> >>      Printf("%s\n", line);
> >>      Printf("Suppressions used:\n");
> >>      Printf("  count      bytes template\n");
> >> -  for (uptr i = 0; i < matched.size(); i++)
> >> -    Printf("%7zu %10zu %s\n", static_cast<uptr>(atomic_load_relaxed(
> >> -        &matched[i]->hit_count)), matched[i]->weight, matched[i]->templ);
> >> +  for (uptr i = 0; i < matched.size(); i++) {
> >> +    Printf("%7zu %10zu %s\n",
> >> +           static_cast<uptr>(atomic_load_relaxed(&matched[i]->hit_count)),
> >> +           matched[i]->weight, matched[i]->templ);
> >> +  }
> >>      Printf("%s\n\n", line);
> >>    }
> >>
> >> @@ -551,8 +633,7 @@ static void ReportIfNotSuspended(ThreadContextBase *tctx, void *arg) {
> >>      const InternalMmapVector<tid_t> &suspended_threads =
> >>          *(const InternalMmapVector<tid_t> *)arg;
> >>      if (tctx->status == ThreadStatusRunning) {
> >> -    uptr i = InternalLowerBound(suspended_threads, 0, suspended_threads.size(),
> >> -                                tctx->os_id, CompareLess<int>());
> >> +    uptr i = InternalLowerBound(suspended_threads, tctx->os_id);
> >>        if (i >= suspended_threads.size() || suspended_threads[i] != tctx->os_id)
> >>          Report("Running thread %d was not suspended. False leaks are possible.\n",
> >>                 tctx->os_id);
> >> @@ -595,43 +676,68 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
> >>      param->success = true;
> >>    }
> >>
> >> -static bool CheckForLeaks() {
> >> -  if (&__lsan_is_turned_off && __lsan_is_turned_off())
> >> -    return false;
> >> -  EnsureMainThreadIDIsCorrect();
> >> -  CheckForLeaksParam param;
> >> -  LockStuffAndStopTheWorld(CheckForLeaksCallback, &param);
> >> -
> >> -  if (!param.success) {
> >> -    Report("LeakSanitizer has encountered a fatal error.\n");
> >> -    Report(
> >> -        "HINT: For debugging, try setting environment variable "
> >> -        "LSAN_OPTIONS=verbosity=1:log_threads=1\n");
> >> -    Report(
> >> -        "HINT: LeakSanitizer does not work under ptrace (strace, gdb, etc)\n");
> >> -    Die();
> >> -  }
> >> -  param.leak_report.ApplySuppressions();
> >> -  uptr unsuppressed_count = param.leak_report.UnsuppressedLeakCount();
> >> -  if (unsuppressed_count > 0) {
> >> +static bool PrintResults(LeakReport &report) {
> >> +  uptr unsuppressed_count = report.UnsuppressedLeakCount();
> >> +  if (unsuppressed_count) {
> >>        Decorator d;
> >> -    Printf("\n"
> >> -           "================================================================="
> >> -           "\n");
> >> +    Printf(
> >> +        "\n"
> >> +        "================================================================="
> >> +        "\n");
> >>        Printf("%s", d.Error());
> >>        Report("ERROR: LeakSanitizer: detected memory leaks\n");
> >>        Printf("%s", d.Default());
> >> -    param.leak_report.ReportTopLeaks(flags()->max_leaks);
> >> +    report.ReportTopLeaks(flags()->max_leaks);
> >>      }
> >>      if (common_flags()->print_suppressions)
> >> -    PrintMatchedSuppressions();
> >> +    GetSuppressionContext()->PrintMatchedSuppressions();
> >>      if (unsuppressed_count > 0) {
> >> -    param.leak_report.PrintSummary();
> >> +    report.PrintSummary();
> >>        return true;
> >>      }
> >>      return false;
> >>    }
> >>
> >> +static bool CheckForLeaks() {
> >> +  if (&__lsan_is_turned_off && __lsan_is_turned_off())
> >> +    return false;
> >> +  // Inside LockStuffAndStopTheWorld we can't run symbolizer, so we can't match
> >> +  // suppressions. However if a stack id was previously suppressed, it should be
> >> +  // suppressed in future checks as well.
> >> +  for (int i = 0;; ++i) {
> >> +    EnsureMainThreadIDIsCorrect();
> >> +    CheckForLeaksParam param;
> >> +    LockStuffAndStopTheWorld(CheckForLeaksCallback, &param);
> >> +    if (!param.success) {
> >> +      Report("LeakSanitizer has encountered a fatal error.\n");
> >> +      Report(
> >> +          "HINT: For debugging, try setting environment variable "
> >> +          "LSAN_OPTIONS=verbosity=1:log_threads=1\n");
> >> +      Report(
> >> +          "HINT: LeakSanitizer does not work under ptrace (strace, gdb, "
> >> +          "etc)\n");
> >> +      Die();
> >> +    }
> >> +    // No new suppressions stacks, so rerun will not help and we can report.
> >> +    if (!param.leak_report.ApplySuppressions())
> >> +      return PrintResults(param.leak_report);
> >> +
> >> +    // No indirect leaks to report, so we are done here.
> >> +    if (!param.leak_report.IndirectUnsuppressedLeakCount())
> >> +      return PrintResults(param.leak_report);
> >> +
> >> +    if (i >= 8) {
> >> +      Report("WARNING: LeakSanitizer gave up on indirect leaks suppression.\n");
> >> +      return PrintResults(param.leak_report);
> >> +    }
> >> +
> >> +    // We found a new previously unseen suppressed call stack. Rerun to make
> >> +    // sure it does not hold indirect leaks.
> >> +    VReport(1, "Rerun with %zu suppressed stacks.",
> >> +            GetSuppressionContext()->GetSortedSuppressedStacks().size());
> >> +  }
> >> +}
> >> +
> >>    static bool has_reported_leaks = false;
> >>    bool HasReportedLeaks() { return has_reported_leaks; }
> >>
> >> @@ -652,21 +758,20 @@ static int DoRecoverableLeakCheck() {
> >>
> >>    void DoRecoverableLeakCheckVoid() { DoRecoverableLeakCheck(); }
> >>
> >> -static Suppression *GetSuppressionForAddr(uptr addr) {
> >> +Suppression *LeakSuppressionContext::GetSuppressionForAddr(uptr addr) {
> >>      Suppression *s = nullptr;
> >>
> >>      // Suppress by module name.
> >> -  SuppressionContext *suppressions = GetSuppressionContext();
> >>      if (const char *module_name =
> >>              Symbolizer::GetOrInit()->GetModuleNameForPc(addr))
> >> -    if (suppressions->Match(module_name, kSuppressionLeak, &s))
> >> +    if (context.Match(module_name, kSuppressionLeak, &s))
> >>          return s;
> >>
> >>      // Suppress by file or function name.
> >>      SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr);
> >>      for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
> >> -    if (suppressions->Match(cur->info.function, kSuppressionLeak, &s) ||
> >> -        suppressions->Match(cur->info.file, kSuppressionLeak, &s)) {
> >> +    if (context.Match(cur->info.function, kSuppressionLeak, &s) ||
> >> +        context.Match(cur->info.file, kSuppressionLeak, &s)) {
> >>          break;
> >>        }
> >>      }
> >> @@ -674,12 +779,18 @@ static Suppression *GetSuppressionForAddr(uptr addr) {
> >>      return s;
> >>    }
> >>
> >> -static Suppression *GetSuppressionForStack(u32 stack_trace_id) {
> >> +Suppression *LeakSuppressionContext::GetSuppressionForStack(
> >> +    u32 stack_trace_id) {
> >> +  LazyInit();
> >>      StackTrace stack = StackDepotGet(stack_trace_id);
> >>      for (uptr i = 0; i < stack.size; i++) {
> >>        Suppression *s = GetSuppressionForAddr(
> >>            StackTrace::GetPreviousInstructionPc(stack.trace[i]));
> >> -    if (s) return s;
> >> +    if (s) {
> >> +      suppressed_stacks_sorted = false;
> >> +      suppressed_stacks.push_back(stack_trace_id);
> >> +      return s;
> >> +    }
> >>      }
> >>      return nullptr;
> >>    }
> >> @@ -784,22 +895,27 @@ void LeakReport::PrintSummary() {
> >>          bytes += leaks_[i].total_size;
> >>          allocations += leaks_[i].hit_count;
> >>      }
> >> -  InternalScopedString summary(kMaxSummaryLength);
> >> +  InternalScopedString summary;
> >>      summary.append("%zu byte(s) leaked in %zu allocation(s).", bytes,
> >>                     allocations);
> >>      ReportErrorSummary(summary.data());
> >>    }
> >>
> >> -void LeakReport::ApplySuppressions() {
> >> +uptr LeakReport::ApplySuppressions() {
> >> +  LeakSuppressionContext *suppressions = GetSuppressionContext();
> >> +  uptr new_suppressions = false;
> >>      for (uptr i = 0; i < leaks_.size(); i++) {
> >> -    Suppression *s = GetSuppressionForStack(leaks_[i].stack_trace_id);
> >> +    Suppression *s =
> >> +        suppressions->GetSuppressionForStack(leaks_[i].stack_trace_id);
> >>        if (s) {
> >>          s->weight += leaks_[i].total_size;
> >>          atomic_store_relaxed(&s->hit_count, atomic_load_relaxed(&s->hit_count) +
> >>              leaks_[i].hit_count);
> >>          leaks_[i].is_suppressed = true;
> >> +      ++new_suppressions;
> >>        }
> >>      }
> >> +  return new_suppressions;
> >>    }
> >>
> >>    uptr LeakReport::UnsuppressedLeakCount() {
> >> @@ -809,6 +925,14 @@ uptr LeakReport::UnsuppressedLeakCount() {
> >>      return result;
> >>    }
> >>
> >> +uptr LeakReport::IndirectUnsuppressedLeakCount() {
> >> +  uptr result = 0;
> >> +  for (uptr i = 0; i < leaks_.size(); i++)
> >> +    if (!leaks_[i].is_suppressed && !leaks_[i].is_directly_leaked)
> >> +      result++;
> >> +  return result;
> >> +}
> >> +
> >>    } // namespace __lsan
> >>    #else // CAN_SANITIZE_LEAKS
> >>    namespace __lsan {
> >> diff --git a/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h
> >> index 1fdce087b3a..fe855cf3754 100644
> >> --- a/libsanitizer/lsan/lsan_common.h
> >> +++ b/libsanitizer/lsan/lsan_common.h
> >> @@ -41,6 +41,8 @@
> >>    #define CAN_SANITIZE_LEAKS 1
> >>    #elif defined(__arm__) && SANITIZER_LINUX
> >>    #define CAN_SANITIZE_LEAKS 1
> >> +#elif SANITIZER_RISCV64 && SANITIZER_LINUX
> >> +#define CAN_SANITIZE_LEAKS 1
> >>    #elif SANITIZER_NETBSD || SANITIZER_FUCHSIA
> >>    #define CAN_SANITIZE_LEAKS 1
> >>    #else
> >> @@ -50,6 +52,7 @@
> >>    namespace __sanitizer {
> >>    class FlagParser;
> >>    class ThreadRegistry;
> >> +class ThreadContextBase;
> >>    struct DTLS;
> >>    }
> >>
> >> @@ -63,8 +66,6 @@ enum ChunkTag {
> >>      kIgnored = 3
> >>    };
> >>
> >> -const u32 kInvalidTid = (u32) -1;
> >> -
> >>    struct Flags {
> >>    #define LSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
> >>    #include "lsan_flags.inc"
> >> @@ -103,8 +104,9 @@ class LeakReport {
> >>                          ChunkTag tag);
> >>      void ReportTopLeaks(uptr max_leaks);
> >>      void PrintSummary();
> >> -  void ApplySuppressions();
> >> +  uptr ApplySuppressions();
> >>      uptr UnsuppressedLeakCount();
> >> +  uptr IndirectUnsuppressedLeakCount();
> >>
> >>     private:
> >>      void PrintReportForLeak(uptr index);
> >> @@ -141,6 +143,7 @@ InternalMmapVector<RootRegion> const *GetRootRegions();
> >>    void ScanRootRegion(Frontier *frontier, RootRegion const &region,
> >>                        uptr region_begin, uptr region_end, bool is_readable);
> >>    void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg);
> >> +void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs);
> >>    // Run stoptheworld while holding any platform-specific locks, as well as the
> >>    // allocator and thread registry locks.
> >>    void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
> >> diff --git a/libsanitizer/lsan/lsan_common_fuchsia.cpp b/libsanitizer/lsan/lsan_common_fuchsia.cpp
> >> index 3c62c9433d3..2d35fa5b1cf 100644
> >> --- a/libsanitizer/lsan/lsan_common_fuchsia.cpp
> >> +++ b/libsanitizer/lsan/lsan_common_fuchsia.cpp
> >> @@ -107,9 +107,7 @@ void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
> >>        auto params = static_cast<const Params *>(data);
> >>        uptr begin = reinterpret_cast<uptr>(chunk);
> >>        uptr end = begin + size;
> >> -    auto i = __sanitizer::InternalLowerBound(params->allocator_caches, 0,
> >> -                                             params->allocator_caches.size(),
> >> -                                             begin, CompareLess<uptr>());
> >> +    auto i = __sanitizer::InternalLowerBound(params->allocator_caches, begin);
> >>        if (i < params->allocator_caches.size() &&
> >>            params->allocator_caches[i] >= begin &&
> >>            end - params->allocator_caches[i] <= sizeof(AllocatorCache)) {
> >> diff --git a/libsanitizer/lsan/lsan_fuchsia.h b/libsanitizer/lsan/lsan_fuchsia.h
> >> index 65d20ea2114..e730d8f25f2 100644
> >> --- a/libsanitizer/lsan/lsan_fuchsia.h
> >> +++ b/libsanitizer/lsan/lsan_fuchsia.h
> >> @@ -23,7 +23,7 @@
> >>
> >>    namespace __lsan {
> >>
> >> -class ThreadContext : public ThreadContextLsanBase {
> >> +class ThreadContext final : public ThreadContextLsanBase {
> >>     public:
> >>      explicit ThreadContext(int tid);
> >>      void OnCreated(void *arg) override;
> >> diff --git a/libsanitizer/lsan/lsan_interceptors.cpp b/libsanitizer/lsan/lsan_interceptors.cpp
> >> index bf8d316770e..90a90a56c54 100644
> >> --- a/libsanitizer/lsan/lsan_interceptors.cpp
> >> +++ b/libsanitizer/lsan/lsan_interceptors.cpp
> >> @@ -460,7 +460,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr,
> >>      if (res == 0) {
> >>        int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th,
> >>                               IsStateDetached(detached));
> >> -    CHECK_NE(tid, 0);
> >> +    CHECK_NE(tid, kMainTid);
> >>        atomic_store(&p.tid, tid, memory_order_release);
> >>        while (atomic_load(&p.tid, memory_order_acquire) != 0)
> >>          internal_sched_yield();
> >> diff --git a/libsanitizer/lsan/lsan_posix.cpp b/libsanitizer/lsan/lsan_posix.cpp
> >> index 8e05915dd1b..5d1c3f6260d 100644
> >> --- a/libsanitizer/lsan/lsan_posix.cpp
> >> +++ b/libsanitizer/lsan/lsan_posix.cpp
> >> @@ -48,7 +48,7 @@ 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,
> >> +  GetThreadStackAndTls(tid == kMainTid, &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;
> >> @@ -75,8 +75,8 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
> >>    }
> >>
> >>    void InitializeMainThread() {
> >> -  u32 tid = ThreadCreate(0, 0, true);
> >> -  CHECK_EQ(tid, 0);
> >> +  u32 tid = ThreadCreate(kMainTid, 0, true);
> >> +  CHECK_EQ(tid, kMainTid);
> >>      ThreadStart(tid, GetTid());
> >>    }
> >>
> >> diff --git a/libsanitizer/lsan/lsan_thread.cpp b/libsanitizer/lsan/lsan_thread.cpp
> >> index 371a1f29dfe..8efb54a6fb7 100644
> >> --- a/libsanitizer/lsan/lsan_thread.cpp
> >> +++ b/libsanitizer/lsan/lsan_thread.cpp
> >> @@ -94,7 +94,7 @@ void ThreadJoin(u32 tid) {
> >>    }
> >>
> >>    void EnsureMainThreadIDIsCorrect() {
> >> -  if (GetCurrentThread() == 0)
> >> +  if (GetCurrentThread() == kMainTid)
> >>        CurrentThreadContext()->os_id = GetTid();
> >>    }
> >>
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h b/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
> >> index 33f89d6d499..eb836bc4787 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
> >> @@ -35,9 +35,9 @@ class CombinedAllocator {
> >>        secondary_.InitLinkerInitialized();
> >>      }
> >>
> >> -  void Init(s32 release_to_os_interval_ms) {
> >> +  void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) {
> >>        stats_.Init();
> >> -    primary_.Init(release_to_os_interval_ms);
> >> +    primary_.Init(release_to_os_interval_ms, heap_start);
> >>        secondary_.Init();
> >>      }
> >>
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
> >> index b90dabbf776..fb5394cd39c 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
> >> @@ -119,7 +119,8 @@ class SizeClassAllocator32 {
> >>      typedef SizeClassAllocator32<Params> ThisT;
> >>      typedef SizeClassAllocator32LocalCache<ThisT> AllocatorCache;
> >>
> >> -  void Init(s32 release_to_os_interval_ms) {
> >> +  void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) {
> >> +    CHECK(!heap_start);
> >>        possible_regions.Init();
> >>        internal_memset(size_class_info_array, 0, sizeof(size_class_info_array));
> >>      }
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
> >> index 0a18b0c58ef..db30e138154 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
> >> @@ -19,7 +19,7 @@ template<class SizeClassAllocator> struct SizeClassAllocator64LocalCache;
> >>    // The template parameter Params is a class containing the actual parameters.
> >>    //
> >>    // Space: a portion of address space of kSpaceSize bytes starting at SpaceBeg.
> >> -// If kSpaceBeg is ~0 then SpaceBeg is chosen dynamically my mmap.
> >> +// If kSpaceBeg is ~0 then SpaceBeg is chosen dynamically by mmap.
> >>    // Otherwise SpaceBeg=kSpaceBeg (fixed address).
> >>    // kSpaceSize is a power of two.
> >>    // At the beginning the entire space is mprotect-ed, then small parts of it
> >> @@ -69,25 +69,45 @@ class SizeClassAllocator64 {
> >>        return base + (static_cast<uptr>(ptr32) << kCompactPtrScale);
> >>      }
> >>
> >> -  void Init(s32 release_to_os_interval_ms) {
> >> +  // If heap_start is nonzero, assumes kSpaceSize bytes are already mapped R/W
> >> +  // at heap_start and places the heap there.  This mode requires kSpaceBeg ==
> >> +  // ~(uptr)0.
> >> +  void Init(s32 release_to_os_interval_ms, uptr heap_start = 0) {
> >>        uptr TotalSpaceSize = kSpaceSize + AdditionalSize();
> >> -    if (kUsingConstantSpaceBeg) {
> >> -      CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize));
> >> -      CHECK_EQ(kSpaceBeg, address_range.Init(TotalSpaceSize,
> >> -                                             PrimaryAllocatorName, kSpaceBeg));
> >> +    PremappedHeap = heap_start != 0;
> >> +    if (PremappedHeap) {
> >> +      CHECK(!kUsingConstantSpaceBeg);
> >> +      NonConstSpaceBeg = heap_start;
> >> +      uptr RegionInfoSize = AdditionalSize();
> >> +      RegionInfoSpace =
> >> +          address_range.Init(RegionInfoSize, PrimaryAllocatorName);
> >> +      CHECK_NE(RegionInfoSpace, ~(uptr)0);
> >> +      CHECK_EQ(RegionInfoSpace,
> >> +               address_range.MapOrDie(RegionInfoSpace, RegionInfoSize,
> >> +                                      "SizeClassAllocator: region info"));
> >> +      MapUnmapCallback().OnMap(RegionInfoSpace, RegionInfoSize);
> >>        } else {
> >> -      // 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);
> >> +      if (kUsingConstantSpaceBeg) {
> >> +        CHECK(IsAligned(kSpaceBeg, SizeClassMap::kMaxSize));
> >> +        CHECK_EQ(kSpaceBeg,
> >> +                 address_range.Init(TotalSpaceSize, PrimaryAllocatorName,
> >> +                                    kSpaceBeg));
> >> +      } else {
> >> +        // 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);
> >> +      }
> >> +      RegionInfoSpace = SpaceEnd();
> >> +      MapWithCallbackOrDie(RegionInfoSpace, AdditionalSize(),
> >> +                           "SizeClassAllocator: region info");
> >>        }
> >>        SetReleaseToOSIntervalMs(release_to_os_interval_ms);
> >> -    MapWithCallbackOrDie(SpaceEnd(), AdditionalSize(),
> >> -                         "SizeClassAllocator: region info");
> >>        // Check that the RegionInfo array is aligned on the CacheLine size.
> >> -    DCHECK_EQ(SpaceEnd() % kCacheLineSize, 0);
> >> +    DCHECK_EQ(RegionInfoSpace % kCacheLineSize, 0);
> >>      }
> >>
> >>      s32 ReleaseToOSIntervalMs() const {
> >> @@ -144,6 +164,17 @@ class SizeClassAllocator64 {
> >>        CompactPtrT *free_array = GetFreeArray(region_beg);
> >>
> >>        BlockingMutexLock l(&region->mutex);
> >> +#if SANITIZER_WINDOWS
> >> +    /* On Windows unmapping of memory during __sanitizer_purge_allocator is
> >> +    explicit and immediate, so unmapped regions must be explicitly mapped back
> >> +    in when they are accessed again. */
> >> +    if (region->rtoi.last_released_bytes > 0) {
> >> +      MmapFixedOrDie(region_beg, region->mapped_user,
> >> +                                      "SizeClassAllocator: region data");
> >> +      region->rtoi.n_freed_at_last_release = 0;
> >> +      region->rtoi.last_released_bytes = 0;
> >> +    }
> >> +#endif
> >>        if (UNLIKELY(region->num_freed_chunks < n_chunks)) {
> >>          if (UNLIKELY(!PopulateFreeArray(stat, class_id, region,
> >>                                          n_chunks - region->num_freed_chunks)))
> >> @@ -360,8 +391,7 @@ class SizeClassAllocator64 {
> >>        }
> >>        ~PackedCounterArray() {
> >>          if (buffer) {
> >> -        memory_mapper->UnmapPackedCounterArrayBuffer(
> >> -            reinterpret_cast<uptr>(buffer), buffer_size);
> >> +        memory_mapper->UnmapPackedCounterArrayBuffer(buffer, buffer_size);
> >>          }
> >>        }
> >>
> >> @@ -586,6 +616,11 @@ class SizeClassAllocator64 {
> >>
> >>      atomic_sint32_t release_to_os_interval_ms_;
> >>
> >> +  uptr RegionInfoSpace;
> >> +
> >> +  // True if the user has already mapped the entire heap R/W.
> >> +  bool PremappedHeap;
> >> +
> >>      struct Stats {
> >>        uptr n_allocated;
> >>        uptr n_freed;
> >> @@ -615,7 +650,7 @@ class SizeClassAllocator64 {
> >>
> >>      RegionInfo *GetRegionInfo(uptr class_id) const {
> >>        DCHECK_LT(class_id, kNumClasses);
> >> -    RegionInfo *regions = reinterpret_cast<RegionInfo *>(SpaceEnd());
> >> +    RegionInfo *regions = reinterpret_cast<RegionInfo *>(RegionInfoSpace);
> >>        return &regions[class_id];
> >>      }
> >>
> >> @@ -640,6 +675,9 @@ class SizeClassAllocator64 {
> >>      }
> >>
> >>      bool MapWithCallback(uptr beg, uptr size, const char *name) {
> >> +    if (PremappedHeap)
> >> +      return beg >= NonConstSpaceBeg &&
> >> +             beg + size <= NonConstSpaceBeg + kSpaceSize;
> >>        uptr mapped = address_range.Map(beg, size, name);
> >>        if (UNLIKELY(!mapped))
> >>          return false;
> >> @@ -649,11 +687,18 @@ class SizeClassAllocator64 {
> >>      }
> >>
> >>      void MapWithCallbackOrDie(uptr beg, uptr size, const char *name) {
> >> +    if (PremappedHeap) {
> >> +      CHECK_GE(beg, NonConstSpaceBeg);
> >> +      CHECK_LE(beg + size, NonConstSpaceBeg + kSpaceSize);
> >> +      return;
> >> +    }
> >>        CHECK_EQ(beg, address_range.MapOrDie(beg, size, name));
> >>        MapUnmapCallback().OnMap(beg, size);
> >>      }
> >>
> >>      void UnmapWithCallbackOrDie(uptr beg, uptr size) {
> >> +    if (PremappedHeap)
> >> +      return;
> >>        MapUnmapCallback().OnUnmap(beg, size);
> >>        address_range.Unmap(beg, size);
> >>      }
> >> @@ -792,17 +837,16 @@ class SizeClassAllocator64 {
> >>          return released_bytes;
> >>        }
> >>
> >> -    uptr MapPackedCounterArrayBuffer(uptr buffer_size) {
> >> +    void *MapPackedCounterArrayBuffer(uptr buffer_size) {
> >>          // TODO(alekseyshl): The idea to explore is to check if we have enough
> >>          // space between num_freed_chunks*sizeof(CompactPtrT) and
> >>          // mapped_free_array to fit buffer_size bytes and use that space instead
> >>          // of mapping a temporary one.
> >> -      return reinterpret_cast<uptr>(
> >> -          MmapOrDieOnFatalError(buffer_size, "ReleaseToOSPageCounters"));
> >> +      return MmapOrDieOnFatalError(buffer_size, "ReleaseToOSPageCounters");
> >>        }
> >>
> >> -    void UnmapPackedCounterArrayBuffer(uptr buffer, uptr buffer_size) {
> >> -      UnmapOrDie(reinterpret_cast<void *>(buffer), buffer_size);
> >> +    void UnmapPackedCounterArrayBuffer(void *buffer, uptr buffer_size) {
> >> +      UnmapOrDie(buffer, buffer_size);
> >>        }
> >>
> >>        // Releases [from, to) range of pages back to OS.
> >> @@ -823,6 +867,9 @@ class SizeClassAllocator64 {
> >>
> >>      // Attempts to release RAM occupied by freed chunks back to OS. The region is
> >>      // expected to be locked.
> >> +  //
> >> +  // TODO(morehouse): Support a callback on memory release so HWASan can release
> >> +  // aliases as well.
> >>      void MaybeReleaseToOS(uptr class_id, bool force) {
> >>        RegionInfo *region = GetRegionInfo(class_id);
> >>        const uptr chunk_size = ClassIdToSize(class_id);
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h b/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
> >> index 12d8c892307..c50d13303ed 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
> >> @@ -24,7 +24,7 @@
> >>    //             E.g. with kNumBits==3 all size classes after 2^kMidSizeLog
> >>    //             look like 0b1xx0..0, where x is either 0 or 1.
> >>    //
> >> -// Example: kNumBits=3, kMidSizeLog=4, kMidSizeLog=8, kMaxSizeLog=17:
> >> +// Example: kNumBits=3, kMinSizeLog=4, kMidSizeLog=8, kMaxSizeLog=17:
> >>    //
> >>    // Classes 1 - 16 correspond to sizes 16 to 256 (size = class_id * 16).
> >>    // Next 4 classes: 256 + i * 64  (i = 1 to 4).
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
> >> index 59155e9883e..2b39097112d 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
> >> @@ -41,7 +41,7 @@ inline atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr,
> >>                                                  atomic_uint64_t::Type val,
> >>                                                  memory_order mo) {
> >>      DCHECK(mo &
> >> -         (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
> >> +         (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
> >>      DCHECK(!((uptr)ptr % sizeof(*ptr)));
> >>
> >>      atomic_uint64_t::Type ret;
> >> @@ -67,7 +67,7 @@ inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr,
> >>                                               atomic_uint64_t::Type xchg,
> >>                                               memory_order mo) {
> >>      DCHECK(mo &
> >> -         (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
> >> +         (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
> >>      DCHECK(!((uptr)ptr % sizeof(*ptr)));
> >>
> >>      typedef atomic_uint64_t::Type Type;
> >> @@ -90,7 +90,7 @@ template <>
> >>    inline atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr,
> >>                                             memory_order mo) {
> >>      DCHECK(mo &
> >> -         (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
> >> +         (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
> >>      DCHECK(!((uptr)ptr % sizeof(*ptr)));
> >>
> >>      atomic_uint64_t::Type zero = 0;
> >> @@ -103,7 +103,7 @@ template <>
> >>    inline void atomic_store(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type v,
> >>                             memory_order mo) {
> >>      DCHECK(mo &
> >> -         (memory_order_relaxed | memory_order_releasae | memory_order_seq_cst));
> >> +         (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
> >>      DCHECK(!((uptr)ptr % sizeof(*ptr)));
> >>
> >>      __spin_lock(&lock.lock);
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
> >> new file mode 100644
> >> index 00000000000..250ac39e130
> >> --- /dev/null
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
> >> @@ -0,0 +1,108 @@
> >> +//===-- sanitizer_chained_origin_depot.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
> >> +//
> >> +//===----------------------------------------------------------------------===//
> >> +//
> >> +// A storage for chained origins.
> >> +//===----------------------------------------------------------------------===//
> >> +
> >> +#include "sanitizer_chained_origin_depot.h"
> >> +
> >> +namespace __sanitizer {
> >> +
> >> +bool ChainedOriginDepot::ChainedOriginDepotNode::eq(
> >> +    u32 hash, const args_type &args) const {
> >> +  return here_id == args.here_id && prev_id == args.prev_id;
> >> +}
> >> +
> >> +uptr ChainedOriginDepot::ChainedOriginDepotNode::storage_size(
> >> +    const args_type &args) {
> >> +  return sizeof(ChainedOriginDepotNode);
> >> +}
> >> +
> >> +/* This is murmur2 hash for the 64->32 bit case.
> >> +   It does not behave all that well because the keys have a very biased
> >> +   distribution (I've seen 7-element buckets with the table only 14% full).
> >> +
> >> +   here_id is built of
> >> +   * (1 bits) Reserved, zero.
> >> +   * (8 bits) Part id = bits 13..20 of the hash value of here_id's key.
> >> +   * (23 bits) Sequential number (each part has each own sequence).
> >> +
> >> +   prev_id has either the same distribution as here_id (but with 3:8:21)
> >> +   split, or one of two reserved values (-1) or (-2). Either case can
> >> +   dominate depending on the workload.
> >> +*/
> >> +u32 ChainedOriginDepot::ChainedOriginDepotNode::hash(const args_type &args) {
> >> +  const u32 m = 0x5bd1e995;
> >> +  const u32 seed = 0x9747b28c;
> >> +  const u32 r = 24;
> >> +  u32 h = seed;
> >> +  u32 k = args.here_id;
> >> +  k *= m;
> >> +  k ^= k >> r;
> >> +  k *= m;
> >> +  h *= m;
> >> +  h ^= k;
> >> +
> >> +  k = args.prev_id;
> >> +  k *= m;
> >> +  k ^= k >> r;
> >> +  k *= m;
> >> +  h *= m;
> >> +  h ^= k;
> >> +
> >> +  h ^= h >> 13;
> >> +  h *= m;
> >> +  h ^= h >> 15;
> >> +  return h;
> >> +}
> >> +
> >> +bool ChainedOriginDepot::ChainedOriginDepotNode::is_valid(
> >> +    const args_type &args) {
> >> +  return true;
> >> +}
> >> +
> >> +void ChainedOriginDepot::ChainedOriginDepotNode::store(const args_type &args,
> >> +                                                       u32 other_hash) {
> >> +  here_id = args.here_id;
> >> +  prev_id = args.prev_id;
> >> +}
> >> +
> >> +ChainedOriginDepot::ChainedOriginDepotNode::args_type
> >> +ChainedOriginDepot::ChainedOriginDepotNode::load() const {
> >> +  args_type ret = {here_id, prev_id};
> >> +  return ret;
> >> +}
> >> +
> >> +ChainedOriginDepot::ChainedOriginDepotNode::Handle
> >> +ChainedOriginDepot::ChainedOriginDepotNode::get_handle() {
> >> +  return Handle(this);
> >> +}
> >> +
> >> +ChainedOriginDepot::ChainedOriginDepot() {}
> >> +
> >> +StackDepotStats *ChainedOriginDepot::GetStats() { return depot.GetStats(); }
> >> +
> >> +bool ChainedOriginDepot::Put(u32 here_id, u32 prev_id, u32 *new_id) {
> >> +  ChainedOriginDepotDesc desc = {here_id, prev_id};
> >> +  bool inserted;
> >> +  ChainedOriginDepotNode::Handle h = depot.Put(desc, &inserted);
> >> +  *new_id = h.valid() ? h.id() : 0;
> >> +  return inserted;
> >> +}
> >> +
> >> +u32 ChainedOriginDepot::Get(u32 id, u32 *other) {
> >> +  ChainedOriginDepotDesc desc = depot.Get(id);
> >> +  *other = desc.prev_id;
> >> +  return desc.here_id;
> >> +}
> >> +
> >> +void ChainedOriginDepot::LockAll() { depot.LockAll(); }
> >> +
> >> +void ChainedOriginDepot::UnlockAll() { depot.UnlockAll(); }
> >> +
> >> +}  // namespace __sanitizer
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
> >> new file mode 100644
> >> index 00000000000..453cdf6b544
> >> --- /dev/null
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
> >> @@ -0,0 +1,88 @@
> >> +//===-- sanitizer_chained_origin_depot.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
> >> +//
> >> +//===----------------------------------------------------------------------===//
> >> +//
> >> +// A storage for chained origins.
> >> +//===----------------------------------------------------------------------===//
> >> +
> >> +#ifndef SANITIZER_CHAINED_ORIGIN_DEPOT_H
> >> +#define SANITIZER_CHAINED_ORIGIN_DEPOT_H
> >> +
> >> +#include "sanitizer_common.h"
> >> +#include "sanitizer_stackdepotbase.h"
> >> +
> >> +namespace __sanitizer {
> >> +
> >> +class ChainedOriginDepot {
> >> + public:
> >> +  ChainedOriginDepot();
> >> +
> >> +  // Gets the statistic of the origin chain storage.
> >> +  StackDepotStats *GetStats();
> >> +
> >> +  // Stores a chain with StackDepot ID here_id and previous chain ID prev_id.
> >> +  // If successful, returns true and the new chain id new_id.
> >> +  // If the same element already exists, returns false and sets new_id to the
> >> +  // existing ID.
> >> +  bool Put(u32 here_id, u32 prev_id, u32 *new_id);
> >> +
> >> +  // Retrieves the stored StackDepot ID for the given origin ID.
> >> +  u32 Get(u32 id, u32 *other);
> >> +
> >> +  void LockAll();
> >> +  void UnlockAll();
> >> +
> >> + private:
> >> +  struct ChainedOriginDepotDesc {
> >> +    u32 here_id;
> >> +    u32 prev_id;
> >> +  };
> >> +
> >> +  struct ChainedOriginDepotNode {
> >> +    ChainedOriginDepotNode *link;
> >> +    u32 id;
> >> +    u32 here_id;
> >> +    u32 prev_id;
> >> +
> >> +    typedef ChainedOriginDepotDesc args_type;
> >> +
> >> +    bool eq(u32 hash, const args_type &args) const;
> >> +
> >> +    static uptr storage_size(const args_type &args);
> >> +
> >> +    static u32 hash(const args_type &args);
> >> +
> >> +    static bool is_valid(const args_type &args);
> >> +
> >> +    void store(const args_type &args, u32 other_hash);
> >> +
> >> +    args_type load() const;
> >> +
> >> +    struct Handle {
> >> +      ChainedOriginDepotNode *node_;
> >> +      Handle() : node_(nullptr) {}
> >> +      explicit Handle(ChainedOriginDepotNode *node) : node_(node) {}
> >> +      bool valid() { return node_; }
> >> +      u32 id() { return node_->id; }
> >> +      int here_id() { return node_->here_id; }
> >> +      int prev_id() { return node_->prev_id; }
> >> +    };
> >> +
> >> +    Handle get_handle();
> >> +
> >> +    typedef Handle handle_type;
> >> +  };
> >> +
> >> +  StackDepotBase<ChainedOriginDepotNode, 4, 20> depot;
> >> +
> >> +  ChainedOriginDepot(const ChainedOriginDepot &) = delete;
> >> +  void operator=(const ChainedOriginDepot &) = delete;
> >> +};
> >> +
> >> +}  // namespace __sanitizer
> >> +
> >> +#endif  // SANITIZER_CHAINED_ORIGIN_DEPOT_H
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cpp b/libsanitizer/sanitizer_common/sanitizer_common.cpp
> >> index 87efda5bd37..33960d94a2f 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_common.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_common.cpp
> >> @@ -87,7 +87,7 @@ const char *StripModuleName(const char *module) {
> >>    void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {
> >>      if (!common_flags()->print_summary)
> >>        return;
> >> -  InternalScopedString buff(kMaxSummaryLength);
> >> +  InternalScopedString buff;
> >>      buff.append("SUMMARY: %s: %s",
> >>                  alt_tool_name ? alt_tool_name : SanitizerToolName, error_message);
> >>      __sanitizer_report_error_summary(buff.data());
> >> @@ -274,6 +274,14 @@ uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len) {
> >>      return name_len;
> >>    }
> >>
> >> +uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len) {
> >> +  ReadBinaryNameCached(buf, buf_len);
> >> +  const char *exec_name_pos = StripModuleName(buf);
> >> +  uptr name_len = exec_name_pos - buf;
> >> +  buf[name_len] = '\0';
> >> +  return name_len;
> >> +}
> >> +
> >>    #if !SANITIZER_GO
> >>    void PrintCmdline() {
> >>      char **argv = GetArgv();
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h
> >> index bce24d68045..7b65dd7dfb8 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_common.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_common.h
> >> @@ -44,7 +44,7 @@ const uptr kMaxPathLength = 4096;
> >>
> >>    const uptr kMaxThreadStackSize = 1 << 30;  // 1Gb
> >>
> >> -static const uptr kErrorMessageBufferSize = 1 << 16;
> >> +const uptr kErrorMessageBufferSize = 1 << 16;
> >>
> >>    // Denotes fake PC values that come from JIT/JAVA/etc.
> >>    // For such PC values __tsan_symbolize_external_ex() will be called.
> >> @@ -135,6 +135,15 @@ void UnmapFromTo(uptr from, uptr to);
> >>    uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
> >>                          uptr min_shadow_base_alignment, uptr &high_mem_end);
> >>
> >> +// Let S = max(shadow_size, num_aliases * alias_size, ring_buffer_size).
> >> +// Reserves 2*S bytes of address space to the right of the returned address and
> >> +// ring_buffer_size bytes to the left.  The returned address is aligned to 2*S.
> >> +// Also creates num_aliases regions of accessible memory starting at offset S
> >> +// from the returned address.  Each region has size alias_size and is backed by
> >> +// the same physical memory.
> >> +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
> >> +                                uptr num_aliases, uptr ring_buffer_size);
> >> +
> >>    // Reserve memory range [beg, end]. If madvise_shadow is true then apply
> >>    // madvise (e.g. hugepages, core dumping) requested by options.
> >>    void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name,
> >> @@ -248,6 +257,7 @@ const char *StripModuleName(const char *module);
> >>    // OS
> >>    uptr ReadBinaryName(/*out*/char *buf, uptr buf_len);
> >>    uptr ReadBinaryNameCached(/*out*/char *buf, uptr buf_len);
> >> +uptr ReadBinaryDir(/*out*/ char *buf, uptr buf_len);
> >>    uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len);
> >>    const char *GetProcessName();
> >>    void UpdateProcessName();
> >> @@ -294,8 +304,8 @@ void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
> >>                                          const char *mmap_type, error_t err,
> >>                                          bool raw_report = false);
> >>
> >> -// Specific tools may override behavior of "Die" and "CheckFailed" functions
> >> -// to do tool-specific job.
> >> +// Specific tools may override behavior of "Die" function to do tool-specific
> >> +// job.
> >>    typedef void (*DieCallbackType)(void);
> >>
> >>    // It's possible to add several callbacks that would be run when "Die" is
> >> @@ -307,9 +317,7 @@ bool RemoveDieCallback(DieCallbackType callback);
> >>
> >>    void SetUserDieCallback(DieCallbackType callback);
> >>
> >> -typedef void (*CheckFailedCallbackType)(const char *, int, const char *,
> >> -                                       u64, u64);
> >> -void SetCheckFailedCallback(CheckFailedCallbackType callback);
> >> +void SetCheckUnwindCallback(void (*callback)());
> >>
> >>    // Callback will be called if soft_rss_limit_mb is given and the limit is
> >>    // exceeded (exceeded==true) or if rss went down below the limit
> >> @@ -343,8 +351,6 @@ void ReportDeadlySignal(const SignalContext &sig, u32 tid,
> >>    void SetAlternateSignalStack();
> >>    void UnsetAlternateSignalStack();
> >>
> >> -// We don't want a summary too long.
> >> -const int kMaxSummaryLength = 1024;
> >>    // Construct a one-line string:
> >>    //   SUMMARY: SanitizerToolName: error_message
> >>    // and pass it to __sanitizer_report_error_summary.
> >> @@ -441,8 +447,14 @@ inline uptr Log2(uptr x) {
> >>
> >>    // Don't use std::min, std::max or std::swap, to minimize dependency
> >>    // on libstdc++.
> >> -template<class T> T Min(T a, T b) { return a < b ? a : b; }
> >> -template<class T> T Max(T a, T b) { return a > b ? a : b; }
> >> +template <class T>
> >> +constexpr T Min(T a, T b) {
> >> +  return a < b ? a : b;
> >> +}
> >> +template <class T>
> >> +constexpr T Max(T a, T b) {
> >> +  return a > b ? a : b;
> >> +}
> >>    template<class T> void Swap(T& a, T& b) {
> >>      T tmp = a;
> >>      a = b;
> >> @@ -467,6 +479,7 @@ inline int ToLower(int c) {
> >>    template<typename T>
> >>    class InternalMmapVectorNoCtor {
> >>     public:
> >> +  using value_type = T;
> >>      void Initialize(uptr initial_capacity) {
> >>        capacity_bytes_ = 0;
> >>        size_ = 0;
> >> @@ -590,21 +603,21 @@ class InternalMmapVector : public InternalMmapVectorNoCtor<T> {
> >>      InternalMmapVector &operator=(InternalMmapVector &&) = delete;
> >>    };
> >>
> >> -class InternalScopedString : public InternalMmapVector<char> {
> >> +class InternalScopedString {
> >>     public:
> >> -  explicit InternalScopedString(uptr max_length)
> >> -      : InternalMmapVector<char>(max_length), length_(0) {
> >> -    (*this)[0] = '\0';
> >> -  }
> >> -  uptr length() { return length_; }
> >> +  InternalScopedString() : buffer_(1) { buffer_[0] = '\0'; }
> >> +
> >> +  uptr length() const { return buffer_.size() - 1; }
> >>      void clear() {
> >> -    (*this)[0] = '\0';
> >> -    length_ = 0;
> >> +    buffer_.resize(1);
> >> +    buffer_[0] = '\0';
> >>      }
> >>      void append(const char *format, ...);
> >> +  const char *data() const { return buffer_.data(); }
> >> +  char *data() { return buffer_.data(); }
> >>
> >>     private:
> >> -  uptr length_;
> >> +  InternalMmapVector<char> buffer_;
> >>    };
> >>
> >>    template <class T>
> >> @@ -651,9 +664,13 @@ void Sort(T *v, uptr size, Compare comp = {}) {
> >>
> >>    // Works like std::lower_bound: finds the first element that is not less
> >>    // than the val.
> >> -template <class Container, class Value, class Compare>
> >> -uptr InternalLowerBound(const Container &v, uptr first, uptr last,
> >> -                        const Value &val, Compare comp) {
> >> +template <class Container,
> >> +          class Compare = CompareLess<typename Container::value_type>>
> >> +uptr InternalLowerBound(const Container &v,
> >> +                        const typename Container::value_type &val,
> >> +                        Compare comp = {}) {
> >> +  uptr first = 0;
> >> +  uptr last = v.size();
> >>      while (last > first) {
> >>        uptr mid = (first + last) / 2;
> >>        if (comp(v[mid], val))
> >> @@ -677,6 +694,27 @@ enum ModuleArch {
> >>      kModuleArchRISCV64
> >>    };
> >>
> >> +// Sorts and removes duplicates from the container.
> >> +template <class Container,
> >> +          class Compare = CompareLess<typename Container::value_type>>
> >> +void SortAndDedup(Container &v, Compare comp = {}) {
> >> +  Sort(v.data(), v.size(), comp);
> >> +  uptr size = v.size();
> >> +  if (size < 2)
> >> +    return;
> >> +  uptr last = 0;
> >> +  for (uptr i = 1; i < size; ++i) {
> >> +    if (comp(v[last], v[i])) {
> >> +      ++last;
> >> +      if (last != i)
> >> +        v[last] = v[i];
> >> +    } else {
> >> +      CHECK(!comp(v[i], v[last]));
> >> +    }
> >> +  }
> >> +  v.resize(last + 1);
> >> +}
> >> +
> >>    // Opens the file 'file_name" and reads up to 'max_len' bytes.
> >>    // The resulting buffer is mmaped and stored in '*buff'.
> >>    // Returns true if file was successfully opened and read.
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
> >> index 2f2787e283a..7867fccde39 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
> >> @@ -239,7 +239,7 @@ extern const short *_tolower_tab_;
> >>        COMMON_INTERCEPT_FUNCTION(fn)
> >>    #endif
> >>
> >> -#ifdef __GLIBC__
> >> +#if SANITIZER_GLIBC
> >>    // If we could not find the versioned symbol, fall back to an unversioned
> >>    // lookup. This is needed to work around a GLibc bug that causes dlsym
> >>    // with RTLD_NEXT to return the oldest versioned symbol.
> >> @@ -2195,6 +2195,7 @@ INTERCEPTOR(int, clock_gettime, u32 clk_id, void *tp) {
> >>      }
> >>      return res;
> >>    }
> >> +#if SANITIZER_GLIBC
> >>    namespace __sanitizer {
> >>    extern "C" {
> >>    int real_clock_gettime(u32 clk_id, void *tp) {
> >> @@ -2204,6 +2205,7 @@ int real_clock_gettime(u32 clk_id, void *tp) {
> >>    }
> >>    }  // extern "C"
> >>    }  // namespace __sanitizer
> >> +#endif
> >>    INTERCEPTOR(int, clock_settime, u32 clk_id, const void *tp) {
> >>      void *ctx;
> >>      COMMON_INTERCEPTOR_ENTER(ctx, clock_settime, clk_id, tp);
> >> @@ -3355,7 +3357,7 @@ INTERCEPTOR(char *, setlocale, int category, char *locale) {
> >>        COMMON_INTERCEPTOR_READ_RANGE(ctx, locale, REAL(strlen)(locale) + 1);
> >>      char *res = REAL(setlocale)(category, locale);
> >>      if (res) {
> >> -    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
> >> +    COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
> >>        unpoison_ctype_arrays(ctx);
> >>      }
> >>      return res;
> >> @@ -4030,7 +4032,7 @@ INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) {
> >>      // 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(sigwait)(set, sig);
> >> +  int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigwait)(set, sig);
> >>      if (!res && sig) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, sig, sizeof(*sig));
> >>      return res;
> >>    }
> >> @@ -4047,7 +4049,7 @@ INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) {
> >>      // 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(sigwaitinfo)(set, info);
> >> +  int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigwaitinfo)(set, info);
> >>      if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
> >>      return res;
> >>    }
> >> @@ -4066,7 +4068,7 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info,
> >>      // 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(sigtimedwait)(set, info, timeout);
> >> +  int res = COMMON_INTERCEPTOR_BLOCK_REAL(sigtimedwait)(set, info, timeout);
> >>      if (res > 0 && info) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, info, siginfo_t_sz);
> >>      return res;
> >>    }
> >> @@ -5995,6 +5997,9 @@ void unpoison_file(__sanitizer_FILE *fp) {
> >>      if (fp->_IO_read_base && fp->_IO_read_base < fp->_IO_read_end)
> >>        COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_read_base,
> >>                                            fp->_IO_read_end - fp->_IO_read_base);
> >> +  if (fp->_IO_write_base && fp->_IO_write_base < fp->_IO_write_end)
> >> +    COMMON_INTERCEPTOR_INITIALIZE_RANGE(fp->_IO_write_base,
> >> +                                        fp->_IO_write_end - fp->_IO_write_base);
> >>    #endif
> >>    #endif  // SANITIZER_HAS_STRUCT_FILE
> >>    }
> >> @@ -6221,6 +6226,8 @@ INTERCEPTOR(void, _obstack_newchunk, __sanitizer_obstack *obstack, int length) {
> >>    INTERCEPTOR(int, fflush, __sanitizer_FILE *fp) {
> >>      void *ctx;
> >>      COMMON_INTERCEPTOR_ENTER(ctx, fflush, fp);
> >> +  if (fp)
> >> +    unpoison_file(fp);
> >>      int res = REAL(fflush)(fp);
> >>      // FIXME: handle fp == NULL
> >>      if (fp) {
> >> @@ -6240,6 +6247,8 @@ INTERCEPTOR(int, fclose, __sanitizer_FILE *fp) {
> >>      COMMON_INTERCEPTOR_ENTER(ctx, fclose, fp);
> >>      COMMON_INTERCEPTOR_FILE_CLOSE(ctx, fp);
> >>      const FileMetadata *m = GetInterceptorMetadata(fp);
> >> +  if (fp)
> >> +    unpoison_file(fp);
> >>      int res = REAL(fclose)(fp);
> >>      if (m) {
> >>        COMMON_INTERCEPTOR_INITIALIZE_RANGE(*m->addr, *m->size);
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
> >> index 490a04b2181..7f181258eab 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_ioctl.inc
> >> @@ -330,13 +330,17 @@ static void ioctl_table_fill() {
> >>      _(SOUND_PCM_WRITE_CHANNELS, WRITE, sizeof(int));
> >>      _(SOUND_PCM_WRITE_FILTER, WRITE, sizeof(int));
> >>      _(TCFLSH, NONE, 0);
> >> +#if SANITIZER_GLIBC
> >>      _(TCGETA, WRITE, struct_termio_sz);
> >> +#endif
> >>      _(TCGETS, WRITE, struct_termios_sz);
> >>      _(TCSBRK, NONE, 0);
> >>      _(TCSBRKP, NONE, 0);
> >> +#if SANITIZER_GLIBC
> >>      _(TCSETA, READ, struct_termio_sz);
> >>      _(TCSETAF, READ, struct_termio_sz);
> >>      _(TCSETAW, READ, struct_termio_sz);
> >> +#endif
> >>      _(TCSETS, READ, struct_termios_sz);
> >>      _(TCSETSF, READ, struct_termios_sz);
> >>      _(TCSETSW, READ, struct_termios_sz);
> >> @@ -364,7 +368,7 @@ static void ioctl_table_fill() {
> >>      _(VT_WAITACTIVE, NONE, 0);
> >>    #endif
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC
> >>      // _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE
> >>      _(CYGETDEFTHRESH, WRITE, sizeof(int));
> >>      _(CYGETDEFTIMEOUT, WRITE, sizeof(int));
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
> >> index 20f42f1ea94..72e482754b6 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_vfork_aarch64.inc.S
> >> @@ -1,6 +1,7 @@
> >>    #if defined(__aarch64__) && defined(__linux__)
> >>
> >>    #include "sanitizer_common/sanitizer_asm.h"
> >> +#include "builtins/assembly.h"
> >>
> >>    ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
> >>
> >> @@ -9,6 +10,7 @@ ASM_HIDDEN(COMMON_INTERCEPTOR_SPILL_AREA)
> >>    ASM_TYPE_FUNCTION(ASM_WRAPPER_NAME(vfork))
> >>    ASM_WRAPPER_NAME(vfork):
> >>            // Save x30 in the off-stack spill area.
> >> +        hint    #25 // paciasp
> >>            stp     xzr, x30, [sp, #-16]!
> >>            bl      COMMON_INTERCEPTOR_SPILL_AREA
> >>            ldp     xzr, x30, [sp], 16
> >> @@ -33,6 +35,7 @@ ASM_WRAPPER_NAME(vfork):
> >>            bl     COMMON_INTERCEPTOR_SPILL_AREA
> >>            ldr    x30, [x0]
> >>            ldp    x0, xzr, [sp], 16
> >> +        hint   #29 // autiasp
> >>
> >>            ret
> >>    ASM_SIZE(vfork)
> >> @@ -40,4 +43,6 @@ ASM_SIZE(vfork)
> >>    .weak vfork
> >>    .set vfork, ASM_WRAPPER_NAME(vfork)
> >>
> >> +GNU_PROPERTY_BTI_PAC
> >> +
> >>    #endif
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
> >> index c78b6e10b68..932e5478616 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
> >> @@ -13,6 +13,7 @@ INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
> >>    INTERFACE_FUNCTION(__sanitizer_set_death_callback)
> >>    INTERFACE_FUNCTION(__sanitizer_set_report_path)
> >>    INTERFACE_FUNCTION(__sanitizer_set_report_fd)
> >> +INTERFACE_FUNCTION(__sanitizer_get_report_path)
> >>    INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
> >>    INTERFACE_WEAK_FUNCTION(__sanitizer_on_print)
> >>    INTERFACE_WEAK_FUNCTION(__sanitizer_report_error_summary)
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
> >> index 047c5a17ea6..1037938f3d3 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
> >> @@ -92,14 +92,13 @@ void *BackgroundThread(void *arg) {
> >>    #endif
> >>
> >>    void WriteToSyslog(const char *msg) {
> >> -  InternalScopedString msg_copy(kErrorMessageBufferSize);
> >> +  InternalScopedString msg_copy;
> >>      msg_copy.append("%s", msg);
> >> -  char *p = msg_copy.data();
> >> -  char *q;
> >> +  const char *p = msg_copy.data();
> >>
> >>      // Print one line at a time.
> >>      // syslog, at least on Android, has an implicit message length limit.
> >> -  while ((q = internal_strchr(p, '\n'))) {
> >> +  while (char* q = internal_strchr(p, '\n')) {
> >>        *q = '\0';
> >>        WriteOneLineToSyslog(p);
> >>        p = q + 1;
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_file.cpp b/libsanitizer/sanitizer_common/sanitizer_file.cpp
> >> index 7cce60906b7..0b92dccde4a 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_file.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_file.cpp
> >> @@ -58,6 +58,9 @@ void ReportFile::ReopenIfNecessary() {
> >>      } else {
> >>        internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
> >>      }
> >> +  if (common_flags()->log_suffix) {
> >> +    internal_strlcat(full_path, common_flags()->log_suffix, kMaxPathLength);
> >> +  }
> >>      error_t err;
> >>      fd = OpenFile(full_path, WrOnly, &err);
> >>      if (fd == kInvalidFd) {
> >> @@ -95,6 +98,12 @@ void ReportFile::SetReportPath(const char *path) {
> >>      }
> >>    }
> >>
> >> +const char *ReportFile::GetReportPath() {
> >> +  SpinMutexLock l(mu);
> >> +  ReopenIfNecessary();
> >> +  return full_path;
> >> +}
> >> +
> >>    bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
> >>                          uptr *read_len, uptr max_len, error_t *errno_p) {
> >>      *buff = nullptr;
> >> @@ -213,6 +222,10 @@ void __sanitizer_set_report_fd(void *fd) {
> >>      report_file.fd = (fd_t)reinterpret_cast<uptr>(fd);
> >>      report_file.fd_pid = internal_getpid();
> >>    }
> >> +
> >> +const char *__sanitizer_get_report_path() {
> >> +  return report_file.GetReportPath();
> >> +}
> >>    } // extern "C"
> >>
> >>    #endif  // !SANITIZER_FUCHSIA
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_file.h b/libsanitizer/sanitizer_common/sanitizer_file.h
> >> index 26681f0493d..08671ab67d0 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_file.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_file.h
> >> @@ -26,6 +26,7 @@ struct ReportFile {
> >>      void Write(const char *buffer, uptr length);
> >>      bool SupportsColors();
> >>      void SetReportPath(const char *path);
> >> +  const char *GetReportPath();
> >>
> >>      // Don't use fields directly. They are only declared public to allow
> >>      // aggregate initialization.
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.cpp b/libsanitizer/sanitizer_common/sanitizer_flags.cpp
> >> index 21048be7304..d52e96a7c38 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_flags.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_flags.cpp
> >> @@ -35,6 +35,7 @@ void CommonFlags::CopyFrom(const CommonFlags &other) {
> >>    // Copy the string from "s" to "out", making the following substitutions:
> >>    // %b = binary basename
> >>    // %p = pid
> >> +// %d = binary directory
> >>    void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
> >>      char *out_end = out + out_size;
> >>      while (*s && out < out_end - 1) {
> >> @@ -64,6 +65,12 @@ void SubstituteForFlagValue(const char *s, char *out, uptr out_size) {
> >>            s += 2; // skip "%p"
> >>            break;
> >>          }
> >> +      case 'd': {
> >> +        uptr len = ReadBinaryDir(out, out_end - out);
> >> +        out += len;
> >> +        s += 2;  // skip "%d"
> >> +        break;
> >> +      }
> >>          default:
> >>            *out++ = *s++;
> >>            break;
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.inc b/libsanitizer/sanitizer_common/sanitizer_flags.inc
> >> index cfb5822645f..3bc44c6b1eb 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_flags.inc
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_flags.inc
> >> @@ -59,6 +59,8 @@ COMMON_FLAG(
> >>        bool, log_exe_name, false,
> >>        "Mention name of executable when reporting error and "
> >>        "append executable name to logs (as in \"log_path.exe_name.pid\").")
> >> +COMMON_FLAG(const char *, log_suffix, nullptr,
> >> +            "String to append to log file name, e.g. \".txt\".")
> >>    COMMON_FLAG(
> >>        bool, log_to_syslog, (bool)SANITIZER_ANDROID || (bool)SANITIZER_MAC,
> >>        "Write all sanitizer output to syslog in addition to other means of "
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
> >> index 7200ffdac0f..4f692f99c20 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
> >> @@ -14,7 +14,6 @@
> >>    #include "sanitizer_fuchsia.h"
> >>    #if SANITIZER_FUCHSIA
> >>
> >> -#include <limits.h>
> >>    #include <pthread.h>
> >>    #include <stdlib.h>
> >>    #include <unistd.h>
> >> @@ -69,9 +68,7 @@ uptr internal_getpid() {
> >>      return pid;
> >>    }
> >>
> >> -int internal_dlinfo(void *handle, int request, void *p) {
> >> -  UNIMPLEMENTED();
> >> -}
> >> +int internal_dlinfo(void *handle, int request, void *p) { UNIMPLEMENTED(); }
> >>
> >>    uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); }
> >>
> >> @@ -153,9 +150,9 @@ void BlockingMutex::CheckLocked() {
> >>      CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
> >>    }
> >>
> >> -uptr GetPageSize() { return PAGE_SIZE; }
> >> +uptr GetPageSize() { return _zx_system_get_page_size(); }
> >>
> >> -uptr GetMmapGranularity() { return PAGE_SIZE; }
> >> +uptr GetMmapGranularity() { return _zx_system_get_page_size(); }
> >>
> >>    sanitizer_shadow_bounds_t ShadowBounds;
> >>
> >> @@ -168,7 +165,7 @@ uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); }
> >>
> >>    static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type,
> >>                                      bool raw_report, bool die_for_nomem) {
> >> -  size = RoundUpTo(size, PAGE_SIZE);
> >> +  size = RoundUpTo(size, GetPageSize());
> >>
> >>      zx_handle_t vmo;
> >>      zx_status_t status = _zx_vmo_create(size, 0, &vmo);
> >> @@ -214,15 +211,14 @@ void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
> >>
> >>    uptr ReservedAddressRange::Init(uptr init_size, const char *name,
> >>                                    uptr fixed_addr) {
> >> -  init_size = RoundUpTo(init_size, PAGE_SIZE);
> >> +  init_size = RoundUpTo(init_size, GetPageSize());
> >>      DCHECK_EQ(os_handle_, ZX_HANDLE_INVALID);
> >>      uintptr_t base;
> >>      zx_handle_t vmar;
> >> -  zx_status_t status =
> >> -      _zx_vmar_allocate(
> >> -          _zx_vmar_root_self(),
> >> -          ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC,
> >> -          0, init_size, &vmar, &base);
> >> +  zx_status_t status = _zx_vmar_allocate(
> >> +      _zx_vmar_root_self(),
> >> +      ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0,
> >> +      init_size, &vmar, &base);
> >>      if (status != ZX_OK)
> >>        ReportMmapFailureAndDie(init_size, name, "zx_vmar_allocate", status);
> >>      base_ = reinterpret_cast<void *>(base);
> >> @@ -236,7 +232,7 @@ uptr ReservedAddressRange::Init(uptr init_size, const char *name,
> >>    static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size,
> >>                                 void *base, const char *name, bool die_for_nomem) {
> >>      uptr offset = fixed_addr - reinterpret_cast<uptr>(base);
> >> -  map_size = RoundUpTo(map_size, PAGE_SIZE);
> >> +  map_size = RoundUpTo(map_size, GetPageSize());
> >>      zx_handle_t vmo;
> >>      zx_status_t status = _zx_vmo_create(map_size, 0, &vmo);
> >>      if (status != ZX_OK) {
> >> @@ -264,19 +260,19 @@ static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size,
> >>
> >>    uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size,
> >>                                   const char *name) {
> >> -  return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_,
> >> -                          name_, false);
> >> +  return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, name_,
> >> +                          false);
> >>    }
> >>
> >>    uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr map_size,
> >>                                        const char *name) {
> >> -  return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_,
> >> -                          name_, true);
> >> +  return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, name_, true);
> >>    }
> >>
> >>    void UnmapOrDieVmar(void *addr, uptr size, zx_handle_t target_vmar) {
> >> -  if (!addr || !size) return;
> >> -  size = RoundUpTo(size, PAGE_SIZE);
> >> +  if (!addr || !size)
> >> +    return;
> >> +  size = RoundUpTo(size, GetPageSize());
> >>
> >>      zx_status_t status =
> >>          _zx_vmar_unmap(target_vmar, reinterpret_cast<uintptr_t>(addr), size);
> >> @@ -316,7 +312,7 @@ void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {
> >>
> >>    void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
> >>                                       const char *mem_type) {
> >> -  CHECK_GE(size, PAGE_SIZE);
> >> +  CHECK_GE(size, GetPageSize());
> >>      CHECK(IsPowerOfTwo(size));
> >>      CHECK(IsPowerOfTwo(alignment));
> >>
> >> @@ -356,7 +352,8 @@ void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
> >>                _zx_vmar_root_self(),
> >>                ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC_OVERWRITE,
> >>                addr - info.base, vmo, 0, size, &new_addr);
> >> -        if (status == ZX_OK) CHECK_EQ(new_addr, addr);
> >> +        if (status == ZX_OK)
> >> +          CHECK_EQ(new_addr, addr);
> >>          }
> >>        }
> >>        if (status == ZX_OK && addr != map_addr)
> >> @@ -381,9 +378,18 @@ void UnmapOrDie(void *addr, uptr size) {
> >>      UnmapOrDieVmar(addr, size, _zx_vmar_root_self());
> >>    }
> >>
> >> -// This is used on the shadow mapping, which cannot be changed.
> >> -// Zircon doesn't have anything like MADV_DONTNEED.
> >> -void ReleaseMemoryPagesToOS(uptr beg, uptr end) {}
> >> +void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
> >> +  uptr beg_aligned = RoundUpTo(beg, GetPageSize());
> >> +  uptr end_aligned = RoundDownTo(end, GetPageSize());
> >> +  if (beg_aligned < end_aligned) {
> >> +    zx_handle_t root_vmar = _zx_vmar_root_self();
> >> +    CHECK_NE(root_vmar, ZX_HANDLE_INVALID);
> >> +    zx_status_t status =
> >> +        _zx_vmar_op_range(root_vmar, ZX_VMAR_OP_DECOMMIT, beg_aligned,
> >> +                          end_aligned - beg_aligned, nullptr, 0);
> >> +    CHECK_EQ(status, ZX_OK);
> >> +  }
> >> +}
> >>
> >>    void DumpProcessMap() {
> >>      // TODO(mcgrathr): write it
> >> @@ -412,8 +418,9 @@ bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
> >>        uint64_t vmo_size;
> >>        status = _zx_vmo_get_size(vmo, &vmo_size);
> >>        if (status == ZX_OK) {
> >> -      if (vmo_size < max_len) max_len = vmo_size;
> >> -      size_t map_size = RoundUpTo(max_len, PAGE_SIZE);
> >> +      if (vmo_size < max_len)
> >> +        max_len = vmo_size;
> >> +      size_t map_size = RoundUpTo(max_len, GetPageSize());
> >>          uintptr_t addr;
> >>          status = _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ, 0, vmo, 0,
> >>                                map_size, &addr);
> >> @@ -425,7 +432,8 @@ bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
> >>        }
> >>        _zx_handle_close(vmo);
> >>      }
> >> -  if (status != ZX_OK && errno_p) *errno_p = status;
> >> +  if (status != ZX_OK && errno_p)
> >> +    *errno_p = status;
> >>      return status == ZX_OK;
> >>    }
> >>
> >> @@ -499,9 +507,7 @@ bool GetRandom(void *buffer, uptr length, bool blocking) {
> >>      return true;
> >>    }
> >>
> >> -u32 GetNumberOfCPUs() {
> >> -  return zx_system_get_num_cpus();
> >> -}
> >> +u32 GetNumberOfCPUs() { return zx_system_get_num_cpus(); }
> >>
> >>    uptr GetRSS() { UNIMPLEMENTED(); }
> >>
> >> @@ -529,6 +535,10 @@ void __sanitizer_set_report_path(const char *path) {
> >>    void __sanitizer_set_report_fd(void *fd) {
> >>      UNREACHABLE("not available on Fuchsia");
> >>    }
> >> +
> >> +const char *__sanitizer_get_report_path() {
> >> +  UNREACHABLE("not available on Fuchsia");
> >> +}
> >>    }  // extern "C"
> >>
> >>    #endif  // SANITIZER_FUCHSIA
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
> >> index be8023e9e16..0b001c1c483 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
> >> @@ -28,6 +28,10 @@ extern "C" {
> >>      // (casted to void *).
> >>      SANITIZER_INTERFACE_ATTRIBUTE
> >>      void __sanitizer_set_report_fd(void *fd);
> >> +  // Get the current full report file path, if a path was specified by
> >> +  // an earlier call to __sanitizer_set_report_path. Returns null otherwise.
> >> +  SANITIZER_INTERFACE_ATTRIBUTE
> >> +  const char *__sanitizer_get_report_path();
> >>
> >>      typedef struct {
> >>          int coverage_sandboxed;
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
> >> index d8f0540037d..84053fec264 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
> >> @@ -409,6 +409,9 @@ inline void Trap() {
> >>        (void)enable_fp;                      \
> >>      } while (0)
> >>
> >> +constexpr u32 kInvalidTid = -1;
> >> +constexpr u32 kMainTid = 0;
> >> +
> >>    }  // namespace __sanitizer
> >>
> >>    namespace __asan {
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_libignore.cpp b/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
> >> index 9ea19bc21fa..a65d3d896e3 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
> >> @@ -38,7 +38,7 @@ void LibIgnore::AddIgnoredLibrary(const char *name_templ) {
> >>    void LibIgnore::OnLibraryLoaded(const char *name) {
> >>      BlockingMutexLock lock(&mutex_);
> >>      // Try to match suppressions with symlink target.
> >> -  InternalScopedString buf(kMaxPathLength);
> >> +  InternalMmapVector<char> buf(kMaxPathLength);
> >>      if (name && internal_readlink(name, buf.data(), buf.size() - 1) > 0 &&
> >>          buf[0]) {
> >>        for (uptr i = 0; i < count_; i++) {
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
> >> index 379f6d9e294..b371477755f 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_linux.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
> >> @@ -183,6 +183,14 @@ uptr internal_munmap(void *addr, uptr length) {
> >>      return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
> >>    }
> >>
> >> +#if SANITIZER_LINUX
> >> +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
> >> +                     void *new_address) {
> >> +  return internal_syscall(SYSCALL(mremap), (uptr)old_address, old_size,
> >> +                          new_size, flags, (uptr)new_address);
> >> +}
> >> +#endif
> >> +
> >>    int internal_mprotect(void *addr, uptr length, int prot) {
> >>      return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot);
> >>    }
> >> @@ -489,22 +497,24 @@ int TgKill(pid_t pid, tid_t tid, int sig) {
> >>    }
> >>    #endif
> >>
> >> -#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
> >> +#if SANITIZER_GLIBC
> >>    u64 NanoTime() {
> >> -#if SANITIZER_FREEBSD
> >> -  timeval tv;
> >> -#else
> >>      kernel_timeval tv;
> >> -#endif
> >>      internal_memset(&tv, 0, sizeof(tv));
> >>      internal_syscall(SYSCALL(gettimeofday), &tv, 0);
> >> -  return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
> >> +  return (u64)tv.tv_sec * 1000 * 1000 * 1000 + tv.tv_usec * 1000;
> >>    }
> >> -
> >> +// Used by real_clock_gettime.
> >>    uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) {
> >>      return internal_syscall(SYSCALL(clock_gettime), clk_id, tp);
> >>    }
> >> -#endif  // !SANITIZER_SOLARIS && !SANITIZER_NETBSD
> >> +#elif !SANITIZER_SOLARIS && !SANITIZER_NETBSD
> >> +u64 NanoTime() {
> >> +  struct timespec ts;
> >> +  clock_gettime(CLOCK_REALTIME, &ts);
> >> +  return (u64)ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
> >> +}
> >> +#endif
> >>
> >>    // Like getenv, but reads env directly from /proc (on Linux) or parses the
> >>    // 'environ' array (on some others) and does not use libc. This function
> >> @@ -1334,50 +1344,42 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
> >>    #elif SANITIZER_RISCV64
> >>    uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
> >>                        int *parent_tidptr, void *newtls, int *child_tidptr) {
> >> -  long long res;
> >>      if (!fn || !child_stack)
> >>        return -EINVAL;
> >> +
> >>      CHECK_EQ(0, (uptr)child_stack % 16);
> >> -  child_stack = (char *)child_stack - 2 * sizeof(unsigned long long);
> >> -  ((unsigned long long *)child_stack)[0] = (uptr)fn;
> >> -  ((unsigned long long *)child_stack)[1] = (uptr)arg;
> >>
> >> -  register int (*__fn)(void *) __asm__("a0") = fn;
> >> +  register int res __asm__("a0");
> >> +  register int __flags __asm__("a0") = flags;
> >>      register void *__stack __asm__("a1") = child_stack;
> >> -  register int __flags __asm__("a2") = flags;
> >> -  register void *__arg __asm__("a3") = arg;
> >> -  register int *__ptid __asm__("a4") = parent_tidptr;
> >> -  register void *__tls __asm__("a5") = newtls;
> >> -  register int *__ctid __asm__("a6") = child_tidptr;
> >> +  register int *__ptid __asm__("a2") = parent_tidptr;
> >> +  register void *__tls __asm__("a3") = newtls;
> >> +  register int *__ctid __asm__("a4") = child_tidptr;
> >> +  register int (*__fn)(void *) __asm__("a5") = fn;
> >> +  register void *__arg __asm__("a6") = arg;
> >> +  register int nr_clone __asm__("a7") = __NR_clone;
> >>
> >>      __asm__ __volatile__(
> >> -      "mv a0,a2\n"          /* flags  */
> >> -      "mv a2,a4\n"          /* ptid  */
> >> -      "mv a3,a5\n"          /* tls  */
> >> -      "mv a4,a6\n"          /* ctid  */
> >> -      "addi a7, zero, %9\n" /* clone  */
> >> -
> >>          "ecall\n"
> >>
> >> -      /* if (%r0 != 0)
> >> -       *   return %r0;
> >> +      /* if (a0 != 0)
> >> +       *   return a0;
> >>           */
> >>          "bnez a0, 1f\n"
> >>
> >> -      /* In the child, now. Call "fn(arg)". */
> >> -      "ld  a0,  8(sp)\n"
> >> -      "ld  a1, 16(sp)\n"
> >> -      "jalr a1\n"
> >> +      // In the child, now. Call "fn(arg)".
> >> +      "mv a0, a6\n"
> >> +      "jalr a5\n"
> >>
> >> -      /* Call _exit(%r0).  */
> >> -      "addi  a7, zero, %10\n"
> >> +      // Call _exit(a0).
> >> +      "addi a7, zero, %9\n"
> >>          "ecall\n"
> >>          "1:\n"
> >>
> >>          : "=r"(res)
> >> -      : "i"(-EINVAL), "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg),
> >> -        "r"(__ptid), "r"(__tls), "r"(__ctid), "i"(__NR_clone), "i"(__NR_exit)
> >> -      : "ra", "memory");
> >> +      : "0"(__flags), "r"(__stack), "r"(__ptid), "r"(__tls), "r"(__ctid),
> >> +        "r"(__fn), "r"(__arg), "r"(nr_clone), "i"(__NR_exit)
> >> +      : "memory");
> >>      return res;
> >>    }
> >>    #elif defined(__aarch64__)
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h b/libsanitizer/sanitizer_common/sanitizer_linux.h
> >> index 24902d1b6bc..9a23fcfb3b9 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_linux.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_linux.h
> >> @@ -49,7 +49,9 @@ uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
> >>    uptr internal_sigaltstack(const void* ss, void* oss);
> >>    uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
> >>        __sanitizer_sigset_t *oldset);
> >> +#if SANITIZER_GLIBC
> >>    uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp);
> >> +#endif
> >>
> >>    // Linux-only syscalls.
> >>    #if SANITIZER_LINUX
> >> @@ -96,7 +98,6 @@ class ThreadLister {
> >>    // Exposed for testing.
> >>    uptr ThreadDescriptorSize();
> >>    uptr ThreadSelf();
> >> -uptr ThreadSelfOffset();
> >>
> >>    // Matches a library's file name against a base name (stripping path and version
> >>    // information).
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
> >> index bc10e89b1ed..572aa86fa53 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
> >> @@ -36,6 +36,7 @@
> >>    #include <link.h>
> >>    #include <pthread.h>
> >>    #include <signal.h>
> >> +#include <sys/mman.h>
> >>    #include <sys/resource.h>
> >>    #include <syslog.h>
> >>
> >> @@ -48,6 +49,10 @@
> >>    #include <osreldate.h>
> >>    #include <sys/sysctl.h>
> >>    #define pthread_getattr_np pthread_attr_get_np
> >> +// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
> >> +// that, it was never implemented. So just define it to zero.
> >> +#undef MAP_NORESERVE
> >> +#define MAP_NORESERVE 0
> >>    #endif
> >>
> >>    #if SANITIZER_NETBSD
> >> @@ -183,85 +188,35 @@ __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
> >>    #endif
> >>    }
> >>
> >> -#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && \
> >> -    !SANITIZER_NETBSD && !SANITIZER_SOLARIS
> >> -static uptr g_tls_size;
> >> +// True if we can use dlpi_tls_data. glibc before 2.25 may leave NULL (BZ
> >> +// #19826) so dlpi_tls_data cannot be used.
> >> +//
> >> +// musl before 1.2.3 and FreeBSD as of 12.2 incorrectly set dlpi_tls_data to
> >> +// the TLS initialization image
> >> +// https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=254774
> >> +__attribute__((unused)) static int g_use_dlpi_tls_data;
> >>
> >> -#ifdef __i386__
> >> -#define CHECK_GET_TLS_STATIC_INFO_VERSION (!__GLIBC_PREREQ(2, 27))
> >> -#else
> >> -#define CHECK_GET_TLS_STATIC_INFO_VERSION 0
> >> -#endif
> >> +#if SANITIZER_GLIBC && !SANITIZER_GO
> >> +__attribute__((unused)) static uptr g_tls_size;
> >> +void InitTlsSize() {
> >> +  int major, minor, patch;
> >> +  g_use_dlpi_tls_data =
> >> +      GetLibcVersion(&major, &minor, &patch) && major == 2 && minor >= 25;
> >>
> >> -#if CHECK_GET_TLS_STATIC_INFO_VERSION
> >> -#define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
> >> -#else
> >> -#define DL_INTERNAL_FUNCTION
> >> +#if defined(__x86_64__) || defined(__powerpc64__)
> >> +  void *get_tls_static_info = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
> >> +  size_t tls_align;
> >> +  ((void (*)(size_t *, size_t *))get_tls_static_info)(&g_tls_size, &tls_align);
> >>    #endif
> >> -
> >> -namespace {
> >> -struct GetTlsStaticInfoCall {
> >> -  typedef void (*get_tls_func)(size_t*, size_t*);
> >> -};
> >> -struct GetTlsStaticInfoRegparmCall {
> >> -  typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
> >> -};
> >> -
> >> -template <typename T>
> >> -void CallGetTls(void* ptr, size_t* size, size_t* align) {
> >> -  typename T::get_tls_func get_tls;
> >> -  CHECK_EQ(sizeof(get_tls), sizeof(ptr));
> >> -  internal_memcpy(&get_tls, &ptr, sizeof(ptr));
> >> -  CHECK_NE(get_tls, 0);
> >> -  get_tls(size, align);
> >> -}
> >> -
> >> -bool CmpLibcVersion(int major, int minor, int patch) {
> >> -  int ma;
> >> -  int mi;
> >> -  int pa;
> >> -  if (!GetLibcVersion(&ma, &mi, &pa))
> >> -    return false;
> >> -  if (ma > major)
> >> -    return true;
> >> -  if (ma < major)
> >> -    return false;
> >> -  if (mi > minor)
> >> -    return true;
> >> -  if (mi < minor)
> >> -    return false;
> >> -  return pa >= patch;
> >> -}
> >> -
> >> -}  // namespace
> >> -
> >> -void InitTlsSize() {
> >> -  // all current supported platforms have 16 bytes stack alignment
> >> -  const size_t kStackAlign = 16;
> >> -  void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
> >> -  size_t tls_size = 0;
> >> -  size_t tls_align = 0;
> >> -  // On i?86, _dl_get_tls_static_info used to be internal_function, i.e.
> >> -  // __attribute__((regparm(3), stdcall)) before glibc 2.27 and is normal
> >> -  // function in 2.27 and later.
> >> -  if (CHECK_GET_TLS_STATIC_INFO_VERSION && !CmpLibcVersion(2, 27, 0))
> >> -    CallGetTls<GetTlsStaticInfoRegparmCall>(get_tls_static_info_ptr,
> >> -                                            &tls_size, &tls_align);
> >> -  else
> >> -    CallGetTls<GetTlsStaticInfoCall>(get_tls_static_info_ptr,
> >> -                                     &tls_size, &tls_align);
> >> -  if (tls_align < kStackAlign)
> >> -    tls_align = kStackAlign;
> >> -  g_tls_size = RoundUpTo(tls_size, tls_align);
> >>    }
> >>    #else
> >>    void InitTlsSize() { }
> >> -#endif
> >> +#endif  // SANITIZER_GLIBC && !SANITIZER_GO
> >>
> >> -#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) ||       \
> >> -     defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \
> >> -     defined(__arm__) || SANITIZER_RISCV64) &&                              \
> >> -    SANITIZER_LINUX && !SANITIZER_ANDROID
> >> +// On glibc x86_64, ThreadDescriptorSize() needs to be precise due to the usage
> >> +// of g_tls_size. On other targets, ThreadDescriptorSize() is only used by lsan
> >> +// to get the pointer to thread-specific data keys in the thread control block.
> >> +#if (SANITIZER_FREEBSD || SANITIZER_LINUX) && !SANITIZER_ANDROID
> >>    // sizeof(struct pthread) from glibc.
> >>    static atomic_uintptr_t thread_descriptor_size;
> >>
> >> @@ -294,9 +249,18 @@ uptr ThreadDescriptorSize() {
> >>          val = FIRST_32_SECOND_64(1168, 2288);
> >>        else if (minor <= 14)
> >>          val = FIRST_32_SECOND_64(1168, 2304);
> >> -    else
> >> +    else if (minor < 32)  // Unknown version
> >>          val = FIRST_32_SECOND_64(1216, 2304);
> >> +    else  // minor == 32
> >> +      val = FIRST_32_SECOND_64(1344, 2496);
> >>      }
> >> +#elif defined(__s390__) || defined(__sparc__)
> >> +  // The size of a prefix of TCB including pthread::{specific_1stblock,specific}
> >> +  // suffices. Just return offsetof(struct pthread, specific_used), which hasn't
> >> +  // changed since 2007-05. Technically this applies to i386/x86_64 as well but
> >> +  // we call _dl_get_tls_static_info and need the precise size of struct
> >> +  // pthread.
> >> +  return FIRST_32_SECOND_64(524, 1552);
> >>    #elif defined(__mips__)
> >>      // TODO(sagarthakur): add more values as per different glibc versions.
> >>      val = FIRST_32_SECOND_64(1152, 1776);
> >> @@ -320,21 +284,12 @@ uptr ThreadDescriptorSize() {
> >>      val = 1776;
> >>    #elif defined(__powerpc64__)
> >>      val = 1776; // from glibc.ppc64le 2.20-8.fc21
> >> -#elif defined(__s390__)
> >> -  val = FIRST_32_SECOND_64(1152, 1776); // valid for glibc 2.22
> >>    #endif
> >>      if (val)
> >>        atomic_store_relaxed(&thread_descriptor_size, val);
> >>      return val;
> >>    }
> >>
> >> -// The offset at which pointer to self is located in the thread descriptor.
> >> -const uptr kThreadSelfOffset = FIRST_32_SECOND_64(8, 16);
> >> -
> >> -uptr ThreadSelfOffset() {
> >> -  return kThreadSelfOffset;
> >> -}
> >> -
> >>    #if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
> >>    // TlsPreTcbSize includes size of struct pthread_descr and size of tcb
> >>    // head structure. It lies before the static tls blocks.
> >> @@ -353,68 +308,74 @@ static uptr TlsPreTcbSize() {
> >>    }
> >>    #endif
> >>
> >> -uptr ThreadSelf() {
> >> -  uptr descr_addr;
> >> -#if defined(__i386__)
> >> -  asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
> >> -#elif defined(__x86_64__)
> >> -  asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
> >> -#elif defined(__mips__)
> >> -  // MIPS uses TLS variant I. The thread pointer (in hardware register $29)
> >> -  // points to the end of the TCB + 0x7000. The pthread_descr structure is
> >> -  // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
> >> -  // TCB and the size of pthread_descr.
> >> -  const uptr kTlsTcbOffset = 0x7000;
> >> -  uptr thread_pointer;
> >> -  asm volatile(".set push;\
> >> -                .set mips64r2;\
> >> -                rdhwr %0,$29;\
> >> -                .set pop" : "=r" (thread_pointer));
> >> -  descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
> >> -#elif defined(__aarch64__) || defined(__arm__)
> >> -  descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
> >> -                                      ThreadDescriptorSize();
> >> -#elif SANITIZER_RISCV64
> >> -  // https://github.com/riscv/riscv-elf-psabi-doc/issues/53
> >> -  uptr thread_pointer = reinterpret_cast<uptr>(__builtin_thread_pointer());
> >> -  descr_addr = thread_pointer - TlsPreTcbSize();
> >> -#elif defined(__s390__)
> >> -  descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer());
> >> -#elif defined(__powerpc64__)
> >> -  // PPC64LE uses TLS variant I. The thread pointer (in GPR 13)
> >> -  // points to the end of the TCB + 0x7000. The pthread_descr structure is
> >> -  // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
> >> -  // TCB and the size of pthread_descr.
> >> -  const uptr kTlsTcbOffset = 0x7000;
> >> -  uptr thread_pointer;
> >> -  asm("addi %0,13,%1" : "=r"(thread_pointer) : "I"(-kTlsTcbOffset));
> >> -  descr_addr = thread_pointer - TlsPreTcbSize();
> >> -#else
> >> -#error "unsupported CPU arch"
> >> -#endif
> >> -  return descr_addr;
> >> -}
> >> -#endif  // (x86_64 || i386 || MIPS) && SANITIZER_LINUX
> >> +#if !SANITIZER_GO
> >> +namespace {
> >> +struct TlsBlock {
> >> +  uptr begin, end, align;
> >> +  size_t tls_modid;
> >> +  bool operator<(const TlsBlock &rhs) const { return begin < rhs.begin; }
> >> +};
> >> +}  // namespace
> >>
> >> -#if SANITIZER_FREEBSD
> >> -static void **ThreadSelfSegbase() {
> >> -  void **segbase = 0;
> >> -#if defined(__i386__)
> >> -  // sysarch(I386_GET_GSBASE, segbase);
> >> -  __asm __volatile("mov %%gs:0, %0" : "=r" (segbase));
> >> -#elif defined(__x86_64__)
> >> -  // sysarch(AMD64_GET_FSBASE, segbase);
> >> -  __asm __volatile("movq %%fs:0, %0" : "=r" (segbase));
> >> -#else
> >> -#error "unsupported CPU arch"
> >> +extern "C" void *__tls_get_addr(size_t *);
> >> +
> >> +static int CollectStaticTlsBlocks(struct dl_phdr_info *info, size_t size,
> >> +                                  void *data) {
> >> +  if (!info->dlpi_tls_modid)
> >> +    return 0;
> >> +  uptr begin = (uptr)info->dlpi_tls_data;
> >> +#ifndef __s390__
> >> +  if (!g_use_dlpi_tls_data) {
> >> +    // Call __tls_get_addr as a fallback. This forces TLS allocation on glibc
> >> +    // and FreeBSD.
> >> +    size_t mod_and_off[2] = {info->dlpi_tls_modid, 0};
> >> +    begin = (uptr)__tls_get_addr(mod_and_off);
> >> +  }
> >>    #endif
> >> -  return segbase;
> >> +  for (unsigned i = 0; i != info->dlpi_phnum; ++i)
> >> +    if (info->dlpi_phdr[i].p_type == PT_TLS) {
> >> +      static_cast<InternalMmapVector<TlsBlock> *>(data)->push_back(
> >> +          TlsBlock{begin, begin + info->dlpi_phdr[i].p_memsz,
> >> +                   info->dlpi_phdr[i].p_align, info->dlpi_tls_modid});
> >> +      break;
> >> +    }
> >> +  return 0;
> >>    }
> >>
> >> -uptr ThreadSelf() {
> >> -  return (uptr)ThreadSelfSegbase()[2];
> >> -}
> >> -#endif  // SANITIZER_FREEBSD
> >> +__attribute__((unused)) static void GetStaticTlsBoundary(uptr *addr, uptr *size,
> >> +                                                         uptr *align) {
> >> +  InternalMmapVector<TlsBlock> ranges;
> >> +  dl_iterate_phdr(CollectStaticTlsBlocks, &ranges);
> >> +  uptr len = ranges.size();
> >> +  Sort(ranges.begin(), len);
> >> +  // Find the range with tls_modid=1. For glibc, because libc.so uses PT_TLS,
> >> +  // this module is guaranteed to exist and is one of the initially loaded
> >> +  // modules.
> >> +  uptr one = 0;
> >> +  while (one != len && ranges[one].tls_modid != 1) ++one;
> >> +  if (one == len) {
> >> +    // This may happen with musl if no module uses PT_TLS.
> >> +    *addr = 0;
> >> +    *size = 0;
> >> +    *align = 1;
> >> +    return;
> >> +  }
> >> +  // Find the maximum consecutive ranges. We consider two modules consecutive if
> >> +  // the gap is smaller than the alignment. The dynamic loader places static TLS
> >> +  // blocks this way not to waste space.
> >> +  uptr l = one;
> >> +  *align = ranges[l].align;
> >> +  while (l != 0 && ranges[l].begin < ranges[l - 1].end + ranges[l - 1].align)
> >> +    *align = Max(*align, ranges[--l].align);
> >> +  uptr r = one + 1;
> >> +  while (r != len && ranges[r].begin < ranges[r - 1].end + ranges[r - 1].align)
> >> +    *align = Max(*align, ranges[r++].align);
> >> +  *addr = ranges[l].begin;
> >> +  *size = ranges[r - 1].end - ranges[l].begin;
> >> +}
> >> +#endif  // !SANITIZER_GO
> >> +#endif  // (x86_64 || i386 || mips || ...) && (SANITIZER_FREEBSD ||
> >> +        // SANITIZER_LINUX) && !SANITIZER_ANDROID
> >>
> >>    #if SANITIZER_NETBSD
> >>    static struct tls_tcb * ThreadSelfTlsTcb() {
> >> @@ -465,33 +426,67 @@ static void GetTls(uptr *addr, uptr *size) {
> >>        *addr = 0;
> >>        *size = 0;
> >>      }
> >> -#elif SANITIZER_LINUX
> >> -#if defined(__x86_64__) || defined(__i386__) || defined(__s390__)
> >> -  *addr = ThreadSelf();
> >> -  *size = GetTlsSize();
> >> +#elif SANITIZER_GLIBC && defined(__x86_64__)
> >> +  // For x86-64, use an O(1) approach which requires precise
> >> +  // ThreadDescriptorSize. g_tls_size was initialized in InitTlsSize.
> >> +  asm("mov %%fs:16,%0" : "=r"(*addr));
> >> +  *size = g_tls_size;
> >>      *addr -= *size;
> >>      *addr += ThreadDescriptorSize();
> >> -#elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) || \
> >> -    defined(__arm__) || SANITIZER_RISCV64
> >> -  *addr = ThreadSelf();
> >> -  *size = GetTlsSize();
> >> +#elif SANITIZER_GLIBC && defined(__powerpc64__)
> >> +  // Workaround for glibc<2.25(?). 2.27 is known to not need this.
> >> +  uptr tp;
> >> +  asm("addi %0,13,-0x7000" : "=r"(tp));
> >> +  const uptr pre_tcb_size = TlsPreTcbSize();
> >> +  *addr = tp - pre_tcb_size;
> >> +  *size = g_tls_size + pre_tcb_size;
> >> +#elif SANITIZER_FREEBSD || SANITIZER_LINUX
> >> +  uptr align;
> >> +  GetStaticTlsBoundary(addr, size, &align);
> >> +#if defined(__x86_64__) || defined(__i386__) || defined(__s390__) || \
> >> +    defined(__sparc__)
> >> +  if (SANITIZER_GLIBC) {
> >> +#if defined(__x86_64__) || defined(__i386__)
> >> +    align = Max<uptr>(align, 64);
> >>    #else
> >> -  *addr = 0;
> >> -  *size = 0;
> >> +    align = Max<uptr>(align, 16);
> >>    #endif
> >> -#elif SANITIZER_FREEBSD
> >> -  void** segbase = ThreadSelfSegbase();
> >> -  *addr = 0;
> >> -  *size = 0;
> >> -  if (segbase != 0) {
> >> -    // tcbalign = 16
> >> -    // tls_size = round(tls_static_space, tcbalign);
> >> -    // dtv = segbase[1];
> >> -    // dtv[2] = segbase - tls_static_space;
> >> -    void **dtv = (void**) segbase[1];
> >> -    *addr = (uptr) dtv[2];
> >> -    *size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]);
> >>      }
> >> +  const uptr tp = RoundUpTo(*addr + *size, align);
> >> +
> >> +  // lsan requires the range to additionally cover the static TLS surplus
> >> +  // (elf/dl-tls.c defines 1664). Otherwise there may be false positives for
> >> +  // allocations only referenced by tls in dynamically loaded modules.
> >> +  if (SANITIZER_GLIBC)
> >> +    *size += 1644;
> >> +  else if (SANITIZER_FREEBSD)
> >> +    *size += 128;  // RTLD_STATIC_TLS_EXTRA
> >> +
> >> +  // Extend the range to include the thread control block. On glibc, lsan needs
> >> +  // the range to include pthread::{specific_1stblock,specific} so that
> >> +  // allocations only referenced by pthread_setspecific can be scanned. This may
> >> +  // underestimate by at most TLS_TCB_ALIGN-1 bytes but it should be fine
> >> +  // because the number of bytes after pthread::specific is larger.
> >> +  *addr = tp - RoundUpTo(*size, align);
> >> +  *size = tp - *addr + ThreadDescriptorSize();
> >> +#else
> >> +  if (SANITIZER_GLIBC)
> >> +    *size += 1664;
> >> +  else if (SANITIZER_FREEBSD)
> >> +    *size += 128;  // RTLD_STATIC_TLS_EXTRA
> >> +#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
> >> +  const uptr pre_tcb_size = TlsPreTcbSize();
> >> +  *addr -= pre_tcb_size;
> >> +  *size += pre_tcb_size;
> >> +#else
> >> +  // arm and aarch64 reserve two words at TP, so this underestimates the range.
> >> +  // However, this is sufficient for the purpose of finding the pointers to
> >> +  // thread-specific data keys.
> >> +  const uptr tcb_size = ThreadDescriptorSize();
> >> +  *addr -= tcb_size;
> >> +  *size += tcb_size;
> >> +#endif
> >> +#endif
> >>    #elif SANITIZER_NETBSD
> >>      struct tls_tcb * const tcb = ThreadSelfTlsTcb();
> >>      *addr = 0;
> >> @@ -518,15 +513,13 @@ static void GetTls(uptr *addr, uptr *size) {
> >>
> >>    #if !SANITIZER_GO
> >>    uptr GetTlsSize() {
> >> -#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD || \
> >> +#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
> >>        SANITIZER_SOLARIS
> >>      uptr addr, size;
> >>      GetTls(&addr, &size);
> >>      return size;
> >> -#elif defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
> >> -  return RoundUpTo(g_tls_size + TlsPreTcbSize(), 16);
> >>    #else
> >> -  return g_tls_size;
> >> +  return 0;
> >>    #endif
> >>    }
> >>    #endif
> >> @@ -547,10 +540,9 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
> >>      if (!main) {
> >>        // If stack and tls intersect, make them non-intersecting.
> >>        if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
> >> -      CHECK_GT(*tls_addr + *tls_size, *stk_addr);
> >> -      CHECK_LE(*tls_addr + *tls_size, *stk_addr + *stk_size);
> >> -      *stk_size -= *tls_size;
> >> -      *tls_addr = *stk_addr + *stk_size;
> >> +      if (*stk_addr + *stk_size < *tls_addr + *tls_size)
> >> +        *tls_size = *stk_addr + *stk_size - *tls_addr;
> >> +      *stk_size = *tls_addr - *stk_addr;
> >>        }
> >>      }
> >>    #endif
> >> @@ -569,20 +561,12 @@ struct DlIteratePhdrData {
> >>      bool first;
> >>    };
> >>
> >> -static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
> >> -  DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
> >> -  InternalScopedString module_name(kMaxPathLength);
> >> -  if (data->first) {
> >> -    data->first = false;
> >> -    // First module is the binary itself.
> >> -    ReadBinaryNameCached(module_name.data(), module_name.size());
> >> -  } else if (info->dlpi_name) {
> >> -    module_name.append("%s", info->dlpi_name);
> >> -  }
> >> +static int AddModuleSegments(const char *module_name, dl_phdr_info *info,
> >> +                             InternalMmapVectorNoCtor<LoadedModule> *modules) {
> >>      if (module_name[0] == '\0')
> >>        return 0;
> >>      LoadedModule cur_module;
> >> -  cur_module.set(module_name.data(), info->dlpi_addr);
> >> +  cur_module.set(module_name, info->dlpi_addr);
> >>      for (int i = 0; i < (int)info->dlpi_phnum; i++) {
> >>        const Elf_Phdr *phdr = &info->dlpi_phdr[i];
> >>        if (phdr->p_type == PT_LOAD) {
> >> @@ -594,7 +578,26 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
> >>                                     writable);
> >>        }
> >>      }
> >> -  data->modules->push_back(cur_module);
> >> +  modules->push_back(cur_module);
> >> +  return 0;
> >> +}
> >> +
> >> +static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
> >> +  DlIteratePhdrData *data = (DlIteratePhdrData *)arg;
> >> +  if (data->first) {
> >> +    InternalMmapVector<char> module_name(kMaxPathLength);
> >> +    data->first = false;
> >> +    // First module is the binary itself.
> >> +    ReadBinaryNameCached(module_name.data(), module_name.size());
> >> +    return AddModuleSegments(module_name.data(), info, data->modules);
> >> +  }
> >> +
> >> +  if (info->dlpi_name) {
> >> +    InternalScopedString module_name;
> >> +    module_name.append("%s", info->dlpi_name);
> >> +    return AddModuleSegments(module_name.data(), info, data->modules);
> >> +  }
> >> +
> >>      return 0;
> >>    }
> >>
> >> @@ -729,13 +732,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
> >>    }
> >>
> >> @@ -802,20 +801,13 @@ void LogMessageOnPrintf(const char *str) {
> >>
> >>    #endif  // SANITIZER_LINUX
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_GO
> >> +#if SANITIZER_GLIBC && !SANITIZER_GO
> >>    // glibc crashes when using clock_gettime from a preinit_array function as the
> >>    // vDSO function pointers haven't been initialized yet. __progname is
> >>    // initialized after the vDSO function pointers, so if it exists, is not null
> >>    // and is not empty, we can use clock_gettime.
> >>    extern "C" SANITIZER_WEAK_ATTRIBUTE char *__progname;
> >> -inline bool CanUseVDSO() {
> >> -  // Bionic is safe, it checks for the vDSO function pointers to be initialized.
> >> -  if (SANITIZER_ANDROID)
> >> -    return true;
> >> -  if (&__progname && __progname && *__progname)
> >> -    return true;
> >> -  return false;
> >> -}
> >> +inline bool CanUseVDSO() { return &__progname && __progname && *__progname; }
> >>
> >>    // MonotonicNanoTime is a timing function that can leverage the vDSO by calling
> >>    // clock_gettime. real_clock_gettime only exists if clock_gettime is
> >> @@ -835,13 +827,13 @@ u64 MonotonicNanoTime() {
> >>      return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
> >>    }
> >>    #else
> >> -// Non-Linux & Go always use the syscall.
> >> +// Non-glibc & Go always use the regular function.
> >>    u64 MonotonicNanoTime() {
> >>      timespec ts;
> >> -  internal_clock_gettime(CLOCK_MONOTONIC, &ts);
> >> +  clock_gettime(CLOCK_MONOTONIC, &ts);
> >>      return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
> >>    }
> >> -#endif  // SANITIZER_LINUX && !SANITIZER_GO
> >> +#endif  // SANITIZER_GLIBC && !SANITIZER_GO
> >>
> >>    void ReExec() {
> >>      const char *pathname = "/proc/self/exe";
> >> @@ -910,6 +902,65 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
> >>      return shadow_start;
> >>    }
> >>
> >> +static uptr MmapSharedNoReserve(uptr addr, uptr size) {
> >> +  return internal_mmap(
> >> +      reinterpret_cast<void *>(addr), size, PROT_READ | PROT_WRITE,
> >> +      MAP_FIXED | MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
> >> +}
> >> +
> >> +static uptr MremapCreateAlias(uptr base_addr, uptr alias_addr,
> >> +                              uptr alias_size) {
> >> +#if SANITIZER_LINUX
> >> +  return internal_mremap(reinterpret_cast<void *>(base_addr), 0, alias_size,
> >> +                         MREMAP_MAYMOVE | MREMAP_FIXED,
> >> +                         reinterpret_cast<void *>(alias_addr));
> >> +#else
> >> +  CHECK(false && "mremap is not supported outside of Linux");
> >> +  return 0;
> >> +#endif
> >> +}
> >> +
> >> +static void CreateAliases(uptr start_addr, uptr alias_size, uptr num_aliases) {
> >> +  uptr total_size = alias_size * num_aliases;
> >> +  uptr mapped = MmapSharedNoReserve(start_addr, total_size);
> >> +  CHECK_EQ(mapped, start_addr);
> >> +
> >> +  for (uptr i = 1; i < num_aliases; ++i) {
> >> +    uptr alias_addr = start_addr + i * alias_size;
> >> +    CHECK_EQ(MremapCreateAlias(start_addr, alias_addr, alias_size), alias_addr);
> >> +  }
> >> +}
> >> +
> >> +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
> >> +                                uptr num_aliases, uptr ring_buffer_size) {
> >> +  CHECK_EQ(alias_size & (alias_size - 1), 0);
> >> +  CHECK_EQ(num_aliases & (num_aliases - 1), 0);
> >> +  CHECK_EQ(ring_buffer_size & (ring_buffer_size - 1), 0);
> >> +
> >> +  const uptr granularity = GetMmapGranularity();
> >> +  shadow_size = RoundUpTo(shadow_size, granularity);
> >> +  CHECK_EQ(shadow_size & (shadow_size - 1), 0);
> >> +
> >> +  const uptr alias_region_size = alias_size * num_aliases;
> >> +  const uptr alignment =
> >> +      2 * Max(Max(shadow_size, alias_region_size), ring_buffer_size);
> >> +  const uptr left_padding = ring_buffer_size;
> >> +
> >> +  const uptr right_size = alignment;
> >> +  const uptr map_size = left_padding + 2 * alignment;
> >> +
> >> +  const uptr map_start = reinterpret_cast<uptr>(MmapNoAccess(map_size));
> >> +  CHECK_NE(map_start, static_cast<uptr>(-1));
> >> +  const uptr right_start = RoundUpTo(map_start + left_padding, alignment);
> >> +
> >> +  UnmapFromTo(map_start, right_start - left_padding);
> >> +  UnmapFromTo(right_start + right_size, map_start + map_size);
> >> +
> >> +  CreateAliases(right_start + right_size / 2, alias_size, num_aliases);
> >> +
> >> +  return right_start;
> >> +}
> >> +
> >>    void InitializePlatformCommonFlags(CommonFlags *cf) {
> >>    #if SANITIZER_ANDROID
> >>      if (&__libc_get_static_tls_bounds == nullptr)
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h b/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h
> >> index 5d1b5264b5e..0e19c4d4a80 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_local_address_space_view.h
> >> @@ -7,7 +7,7 @@
> >>    //===----------------------------------------------------------------------===//
> >>    //
> >>    // `LocalAddressSpaceView` provides the local (i.e. target and current address
> >> -// space are the same) implementation of the `AddressSpaveView` interface which
> >> +// space are the same) implementation of the `AddressSpaceView` interface which
> >>    // provides a simple interface to load memory from another process (i.e.
> >>    // out-of-process)
> >>    //
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
> >> index 011ec6f4a0b..f4c6b442a14 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_mac.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
> >> @@ -37,13 +37,21 @@
> >>    extern char **environ;
> >>    #endif
> >>
> >> -#if defined(__has_include) && __has_include(<os/trace.h>) && defined(__BLOCKS__)
> >> +#if defined(__has_include) && __has_include(<os/trace.h>)
> >>    #define SANITIZER_OS_TRACE 1
> >>    #include <os/trace.h>
> >>    #else
> >>    #define SANITIZER_OS_TRACE 0
> >>    #endif
> >>
> >> +// import new crash reporting api
> >> +#if defined(__has_include) && __has_include(<CrashReporterClient.h>)
> >> +#define HAVE_CRASHREPORTERCLIENT_H 1
> >> +#include <CrashReporterClient.h>
> >> +#else
> >> +#define HAVE_CRASHREPORTERCLIENT_H 0
> >> +#endif
> >> +
> >>    #if !SANITIZER_IOS
> >>    #include <crt_externs.h>  // for _NSGetArgv and _NSGetEnviron
> >>    #else
> >> @@ -62,6 +70,7 @@ extern "C" {
> >>    #include <mach/mach_time.h>
> >>    #include <mach/vm_statistics.h>
> >>    #include <malloc/malloc.h>
> >> +#include <os/log.h>
> >>    #include <pthread.h>
> >>    #include <sched.h>
> >>    #include <signal.h>
> >> @@ -133,6 +142,12 @@ uptr internal_munmap(void *addr, uptr length) {
> >>      return munmap(addr, length);
> >>    }
> >>
> >> +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
> >> +                     void *new_address) {
> >> +  CHECK(false && "internal_mremap is unimplemented on Mac");
> >> +  return 0;
> >> +}
> >> +
> >>    int internal_mprotect(void *addr, uptr length, int prot) {
> >>      return mprotect(addr, length, prot);
> >>    }
> >> @@ -444,7 +459,7 @@ uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
> >>      // On OS X the executable path is saved to the stack by dyld. Reading it
> >>      // from there is much faster than calling dladdr, especially for large
> >>      // binaries with symbols.
> >> -  InternalScopedString exe_path(kMaxPathLength);
> >> +  InternalMmapVector<char> exe_path(kMaxPathLength);
> >>      uint32_t size = exe_path.size();
> >>      if (_NSGetExecutablePath(exe_path.data(), &size) == 0 &&
> >>          realpath(exe_path.data(), buf) != 0) {
> >> @@ -620,6 +635,23 @@ constexpr u16 GetOSMajorKernelOffset() {
> >>
> >>    using VersStr = char[64];
> >>
> >> +static uptr ApproximateOSVersionViaKernelVersion(VersStr vers) {
> >> +  u16 kernel_major = GetDarwinKernelVersion().major;
> >> +  u16 offset = GetOSMajorKernelOffset();
> >> +  CHECK_GE(kernel_major, offset);
> >> +  u16 os_major = kernel_major - offset;
> >> +
> >> +  const char *format = "%d.0";
> >> +  if (TARGET_OS_OSX) {
> >> +    if (os_major >= 16) {  // macOS 11+
> >> +      os_major -= 5;
> >> +    } else {  // macOS 10.15 and below
> >> +      format = "10.%d";
> >> +    }
> >> +  }
> >> +  return internal_snprintf(vers, sizeof(VersStr), format, os_major);
> >> +}
> >> +
> >>    static void GetOSVersion(VersStr vers) {
> >>      uptr len = sizeof(VersStr);
> >>      if (SANITIZER_IOSSIM) {
> >> @@ -633,17 +665,19 @@ static void GetOSVersion(VersStr vers) {
> >>      } else {
> >>        int res =
> >>            internal_sysctlbyname("kern.osproductversion", vers, &len, nullptr, 0);
> >> -    if (res) {
> >> -      // Fallback for XNU 17 (macOS 10.13) and below that do not provide the
> >> -      // `kern.osproductversion` property.
> >> -      u16 kernel_major = GetDarwinKernelVersion().major;
> >> -      u16 offset = GetOSMajorKernelOffset();
> >> -      CHECK_LE(kernel_major, 17);
> >> -      CHECK_GE(kernel_major, offset);
> >> -      u16 os_major = kernel_major - offset;
> >> -
> >> -      auto format = TARGET_OS_OSX ? "10.%d" : "%d.0";
> >> -      len = internal_snprintf(vers, len, format, os_major);
> >> +
> >> +    // XNU 17 (macOS 10.13) and below do not provide the sysctl
> >> +    // `kern.osproductversion` entry (res != 0).
> >> +    bool no_os_version = res != 0;
> >> +
> >> +    // For launchd, sanitizer initialization runs before sysctl is setup
> >> +    // (res == 0 && len != strlen(vers), vers is not a valid version).  However,
> >> +    // the kernel version `kern.osrelease` is available.
> >> +    bool launchd = (res == 0 && internal_strlen(vers) < 3);
> >> +    if (launchd) CHECK_EQ(internal_getpid(), 1);
> >> +
> >> +    if (no_os_version || launchd) {
> >> +      len = ApproximateOSVersionViaKernelVersion(vers);
> >>        }
> >>      }
> >>      CHECK_LT(len, sizeof(VersStr));
> >> @@ -681,7 +715,7 @@ static void MapToMacos(u16 *major, u16 *minor) {
> >>    }
> >>
> >>    static MacosVersion GetMacosAlignedVersionInternal() {
> >> -  VersStr vers;
> >> +  VersStr vers = {};
> >>      GetOSVersion(vers);
> >>
> >>      u16 major, minor;
> >> @@ -707,7 +741,7 @@ MacosVersion GetMacosAlignedVersion() {
> >>    }
> >>
> >>    DarwinKernelVersion GetDarwinKernelVersion() {
> >> -  VersStr vers;
> >> +  VersStr vers = {};
> >>      uptr len = sizeof(VersStr);
> >>      int res = internal_sysctlbyname("kern.osrelease", vers, &len, nullptr, 0);
> >>      CHECK_EQ(res, 0);
> >> @@ -751,7 +785,51 @@ static BlockingMutex syslog_lock(LINKER_INITIALIZED);
> >>    void WriteOneLineToSyslog(const char *s) {
> >>    #if !SANITIZER_GO
> >>      syslog_lock.CheckLocked();
> >> -  asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
> >> +  if (GetMacosAlignedVersion() >= MacosVersion(10, 12)) {
> >> +    os_log_error(OS_LOG_DEFAULT, "%{public}s", s);
> >> +  } else {
> >> +    asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
> >> +  }
> >> +#endif
> >> +}
> >> +
> >> +// buffer to store crash report application information
> >> +static char crashreporter_info_buff[__sanitizer::kErrorMessageBufferSize] = {};
> >> +static BlockingMutex crashreporter_info_mutex(LINKER_INITIALIZED);
> >> +
> >> +extern "C" {
> >> +// Integrate with crash reporter libraries.
> >> +#if HAVE_CRASHREPORTERCLIENT_H
> >> +CRASH_REPORTER_CLIENT_HIDDEN
> >> +struct crashreporter_annotations_t gCRAnnotations
> >> +    __attribute__((section("__DATA," CRASHREPORTER_ANNOTATIONS_SECTION))) = {
> >> +        CRASHREPORTER_ANNOTATIONS_VERSION,
> >> +        0,
> >> +        0,
> >> +        0,
> >> +        0,
> >> +        0,
> >> +        0,
> >> +#if CRASHREPORTER_ANNOTATIONS_VERSION > 4
> >> +        0,
> >> +#endif
> >> +};
> >> +
> >> +#else
> >> +// fall back to old crashreporter api
> >> +static const char *__crashreporter_info__ __attribute__((__used__)) =
> >> +    &crashreporter_info_buff[0];
> >> +asm(".desc ___crashreporter_info__, 0x10");
> >> +#endif
> >> +
> >> +}  // extern "C"
> >> +
> >> +static void CRAppendCrashLogMessage(const char *msg) {
> >> +  BlockingMutexLock l(&crashreporter_info_mutex);
> >> +  internal_strlcat(crashreporter_info_buff, msg,
> >> +                   sizeof(crashreporter_info_buff));
> >> +#if HAVE_CRASHREPORTERCLIENT_H
> >> +  (void)CRSetCrashLogMessage(crashreporter_info_buff);
> >>    #endif
> >>    }
> >>
> >> @@ -947,7 +1025,7 @@ void MaybeReexec() {
> >>      if (DyldNeedsEnvVariable() && !lib_is_in_env) {
> >>        // DYLD_INSERT_LIBRARIES is not set or does not contain the runtime
> >>        // library.
> >> -    InternalScopedString program_name(1024);
> >> +    InternalMmapVector<char> program_name(1024);
> >>        uint32_t buf_size = program_name.size();
> >>        _NSGetExecutablePath(program_name.data(), &buf_size);
> >>        char *new_env = const_cast<char*>(info.dli_fname);
> >> @@ -1066,7 +1144,7 @@ char **GetArgv() {
> >>      return *_NSGetArgv();
> >>    }
> >>
> >> -#if SANITIZER_IOS
> >> +#if SANITIZER_IOS && !SANITIZER_IOSSIM
> >>    // The task_vm_info struct is normally provided by the macOS SDK, but we need
> >>    // fields only available in 10.12+. Declare the struct manually to be able to
> >>    // build against older SDKs.
> >> @@ -1106,26 +1184,35 @@ static uptr GetTaskInfoMaxAddress() {
> >>
> >>    uptr GetMaxUserVirtualAddress() {
> >>      static uptr max_vm = GetTaskInfoMaxAddress();
> >> -  if (max_vm != 0)
> >> -    return max_vm - 1;
> >> +  if (max_vm != 0) {
> >> +    const uptr ret_value = max_vm - 1;
> >> +    CHECK_LE(ret_value, SANITIZER_MMAP_RANGE_SIZE);
> >> +    return ret_value;
> >> +  }
> >>
> >>      // xnu cannot provide vm address limit
> >>    # if SANITIZER_WORDSIZE == 32
> >> -  return 0xffe00000 - 1;
> >> +  constexpr uptr fallback_max_vm = 0xffe00000 - 1;
> >>    # else
> >> -  return 0x200000000 - 1;
> >> +  constexpr uptr fallback_max_vm = 0x200000000 - 1;
> >>    # endif
> >> +  static_assert(fallback_max_vm <= SANITIZER_MMAP_RANGE_SIZE,
> >> +                "Max virtual address must be less than mmap range size.");
> >> +  return fallback_max_vm;
> >>    }
> >>
> >>    #else // !SANITIZER_IOS
> >>
> >>    uptr GetMaxUserVirtualAddress() {
> >>    # if SANITIZER_WORDSIZE == 64
> >> -  return (1ULL << 47) - 1;  // 0x00007fffffffffffUL;
> >> +  constexpr uptr max_vm = (1ULL << 47) - 1;  // 0x00007fffffffffffUL;
> >>    # else // SANITIZER_WORDSIZE == 32
> >>      static_assert(SANITIZER_WORDSIZE == 32, "Wrong wordsize");
> >> -  return (1ULL << 32) - 1;  // 0xffffffff;
> >> +  constexpr uptr max_vm = (1ULL << 32) - 1;  // 0xffffffff;
> >>    # endif
> >> +  static_assert(max_vm <= SANITIZER_MMAP_RANGE_SIZE,
> >> +                "Max virtual address must be less than mmap range size.");
> >> +  return max_vm;
> >>    }
> >>    #endif
> >>
> >> @@ -1180,6 +1267,12 @@ uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
> >>      return shadow_start;
> >>    }
> >>
> >> +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
> >> +                                uptr num_aliases, uptr ring_buffer_size) {
> >> +  CHECK(false && "HWASan aliasing is unimplemented on Mac");
> >> +  return 0;
> >> +}
> >> +
> >>    uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
> >>                                  uptr *largest_gap_found,
> >>                                  uptr *max_occupied_addr) {
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_mac.h
> >> index a2c42b3bf4f..0b6af5a3c0e 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_mac.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_mac.h
> >> @@ -14,26 +14,6 @@
> >>
> >>    #include "sanitizer_common.h"
> >>    #include "sanitizer_platform.h"
> >> -
> >> -/* TARGET_OS_OSX is not present in SDKs before Darwin16 (macOS 10.12) use
> >> -   TARGET_OS_MAC (we have no support for iOS in any form for these versions,
> >> -   so there's no ambiguity).  */
> >> -#if !defined(TARGET_OS_OSX) && TARGET_OS_MAC
> >> -# define TARGET_OS_OSX 1
> >> -#endif
> >> -
> >> -/* Other TARGET_OS_xxx are not present on earlier versions, define them to
> >> -   0 (we have no support for them; they are not valid targets anyway).  */
> >> -#ifndef TARGET_OS_IOS
> >> -#define TARGET_OS_IOS 0
> >> -#endif
> >> -#ifndef TARGET_OS_TV
> >> -#define TARGET_OS_TV 0
> >> -#endif
> >> -#ifndef TARGET_OS_WATCH
> >> -#define TARGET_OS_WATCH 0
> >> -#endif
> >> -
> >>    #if SANITIZER_MAC
> >>    #include "sanitizer_posix.h"
> >>
> >> @@ -84,22 +64,5 @@ void RestrictMemoryToMaxAddress(uptr max_address);
> >>
> >>    }  // namespace __sanitizer
> >>
> >> -extern "C" {
> >> -static char __crashreporter_info_buff__[__sanitizer::kErrorMessageBufferSize] =
> >> -  {};
> >> -static const char *__crashreporter_info__ __attribute__((__used__)) =
> >> -  &__crashreporter_info_buff__[0];
> >> -asm(".desc ___crashreporter_info__, 0x10");
> >> -} // extern "C"
> >> -
> >> -namespace __sanitizer {
> >> -static BlockingMutex crashreporter_info_mutex(LINKER_INITIALIZED);
> >> -
> >> -inline void CRAppendCrashLogMessage(const char *msg) {
> >> -  BlockingMutexLock l(&crashreporter_info_mutex);
> >> -  internal_strlcat(__crashreporter_info_buff__, msg,
> >> -                   sizeof(__crashreporter_info_buff__)); }
> >> -}  // namespace __sanitizer
> >> -
> >>    #endif  // SANITIZER_MAC
> >>    #endif  // SANITIZER_MAC_H
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
> >> index 647bcdfe105..e3b664f68b6 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
> >> @@ -120,11 +120,7 @@ INTERCEPTOR(int, malloc_make_nonpurgeable, void *ptr) {
> >>
> >>    INTERCEPTOR(void, malloc_set_zone_name, malloc_zone_t *zone, const char *name) {
> >>      COMMON_MALLOC_ENTER();
> >> -  // Allocate |sizeof(COMMON_MALLOC_ZONE_NAME "-") + internal_strlen(name)|
> >> -  // bytes.
> >> -  size_t buflen =
> >> -      sizeof(COMMON_MALLOC_ZONE_NAME "-") + (name ? internal_strlen(name) : 0);
> >> -  InternalScopedString new_name(buflen);
> >> +  InternalScopedString new_name;
> >>      if (name && zone->introspect == sanitizer_zone.introspect) {
> >>        new_name.append(COMMON_MALLOC_ZONE_NAME "-%s", name);
> >>        name = new_name.data();
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
> >> index 98ac7365da0..ac20f915fef 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_netbsd.cpp
> >> @@ -105,6 +105,12 @@ uptr internal_munmap(void *addr, uptr length) {
> >>      return _REAL(munmap, addr, length);
> >>    }
> >>
> >> +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
> >> +                     void *new_address) {
> >> +  CHECK(false && "internal_mremap is unimplemented on NetBSD");
> >> +  return 0;
> >> +}
> >> +
> >>    int internal_mprotect(void *addr, uptr length, int prot) {
> >>      DEFINE__REAL(int, mprotect, void *a, uptr b, int c);
> >>      return _REAL(mprotect, addr, length, prot);
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform.h b/libsanitizer/sanitizer_common/sanitizer_platform.h
> >> index b2372a025c0..2f6458431c8 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_platform.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_platform.h
> >> @@ -19,12 +19,25 @@
> >>    # error "This operating system is not supported"
> >>    #endif
> >>
> >> +// Get __GLIBC__ on a glibc platform. Exclude Android: features.h includes C
> >> +// function declarations into a .S file which doesn't compile.
> >> +// https://crbug.com/1162741
> >> +#if __has_include(<features.h>) && !defined(__ANDROID__)
> >> +#include <features.h>
> >> +#endif
> >> +
> >>    #if defined(__linux__)
> >>    # define SANITIZER_LINUX   1
> >>    #else
> >>    # define SANITIZER_LINUX   0
> >>    #endif
> >>
> >> +#if defined(__GLIBC__)
> >> +# define SANITIZER_GLIBC   1
> >> +#else
> >> +# define SANITIZER_GLIBC   0
> >> +#endif
> >> +
> >>    #if defined(__FreeBSD__)
> >>    # define SANITIZER_FREEBSD 1
> >>    #else
> >> @@ -46,6 +59,11 @@
> >>    #if defined(__APPLE__)
> >>    # define SANITIZER_MAC     1
> >>    # include <TargetConditionals.h>
> >> +# if TARGET_OS_OSX
> >> +#  define SANITIZER_OSX    1
> >> +# else
> >> +#  define SANITIZER_OSX    0
> >> +# endif
> >>    # if TARGET_OS_IPHONE
> >>    #  define SANITIZER_IOS    1
> >>    # else
> >> @@ -60,6 +78,7 @@
> >>    # define SANITIZER_MAC     0
> >>    # define SANITIZER_IOS     0
> >>    # define SANITIZER_IOSSIM  0
> >> +# define SANITIZER_OSX     0
> >>    #endif
> >>
> >>    #if defined(__APPLE__) && TARGET_OS_IPHONE && TARGET_OS_WATCH
> >> @@ -247,8 +266,12 @@
> >>    #define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 38)
> >>    #elif defined(__aarch64__)
> >>    # if SANITIZER_MAC
> >> -// Darwin iOS/ARM64 has a 36-bit VMA, 64GiB VM
> >> -#  define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 36)
> >> +#  if SANITIZER_OSX || SANITIZER_IOSSIM
> >> +#   define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47)
> >> +#  else
> >> +    // Darwin iOS/ARM64 has a 36-bit VMA, 64GiB VM
> >> +#   define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 36)
> >> +#  endif
> >>    # else
> >>    #  define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 48)
> >>    # endif
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
> >> index 18bab346ce6..731df710df5 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
> >> @@ -46,6 +46,12 @@
> >>    #define SI_LINUX_NOT_ANDROID 0
> >>    #endif
> >>
> >> +#if SANITIZER_GLIBC
> >> +#define SI_GLIBC 1
> >> +#else
> >> +#define SI_GLIBC 0
> >> +#endif
> >> +
> >>    #if SANITIZER_ANDROID
> >>    #define SI_ANDROID 1
> >>    #else
> >> @@ -159,7 +165,7 @@
> >>      SANITIZER_INTERCEPT_MEMCMP &&  \
> >>          ((SI_POSIX && _GNU_SOURCE) || SI_NETBSD || SI_FREEBSD)
> >>    #define SANITIZER_INTERCEPT_STRNDUP SI_POSIX
> >> -#define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD
> >> +#define SANITIZER_INTERCEPT___STRNDUP SI_GLIBC
> >>    #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
> >>        __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070
> >>    #define SI_MAC_DEPLOYMENT_BELOW_10_7 1
> >> @@ -183,8 +189,8 @@
> >>    #define SANITIZER_INTERCEPT_FPUTS SI_POSIX
> >>    #define SANITIZER_INTERCEPT_PUTS SI_POSIX
> >>
> >> -#define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
> >> -#define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
> >> +#define SANITIZER_INTERCEPT_PREAD64 (SI_GLIBC || SI_SOLARIS32)
> >> +#define SANITIZER_INTERCEPT_PWRITE64 (SI_GLIBC || SI_SOLARIS32)
> >>
> >>    #define SANITIZER_INTERCEPT_READV SI_POSIX
> >>    #define SANITIZER_INTERCEPT_WRITEV SI_POSIX
> >> @@ -192,8 +198,8 @@
> >>    #define SANITIZER_INTERCEPT_PREADV \
> >>      (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
> >>    #define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID
> >> -#define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID
> >> -#define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_PREADV64 SI_GLIBC
> >> +#define SANITIZER_INTERCEPT_PWRITEV64 SI_GLIBC
> >>
> >>    #define SANITIZER_INTERCEPT_PRCTL SI_LINUX
> >>
> >> @@ -201,16 +207,16 @@
> >>    #define SANITIZER_INTERCEPT_STRPTIME SI_POSIX
> >>
> >>    #define SANITIZER_INTERCEPT_SCANF SI_POSIX
> >> -#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_GLIBC
> >>
> >>    #ifndef SANITIZER_INTERCEPT_PRINTF
> >>    #define SANITIZER_INTERCEPT_PRINTF SI_POSIX
> >>    #define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD)
> >> -#define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_GLIBC
> >>    #endif
> >>
> >>    #define SANITIZER_INTERCEPT___PRINTF_CHK \
> >> -  (SANITIZER_INTERCEPT_PRINTF && SI_LINUX_NOT_ANDROID)
> >> +  (SANITIZER_INTERCEPT_PRINTF && SI_GLIBC)
> >>
> >>    #define SANITIZER_INTERCEPT_FREXP SI_NOT_FUCHSIA
> >>    #define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_POSIX
> >> @@ -220,13 +226,11 @@
> >>      (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >>    #define SANITIZER_INTERCEPT_GETPWENT \
> >>      (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> -#define SANITIZER_INTERCEPT_FGETGRENT_R \
> >> -  (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> +#define SANITIZER_INTERCEPT_FGETGRENT_R (SI_GLIBC || SI_SOLARIS)
> >>    #define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID || SI_SOLARIS
> >>    #define SANITIZER_INTERCEPT_GETPWENT_R \
> >> -  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> -#define SANITIZER_INTERCEPT_FGETPWENT_R \
> >> -  (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> +  (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
> >> +#define SANITIZER_INTERCEPT_FGETPWENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS)
> >>    #define SANITIZER_INTERCEPT_SETPWENT \
> >>      (SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >>    #define SANITIZER_INTERCEPT_CLOCK_GETTIME \
> >> @@ -234,8 +238,8 @@
> >>    #define SANITIZER_INTERCEPT_CLOCK_GETCPUCLOCKID SI_LINUX
> >>    #define SANITIZER_INTERCEPT_GETITIMER SI_POSIX
> >>    #define SANITIZER_INTERCEPT_TIME SI_POSIX
> >> -#define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID || SI_SOLARIS
> >> -#define SANITIZER_INTERCEPT_GLOB64 SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_GLOB (SI_GLIBC || SI_SOLARIS)
> >> +#define SANITIZER_INTERCEPT_GLOB64 SI_GLIBC
> >>    #define SANITIZER_INTERCEPT_WAIT SI_POSIX
> >>    #define SANITIZER_INTERCEPT_INET SI_POSIX
> >>    #define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_POSIX
> >> @@ -250,8 +254,7 @@
> >>      (SI_FREEBSD || SI_LINUX_NOT_ANDROID)
> >>    #define SANITIZER_INTERCEPT_GETHOSTBYADDR_R \
> >>      (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> -#define SANITIZER_INTERCEPT_GETHOSTENT_R \
> >> -  (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> +#define SANITIZER_INTERCEPT_GETHOSTENT_R (SI_FREEBSD || SI_GLIBC || SI_SOLARIS)
> >>    #define SANITIZER_INTERCEPT_GETSOCKOPT SI_POSIX
> >>    #define SANITIZER_INTERCEPT_ACCEPT SI_POSIX
> >>    #define SANITIZER_INTERCEPT_ACCEPT4 (SI_LINUX_NOT_ANDROID || SI_NETBSD)
> >> @@ -296,8 +299,7 @@
> >>      (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >>    #define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID || SI_SOLARIS
> >>    #define SANITIZER_INTERCEPT_REALPATH SI_POSIX
> >> -#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME \
> >> -  (SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> +#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME (SI_GLIBC || SI_SOLARIS)
> >>    #define SANITIZER_INTERCEPT_CONFSTR \
> >>      (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >>    #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
> >> @@ -324,7 +326,7 @@
> >>    #define SANITIZER_INTERCEPT_SIGPROCMASK SI_POSIX
> >>    #define SANITIZER_INTERCEPT_PTHREAD_SIGMASK SI_POSIX
> >>    #define SANITIZER_INTERCEPT_BACKTRACE \
> >> -  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> +  (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
> >>    #define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX
> >>    #define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
> >>    #define SANITIZER_INTERCEPT_STATFS \
> >> @@ -342,11 +344,11 @@
> >>    #define SANITIZER_INTERCEPT_SHMCTL                                       \
> >>      (((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64) || \
> >>       SI_NETBSD || SI_SOLARIS)  // NOLINT
> >> -#define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_RANDOM_R SI_GLIBC
> >>    #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_POSIX
> >>    #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \
> >>      (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> -#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_GLIBC
> >>    #define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET_SCHED SI_POSIX
> >>    #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED \
> >>      (SI_POSIX && !SI_NETBSD)
> >> @@ -360,7 +362,7 @@
> >>    #define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID
> >>    #define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED \
> >>      (SI_POSIX && !SI_NETBSD)
> >> -#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_GLIBC
> >>    #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED (SI_POSIX && !SI_NETBSD)
> >>    #define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK \
> >>      (SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> @@ -368,7 +370,7 @@
> >>      (SI_LINUX_NOT_ANDROID && !SI_NETBSD)
> >>    #define SANITIZER_INTERCEPT_THR_EXIT SI_FREEBSD
> >>    #define SANITIZER_INTERCEPT_TMPNAM SI_POSIX
> >> -#define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID || SI_SOLARIS
> >> +#define SANITIZER_INTERCEPT_TMPNAM_R (SI_GLIBC || SI_SOLARIS)
> >>    #define SANITIZER_INTERCEPT_PTSNAME SI_LINUX
> >>    #define SANITIZER_INTERCEPT_PTSNAME_R SI_LINUX
> >>    #define SANITIZER_INTERCEPT_TTYNAME SI_POSIX
> >> @@ -381,7 +383,7 @@
> >>    #define SANITIZER_INTERCEPT_LGAMMAL (SI_POSIX && !SI_NETBSD)
> >>    #define SANITIZER_INTERCEPT_LGAMMA_R (SI_FREEBSD || SI_LINUX || SI_SOLARIS)
> >>    #define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID || SI_SOLARIS
> >> -#define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_DRAND48_R SI_GLIBC
> >>    #define SANITIZER_INTERCEPT_RAND_R \
> >>      (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >>    #define SANITIZER_INTERCEPT_ICONV \
> >> @@ -396,12 +398,12 @@
> >>      (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_MAC || SI_SOLARIS)
> >>
> >>    #define SANITIZER_INTERCEPT_PTHREAD_MUTEX SI_POSIX
> >> -#define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT___PTHREAD_MUTEX SI_GLIBC
> >>    #define SANITIZER_INTERCEPT___LIBC_MUTEX SI_NETBSD
> >>    #define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \
> >> -  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> +  (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
> >>    #define SANITIZER_INTERCEPT_PTHREAD_GETNAME_NP \
> >> -  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> +  (SI_FREEBSD || SI_NETBSD || SI_GLIBC || SI_SOLARIS)
> >>
> >>    #define SANITIZER_INTERCEPT_TLS_GET_ADDR \
> >>      (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
> >> @@ -419,19 +421,19 @@
> >>    #else
> >>    #define SANITIZER_INTERCEPT_AEABI_MEM 0
> >>    #endif
> >> -#define SANITIZER_INTERCEPT___BZERO SI_MAC || SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT___BZERO SI_MAC || SI_GLIBC
> >>    #define SANITIZER_INTERCEPT_BZERO SI_LINUX_NOT_ANDROID
> >>    #define SANITIZER_INTERCEPT_FTIME (!SI_FREEBSD && !SI_NETBSD && SI_POSIX)
> >> -#define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID || SI_SOLARIS
> >> -#define SANITIZER_INTERCEPT_XDRREC SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_XDR (SI_GLIBC || SI_SOLARIS)
> >> +#define SANITIZER_INTERCEPT_XDRREC SI_GLIBC
> >>    #define SANITIZER_INTERCEPT_TSEARCH \
> >>      (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD || SI_SOLARIS)
> >> -#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_GLIBC
> >>    #define SANITIZER_INTERCEPT_FOPEN SI_POSIX
> >> -#define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
> >> +#define SANITIZER_INTERCEPT_FOPEN64 (SI_GLIBC || SI_SOLARIS32)
> >>    #define SANITIZER_INTERCEPT_OPEN_MEMSTREAM \
> >>      (SI_LINUX_NOT_ANDROID || SI_NETBSD || SI_SOLARIS)
> >> -#define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID
> >> +#define SANITIZER_INTERCEPT_OBSTACK SI_GLIBC
> >>    #define SANITIZER_INTERCEPT_FFLUSH SI_POSIX
> >>    #define SANITIZER_INTERCEPT_FCLOSE SI_POSIX
> >>
> >> @@ -456,7 +458,7 @@
> >>    #define SANITIZER_INTERCEPT_CTERMID_R (SI_MAC || SI_FREEBSD || SI_SOLARIS)
> >>
> >>    #define SANITIZER_INTERCEPTOR_HOOKS \
> >> -  (SI_LINUX || SI_MAC || SI_WINDOWS || SI_NETBSD)
> >> +  (SI_LINUX || SI_MAC || SI_WINDOWS || SI_FREEBSD || SI_NETBSD || SI_SOLARIS)
> >>    #define SANITIZER_INTERCEPT_RECV_RECVFROM SI_POSIX
> >>    #define SANITIZER_INTERCEPT_SEND_SENDTO SI_POSIX
> >>    #define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE SI_LINUX
> >> @@ -479,20 +481,12 @@
> >>
> >>    #define SANITIZER_INTERCEPT_MMAP SI_POSIX
> >>    #define SANITIZER_INTERCEPT_MMAP64 SI_LINUX_NOT_ANDROID
> >> -#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO                             \
> >> -  (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA && SI_NOT_RTEMS && \
> >> -   !SI_SOLARIS)  // NOLINT
> >> +#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO (SI_GLIBC || SI_ANDROID)
> >>    #define SANITIZER_INTERCEPT_MEMALIGN \
> >>      (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_RTEMS)
> >> -#define SANITIZER_INTERCEPT___LIBC_MEMALIGN                               \
> >> -  (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && !SI_OPENBSD && SI_NOT_RTEMS && \
> >> -   !SI_ANDROID)  // NOLINT
> >> -#define SANITIZER_INTERCEPT_PVALLOC                                          \
> >> -  (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA && SI_NOT_RTEMS && \
> >> -   !SI_SOLARIS)  // NOLINT
> >> -#define SANITIZER_INTERCEPT_CFREE                                            \
> >> -  (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA && SI_NOT_RTEMS && \
> >> -   !SI_SOLARIS && !SANITIZER_ANDROID)  // NOLINT
> >> +#define SANITIZER_INTERCEPT___LIBC_MEMALIGN SI_GLIBC
> >> +#define SANITIZER_INTERCEPT_PVALLOC (SI_GLIBC || SI_ANDROID)
> >> +#define SANITIZER_INTERCEPT_CFREE (SI_GLIBC && !SANITIZER_RISCV64)
> >>    #define SANITIZER_INTERCEPT_REALLOCARRAY SI_POSIX
> >>    #define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC && SI_NOT_RTEMS)
> >>    #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_NETBSD)
> >> @@ -532,7 +526,7 @@
> >>    #define SANITIZER_INTERCEPT_STRMODE (SI_NETBSD || SI_FREEBSD)
> >>    #define SANITIZER_INTERCEPT_TTYENT SI_NETBSD
> >>    #define SANITIZER_INTERCEPT_PROTOENT (SI_NETBSD || SI_LINUX)
> >> -#define SANITIZER_INTERCEPT_PROTOENT_R (SI_LINUX_NOT_ANDROID)
> >> +#define SANITIZER_INTERCEPT_PROTOENT_R SI_GLIBC
> >>    #define SANITIZER_INTERCEPT_NETENT SI_NETBSD
> >>    #define SANITIZER_INTERCEPT_SETVBUF \
> >>      (SI_NETBSD || SI_FREEBSD || SI_LINUX || SI_MAC)
> >> @@ -583,7 +577,7 @@
> >>    #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_QSORT_R SI_GLIBC
> >>    // sigaltstack on i386 macOS cannot be intercepted due to setjmp()
> >>    // calling it and assuming that it does not clobber registers.
> >>    #define SANITIZER_INTERCEPT_SIGALTSTACK \
> >> @@ -591,4 +585,25 @@
> >>    #define SANITIZER_INTERCEPT_UNAME (SI_POSIX && !SI_FREEBSD)
> >>    #define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD
> >>
> >> +// This macro gives a way for downstream users to override the above
> >> +// interceptor macros irrespective of the platform they are on. They have
> >> +// to do two things:
> >> +// 1. Build compiler-rt with -DSANITIZER_OVERRIDE_INTERCEPTORS.
> >> +// 2. Provide a header file named sanitizer_intercept_overriders.h in the
> >> +//    include path for their compiler-rt build.
> >> +// An example of an overrider for strlen interceptor that one can list in
> >> +// sanitizer_intercept_overriders.h is as follows:
> >> +//
> >> +// #ifdef SANITIZER_INTERCEPT_STRLEN
> >> +// #undef SANITIZER_INTERCEPT_STRLEN
> >> +// #define SANITIZER_INTERCEPT_STRLEN <value of choice>
> >> +// #endif
> >> +//
> >> +// This "feature" is useful for downstream users who do not want some of
> >> +// their libc funtions to be intercepted. They can selectively disable
> >> +// interception of those functions.
> >> +#ifdef SANITIZER_OVERRIDE_INTERCEPTORS
> >> +#include <sanitizer_intercept_overriders.h>
> >> +#endif
> >> +
> >>    #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 b1c15be58de..b5a45ae72cd 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
> >> @@ -35,7 +35,10 @@
> >>    #include <sys/stat.h>
> >>    #include <sys/statvfs.h>
> >>    #include <sys/time.h>
> >> +#pragma clang diagnostic push
> >> +#pragma clang diagnostic ignored "-W#warnings"
> >>    #include <sys/timeb.h>
> >> +#pragma clang diagnostic pop
> >>    #include <sys/times.h>
> >>    #include <sys/timespec.h>
> >>    #include <sys/types.h>
> >> 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 <sys/stat.h>, struct stat
> >> -// takes the form of struct stat64 on 32-bit platforms if _FILE_OFFSET_BITS=64.
> >> -// Also, for some platforms (e.g. mips) there are additional members in the
> >> -// <sys/stat.h> struct stat:s.
> >> +// fine with newer headers, too.
> >>    #include <linux/posix_types.h>
> >> -#if defined(__x86_64__)
> >> +#if defined(__x86_64__) ||  defined(__mips__)
> >>    #include <sys/stat.h>
> >>    #else
> >>    #define ino_t __kernel_ino_t
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
> >> index 1427cec48c4..35a690cba5c 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
> >> @@ -11,18 +11,19 @@
> >>    // Sizes and layouts of platform-specific POSIX data structures.
> >>    //===----------------------------------------------------------------------===//
> >>
> >> -#include "sanitizer_platform.h"
> >> -
> >> -#if SANITIZER_LINUX || SANITIZER_MAC
> >> +#if defined(__linux__) || defined(__APPLE__)
> >>    // Tests in this file assume that off_t-dependent data structures match the
> >>    // libc ABI. For example, struct dirent here is what readdir() function (as
> >>    // exported from libc) returns, and not the user-facing "dirent", which
> >>    // depends on _FILE_OFFSET_BITS setting.
> >>    // To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below.
> >> -#ifdef _FILE_OFFSET_BITS
> >>    #undef _FILE_OFFSET_BITS
> >>    #endif
> >>
> >> +// Must go after undef _FILE_OFFSET_BITS.
> >> +#include "sanitizer_platform.h"
> >> +
> >> +#if SANITIZER_LINUX || SANITIZER_MAC
> >>    // Must go after undef _FILE_OFFSET_BITS.
> >>    #include "sanitizer_glibc_version.h"
> >>
> >> @@ -37,6 +38,7 @@
> >>    #include <pwd.h>
> >>    #include <signal.h>
> >>    #include <stddef.h>
> >> +#include <stdio.h>
> >>    #include <sys/mman.h>
> >>    #include <sys/resource.h>
> >>    #include <sys/socket.h>
> >> @@ -58,7 +60,6 @@
> >>    #endif
> >>
> >>    #if !SANITIZER_ANDROID
> >> -#include <fstab.h>
> >>    #include <sys/mount.h>
> >>    #include <sys/timeb.h>
> >>    #include <utmpx.h>
> >> @@ -110,20 +111,31 @@ typedef struct user_fpregs elf_fpregset_t;
> >>    #include <wordexp.h>
> >>    #endif
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >> -#include <glob.h>
> >> -#include <obstack.h>
> >> -#include <mqueue.h>
> >> +#if SANITIZER_LINUX
> >> +#if SANITIZER_GLIBC
> >> +#include <fstab.h>
> >>    #include <net/if_ppp.h>
> >>    #include <netax25/ax25.h>
> >>    #include <netipx/ipx.h>
> >>    #include <netrom/netrom.h>
> >> +#include <obstack.h>
> >>    #if HAVE_RPC_XDR_H
> >>    # include <rpc/xdr.h>
> >>    #endif
> >>    #include <scsi/scsi.h>
> >> -#include <sys/mtio.h>
> >> +#else
> >> +#include <linux/if_ppp.h>
> >> +#include <linux/kd.h>
> >> +#include <linux/ppp_defs.h>
> >> +#endif  // SANITIZER_GLIBC
> >> +
> >> +#if SANITIZER_ANDROID
> >> +#include <linux/mtio.h>
> >> +#else
> >> +#include <glob.h>
> >> +#include <mqueue.h>
> >>    #include <sys/kd.h>
> >> +#include <sys/mtio.h>
> >>    #include <sys/shm.h>
> >>    #include <sys/statvfs.h>
> >>    #include <sys/timex.h>
> >> @@ -142,20 +154,14 @@ typedef struct user_fpregs elf_fpregset_t;
> >>    #include <sys/msg.h>
> >>    #include <sys/ipc.h>
> >>    #include <crypt.h>
> >> -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
> >> +#endif  // SANITIZER_ANDROID
> >>
> >> -#if SANITIZER_ANDROID
> >> -#include <linux/kd.h>
> >> -#include <linux/mtio.h>
> >> -#include <linux/ppp_defs.h>
> >> -#include <linux/if_ppp.h>
> >> -#endif
> >> -
> >> -#if SANITIZER_LINUX
> >>    #include <link.h>
> >>    #include <sys/vfs.h>
> >>    #include <sys/epoll.h>
> >>    #include <linux/capability.h>
> >> +#else
> >> +#include <fstab.h>
> >>    #endif // SANITIZER_LINUX
> >>
> >>    #if SANITIZER_MAC
> >> @@ -202,8 +208,11 @@ namespace __sanitizer {
> >>      unsigned struct_statfs64_sz = sizeof(struct statfs64);
> >>    #endif // (SANITIZER_MAC && !TARGET_CPU_ARM64) && !SANITIZER_IOS
> >>
> >> -#if !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC
> >>      unsigned struct_fstab_sz = sizeof(struct fstab);
> >> +#endif  // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
> >> +        // SANITIZER_MAC
> >> +#if !SANITIZER_ANDROID
> >>      unsigned struct_statfs_sz = sizeof(struct statfs);
> >>      unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
> >>      unsigned ucontext_t_sz = sizeof(ucontext_t);
> >> @@ -299,7 +308,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(ElfW(Phdr));
> >>    unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> >>    #endif
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC
> >>      int glob_nomatch = GLOB_NOMATCH;
> >>      int glob_altdirfunc = GLOB_ALTDIRFUNC;
> >>    #endif
> >> @@ -422,7 +431,9 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> >>      unsigned struct_input_id_sz = sizeof(struct input_id);
> >>      unsigned struct_mtpos_sz = sizeof(struct mtpos);
> >>      unsigned struct_rtentry_sz = sizeof(struct rtentry);
> >> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
> >>      unsigned struct_termio_sz = sizeof(struct termio);
> >> +#endif
> >>      unsigned struct_vt_consize_sz = sizeof(struct vt_consize);
> >>      unsigned struct_vt_sizes_sz = sizeof(struct vt_sizes);
> >>      unsigned struct_vt_stat_sz = sizeof(struct vt_stat);
> >> @@ -447,7 +458,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> >>      unsigned struct_vt_mode_sz = sizeof(struct vt_mode);
> >>    #endif // SANITIZER_LINUX
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC
> >>      unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct);
> >>      unsigned struct_cyclades_monitor_sz = sizeof(struct cyclades_monitor);
> >>    #if EV_VERSION > (0x010000)
> >> @@ -470,12 +481,10 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> >>      unsigned struct_sockaddr_ax25_sz = sizeof(struct sockaddr_ax25);
> >>      unsigned struct_unimapdesc_sz = sizeof(struct unimapdesc);
> >>      unsigned struct_unimapinit_sz = sizeof(struct unimapinit);
> >> -#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >>      unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
> >>      unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
> >> -#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
> >> +#endif  // SANITIZER_GLIBC
> >>
> >>    #if !SANITIZER_ANDROID && !SANITIZER_MAC
> >>      unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
> >> @@ -881,6 +890,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> >>      unsigned IOCTL_PIO_UNIMAP = PIO_UNIMAP;
> >>      unsigned IOCTL_PIO_UNIMAPCLR = PIO_UNIMAPCLR;
> >>      unsigned IOCTL_PIO_UNISCRNMAP = PIO_UNISCRNMAP;
> >> +#if SANITIZER_GLIBC
> >>      unsigned IOCTL_SCSI_IOCTL_GET_IDLUN = SCSI_IOCTL_GET_IDLUN;
> >>      unsigned IOCTL_SCSI_IOCTL_PROBE_HOST = SCSI_IOCTL_PROBE_HOST;
> >>      unsigned IOCTL_SCSI_IOCTL_TAGGED_DISABLE = SCSI_IOCTL_TAGGED_DISABLE;
> >> @@ -899,6 +909,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
> >>      unsigned IOCTL_SIOCNRGETPARMS = SIOCNRGETPARMS;
> >>      unsigned IOCTL_SIOCNRRTCTL = SIOCNRRTCTL;
> >>      unsigned IOCTL_SIOCNRSETPARMS = SIOCNRSETPARMS;
> >> +#endif
> >>      unsigned IOCTL_TIOCGSERIAL = TIOCGSERIAL;
> >>      unsigned IOCTL_TIOCSERGETMULTI = TIOCSERGETMULTI;
> >>      unsigned IOCTL_TIOCSERSETMULTI = TIOCSERSETMULTI;
> >> @@ -969,7 +980,7 @@ CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr);
> >>    CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum);
> >>    #endif // SANITIZER_LINUX || SANITIZER_FREEBSD
> >>
> >> -#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD
> >>    CHECK_TYPE_SIZE(glob_t);
> >>    CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc);
> >>    CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv);
> >> @@ -980,7 +991,7 @@ CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir);
> >>    CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir);
> >>    CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat);
> >>    CHECK_SIZE_AND_OFFSET(glob_t, gl_stat);
> >> -#endif
> >> +#endif  // SANITIZER_GLIBC || SANITIZER_FREEBSD
> >>
> >>    CHECK_TYPE_SIZE(addrinfo);
> >>    CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags);
> >> @@ -1003,17 +1014,27 @@ CHECK_TYPE_SIZE(iovec);
> >>    CHECK_SIZE_AND_OFFSET(iovec, iov_base);
> >>    CHECK_SIZE_AND_OFFSET(iovec, iov_len);
> >>
> >> +// In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but
> >> +// many implementations don't conform to the standard. Since we pick the
> >> +// non-conforming glibc definition, exclude the checks for musl (incompatible
> >> +// sizes but compatible offsets).
> >>    CHECK_TYPE_SIZE(msghdr);
> >>    CHECK_SIZE_AND_OFFSET(msghdr, msg_name);
> >>    CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen);
> >>    CHECK_SIZE_AND_OFFSET(msghdr, msg_iov);
> >> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
> >>    CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen);
> >> +#endif
> >>    CHECK_SIZE_AND_OFFSET(msghdr, msg_control);
> >> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
> >>    CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen);
> >> +#endif
> >>    CHECK_SIZE_AND_OFFSET(msghdr, msg_flags);
> >>
> >>    CHECK_TYPE_SIZE(cmsghdr);
> >> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
> >>    CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len);
> >> +#endif
> >>    CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level);
> >>    CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type);
> >>
> >> @@ -1121,7 +1142,7 @@ CHECK_SIZE_AND_OFFSET(mntent, mnt_passno);
> >>
> >>    CHECK_TYPE_SIZE(ether_addr);
> >>
> >> -#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC || SANITIZER_FREEBSD
> >>    CHECK_TYPE_SIZE(ipc_perm);
> >>    # if SANITIZER_FREEBSD
> >>    CHECK_SIZE_AND_OFFSET(ipc_perm, key);
> >> @@ -1183,7 +1204,7 @@ CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
> >>    CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data);
> >>    #endif
> >>
> >> -#if SANITIZER_LINUX
> >> +#if SANITIZER_GLIBC || SANITIZER_ANDROID
> >>    COMPILER_CHECK(sizeof(__sanitizer_struct_mallinfo) == sizeof(struct mallinfo));
> >>    #endif
> >>
> >> @@ -1233,7 +1254,7 @@ COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE);
> >>    COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE);
> >>    #endif
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >> +#if SANITIZER_GLIBC
> >>    COMPILER_CHECK(sizeof(__sanitizer_FILE) <= sizeof(FILE));
> >>    CHECK_SIZE_AND_OFFSET(FILE, _flags);
> >>    CHECK_SIZE_AND_OFFSET(FILE, _IO_read_ptr);
> >> @@ -1250,9 +1271,7 @@ CHECK_SIZE_AND_OFFSET(FILE, _IO_save_end);
> >>    CHECK_SIZE_AND_OFFSET(FILE, _markers);
> >>    CHECK_SIZE_AND_OFFSET(FILE, _chain);
> >>    CHECK_SIZE_AND_OFFSET(FILE, _fileno);
> >> -#endif
> >>
> >> -#if SANITIZER_LINUX && !SANITIZER_ANDROID
> >>    COMPILER_CHECK(sizeof(__sanitizer__obstack_chunk) <= sizeof(_obstack_chunk));
> >>    CHECK_SIZE_AND_OFFSET(_obstack_chunk, limit);
> >>    CHECK_SIZE_AND_OFFSET(_obstack_chunk, prev);
> >> @@ -1267,7 +1286,7 @@ CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, read);
> >>    CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, write);
> >>    CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, seek);
> >>    CHECK_SIZE_AND_OFFSET(cookie_io_functions_t, close);
> >> -#endif
> >> +#endif  // SANITIZER_GLIBC
> >>
> >>    #if SANITIZER_LINUX || SANITIZER_FREEBSD
> >>    CHECK_TYPE_SIZE(sem_t);
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
> >> index 0812039b038..836b178c131 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
> >> @@ -83,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;
> >> @@ -443,6 +443,8 @@ struct __sanitizer_cmsghdr {
> >>      int cmsg_type;
> >>    };
> >>    #else
> >> +// In POSIX, int msg_iovlen; socklen_t msg_controllen; socklen_t cmsg_len; but
> >> +// many implementations don't conform to the standard.
> >>    struct __sanitizer_msghdr {
> >>      void *msg_name;
> >>      unsigned msg_namelen;
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
> >> index 2e080098283..f8457a6aac4 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_posix.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
> >> @@ -275,8 +275,8 @@ void ReportFile::Write(const char *buffer, uptr length) {
> >>
> >>    bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
> >>      MemoryMappingLayout proc_maps(/*cache_enabled*/false);
> >> -  InternalScopedString buff(kMaxPathLength);
> >> -  MemoryMappedSegment segment(buff.data(), kMaxPathLength);
> >> +  InternalMmapVector<char> buff(kMaxPathLength);
> >> +  MemoryMappedSegment segment(buff.data(), buff.size());
> >>      while (proc_maps.Next(&segment)) {
> >>        if (segment.IsExecutable() &&
> >>            internal_strcmp(module, segment.filename) == 0) {
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.h b/libsanitizer/sanitizer_common/sanitizer_posix.h
> >> index e1a2b48e5cd..b65dae64476 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_posix.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_posix.h
> >> @@ -40,6 +40,10 @@ uptr internal_write(fd_t fd, const void *buf, uptr count);
> >>    uptr internal_mmap(void *addr, uptr length, int prot, int flags,
> >>                       int fd, u64 offset);
> >>    uptr internal_munmap(void *addr, uptr length);
> >> +#if SANITIZER_LINUX
> >> +uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
> >> +                     void *new_address);
> >> +#endif
> >>    int internal_mprotect(void *addr, uptr length, int prot);
> >>    int internal_madvise(uptr addr, uptr length, int advice);
> >>
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
> >> index 7ff48c35851..d1d8e509c4d 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
> >> @@ -143,7 +143,7 @@ void Abort() {
> >>      if (GetHandleSignalMode(SIGABRT) != kHandleSignalNo) {
> >>        struct sigaction sigact;
> >>        internal_memset(&sigact, 0, sizeof(sigact));
> >> -    sigact.sa_sigaction = (sa_sigaction_t)SIG_DFL;
> >> +    sigact.sa_handler = SIG_DFL;
> >>        internal_sigaction(SIGABRT, &sigact, nullptr);
> >>      }
> >>    #endif
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_printf.cpp b/libsanitizer/sanitizer_common/sanitizer_printf.cpp
> >> index a032787114b..5d16dfde678 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_printf.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_printf.cpp
> >> @@ -249,26 +249,21 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
> >>                                                  va_list args) {
> >>      va_list args2;
> >>      va_copy(args2, args);
> >> -  const int kLen = 16 * 1024;
> >> -  int needed_length;
> >> +  InternalMmapVector<char> v;
> >> +  int needed_length = 0;
> >>      char *buffer = local_buffer;
> >>      // First try to print a message using a local buffer, and then fall back to
> >>      // mmaped buffer.
> >> -  for (int use_mmap = 0; use_mmap < 2; use_mmap++) {
> >> +  for (int use_mmap = 0;; use_mmap++) {
> >>        if (use_mmap) {
> >>          va_end(args);
> >>          va_copy(args, args2);
> >> -      buffer = (char*)MmapOrDie(kLen, "Report");
> >> -      buffer_size = kLen;
> >> +      v.resize(needed_length + 1);
> >> +      buffer_size = v.capacity();
> >> +      v.resize(buffer_size);
> >> +      buffer = &v[0];
> >>        }
> >>        needed_length = 0;
> >> -    // Check that data fits into the current buffer.
> >> -#   define CHECK_NEEDED_LENGTH \
> >> -      if (needed_length >= buffer_size) { \
> >> -        if (!use_mmap) continue; \
> >> -        RAW_CHECK_MSG(needed_length < kLen, \
> >> -                      "Buffer in Report is too short!\n"); \
> >> -      }
> >>        // Fuchsia's logging infrastructure always keeps track of the logging
> >>        // process, thread, and timestamp, so never prepend such information.
> >>        if (!SANITIZER_FUCHSIA && append_pid) {
> >> @@ -277,18 +272,20 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
> >>          if (common_flags()->log_exe_name && exe_name) {
> >>            needed_length += internal_snprintf(buffer, buffer_size,
> >>                                               "==%s", exe_name);
> >> -        CHECK_NEEDED_LENGTH
> >> +        if (needed_length >= buffer_size)
> >> +          continue;
> >>          }
> >>          needed_length += internal_snprintf(
> >>              buffer + needed_length, buffer_size - needed_length, "==%d==", pid);
> >> -      CHECK_NEEDED_LENGTH
> >> +      if (needed_length >= buffer_size)
> >> +        continue;
> >>        }
> >>        needed_length += VSNPrintf(buffer + needed_length,
> >>                                   buffer_size - needed_length, format, args);
> >> -    CHECK_NEEDED_LENGTH
> >> +    if (needed_length >= buffer_size)
> >> +      continue;
> >>        // If the message fit into the buffer, print it and exit.
> >>        break;
> >> -#   undef CHECK_NEEDED_LENGTH
> >>      }
> >>      RawWrite(buffer);
> >>
> >> @@ -297,9 +294,6 @@ static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
> >>      CallPrintfAndReportCallback(buffer);
> >>      LogMessageOnPrintf(buffer);
> >>
> >> -  // If we had mapped any memory, clean up.
> >> -  if (buffer != local_buffer)
> >> -    UnmapOrDie((void *)buffer, buffer_size);
> >>      va_end(args2);
> >>    }
> >>
> >> @@ -346,13 +340,24 @@ int internal_snprintf(char *buffer, uptr length, const char *format, ...) {
> >>
> >>    FORMAT(2, 3)
> >>    void InternalScopedString::append(const char *format, ...) {
> >> -  CHECK_LT(length_, size());
> >> -  va_list args;
> >> -  va_start(args, format);
> >> -  VSNPrintf(data() + length_, size() - length_, format, args);
> >> -  va_end(args);
> >> -  length_ += internal_strlen(data() + length_);
> >> -  CHECK_LT(length_, size());
> >> +  uptr prev_len = length();
> >> +
> >> +  while (true) {
> >> +    buffer_.resize(buffer_.capacity());
> >> +
> >> +    va_list args;
> >> +    va_start(args, format);
> >> +    uptr sz = VSNPrintf(buffer_.data() + prev_len, buffer_.size() - prev_len,
> >> +                        format, args);
> >> +    va_end(args);
> >> +    if (sz < buffer_.size() - prev_len) {
> >> +      buffer_.resize(prev_len + sz + 1);
> >> +      break;
> >> +    }
> >> +
> >> +    buffer_.reserve(buffer_.capacity() * 2);
> >> +  }
> >> +  CHECK_EQ(buffer_[length()], '\0');
> >>    }
> >>
> >>    } // namespace __sanitizer
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
> >> index f2cfcffaf47..1b7dd46d8de 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
> >> @@ -120,7 +120,7 @@ void MemoryMappingLayout::LoadFromCache() {
> >>    void MemoryMappingLayout::DumpListOfModules(
> >>        InternalMmapVectorNoCtor<LoadedModule> *modules) {
> >>      Reset();
> >> -  InternalScopedString module_name(kMaxPathLength);
> >> +  InternalMmapVector<char> module_name(kMaxPathLength);
> >>      MemoryMappedSegment segment(module_name.data(), module_name.size());
> >>      for (uptr i = 0; Next(&segment); i++) {
> >>        const char *cur_name = segment.filename;
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
> >> index d02afcfe87a..1f53e3e46d8 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
> >> @@ -354,8 +354,8 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
> >>    void MemoryMappingLayout::DumpListOfModules(
> >>        InternalMmapVectorNoCtor<LoadedModule> *modules) {
> >>      Reset();
> >> -  InternalScopedString module_name(kMaxPathLength);
> >> -  MemoryMappedSegment segment(module_name.data(), kMaxPathLength);
> >> +  InternalMmapVector<char> module_name(kMaxPathLength);
> >> +  MemoryMappedSegment segment(module_name.data(), module_name.size());
> >>      MemoryMappedSegmentData data;
> >>      segment.data_ = &data;
> >>      while (Next(&segment)) {
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
> >> index 4063ec8deaa..bf813f235bb 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
> >> @@ -9,13 +9,13 @@
> >>    // Information about the process mappings (Solaris-specific parts).
> >>    //===----------------------------------------------------------------------===//
> >>
> >> +// Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment.
> >> +#undef _FILE_OFFSET_BITS
> >>    #include "sanitizer_platform.h"
> >>    #if SANITIZER_SOLARIS
> >>    #include "sanitizer_common.h"
> >>    #include "sanitizer_procmaps.h"
> >>
> >> -// Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment.
> >> -#undef _FILE_OFFSET_BITS
> >>    #include <procfs.h>
> >>    #include <limits.h>
> >>
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
> >> index a288068bf94..52003546948 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
> >> @@ -11,6 +11,24 @@
> >>
> >>    #if __has_feature(ptrauth_calls)
> >>    #include <ptrauth.h>
> >> +#elif defined(__ARM_FEATURE_PAC_DEFAULT) && !defined(__APPLE__)
> >> +inline unsigned long ptrauth_strip(void* __value, unsigned int __key) {
> >> +  // On the stack the link register is protected with Pointer
> >> +  // Authentication Code when compiled with -mbranch-protection.
> >> +  // Let's stripping the PAC unconditionally because xpaclri is in
> >> +  // the NOP space so will do nothing when it is not enabled or not available.
> >> +  unsigned long ret;
> >> +  asm volatile(
> >> +      "mov x30, %1\n\t"
> >> +      "hint #7\n\t"  // xpaclri
> >> +      "mov %0, x30\n\t"
> >> +      : "=r"(ret)
> >> +      : "r"(__value)
> >> +      : "x30");
> >> +  return ret;
> >> +}
> >> +#define ptrauth_auth_data(__value, __old_key, __old_data) __value
> >> +#define ptrauth_string_discriminator(__string) ((int)0)
> >>    #else
> >>    // Copied from <ptrauth.h>
> >>    #define ptrauth_strip(__value, __key) __value
> >> @@ -18,6 +36,6 @@
> >>    #define ptrauth_string_discriminator(__string) ((int)0)
> >>    #endif
> >>
> >> -#define STRIP_PC(pc) ((uptr)ptrauth_strip(pc, 0))
> >> +#define STRIP_PAC_PC(pc) ((uptr)ptrauth_strip(pc, 0))
> >>
> >>    #endif // SANITIZER_PTRAUTH_H
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
> >> index 4692f50d323..44a95214e38 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
> >> @@ -145,8 +145,7 @@ StackTrace StackDepotReverseMap::Get(u32 id) {
> >>      if (!map_.size())
> >>        return StackTrace();
> >>      IdDescPair pair = {id, nullptr};
> >> -  uptr idx =
> >> -      InternalLowerBound(map_, 0, map_.size(), pair, IdDescPair::IdComparator);
> >> +  uptr idx = InternalLowerBound(map_, pair, IdDescPair::IdComparator);
> >>      if (idx > map_.size() || map_[idx].id != id)
> >>        return StackTrace();
> >>      return map_[idx].desc->load();
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
> >> index b28fc1cf736..07e4409f4a5 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
> >> @@ -15,6 +15,7 @@
> >>    #include "sanitizer_common.h"
> >>    #include "sanitizer_flags.h"
> >>    #include "sanitizer_platform.h"
> >> +#include "sanitizer_ptrauth.h"
> >>
> >>    namespace __sanitizer {
> >>
> >> @@ -84,8 +85,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
> >> @@ -108,28 +109,21 @@ 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];
> >>    #elif defined(__riscv)
> >>        // frame[-1] contains the return address
> >>        uhwptr pc1 = frame[-1];
> >>    #else
> >> -    uhwptr pc1 = frame[1];
> >> +    uhwptr pc1 = STRIP_PAC_PC((void *)frame[1]);
> >>    #endif
> >>        // Let's assume that any pointer in the 0th page (i.e. <0x1000 on i386 and
> >>        // x86_64) is invalid and stop unwinding here.  If we're adding support for
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
> >> index 0350fe84b04..15616f899d0 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
> >> @@ -67,8 +67,6 @@ struct StackTrace {
> >>      static uptr GetCurrentPc();
> >>      static inline uptr GetPreviousInstructionPc(uptr pc);
> >>      static uptr GetNextInstructionPc(uptr pc);
> >> -  typedef bool (*SymbolizeCallback)(const void *pc, char *out_buffer,
> >> -                                    int out_size);
> >>    };
> >>
> >>    // Performance-critical, must be in the header.
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
> >> index 7808ba9b0f5..738633209f0 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
> >> @@ -23,8 +23,8 @@ void StackTrace::Print() const {
> >>        Printf("    <empty stack>\n\n");
> >>        return;
> >>      }
> >> -  InternalScopedString frame_desc(GetPageSizeCached() * 2);
> >> -  InternalScopedString dedup_token(GetPageSizeCached());
> >> +  InternalScopedString frame_desc;
> >> +  InternalScopedString dedup_token;
> >>      int dedup_frames = common_flags()->dedup_token_length;
> >>      bool symbolize = RenderNeedsSymbolization(common_flags()->stack_trace_format);
> >>      uptr frame_num = 0;
> >> @@ -125,7 +125,7 @@ void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
> >>        out_buf[out_buf_size - 1] = 0;
> >>        return;
> >>      }
> >> -  InternalScopedString frame_desc(GetPageSizeCached());
> >> +  InternalScopedString frame_desc;
> >>      uptr frame_num = 0;
> >>      // Reserve one byte for the final 0.
> >>      char *out_end = out_buf + out_buf_size - 1;
> >> @@ -156,7 +156,7 @@ void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
> >>      out_buf[0] = 0;
> >>      DataInfo DI;
> >>      if (!Symbolizer::GetOrInit()->SymbolizeData(data_addr, &DI)) return;
> >> -  InternalScopedString data_desc(GetPageSizeCached());
> >> +  InternalScopedString data_desc;
> >>      RenderData(&data_desc, fmt, &DI, common_flags()->strip_path_prefix);
> >>      internal_strncpy(out_buf, data_desc.data(), out_buf_size);
> >>      out_buf[out_buf_size - 1] = 0;
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
> >> index 0f1cadfeae3..53cfddcfbe0 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
> >> @@ -490,6 +490,9 @@ typedef user_regs_struct regs_struct;
> >>    #ifndef NT_X86_XSTATE
> >>    #define NT_X86_XSTATE 0x202
> >>    #endif
> >> +#ifndef PTRACE_GETREGSET
> >> +#define PTRACE_GETREGSET 0x4204
> >> +#endif
> >>    // Compiler may use FP registers to store pointers.
> >>    static constexpr uptr kExtraRegs[] = {NT_X86_XSTATE, NT_FPREGSET};
> >>
> >> @@ -513,6 +516,8 @@ static constexpr uptr kExtraRegs[] = {0};
> >>
> >>    #elif SANITIZER_RISCV64
> >>    typedef struct user_regs_struct regs_struct;
> >> +// sys/ucontext.h already defines REG_SP as 2. Undefine it first.
> >> +#undef REG_SP
> >>    #define REG_SP sp
> >>    static constexpr uptr kExtraRegs[] = {0};
> >>    #define ARCH_IOVEC_FOR_GETREGSET
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp b/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
> >> index 44c83a66c5f..a674034b8e2 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
> >> @@ -34,7 +34,7 @@ SuppressionContext::SuppressionContext(const char *suppression_types[],
> >>    static bool GetPathAssumingFileIsRelativeToExec(const char *file_path,
> >>                                                    /*out*/char *new_file_path,
> >>                                                    uptr new_file_path_size) {
> >> -  InternalScopedString exec(kMaxPathLength);
> >> +  InternalMmapVector<char> exec(kMaxPathLength);
> >>      if (ReadBinaryNameCached(exec.data(), exec.size())) {
> >>        const char *file_name_pos = StripModuleName(exec.data());
> >>        uptr path_to_exec_len = file_name_pos - exec.data();
> >> @@ -69,7 +69,7 @@ void SuppressionContext::ParseFromFile(const char *filename) {
> >>      if (filename[0] == '\0')
> >>        return;
> >>
> >> -  InternalScopedString new_file_path(kMaxPathLength);
> >> +  InternalMmapVector<char> new_file_path(kMaxPathLength);
> >>      filename = FindFile(filename, new_file_path.data(), new_file_path.size());
> >>
> >>      // Read the file.
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
> >> index 710da4c1cec..98418b426c3 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
> >> @@ -356,7 +356,7 @@ void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) {
> >>          InternalFree(info->function);
> >>          info->function = 0;
> >>        }
> >> -    if (0 == internal_strcmp(info->file, "??")) {
> >> +    if (info->file && 0 == internal_strcmp(info->file, "??")) {
> >>          InternalFree(info->file);
> >>          info->file = 0;
> >>        }
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
> >> index 30cba08ed53..01edef9c1aa 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
> >> @@ -54,6 +54,10 @@ bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
> >>      return false;
> >>    }
> >>
> >> +// This is mainly used by hwasan for online symbolization. This isn't needed
> >> +// since hwasan can always just dump stack frames for offline symbolization.
> >> +bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { return false; }
> >> +
> >>    // This is used in some places for suppression checking, which we
> >>    // don't really support for Fuchsia.  It's also used in UBSan to
> >>    // identify a PC location to a function name, so we always fill in
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
> >> index 4dd5cc3ad7c..4cd4b4636f0 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
> >> @@ -400,11 +400,20 @@ const char *Symbolizer::PlatformDemangle(const char *name) {
> >>
> >>    static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
> >>      const char *path = common_flags()->external_symbolizer_path;
> >> +
> >> +  if (path && internal_strchr(path, '%')) {
> >> +    char *new_path = (char *)InternalAlloc(kMaxPathLength);
> >> +    SubstituteForFlagValue(path, new_path, kMaxPathLength);
> >> +    path = new_path;
> >> +  }
> >> +
> >>      const char *binary_name = path ? StripModuleName(path) : "";
> >> +  static const char kLLVMSymbolizerPrefix[] = "llvm-symbolizer";
> >>      if (path && path[0] == '\0') {
> >>        VReport(2, "External symbolizer is explicitly disabled.\n");
> >>        return nullptr;
> >> -  } else if (!internal_strcmp(binary_name, "llvm-symbolizer")) {
> >> +  } else if (!internal_strncmp(binary_name, kLLVMSymbolizerPrefix,
> >> +                               internal_strlen(kLLVMSymbolizerPrefix))) {
> >>        VReport(2, "Using llvm-symbolizer at user-specified path: %s\n", path);
> >>        return new(*allocator) LLVMSymbolizer(path, allocator);
> >>      } else if (!internal_strcmp(binary_name, "atos")) {
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
> >> index 06301b83ea1..9287993e665 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
> >> @@ -31,7 +31,7 @@ namespace __sanitizer {
> >>    void ReportErrorSummary(const char *error_type, const AddressInfo &info,
> >>                            const char *alt_tool_name) {
> >>      if (!common_flags()->print_summary) return;
> >> -  InternalScopedString buff(kMaxSummaryLength);
> >> +  InternalScopedString buff;
> >>      buff.append("%s ", error_type);
> >>      RenderFrame(&buff, "%L %F", 0, info.address, &info,
> >>                  common_flags()->symbolize_vs_style,
> >> @@ -150,7 +150,7 @@ static void PrintMemoryByte(InternalScopedString *str, const char *before,
> >>    static void MaybeDumpInstructionBytes(uptr pc) {
> >>      if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
> >>        return;
> >> -  InternalScopedString str(1024);
> >> +  InternalScopedString str;
> >>      str.append("First 16 instruction bytes at pc: ");
> >>      if (IsAccessibleMemoryRange(pc, 16)) {
> >>        for (int i = 0; i < 16; ++i) {
> >> @@ -211,7 +211,7 @@ static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
> >>        Report("The signal is caused by a %s memory access.\n", access_type);
> >>        if (!sig.is_true_faulting_addr)
> >>          Report("Hint: this fault was caused by a dereference of a high value "
> >> -             "address (see register values below).  Dissassemble the provided "
> >> +             "address (see register values below).  Disassemble the provided "
> >>                 "pc to learn which register was used.\n");
> >>        else if (sig.addr < GetPageSizeCached())
> >>          Report("Hint: address points to the zero page.\n");
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
> >> index 48fa2d1033a..702d901353d 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
> >> @@ -136,9 +136,10 @@ void InitializeDbgHelpIfNeeded() {
> >>    bool WinSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *frame) {
> >>      InitializeDbgHelpIfNeeded();
> >>
> >> -  // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
> >> -  char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
> >> -  PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
> >> +  // See https://docs.microsoft.com/en-us/windows/win32/debug/retrieving-symbol-information-by-address
> >> +  InternalMmapVector<char> buffer(sizeof(SYMBOL_INFO) +
> >> +                                  MAX_SYM_NAME * sizeof(CHAR));
> >> +  PSYMBOL_INFO symbol = (PSYMBOL_INFO)&buffer[0];
> >>      symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
> >>      symbol->MaxNameLen = MAX_SYM_NAME;
> >>      DWORD64 offset = 0;
> >> @@ -223,7 +224,7 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
> >>      // Compute the command line. Wrap double quotes around everything.
> >>      const char *argv[kArgVMax];
> >>      GetArgV(path_, argv);
> >> -  InternalScopedString command_line(kMaxPathLength * 3);
> >> +  InternalScopedString command_line;
> >>      for (int i = 0; argv[i]; i++) {
> >>        const char *arg = argv[i];
> >>        int arglen = internal_strlen(arg);
> >> @@ -281,8 +282,15 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
> >>        return;
> >>      }
> >>
> >> -  // Add llvm-symbolizer in case the binary has dwarf.
> >> +  // Add llvm-symbolizer.
> >>      const char *user_path = common_flags()->external_symbolizer_path;
> >> +
> >> +  if (user_path && internal_strchr(user_path, '%')) {
> >> +    char *new_path = (char *)InternalAlloc(kMaxPathLength);
> >> +    SubstituteForFlagValue(user_path, new_path, kMaxPathLength);
> >> +    user_path = new_path;
> >> +  }
> >> +
> >>      const char *path =
> >>          user_path ? user_path : FindPathToBinary("llvm-symbolizer.exe");
> >>      if (path) {
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_termination.cpp b/libsanitizer/sanitizer_common/sanitizer_termination.cpp
> >> index 84be6fc3234..6a54734353c 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_termination.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_termination.cpp
> >> @@ -59,26 +59,31 @@ void NORETURN Die() {
> >>      internal__exit(common_flags()->exitcode);
> >>    }
> >>
> >> -static CheckFailedCallbackType CheckFailedCallback;
> >> -void SetCheckFailedCallback(CheckFailedCallbackType callback) {
> >> -  CheckFailedCallback = callback;
> >> +static void (*CheckUnwindCallback)();
> >> +void SetCheckUnwindCallback(void (*callback)()) {
> >> +  CheckUnwindCallback = callback;
> >>    }
> >>
> >> -const int kSecondsToSleepWhenRecursiveCheckFailed = 2;
> >> -
> >>    void NORETURN CheckFailed(const char *file, int line, const char *cond,
> >>                              u64 v1, u64 v2) {
> >> -  static atomic_uint32_t num_calls;
> >> -  if (atomic_fetch_add(&num_calls, 1, memory_order_relaxed) > 10) {
> >> -    SleepForSeconds(kSecondsToSleepWhenRecursiveCheckFailed);
> >> +  u32 tid = GetTid();
> >> +  Printf("%s: CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx) (tid=%u)\n",
> >> +         SanitizerToolName, StripModuleName(file), line, cond, (uptr)v1,
> >> +         (uptr)v2, tid);
> >> +  static atomic_uint32_t first_tid;
> >> +  u32 cmp = 0;
> >> +  if (!atomic_compare_exchange_strong(&first_tid, &cmp, tid,
> >> +                                      memory_order_relaxed)) {
> >> +    if (cmp == tid) {
> >> +      // Recursing into CheckFailed.
> >> +    } else {
> >> +      // Another thread fails already, let it print the stack and terminate.
> >> +      SleepForSeconds(2);
> >> +    }
> >>        Trap();
> >>      }
> >> -
> >> -  if (CheckFailedCallback) {
> >> -    CheckFailedCallback(file, line, cond, v1, v2);
> >> -  }
> >> -  Report("Sanitizer CHECK failed: %s:%d %s (%lld, %lld)\n", file, line, cond,
> >> -                                                            v1, v2);
> >> +  if (CheckUnwindCallback)
> >> +    CheckUnwindCallback();
> >>      Die();
> >>    }
> >>
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
> >> index f2c6f279931..3273da38bfd 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
> >> @@ -85,7 +85,7 @@ void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
> >>      unique_id = _unique_id;
> >>      detached = _detached;
> >>      // Parent tid makes no sense for the main thread.
> >> -  if (tid != 0)
> >> +  if (tid != kMainTid)
> >>        parent_tid = _parent_tid;
> >>      OnCreated(arg);
> >>    }
> >> @@ -99,8 +99,6 @@ void ThreadContextBase::Reset() {
> >>
> >>    // ThreadRegistry implementation.
> >>
> >> -const u32 ThreadRegistry::kUnknownTid = ~0U;
> >> -
> >>    ThreadRegistry::ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
> >>                                   u32 thread_quarantine_size, u32 max_reuse)
> >>        : context_factory_(factory),
> >> @@ -135,7 +133,7 @@ uptr ThreadRegistry::GetMaxAliveThreads() {
> >>    u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
> >>                                     void *arg) {
> >>      BlockingMutexLock l(&mtx_);
> >> -  u32 tid = kUnknownTid;
> >> +  u32 tid = kInvalidTid;
> >>      ThreadContextBase *tctx = QuarantinePop();
> >>      if (tctx) {
> >>        tid = tctx->tid;
> >> @@ -155,7 +153,7 @@ u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
> >>        Die();
> >>      }
> >>      CHECK_NE(tctx, 0);
> >> -  CHECK_NE(tid, kUnknownTid);
> >> +  CHECK_NE(tid, kInvalidTid);
> >>      CHECK_LT(tid, max_threads_);
> >>      CHECK_EQ(tctx->status, ThreadStatusInvalid);
> >>      alive_threads_++;
> >> @@ -186,7 +184,7 @@ u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) {
> >>        if (tctx != 0 && cb(tctx, arg))
> >>          return tctx->tid;
> >>      }
> >> -  return kUnknownTid;
> >> +  return kInvalidTid;
> >>    }
> >>
> >>    ThreadContextBase *
> >> @@ -278,7 +276,7 @@ void ThreadRegistry::JoinThread(u32 tid, void *arg) {
> >>    // really started.  We just did CreateThread for a prospective new
> >>    // thread before trying to create it, and then failed to actually
> >>    // create it, and so never called StartThread.
> >> -void ThreadRegistry::FinishThread(u32 tid) {
> >> +ThreadStatus ThreadRegistry::FinishThread(u32 tid) {
> >>      BlockingMutexLock l(&mtx_);
> >>      CHECK_GT(alive_threads_, 0);
> >>      alive_threads_--;
> >> @@ -286,6 +284,7 @@ void ThreadRegistry::FinishThread(u32 tid) {
> >>      ThreadContextBase *tctx = threads_[tid];
> >>      CHECK_NE(tctx, 0);
> >>      bool dead = tctx->detached;
> >> +  ThreadStatus prev_status = tctx->status;
> >>      if (tctx->status == ThreadStatusRunning) {
> >>        CHECK_GT(running_threads_, 0);
> >>        running_threads_--;
> >> @@ -300,6 +299,7 @@ void ThreadRegistry::FinishThread(u32 tid) {
> >>        QuarantinePush(tctx);
> >>      }
> >>      tctx->SetDestroyed();
> >> +  return prev_status;
> >>    }
> >>
> >>    void ThreadRegistry::StartThread(u32 tid, tid_t os_id, ThreadType thread_type,
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
> >> index 85c522a31ca..dcd445c28ae 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
> >> @@ -87,8 +87,6 @@ typedef ThreadContextBase* (*ThreadContextFactory)(u32 tid);
> >>
> >>    class ThreadRegistry {
> >>     public:
> >> -  static const u32 kUnknownTid;
> >> -
> >>      ThreadRegistry(ThreadContextFactory factory, u32 max_threads,
> >>                     u32 thread_quarantine_size, u32 max_reuse = 0);
> >>      void GetNumberOfThreads(uptr *total = nullptr, uptr *running = nullptr,
> >> @@ -113,7 +111,7 @@ class ThreadRegistry {
> >>      void RunCallbackForEachThreadLocked(ThreadCallback cb, void *arg);
> >>
> >>      typedef bool (*FindThreadCallback)(ThreadContextBase *tctx, void *arg);
> >> -  // Finds a thread using the provided callback. Returns kUnknownTid if no
> >> +  // Finds a thread using the provided callback. Returns kInvalidTid if no
> >>      // thread is found.
> >>      u32 FindThread(FindThreadCallback cb, void *arg);
> >>      // Should be guarded by ThreadRegistryLock. Return 0 if no thread
> >> @@ -126,7 +124,8 @@ class ThreadRegistry {
> >>      void SetThreadNameByUserId(uptr user_id, const char *name);
> >>      void DetachThread(u32 tid, void *arg);
> >>      void JoinThread(u32 tid, void *arg);
> >> -  void FinishThread(u32 tid);
> >> +  // Finishes thread and returns previous status.
> >> +  ThreadStatus FinishThread(u32 tid);
> >>      void StartThread(u32 tid, tid_t os_id, ThreadType thread_type, void *arg);
> >>      void SetThreadUserId(u32 tid, uptr user_id);
> >>
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
> >> index 10748f96420..1f664b6cf5b 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
> >> @@ -12,6 +12,7 @@
> >>
> >>    #include "sanitizer_tls_get_addr.h"
> >>
> >> +#include "sanitizer_atomic.h"
> >>    #include "sanitizer_flags.h"
> >>    #include "sanitizer_platform_interceptors.h"
> >>
> >> @@ -42,39 +43,54 @@ static atomic_uintptr_t number_of_live_dtls;
> >>
> >>    static const uptr kDestroyedThread = -1;
> >>
> >> -static inline void DTLS_Deallocate(DTLS::DTV *dtv, uptr size) {
> >> -  if (!size) return;
> >> -  VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size);
> >> -  UnmapOrDie(dtv, size * sizeof(DTLS::DTV));
> >> +static void DTLS_Deallocate(DTLS::DTVBlock *block) {
> >> +  VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", block);
> >> +  UnmapOrDie(block, sizeof(DTLS::DTVBlock));
> >>      atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed);
> >>    }
> >>
> >> -static inline void DTLS_Resize(uptr new_size) {
> >> -  if (dtls.dtv_size >= new_size) return;
> >> -  new_size = RoundUpToPowerOfTwo(new_size);
> >> -  new_size = Max(new_size, 4096UL / sizeof(DTLS::DTV));
> >> -  DTLS::DTV *new_dtv =
> >> -      (DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize");
> >> +static DTLS::DTVBlock *DTLS_NextBlock(atomic_uintptr_t *cur) {
> >> +  uptr v = atomic_load(cur, memory_order_acquire);
> >> +  if (v == kDestroyedThread)
> >> +    return nullptr;
> >> +  DTLS::DTVBlock *next = (DTLS::DTVBlock *)v;
> >> +  if (next)
> >> +    return next;
> >> +  DTLS::DTVBlock *new_dtv =
> >> +      (DTLS::DTVBlock *)MmapOrDie(sizeof(DTLS::DTVBlock), "DTLS_NextBlock");
> >> +  uptr prev = 0;
> >> +  if (!atomic_compare_exchange_strong(cur, &prev, (uptr)new_dtv,
> >> +                                      memory_order_seq_cst)) {
> >> +    UnmapOrDie(new_dtv, sizeof(DTLS::DTVBlock));
> >> +    return (DTLS::DTVBlock *)prev;
> >> +  }
> >>      uptr num_live_dtls =
> >>          atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed);
> >> -  VReport(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls);
> >> -  CHECK_LT(num_live_dtls, 1 << 20);
> >> -  uptr old_dtv_size = dtls.dtv_size;
> >> -  DTLS::DTV *old_dtv = dtls.dtv;
> >> -  if (old_dtv_size)
> >> -    internal_memcpy(new_dtv, dtls.dtv, dtls.dtv_size * sizeof(DTLS::DTV));
> >> -  dtls.dtv = new_dtv;
> >> -  dtls.dtv_size = new_size;
> >> -  if (old_dtv_size)
> >> -    DTLS_Deallocate(old_dtv, old_dtv_size);
> >> +  VReport(2, "__tls_get_addr: DTLS_NextBlock %p %zd\n", &dtls, num_live_dtls);
> >> +  return new_dtv;
> >> +}
> >> +
> >> +static DTLS::DTV *DTLS_Find(uptr id) {
> >> +  VReport(2, "__tls_get_addr: DTLS_Find %p %zd\n", &dtls, id);
> >> +  static constexpr uptr kPerBlock = ARRAY_SIZE(DTLS::DTVBlock::dtvs);
> >> +  DTLS::DTVBlock *cur = DTLS_NextBlock(&dtls.dtv_block);
> >> +  if (!cur)
> >> +    return nullptr;
> >> +  for (; id >= kPerBlock; id -= kPerBlock) cur = DTLS_NextBlock(&cur->next);
> >> +  return cur->dtvs + id;
> >>    }
> >>
> >>    void DTLS_Destroy() {
> >>      if (!common_flags()->intercept_tls_get_addr) return;
> >> -  VReport(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size);
> >> -  uptr s = dtls.dtv_size;
> >> -  dtls.dtv_size = kDestroyedThread;  // Do this before unmap for AS-safety.
> >> -  DTLS_Deallocate(dtls.dtv, s);
> >> +  VReport(2, "__tls_get_addr: DTLS_Destroy %p\n", &dtls);
> >> +  DTLS::DTVBlock *block = (DTLS::DTVBlock *)atomic_exchange(
> >> +      &dtls.dtv_block, kDestroyedThread, memory_order_release);
> >> +  while (block) {
> >> +    DTLS::DTVBlock *next =
> >> +        (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire);
> >> +    DTLS_Deallocate(block);
> >> +    block = next;
> >> +  }
> >>    }
> >>
> >>    #if defined(__powerpc64__) || defined(__mips__)
> >> @@ -96,9 +112,9 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
> >>      if (!common_flags()->intercept_tls_get_addr) return 0;
> >>      TlsGetAddrParam *arg = reinterpret_cast<TlsGetAddrParam *>(arg_void);
> >>      uptr dso_id = arg->dso_id;
> >> -  if (dtls.dtv_size == kDestroyedThread) return 0;
> >> -  DTLS_Resize(dso_id + 1);
> >> -  if (dtls.dtv[dso_id].beg) return 0;
> >> +  DTLS::DTV *dtv = DTLS_Find(dso_id);
> >> +  if (!dtv || dtv->beg)
> >> +    return 0;
> >>      uptr tls_size = 0;
> >>      uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset - kDtvOffset;
> >>      VReport(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p "
> >> @@ -126,9 +142,9 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
> >>        // This may happen inside the DTOR of main thread, so just ignore it.
> >>        tls_size = 0;
> >>      }
> >> -  dtls.dtv[dso_id].beg = tls_beg;
> >> -  dtls.dtv[dso_id].size = tls_size;
> >> -  return dtls.dtv + dso_id;
> >> +  dtv->beg = tls_beg;
> >> +  dtv->size = tls_size;
> >> +  return dtv;
> >>    }
> >>
> >>    void DTLS_on_libc_memalign(void *ptr, uptr size) {
> >> @@ -141,7 +157,8 @@ void DTLS_on_libc_memalign(void *ptr, uptr size) {
> >>    DTLS *DTLS_Get() { return &dtls; }
> >>
> >>    bool DTLSInDestruction(DTLS *dtls) {
> >> -  return dtls->dtv_size == kDestroyedThread;
> >> +  return atomic_load(&dtls->dtv_block, memory_order_relaxed) ==
> >> +         kDestroyedThread;
> >>    }
> >>
> >>    #else
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
> >> index c7cd5a8bffc..a599c0bbc75 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
> >> @@ -28,6 +28,7 @@
> >>    #ifndef SANITIZER_TLS_GET_ADDR_H
> >>    #define SANITIZER_TLS_GET_ADDR_H
> >>
> >> +#include "sanitizer_atomic.h"
> >>    #include "sanitizer_common.h"
> >>
> >>    namespace __sanitizer {
> >> @@ -38,15 +39,31 @@ struct DTLS {
> >>      struct DTV {
> >>        uptr beg, size;
> >>      };
> >> +  struct DTVBlock {
> >> +    atomic_uintptr_t next;
> >> +    DTV dtvs[(4096UL - sizeof(next)) / sizeof(DTLS::DTV)];
> >> +  };
> >> +
> >> +  static_assert(sizeof(DTVBlock) <= 4096UL, "Unexpected block size");
> >>
> >> -  uptr dtv_size;
> >> -  DTV *dtv;  // dtv_size elements, allocated by MmapOrDie.
> >> +  atomic_uintptr_t dtv_block;
> >>
> >>      // Auxiliary fields, don't access them outside sanitizer_tls_get_addr.cpp
> >>      uptr last_memalign_size;
> >>      uptr last_memalign_ptr;
> >>    };
> >>
> >> +template <typename Fn>
> >> +void ForEachDVT(DTLS *dtls, const Fn &fn) {
> >> +  DTLS::DTVBlock *block =
> >> +      (DTLS::DTVBlock *)atomic_load(&dtls->dtv_block, memory_order_acquire);
> >> +  while (block) {
> >> +    int id = 0;
> >> +    for (auto &d : block->dtvs) fn(d, id++);
> >> +    block = (DTLS::DTVBlock *)atomic_load(&block->next, memory_order_acquire);
> >> +  }
> >> +}
> >> +
> >>    // Returns pointer and size of a linker-allocated TLS block.
> >>    // Each block is returned exactly once.
> >>    DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, uptr static_tls_begin,
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp b/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
> >> index e2edf428004..7e01c81d042 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
> >> @@ -43,6 +43,10 @@ void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) {
> >>      trace_buffer[0] = pc;
> >>    }
> >>
> >> +#ifdef __clang__
> >> +#pragma clang diagnostic push
> >> +#pragma clang diagnostic ignored "-Wframe-larger-than="
> >> +#endif
> >>    void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
> >>      CHECK(context);
> >>      CHECK_GE(max_depth, 2);
> >> @@ -74,6 +78,9 @@ void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
> >>        trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
> >>      }
> >>    }
> >> +#ifdef __clang__
> >> +#pragma clang diagnostic pop
> >> +#endif
> >>    #endif  // #if !SANITIZER_GO
> >>
> >>    #endif  // SANITIZER_WINDOWS
> >> diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_win.cpp
> >> index 85ac2633bde..f383e130fa5 100644
> >> --- a/libsanitizer/sanitizer_common/sanitizer_win.cpp
> >> +++ b/libsanitizer/sanitizer_common/sanitizer_win.cpp
> >> @@ -334,8 +334,12 @@ bool MprotectNoAccess(uptr addr, uptr size) {
> >>    }
> >>
> >>    void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
> >> -  // This is almost useless on 32-bits.
> >> -  // FIXME: add madvise-analog when we move to 64-bits.
> >> +  uptr beg_aligned = RoundDownTo(beg, GetPageSizeCached()),
> >> +       end_aligned = RoundDownTo(end, GetPageSizeCached());
> >> +  CHECK(beg < end);                // make sure the region is sane
> >> +  if (beg_aligned == end_aligned)  // make sure we're freeing at least 1 page;
> >> +    return;
> >> +  UnmapOrDie((void *)beg, end_aligned - beg_aligned);
> >>    }
> >>
> >>    void SetShadowRegionHugePageMode(uptr addr, uptr size) {
> >> @@ -386,6 +390,12 @@ uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
> >>      return 0;
> >>    }
> >>
> >> +uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
> >> +                                uptr num_aliases, uptr ring_buffer_size) {
> >> +  CHECK(false && "HWASan aliasing is unimplemented on Windows");
> >> +  return 0;
> >> +}
> >> +
> >>    bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
> >>      MEMORY_BASIC_INFORMATION mbi;
> >>      CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi)));
> >> @@ -564,7 +574,7 @@ void Abort() {
> >>    // load the image at this address. Therefore, we call it the preferred base. Any
> >>    // addresses in the DWARF typically assume that the object has been loaded at
> >>    // this address.
> >> -static uptr GetPreferredBase(const char *modname) {
> >> +static uptr GetPreferredBase(const char *modname, char *buf, size_t buf_size) {
> >>      fd_t fd = OpenFile(modname, RdOnly, nullptr);
> >>      if (fd == kInvalidFd)
> >>        return 0;
> >> @@ -586,12 +596,10 @@ static uptr GetPreferredBase(const char *modname) {
> >>      // IMAGE_FILE_HEADER
> >>      // IMAGE_OPTIONAL_HEADER
> >>      // Seek to e_lfanew and read all that data.
> >> -  char buf[4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER)];
> >>      if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) ==
> >>          INVALID_SET_FILE_POINTER)
> >>        return 0;
> >> -  if (!ReadFromFile(fd, &buf[0], sizeof(buf), &bytes_read) ||
> >> -      bytes_read != sizeof(buf))
> >> +  if (!ReadFromFile(fd, buf, buf_size, &bytes_read) || bytes_read != buf_size)
> >>        return 0;
> >>
> >>      // Check for "PE\0\0" before the PE header.
> >> @@ -633,6 +641,10 @@ void ListOfModules::init() {
> >>        }
> >>      }
> >>
> >> +  InternalMmapVector<char> buf(4 + sizeof(IMAGE_FILE_HEADER) +
> >> +                               sizeof(IMAGE_OPTIONAL_HEADER));
> >> +  InternalMmapVector<wchar_t> modname_utf16(kMaxPathLength);
> >> +  InternalMmapVector<char> module_name(kMaxPathLength);
> >>      // |num_modules| is the number of modules actually present,
> >>      size_t num_modules = bytes_required / sizeof(HMODULE);
> >>      for (size_t i = 0; i < num_modules; ++i) {
> >> @@ -642,15 +654,13 @@ void ListOfModules::init() {
> >>          continue;
> >>
> >>        // Get the UTF-16 path and convert to UTF-8.
> >> -    wchar_t modname_utf16[kMaxPathLength];
> >>        int modname_utf16_len =
> >> -        GetModuleFileNameW(handle, modname_utf16, kMaxPathLength);
> >> +        GetModuleFileNameW(handle, &modname_utf16[0], kMaxPathLength);
> >>        if (modname_utf16_len == 0)
> >>          modname_utf16[0] = '\0';
> >> -    char module_name[kMaxPathLength];
> >> -    int module_name_len =
> >> -        ::WideCharToMultiByte(CP_UTF8, 0, modname_utf16, modname_utf16_len + 1,
> >> -                              &module_name[0], kMaxPathLength, NULL, NULL);
> >> +    int module_name_len = ::WideCharToMultiByte(
> >> +        CP_UTF8, 0, &modname_utf16[0], modname_utf16_len + 1, &module_name[0],
> >> +        kMaxPathLength, NULL, NULL);
> >>        module_name[module_name_len] = '\0';
> >>
> >>        uptr base_address = (uptr)mi.lpBaseOfDll;
> >> @@ -660,15 +670,16 @@ void ListOfModules::init() {
> >>        // RVA when computing the module offset. This helps llvm-symbolizer find the
> >>        // right DWARF CU. In the common case that the image is loaded at it's
> >>        // preferred address, we will now print normal virtual addresses.
> >> -    uptr preferred_base = GetPreferredBase(&module_name[0]);
> >> +    uptr preferred_base =
> >> +        GetPreferredBase(&module_name[0], &buf[0], buf.size());
> >>        uptr adjusted_base = base_address - preferred_base;
> >>
> >> -    LoadedModule cur_module;
> >> -    cur_module.set(module_name, adjusted_base);
> >> +    modules_.push_back(LoadedModule());
> >> +    LoadedModule &cur_module = modules_.back();
> >> +    cur_module.set(&module_name[0], adjusted_base);
> >>        // We add the whole module as one single address range.
> >>        cur_module.addAddressRange(base_address, end_address, /*executable*/ true,
> >>                                   /*writable*/ true);
> >> -    modules_.push_back(cur_module);
> >>      }
> >>      UnmapOrDie(hmodules, modules_buffer_size);
> >>    }
> >> @@ -956,22 +967,27 @@ void SignalContext::InitPcSpBp() {
> >>
> >>    uptr SignalContext::GetAddress() const {
> >>      EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
> >> -  return exception_record->ExceptionInformation[1];
> >> +  if (exception_record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
> >> +    return exception_record->ExceptionInformation[1];
> >> +  return (uptr)exception_record->ExceptionAddress;
> >>    }
> >>
> >>    bool SignalContext::IsMemoryAccess() const {
> >> -  return GetWriteFlag() != SignalContext::UNKNOWN;
> >> +  return ((EXCEPTION_RECORD *)siginfo)->ExceptionCode ==
> >> +         EXCEPTION_ACCESS_VIOLATION;
> >>    }
> >>
> >> -bool SignalContext::IsTrueFaultingAddress() const {
> >> -  // FIXME: Provide real implementation for this. See Linux and Mac variants.
> >> -  return IsMemoryAccess();
> >> -}
> >> +bool SignalContext::IsTrueFaultingAddress() const { return true; }
> >>
> >>    SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
> >>      EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
> >> +
> >> +  // The write flag is only available for access violation exceptions.
> >> +  if (exception_record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
> >> +    return SignalContext::UNKNOWN;
> >> +
> >>      // The contents of this array are documented at
> >> -  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx
> >> +  // https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record
> >>      // The first element indicates read as 0, write as 1, or execute as 8.  The
> >>      // second element is the faulting address.
> >>      switch (exception_record->ExceptionInformation[0]) {
> >> @@ -1037,10 +1053,24 @@ const char *SignalContext::Describe() const {
> >>    }
> >>
> >>    uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
> >> -  // FIXME: Actually implement this function.
> >> -  CHECK_GT(buf_len, 0);
> >> -  buf[0] = 0;
> >> -  return 0;
> >> +  if (buf_len == 0)
> >> +    return 0;
> >> +
> >> +  // Get the UTF-16 path and convert to UTF-8.
> >> +  InternalMmapVector<wchar_t> binname_utf16(kMaxPathLength);
> >> +  int binname_utf16_len =
> >> +      GetModuleFileNameW(NULL, &binname_utf16[0], kMaxPathLength);
> >> +  if (binname_utf16_len == 0) {
> >> +    buf[0] = '\0';
> >> +    return 0;
> >> +  }
> >> +  int binary_name_len =
> >> +      ::WideCharToMultiByte(CP_UTF8, 0, &binname_utf16[0], binname_utf16_len,
> >> +                            buf, buf_len, NULL, NULL);
> >> +  if ((unsigned)binary_name_len == buf_len)
> >> +    --binary_name_len;
> >> +  buf[binary_name_len] = '\0';
> >> +  return binary_name_len;
> >>    }
> >>
> >>    uptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) {
> >> diff --git a/libsanitizer/tsan/tsan_clock.cpp b/libsanitizer/tsan/tsan_clock.cpp
> >> index c91b29cb22b..8e5188392ca 100644
> >> --- a/libsanitizer/tsan/tsan_clock.cpp
> >> +++ b/libsanitizer/tsan/tsan_clock.cpp
> >> @@ -150,7 +150,7 @@ void ThreadClock::acquire(ClockCache *c, SyncClock *src) {
> >>      bool acquired = false;
> >>      for (unsigned i = 0; i < kDirtyTids; i++) {
> >>        SyncClock::Dirty dirty = src->dirty_[i];
> >> -    unsigned tid = dirty.tid;
> >> +    unsigned tid = dirty.tid();
> >>        if (tid != kInvalidTid) {
> >>          if (clk_[tid] < dirty.epoch) {
> >>            clk_[tid] = dirty.epoch;
> >> @@ -299,10 +299,10 @@ void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) {
> >>        dst->tab_idx_ = cached_idx_;
> >>        dst->size_ = cached_size_;
> >>        dst->blocks_ = cached_blocks_;
> >> -    CHECK_EQ(dst->dirty_[0].tid, kInvalidTid);
> >> +    CHECK_EQ(dst->dirty_[0].tid(), kInvalidTid);
> >>        // The cached clock is shared (immutable),
> >>        // so this is where we store the current clock.
> >> -    dst->dirty_[0].tid = tid_;
> >> +    dst->dirty_[0].set_tid(tid_);
> >>        dst->dirty_[0].epoch = clk_[tid_];
> >>        dst->release_store_tid_ = tid_;
> >>        dst->release_store_reused_ = reused_;
> >> @@ -336,8 +336,7 @@ void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) {
> >>        ce.reused = 0;
> >>        i++;
> >>      }
> >> -  for (uptr i = 0; i < kDirtyTids; i++)
> >> -    dst->dirty_[i].tid = kInvalidTid;
> >> +  for (uptr i = 0; i < kDirtyTids; i++) dst->dirty_[i].set_tid(kInvalidTid);
> >>      dst->release_store_tid_ = tid_;
> >>      dst->release_store_reused_ = reused_;
> >>      // Rememeber that we don't need to acquire it in future.
> >> @@ -369,10 +368,10 @@ void ThreadClock::UpdateCurrentThread(ClockCache *c, SyncClock *dst) const {
> >>      // Update the threads time, but preserve 'acquired' flag.
> >>      for (unsigned i = 0; i < kDirtyTids; i++) {
> >>        SyncClock::Dirty *dirty = &dst->dirty_[i];
> >> -    const unsigned tid = dirty->tid;
> >> +    const unsigned tid = dirty->tid();
> >>        if (tid == tid_ || tid == kInvalidTid) {
> >>          CPP_STAT_INC(StatClockReleaseFast);
> >> -      dirty->tid = tid_;
> >> +      dirty->set_tid(tid_);
> >>          dirty->epoch = clk_[tid_];
> >>          return;
> >>        }
> >> @@ -393,8 +392,8 @@ bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const {
> >>        return false;
> >>      for (unsigned i = 0; i < kDirtyTids; i++) {
> >>        SyncClock::Dirty dirty = src->dirty_[i];
> >> -    if (dirty.tid != kInvalidTid) {
> >> -      if (clk_[dirty.tid] < dirty.epoch)
> >> +    if (dirty.tid() != kInvalidTid) {
> >> +      if (clk_[dirty.tid()] < dirty.epoch)
> >>            return false;
> >>        }
> >>      }
> >> @@ -453,8 +452,7 @@ void SyncClock::ResetImpl() {
> >>      blocks_ = 0;
> >>      release_store_tid_ = kInvalidTid;
> >>      release_store_reused_ = 0;
> >> -  for (uptr i = 0; i < kDirtyTids; i++)
> >> -    dirty_[i].tid = kInvalidTid;
> >> +  for (uptr i = 0; i < kDirtyTids; i++) dirty_[i].set_tid(kInvalidTid);
> >>    }
> >>
> >>    void SyncClock::Resize(ClockCache *c, uptr nclk) {
> >> @@ -503,10 +501,10 @@ void SyncClock::Resize(ClockCache *c, uptr nclk) {
> >>    void SyncClock::FlushDirty() {
> >>      for (unsigned i = 0; i < kDirtyTids; i++) {
> >>        Dirty *dirty = &dirty_[i];
> >> -    if (dirty->tid != kInvalidTid) {
> >> -      CHECK_LT(dirty->tid, size_);
> >> -      elem(dirty->tid).epoch = dirty->epoch;
> >> -      dirty->tid = kInvalidTid;
> >> +    if (dirty->tid() != kInvalidTid) {
> >> +      CHECK_LT(dirty->tid(), size_);
> >> +      elem(dirty->tid()).epoch = dirty->epoch;
> >> +      dirty->set_tid(kInvalidTid);
> >>        }
> >>      }
> >>    }
> >> @@ -559,7 +557,7 @@ ALWAYS_INLINE bool SyncClock::Cachable() const {
> >>      if (size_ == 0)
> >>        return false;
> >>      for (unsigned i = 0; i < kDirtyTids; i++) {
> >> -    if (dirty_[i].tid != kInvalidTid)
> >> +    if (dirty_[i].tid() != kInvalidTid)
> >>          return false;
> >>      }
> >>      return atomic_load_relaxed(ref_ptr(tab_)) == 1;
> >> @@ -606,7 +604,7 @@ ALWAYS_INLINE void SyncClock::append_block(u32 idx) {
> >>    u64 SyncClock::get(unsigned tid) const {
> >>      for (unsigned i = 0; i < kDirtyTids; i++) {
> >>        Dirty dirty = dirty_[i];
> >> -    if (dirty.tid == tid)
> >> +    if (dirty.tid() == tid)
> >>          return dirty.epoch;
> >>      }
> >>      return elem(tid).epoch;
> >> @@ -625,9 +623,8 @@ void SyncClock::DebugDump(int(*printf)(const char *s, ...)) {
> >>      for (uptr i = 0; i < size_; i++)
> >>        printf("%s%llu", i == 0 ? "" : ",", elem(i).reused);
> >>      printf("] release_store_tid=%d/%d dirty_tids=%d[%llu]/%d[%llu]",
> >> -      release_store_tid_, release_store_reused_,
> >> -      dirty_[0].tid, dirty_[0].epoch,
> >> -      dirty_[1].tid, dirty_[1].epoch);
> >> +         release_store_tid_, release_store_reused_, dirty_[0].tid(),
> >> +         dirty_[0].epoch, dirty_[1].tid(), dirty_[1].epoch);
> >>    }
> >>
> >>    void SyncClock::Iter::Next() {
> >> diff --git a/libsanitizer/tsan/tsan_clock.h b/libsanitizer/tsan/tsan_clock.h
> >> index 736cdae06ba..31376a1bc9e 100644
> >> --- a/libsanitizer/tsan/tsan_clock.h
> >> +++ b/libsanitizer/tsan/tsan_clock.h
> >> @@ -17,7 +17,7 @@
> >>
> >>    namespace __tsan {
> >>
> >> -typedef DenseSlabAlloc<ClockBlock, 1<<16, 1<<10> ClockAlloc;
> >> +typedef DenseSlabAlloc<ClockBlock, 1 << 22, 1 << 10> ClockAlloc;
> >>    typedef DenseSlabAllocCache ClockCache;
> >>
> >>    // The clock that lives in sync variables (mutexes, atomics, etc).
> >> @@ -65,10 +65,20 @@ class SyncClock {
> >>      static const uptr kDirtyTids = 2;
> >>
> >>      struct Dirty {
> >> -    u64 epoch  : kClkBits;
> >> -    u64 tid : 64 - kClkBits;  // kInvalidId if not active
> >> +    u32 tid() const { return tid_ == kShortInvalidTid ? kInvalidTid : tid_; }
> >> +    void set_tid(u32 tid) {
> >> +      tid_ = tid == kInvalidTid ? kShortInvalidTid : tid;
> >> +    }
> >> +    u64 epoch : kClkBits;
> >> +
> >> +   private:
> >> +    // Full kInvalidTid won't fit into Dirty::tid.
> >> +    static const u64 kShortInvalidTid = (1ull << (64 - kClkBits)) - 1;
> >> +    u64 tid_ : 64 - kClkBits;  // kInvalidId if not active
> >>      };
> >>
> >> +  static_assert(sizeof(Dirty) == 8, "Dirty is not 64bit");
> >> +
> >>      unsigned release_store_tid_;
> >>      unsigned release_store_reused_;
> >>      Dirty dirty_[kDirtyTids];
> >> diff --git a/libsanitizer/tsan/tsan_defs.h b/libsanitizer/tsan/tsan_defs.h
> >> index 293d7deccc3..f53787aeba9 100644
> >> --- a/libsanitizer/tsan/tsan_defs.h
> >> +++ b/libsanitizer/tsan/tsan_defs.h
> >> @@ -98,8 +98,6 @@ const bool kCollectHistory = false;
> >>    const bool kCollectHistory = true;
> >>    #endif
> >>
> >> -const u16 kInvalidTid = kMaxTid + 1;
> >> -
> >>    // The following "build consistency" machinery ensures that all source files
> >>    // are built in the same configuration. Inconsistent builds lead to
> >>    // hard to debug crashes.
> >> diff --git a/libsanitizer/tsan/tsan_dense_alloc.h b/libsanitizer/tsan/tsan_dense_alloc.h
> >> index 64fc50e95c2..6c89e405980 100644
> >> --- a/libsanitizer/tsan/tsan_dense_alloc.h
> >> +++ b/libsanitizer/tsan/tsan_dense_alloc.h
> >> @@ -29,28 +29,40 @@ class DenseSlabAllocCache {
> >>      typedef u32 IndexT;
> >>      uptr pos;
> >>      IndexT cache[kSize];
> >> -  template<typename T, uptr kL1Size, uptr kL2Size> friend class DenseSlabAlloc;
> >> +  template <typename, uptr, uptr, u64>
> >> +  friend class DenseSlabAlloc;
> >>    };
> >>
> >> -template<typename T, uptr kL1Size, uptr kL2Size>
> >> +template <typename T, uptr kL1Size, uptr kL2Size, u64 kReserved = 0>
> >>    class DenseSlabAlloc {
> >>     public:
> >>      typedef DenseSlabAllocCache Cache;
> >>      typedef typename Cache::IndexT IndexT;
> >>
> >> -  explicit DenseSlabAlloc(const char *name) {
> >> -    // Check that kL1Size and kL2Size are sane.
> >> -    CHECK_EQ(kL1Size & (kL1Size - 1), 0);
> >> -    CHECK_EQ(kL2Size & (kL2Size - 1), 0);
> >> -    CHECK_GE(1ull << (sizeof(IndexT) * 8), kL1Size * kL2Size);
> >> -    // Check that it makes sense to use the dense alloc.
> >> -    CHECK_GE(sizeof(T), sizeof(IndexT));
> >> -    internal_memset(map_, 0, sizeof(map_));
> >> +  static_assert((kL1Size & (kL1Size - 1)) == 0,
> >> +                "kL1Size must be a power-of-two");
> >> +  static_assert((kL2Size & (kL2Size - 1)) == 0,
> >> +                "kL2Size must be a power-of-two");
> >> +  static_assert((kL1Size * kL2Size) <= (1ull << (sizeof(IndexT) * 8)),
> >> +                "kL1Size/kL2Size are too large");
> >> +  static_assert(((kL1Size * kL2Size - 1) & kReserved) == 0,
> >> +                "reserved bits don't fit");
> >> +  static_assert(sizeof(T) > sizeof(IndexT),
> >> +                "it doesn't make sense to use dense alloc");
> >> +
> >> +  explicit DenseSlabAlloc(LinkerInitialized, const char *name) {
> >>        freelist_ = 0;
> >>        fillpos_ = 0;
> >>        name_ = name;
> >>      }
> >>
> >> +  explicit DenseSlabAlloc(const char *name)
> >> +      : DenseSlabAlloc(LINKER_INITIALIZED, name) {
> >> +    // It can be very large.
> >> +    // Don't page it in for linker initialized objects.
> >> +    internal_memset(map_, 0, sizeof(map_));
> >> +  }
> >> +
> >>      ~DenseSlabAlloc() {
> >>        for (uptr i = 0; i < kL1Size; i++) {
> >>          if (map_[i] != 0)
> >> diff --git a/libsanitizer/tsan/tsan_external.cpp b/libsanitizer/tsan/tsan_external.cpp
> >> index 466b2bf0f66..a87e12f2936 100644
> >> --- a/libsanitizer/tsan/tsan_external.cpp
> >> +++ b/libsanitizer/tsan/tsan_external.cpp
> >> @@ -111,12 +111,12 @@ void __tsan_external_assign_tag(void *addr, void *tag) {
> >>
> >>    SANITIZER_INTERFACE_ATTRIBUTE
> >>    void __tsan_external_read(void *addr, void *caller_pc, void *tag) {
> >> -  ExternalAccess(addr, STRIP_PC(caller_pc), tag, MemoryRead);
> >> +  ExternalAccess(addr, STRIP_PAC_PC(caller_pc), tag, MemoryRead);
> >>    }
> >>
> >>    SANITIZER_INTERFACE_ATTRIBUTE
> >>    void __tsan_external_write(void *addr, void *caller_pc, void *tag) {
> >> -  ExternalAccess(addr, STRIP_PC(caller_pc), tag, MemoryWrite);
> >> +  ExternalAccess(addr, STRIP_PAC_PC(caller_pc), tag, MemoryWrite);
> >>    }
> >>    }  // extern "C"
> >>
> >> diff --git a/libsanitizer/tsan/tsan_interceptors_mac.cpp b/libsanitizer/tsan/tsan_interceptors_mac.cpp
> >> index aa29536d861..ed10fccc980 100644
> >> --- a/libsanitizer/tsan/tsan_interceptors_mac.cpp
> >> +++ b/libsanitizer/tsan/tsan_interceptors_mac.cpp
> >> @@ -438,6 +438,7 @@ struct fake_shared_weak_count {
> >>      virtual void on_zero_shared() = 0;
> >>      virtual void _unused_0x18() = 0;
> >>      virtual void on_zero_shared_weak() = 0;
> >> +  virtual ~fake_shared_weak_count() = 0;  // suppress -Wnon-virtual-dtor
> >>    };
> >>    }  // namespace
> >>
> >> diff --git a/libsanitizer/tsan/tsan_interceptors_posix.cpp b/libsanitizer/tsan/tsan_interceptors_posix.cpp
> >> index aa04d8dfb67..2651e22c39f 100644
> >> --- a/libsanitizer/tsan/tsan_interceptors_posix.cpp
> >> +++ b/libsanitizer/tsan/tsan_interceptors_posix.cpp
> >> @@ -54,10 +54,6 @@ using namespace __tsan;
> >>    #define vfork __vfork14
> >>    #endif
> >>
> >> -#if SANITIZER_ANDROID
> >> -#define mallopt(a, b)
> >> -#endif
> >> -
> >>    #ifdef __mips__
> >>    const int kSigCount = 129;
> >>    #else
> >> @@ -85,6 +81,8 @@ extern "C" int pthread_attr_init(void *attr);
> >>    extern "C" int pthread_attr_destroy(void *attr);
> >>    DECLARE_REAL(int, pthread_attr_getdetachstate, void *, void *)
> >>    extern "C" int pthread_attr_setstacksize(void *attr, uptr stacksize);
> >> +extern "C" int pthread_atfork(void (*prepare)(void), void (*parent)(void),
> >> +                              void (*child)(void));
> >>    extern "C" int pthread_key_create(unsigned *key, void (*destructor)(void* v));
> >>    extern "C" int pthread_setspecific(unsigned key, const void *v);
> >>    DECLARE_REAL(int, pthread_mutexattr_gettype, void *, void *)
> >> @@ -97,7 +95,7 @@ extern "C" void _exit(int status);
> >>    extern "C" int fileno_unlocked(void *stream);
> >>    extern "C" int dirfd(void *dirp);
> >>    #endif
> >> -#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_NETBSD
> >> +#if SANITIZER_GLIBC
> >>    extern "C" int mallopt(int param, int value);
> >>    #endif
> >>    #if SANITIZER_NETBSD
> >> @@ -659,8 +657,11 @@ TSAN_INTERCEPTOR(void*, malloc, uptr size) {
> >>      return p;
> >>    }
> >>
> >> +// In glibc<2.25, dynamic TLS blocks are allocated by __libc_memalign. Intercept
> >> +// __libc_memalign so that (1) we can detect races (2) free will not be called
> >> +// on libc internally allocated blocks.
> >>    TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) {
> >> -  SCOPED_TSAN_INTERCEPTOR(__libc_memalign, align, sz);
> >> +  SCOPED_INTERCEPTOR_RAW(__libc_memalign, align, sz);
> >>      return user_memalign(thr, pc, align, sz);
> >>    }
> >>
> >> @@ -773,6 +774,11 @@ static void *mmap_interceptor(ThreadState *thr, uptr pc, Mmap real_mmap,
> >>      if (!fix_mmap_addr(&addr, sz, flags)) return MAP_FAILED;
> >>      void *res = real_mmap(addr, sz, prot, flags, fd, off);
> >>      if (res != MAP_FAILED) {
> >> +    if (!IsAppMem((uptr)res) || !IsAppMem((uptr)res + sz - 1)) {
> >> +      Report("ThreadSanitizer: mmap at bad address: addr=%p size=%p res=%p\n",
> >> +             addr, (void*)sz, res);
> >> +      Die();
> >> +    }
> >>        if (fd > 0) FdAccess(thr, pc, fd);
> >>        MemoryRangeImitateWriteOrResetRange(thr, pc, (uptr)res, sz);
> >>      }
> >> @@ -1122,27 +1128,37 @@ static void *init_cond(void *c, bool force = false) {
> >>      return (void*)cond;
> >>    }
> >>
> >> +namespace {
> >> +
> >> +template <class Fn>
> >>    struct CondMutexUnlockCtx {
> >>      ScopedInterceptor *si;
> >>      ThreadState *thr;
> >>      uptr pc;
> >>      void *m;
> >> +  void *c;
> >> +  const Fn &fn;
> >> +
> >> +  int Cancel() const { return fn(); }
> >> +  void Unlock() const;
> >>    };
> >>
> >> -static void cond_mutex_unlock(CondMutexUnlockCtx *arg) {
> >> +template <class Fn>
> >> +void CondMutexUnlockCtx<Fn>::Unlock() const {
> >>      // pthread_cond_wait interceptor has enabled async signal delivery
> >>      // (see BlockingCall below). Disable async signals since we are running
> >>      // tsan code. Also ScopedInterceptor and BlockingCall destructors won't run
> >>      // since the thread is cancelled, so we have to manually execute them
> >>      // (the thread still can run some user code due to pthread_cleanup_push).
> >> -  ThreadSignalContext *ctx = SigCtx(arg->thr);
> >> +  ThreadSignalContext *ctx = SigCtx(thr);
> >>      CHECK_EQ(atomic_load(&ctx->in_blocking_func, memory_order_relaxed), 1);
> >>      atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed);
> >> -  MutexPostLock(arg->thr, arg->pc, (uptr)arg->m, MutexFlagDoPreLockOnPostLock);
> >> +  MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock);
> >>      // Undo BlockingCall ctor effects.
> >> -  arg->thr->ignore_interceptors--;
> >> -  arg->si->~ScopedInterceptor();
> >> +  thr->ignore_interceptors--;
> >> +  si->~ScopedInterceptor();
> >>    }
> >> +}  // namespace
> >>
> >>    INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
> >>      void *cond = init_cond(c, true);
> >> @@ -1151,20 +1167,24 @@ INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
> >>      return REAL(pthread_cond_init)(cond, a);
> >>    }
> >>
> >> -static int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si,
> >> -                     int (*fn)(void *c, void *m, void *abstime), void *c,
> >> -                     void *m, void *t) {
> >> +template <class Fn>
> >> +int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si, const Fn &fn,
> >> +              void *c, void *m) {
> >>      MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
> >>      MutexUnlock(thr, pc, (uptr)m);
> >> -  CondMutexUnlockCtx arg = {si, thr, pc, m};
> >>      int res = 0;
> >>      // This ensures that we handle mutex lock even in case of pthread_cancel.
> >>      // See test/tsan/cond_cancel.cpp.
> >>      {
> >>        // Enable signal delivery while the thread is blocked.
> >>        BlockingCall bc(thr);
> >> +    CondMutexUnlockCtx<Fn> arg = {si, thr, pc, m, c, fn};
> >>        res = call_pthread_cancel_with_cleanup(
> >> -        fn, c, m, t, (void (*)(void *arg))cond_mutex_unlock, &arg);
> >> +        [](void *arg) -> int {
> >> +          return ((const CondMutexUnlockCtx<Fn> *)arg)->Cancel();
> >> +        },
> >> +        [](void *arg) { ((const CondMutexUnlockCtx<Fn> *)arg)->Unlock(); },
> >> +        &arg);
> >>      }
> >>      if (res == errno_EOWNERDEAD) MutexRepair(thr, pc, (uptr)m);
> >>      MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock);
> >> @@ -1174,25 +1194,46 @@ static int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si,
> >>    INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
> >>      void *cond = init_cond(c);
> >>      SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m);
> >> -  return cond_wait(thr, pc, &si, (int (*)(void *c, void *m, void *abstime))REAL(
> >> -                                     pthread_cond_wait),
> >> -                   cond, m, 0);
> >> +  return cond_wait(
> >> +      thr, pc, &si, [=]() { return REAL(pthread_cond_wait)(cond, m); }, cond,
> >> +      m);
> >>    }
> >>
> >>    INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) {
> >>      void *cond = init_cond(c);
> >>      SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, cond, m, abstime);
> >> -  return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait), cond, m,
> >> -                   abstime);
> >> +  return cond_wait(
> >> +      thr, pc, &si,
> >> +      [=]() { return REAL(pthread_cond_timedwait)(cond, m, abstime); }, cond,
> >> +      m);
> >>    }
> >>
> >> +#if SANITIZER_LINUX
> >> +INTERCEPTOR(int, pthread_cond_clockwait, void *c, void *m,
> >> +            __sanitizer_clockid_t clock, void *abstime) {
> >> +  void *cond = init_cond(c);
> >> +  SCOPED_TSAN_INTERCEPTOR(pthread_cond_clockwait, cond, m, clock, abstime);
> >> +  return cond_wait(
> >> +      thr, pc, &si,
> >> +      [=]() { return REAL(pthread_cond_clockwait)(cond, m, clock, abstime); },
> >> +      cond, m);
> >> +}
> >> +#define TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT TSAN_INTERCEPT(pthread_cond_clockwait)
> >> +#else
> >> +#define TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT
> >> +#endif
> >> +
> >>    #if SANITIZER_MAC
> >>    INTERCEPTOR(int, pthread_cond_timedwait_relative_np, void *c, void *m,
> >>                void *reltime) {
> >>      void *cond = init_cond(c);
> >>      SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait_relative_np, cond, m, reltime);
> >> -  return cond_wait(thr, pc, &si, REAL(pthread_cond_timedwait_relative_np), cond,
> >> -                   m, reltime);
> >> +  return cond_wait(
> >> +      thr, pc, &si,
> >> +      [=]() {
> >> +        return REAL(pthread_cond_timedwait_relative_np)(cond, m, reltime);
> >> +      },
> >> +      cond, m);
> >>    }
> >>    #endif
> >>
> >> @@ -1937,7 +1978,8 @@ static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
> >>      // because in async signal processing case (when handler is called directly
> >>      // from rtl_generic_sighandler) we have not yet received the reraised
> >>      // signal; and it looks too fragile to intercept all ways to reraise a signal.
> >> -  if (flags()->report_bugs && !sync && sig != SIGTERM && errno != 99) {
> >> +  if (ShouldReport(thr, ReportTypeErrnoInSignal) && !sync && sig != SIGTERM &&
> >> +      errno != 99) {
> >>        VarSizeStackTrace stack;
> >>        // StackTrace::GetNestInstructionPc(pc) is used because return address is
> >>        // expected, OutputReport() will undo this.
> >> @@ -2107,26 +2149,32 @@ TSAN_INTERCEPTOR(int, fork, int fake) {
> >>      if (in_symbolizer())
> >>        return REAL(fork)(fake);
> >>      SCOPED_INTERCEPTOR_RAW(fork, fake);
> >> +  return REAL(fork)(fake);
> >> +}
> >> +
> >> +void atfork_prepare() {
> >> +  if (in_symbolizer())
> >> +    return;
> >> +  ThreadState *thr = cur_thread();
> >> +  const uptr pc = StackTrace::GetCurrentPc();
> >>      ForkBefore(thr, pc);
> >> -  int pid;
> >> -  {
> >> -    // On OS X, REAL(fork) can call intercepted functions (OSSpinLockLock), and
> >> -    // we'll assert in CheckNoLocks() unless we ignore interceptors.
> >> -    ScopedIgnoreInterceptors ignore;
> >> -    pid = REAL(fork)(fake);
> >> -  }
> >> -  if (pid == 0) {
> >> -    // child
> >> -    ForkChildAfter(thr, pc);
> >> -    FdOnFork(thr, pc);
> >> -  } else if (pid > 0) {
> >> -    // parent
> >> -    ForkParentAfter(thr, pc);
> >> -  } else {
> >> -    // error
> >> -    ForkParentAfter(thr, pc);
> >> -  }
> >> -  return pid;
> >> +}
> >> +
> >> +void atfork_parent() {
> >> +  if (in_symbolizer())
> >> +    return;
> >> +  ThreadState *thr = cur_thread();
> >> +  const uptr pc = StackTrace::GetCurrentPc();
> >> +  ForkParentAfter(thr, pc);
> >> +}
> >> +
> >> +void atfork_child() {
> >> +  if (in_symbolizer())
> >> +    return;
> >> +  ThreadState *thr = cur_thread();
> >> +  const uptr pc = StackTrace::GetCurrentPc();
> >> +  ForkChildAfter(thr, pc);
> >> +  FdOnFork(thr, pc);
> >>    }
> >>
> >>    TSAN_INTERCEPTOR(int, vfork, int fake) {
> >> @@ -2479,13 +2527,10 @@ static USED void syscall_fd_release(uptr pc, int fd) {
> >>      FdRelease(thr, pc, fd);
> >>    }
> >>
> >> -static void syscall_pre_fork(uptr pc) {
> >> -  TSAN_SYSCALL();
> >> -  ForkBefore(thr, pc);
> >> -}
> >> +static void syscall_pre_fork(uptr pc) { ForkBefore(cur_thread(), pc); }
> >>
> >>    static void syscall_post_fork(uptr pc, int pid) {
> >> -  TSAN_SYSCALL();
> >> +  ThreadState *thr = cur_thread();
> >>      if (pid == 0) {
> >>        // child
> >>        ForkChildAfter(thr, pc);
> >> @@ -2635,7 +2680,7 @@ void InitializeInterceptors() {
> >>    #endif
> >>
> >>      // Instruct libc malloc to consume less memory.
> >> -#if SANITIZER_LINUX
> >> +#if SANITIZER_GLIBC
> >>      mallopt(1, 0);  // M_MXFAST
> >>      mallopt(-3, 32*1024);  // M_MMAP_THRESHOLD
> >>    #endif
> >> @@ -2698,6 +2743,8 @@ void InitializeInterceptors() {
> >>      TSAN_INTERCEPT_VER(pthread_cond_timedwait, PTHREAD_ABI_BASE);
> >>      TSAN_INTERCEPT_VER(pthread_cond_destroy, PTHREAD_ABI_BASE);
> >>
> >> +  TSAN_MAYBE_PTHREAD_COND_CLOCKWAIT;
> >> +
> >>      TSAN_INTERCEPT(pthread_mutex_init);
> >>      TSAN_INTERCEPT(pthread_mutex_destroy);
> >>      TSAN_INTERCEPT(pthread_mutex_trylock);
> >> @@ -2799,6 +2846,10 @@ void InitializeInterceptors() {
> >>        Printf("ThreadSanitizer: failed to setup atexit callback\n");
> >>        Die();
> >>      }
> >> +  if (pthread_atfork(atfork_prepare, atfork_parent, atfork_child)) {
> >> +    Printf("ThreadSanitizer: failed to setup atfork callbacks\n");
> >> +    Die();
> >> +  }
> >>
> >>    #if !SANITIZER_MAC && !SANITIZER_NETBSD && !SANITIZER_FREEBSD
> >>      if (pthread_key_create(&interceptor_ctx()->finalize_key, &thread_finalize)) {
> >> diff --git a/libsanitizer/tsan/tsan_interface.cpp b/libsanitizer/tsan/tsan_interface.cpp
> >> index 55f1c9834f7..9bd0e8580b1 100644
> >> --- a/libsanitizer/tsan/tsan_interface.cpp
> >> +++ b/libsanitizer/tsan/tsan_interface.cpp
> >> @@ -40,13 +40,13 @@ void __tsan_write16(void *addr) {
> >>    }
> >>
> >>    void __tsan_read16_pc(void *addr, void *pc) {
> >> -  MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
> >> -  MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr + 8, kSizeLog8);
> >> +  MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
> >> +  MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr + 8, kSizeLog8);
> >>    }
> >>
> >>    void __tsan_write16_pc(void *addr, void *pc) {
> >> -  MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
> >> -  MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr + 8, kSizeLog8);
> >> +  MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
> >> +  MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr + 8, kSizeLog8);
> >>    }
> >>
> >>    // __tsan_unaligned_read/write calls are emitted by compiler.
> >> diff --git a/libsanitizer/tsan/tsan_interface.h b/libsanitizer/tsan/tsan_interface.h
> >> index 6d7286ca5b8..6e022b56850 100644
> >> --- a/libsanitizer/tsan/tsan_interface.h
> >> +++ b/libsanitizer/tsan/tsan_interface.h
> >> @@ -204,7 +204,7 @@ __extension__ typedef __int128 a128;
> >>    #endif
> >>
> >>    // Part of ABI, do not change.
> >> -// https://github.com/llvm/llvm-project/blob/master/libcxx/include/atomic
> >> +// https://github.com/llvm/llvm-project/blob/main/libcxx/include/atomic
> >>    typedef enum {
> >>      mo_relaxed,
> >>      mo_consume,
> >> @@ -415,6 +415,13 @@ void __tsan_go_atomic32_compare_exchange(ThreadState *thr, uptr cpc, uptr pc,
> >>    SANITIZER_INTERFACE_ATTRIBUTE
> >>    void __tsan_go_atomic64_compare_exchange(ThreadState *thr, uptr cpc, uptr pc,
> >>                                             u8 *a);
> >> +
> >> +SANITIZER_INTERFACE_ATTRIBUTE
> >> +void __tsan_on_initialize();
> >> +
> >> +SANITIZER_INTERFACE_ATTRIBUTE
> >> +int __tsan_on_finalize(int failed);
> >> +
> >>    }  // extern "C"
> >>
> >>    }  // namespace __tsan
> >> diff --git a/libsanitizer/tsan/tsan_interface_inl.h b/libsanitizer/tsan/tsan_interface_inl.h
> >> index f5d743c1077..5e77d4d3d28 100644
> >> --- a/libsanitizer/tsan/tsan_interface_inl.h
> >> +++ b/libsanitizer/tsan/tsan_interface_inl.h
> >> @@ -51,35 +51,35 @@ void __tsan_write8(void *addr) {
> >>    }
> >>
> >>    void __tsan_read1_pc(void *addr, void *pc) {
> >> -  MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog1);
> >> +  MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog1);
> >>    }
> >>
> >>    void __tsan_read2_pc(void *addr, void *pc) {
> >> -  MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog2);
> >> +  MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog2);
> >>    }
> >>
> >>    void __tsan_read4_pc(void *addr, void *pc) {
> >> -  MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog4);
> >> +  MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog4);
> >>    }
> >>
> >>    void __tsan_read8_pc(void *addr, void *pc) {
> >> -  MemoryRead(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
> >> +  MemoryRead(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
> >>    }
> >>
> >>    void __tsan_write1_pc(void *addr, void *pc) {
> >> -  MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog1);
> >> +  MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog1);
> >>    }
> >>
> >>    void __tsan_write2_pc(void *addr, void *pc) {
> >> -  MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog2);
> >> +  MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog2);
> >>    }
> >>
> >>    void __tsan_write4_pc(void *addr, void *pc) {
> >> -  MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog4);
> >> +  MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog4);
> >>    }
> >>
> >>    void __tsan_write8_pc(void *addr, void *pc) {
> >> -  MemoryWrite(cur_thread(), STRIP_PC(pc), (uptr)addr, kSizeLog8);
> >> +  MemoryWrite(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, kSizeLog8);
> >>    }
> >>
> >>    void __tsan_vptr_update(void **vptr_p, void *new_val) {
> >> @@ -101,7 +101,7 @@ void __tsan_vptr_read(void **vptr_p) {
> >>    }
> >>
> >>    void __tsan_func_entry(void *pc) {
> >> -  FuncEntry(cur_thread(), STRIP_PC(pc));
> >> +  FuncEntry(cur_thread(), STRIP_PAC_PC(pc));
> >>    }
> >>
> >>    void __tsan_func_exit() {
> >> @@ -125,9 +125,9 @@ void __tsan_write_range(void *addr, uptr size) {
> >>    }
> >>
> >>    void __tsan_read_range_pc(void *addr, uptr size, void *pc) {
> >> -  MemoryAccessRange(cur_thread(), STRIP_PC(pc), (uptr)addr, size, false);
> >> +  MemoryAccessRange(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, size, false);
> >>    }
> >>
> >>    void __tsan_write_range_pc(void *addr, uptr size, void *pc) {
> >> -  MemoryAccessRange(cur_thread(), STRIP_PC(pc), (uptr)addr, size, true);
> >> +  MemoryAccessRange(cur_thread(), STRIP_PAC_PC(pc), (uptr)addr, size, true);
> >>    }
> >> diff --git a/libsanitizer/tsan/tsan_mman.cpp b/libsanitizer/tsan/tsan_mman.cpp
> >> index 743e67bf2f7..45a39f0f8ec 100644
> >> --- a/libsanitizer/tsan/tsan_mman.cpp
> >> +++ b/libsanitizer/tsan/tsan_mman.cpp
> >> @@ -145,7 +145,7 @@ void AllocatorPrintStats() {
> >>
> >>    static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
> >>      if (atomic_load_relaxed(&thr->in_signal_handler) == 0 ||
> >> -      !flags()->report_signal_unsafe)
> >> +      !ShouldReport(thr, ReportTypeSignalUnsafe))
> >>        return;
> >>      VarSizeStackTrace stack;
> >>      ObtainCurrentStack(thr, pc, &stack);
> >> diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h
> >> index 16169cab666..101522d8fa4 100644
> >> --- a/libsanitizer/tsan/tsan_platform.h
> >> +++ b/libsanitizer/tsan/tsan_platform.h
> >> @@ -23,9 +23,21 @@
> >>
> >>    namespace __tsan {
> >>
> >> +#if defined(__x86_64__)
> >> +#define HAS_48_BIT_ADDRESS_SPACE 1
> >> +#elif SANITIZER_IOSSIM // arm64 iOS simulators (order of #if matters)
> >> +#define HAS_48_BIT_ADDRESS_SPACE 1
> >> +#elif SANITIZER_IOS // arm64 iOS devices (order of #if matters)
> >> +#define HAS_48_BIT_ADDRESS_SPACE 0
> >> +#elif SANITIZER_MAC // arm64 macOS (order of #if matters)
> >> +#define HAS_48_BIT_ADDRESS_SPACE 1
> >> +#else
> >> +#define HAS_48_BIT_ADDRESS_SPACE 0
> >> +#endif
> >> +
> >>    #if !SANITIZER_GO
> >>
> >> -#if defined(__x86_64__)
> >> +#if HAS_48_BIT_ADDRESS_SPACE
> >>    /*
> >>    C/C++ on linux/x86_64 and freebsd/x86_64
> >>    0000 0000 1000 - 0080 0000 0000: main binary and/or MAP_32BIT mappings (512GB)
> >> @@ -93,7 +105,7 @@ fe00 0000 00 - ff00 0000 00: heap                                        (4 GB)
> >>    ff00 0000 00 - ff80 0000 00: -                                           (2 GB)
> >>    ff80 0000 00 - ffff ffff ff: modules and main thread stack              (<2 GB)
> >>    */
> >> -struct Mapping {
> >> +struct Mapping40 {
> >>      static const uptr kMetaShadowBeg = 0x4000000000ull;
> >>      static const uptr kMetaShadowEnd = 0x5000000000ull;
> >>      static const uptr kTraceMemBeg   = 0xb000000000ull;
> >> @@ -114,6 +126,7 @@ struct Mapping {
> >>    };
> >>
> >>    #define TSAN_MID_APP_RANGE 1
> >> +#define TSAN_RUNTIME_VMA 1
> >>    #elif defined(__aarch64__) && defined(__APPLE__)
> >>    /*
> >>    C/C++ on Darwin/iOS/ARM64 (36-bit VMA, 64 GB VM)
> >> @@ -146,7 +159,7 @@ struct Mapping {
> >>      static const uptr kVdsoBeg       = 0x7000000000000000ull;
> >>    };
> >>
> >> -#elif defined(__aarch64__)
> >> +#elif defined(__aarch64__) && !defined(__APPLE__)
> >>    // AArch64 supports multiple VMA which leads to multiple address transformation
> >>    // functions.  To support these multiple VMAS transformations and mappings TSAN
> >>    // runtime for AArch64 uses an external memory read (vmaSize) to select which
> >> @@ -354,7 +367,7 @@ struct Mapping47 {
> >>    #define TSAN_RUNTIME_VMA 1
> >>    #endif
> >>
> >> -#elif SANITIZER_GO && !SANITIZER_WINDOWS && defined(__x86_64__)
> >> +#elif SANITIZER_GO && !SANITIZER_WINDOWS && HAS_48_BIT_ADDRESS_SPACE
> >>
> >>    /* Go on linux, darwin and freebsd on x86_64
> >>    0000 0000 1000 - 0000 1000 0000: executable
> >> @@ -502,7 +515,7 @@ Go on linux/mips64 (47-bit VMA)
> >>    6000 0000 0000 - 6200 0000 0000: traces
> >>    6200 0000 0000 - 8000 0000 0000: -
> >>    */
> >> -struct Mapping {
> >> +struct Mapping47 {
> >>      static const uptr kMetaShadowBeg = 0x300000000000ull;
> >>      static const uptr kMetaShadowEnd = 0x400000000000ull;
> >>      static const uptr kTraceMemBeg = 0x600000000000ull;
> >> @@ -512,6 +525,9 @@ struct Mapping {
> >>      static const uptr kAppMemBeg = 0x000000001000ull;
> >>      static const uptr kAppMemEnd = 0x00e000000000ull;
> >>    };
> >> +
> >> +#define TSAN_RUNTIME_VMA 1
> >> +
> >>    #else
> >>    # error "Unknown platform"
> >>    #endif
> >> @@ -592,6 +608,16 @@ uptr MappingArchImpl(void) {
> >>      }
> >>      DCHECK(0);
> >>      return 0;
> >> +#elif defined(__mips64)
> >> +  switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> +    case 40: return MappingImpl<Mapping40, Type>();
> >> +#else
> >> +    case 47: return MappingImpl<Mapping47, Type>();
> >> +#endif
> >> +  }
> >> +  DCHECK(0);
> >> +  return 0;
> >>    #else
> >>      return MappingImpl<Mapping, Type>();
> >>    #endif
> >> @@ -749,6 +775,16 @@ bool IsAppMem(uptr mem) {
> >>      }
> >>      DCHECK(0);
> >>      return false;
> >> +#elif defined(__mips64)
> >> +  switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> +    case 40: return IsAppMemImpl<Mapping40>(mem);
> >> +#else
> >> +    case 47: return IsAppMemImpl<Mapping47>(mem);
> >> +#endif
> >> +  }
> >> +  DCHECK(0);
> >> +  return false;
> >>    #else
> >>      return IsAppMemImpl<Mapping>(mem);
> >>    #endif
> >> @@ -780,6 +816,16 @@ bool IsShadowMem(uptr mem) {
> >>      }
> >>      DCHECK(0);
> >>      return false;
> >> +#elif defined(__mips64)
> >> +  switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> +    case 40: return IsShadowMemImpl<Mapping40>(mem);
> >> +#else
> >> +    case 47: return IsShadowMemImpl<Mapping47>(mem);
> >> +#endif
> >> +  }
> >> +  DCHECK(0);
> >> +  return false;
> >>    #else
> >>      return IsShadowMemImpl<Mapping>(mem);
> >>    #endif
> >> @@ -811,6 +857,16 @@ bool IsMetaMem(uptr mem) {
> >>      }
> >>      DCHECK(0);
> >>      return false;
> >> +#elif defined(__mips64)
> >> +  switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> +    case 40: return IsMetaMemImpl<Mapping40>(mem);
> >> +#else
> >> +    case 47: return IsMetaMemImpl<Mapping47>(mem);
> >> +#endif
> >> +  }
> >> +  DCHECK(0);
> >> +  return false;
> >>    #else
> >>      return IsMetaMemImpl<Mapping>(mem);
> >>    #endif
> >> @@ -852,6 +908,16 @@ uptr MemToShadow(uptr x) {
> >>      }
> >>      DCHECK(0);
> >>      return 0;
> >> +#elif defined(__mips64)
> >> +  switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> +    case 40: return MemToShadowImpl<Mapping40>(x);
> >> +#else
> >> +    case 47: return MemToShadowImpl<Mapping47>(x);
> >> +#endif
> >> +  }
> >> +  DCHECK(0);
> >> +  return 0;
> >>    #else
> >>      return MemToShadowImpl<Mapping>(x);
> >>    #endif
> >> @@ -895,6 +961,16 @@ u32 *MemToMeta(uptr x) {
> >>      }
> >>      DCHECK(0);
> >>      return 0;
> >> +#elif defined(__mips64)
> >> +  switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> +    case 40: return MemToMetaImpl<Mapping40>(x);
> >> +#else
> >> +    case 47: return MemToMetaImpl<Mapping47>(x);
> >> +#endif
> >> +  }
> >> +  DCHECK(0);
> >> +  return 0;
> >>    #else
> >>      return MemToMetaImpl<Mapping>(x);
> >>    #endif
> >> @@ -951,6 +1027,16 @@ uptr ShadowToMem(uptr s) {
> >>      }
> >>      DCHECK(0);
> >>      return 0;
> >> +#elif defined(__mips64)
> >> +  switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> +    case 40: return ShadowToMemImpl<Mapping40>(s);
> >> +#else
> >> +    case 47: return ShadowToMemImpl<Mapping47>(s);
> >> +#endif
> >> +  }
> >> +  DCHECK(0);
> >> +  return 0;
> >>    #else
> >>      return ShadowToMemImpl<Mapping>(s);
> >>    #endif
> >> @@ -990,6 +1076,16 @@ uptr GetThreadTrace(int tid) {
> >>      }
> >>      DCHECK(0);
> >>      return 0;
> >> +#elif defined(__mips64)
> >> +  switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> +    case 40: return GetThreadTraceImpl<Mapping40>(tid);
> >> +#else
> >> +    case 47: return GetThreadTraceImpl<Mapping47>(tid);
> >> +#endif
> >> +  }
> >> +  DCHECK(0);
> >> +  return 0;
> >>    #else
> >>      return GetThreadTraceImpl<Mapping>(tid);
> >>    #endif
> >> @@ -1024,6 +1120,16 @@ uptr GetThreadTraceHeader(int tid) {
> >>      }
> >>      DCHECK(0);
> >>      return 0;
> >> +#elif defined(__mips64)
> >> +  switch (vmaSize) {
> >> +#if !SANITIZER_GO
> >> +    case 40: return GetThreadTraceHeaderImpl<Mapping40>(tid);
> >> +#else
> >> +    case 47: return GetThreadTraceHeaderImpl<Mapping47>(tid);
> >> +#endif
> >> +  }
> >> +  DCHECK(0);
> >> +  return 0;
> >>    #else
> >>      return GetThreadTraceHeaderImpl<Mapping>(tid);
> >>    #endif
> >> @@ -1040,9 +1146,8 @@ int ExtractRecvmsgFDs(void *msg, int *fds, int nfd);
> >>    uptr ExtractLongJmpSp(uptr *env);
> >>    void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size);
> >>
> >> -int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
> >> -    void *abstime), void *c, void *m, void *abstime,
> >> -    void(*cleanup)(void *arg), void *arg);
> >> +int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),
> >> +                                     void (*cleanup)(void *arg), void *arg);
> >>
> >>    void DestroyThreadState();
> >>    void PlatformCleanUpThreadState(ThreadState *thr);
> >> diff --git a/libsanitizer/tsan/tsan_platform_linux.cpp b/libsanitizer/tsan/tsan_platform_linux.cpp
> >> index d136dcb1cec..e5b6690edfd 100644
> >> --- a/libsanitizer/tsan/tsan_platform_linux.cpp
> >> +++ b/libsanitizer/tsan/tsan_platform_linux.cpp
> >> @@ -250,6 +250,20 @@ void InitializePlatformEarly() {
> >>        Die();
> >>      }
> >>    # endif
> >> +#elif defined(__mips64)
> >> +# if !SANITIZER_GO
> >> +  if (vmaSize != 40) {
> >> +    Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
> >> +    Printf("FATAL: Found %zd - Supported 40\n", vmaSize);
> >> +    Die();
> >> +  }
> >> +# else
> >> +  if (vmaSize != 47) {
> >> +    Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
> >> +    Printf("FATAL: Found %zd - Supported 47\n", vmaSize);
> >> +    Die();
> >> +  }
> >> +# endif
> >>    #endif
> >>    #endif
> >>    }
> >> @@ -443,14 +457,13 @@ void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {
> >>
> >>    // Note: this function runs with async signals enabled,
> >>    // so it must not touch any tsan state.
> >> -int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
> >> -    void *abstime), void *c, void *m, void *abstime,
> >> -    void(*cleanup)(void *arg), void *arg) {
> >> +int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),
> >> +                                     void (*cleanup)(void *arg), void *arg) {
> >>      // pthread_cleanup_push/pop are hardcore macros mess.
> >>      // We can't intercept nor call them w/o including pthread.h.
> >>      int res;
> >>      pthread_cleanup_push(cleanup, arg);
> >> -  res = fn(c, m, abstime);
> >> +  res = fn(arg);
> >>      pthread_cleanup_pop(0);
> >>      return res;
> >>    }
> >> @@ -484,7 +497,7 @@ ThreadState *cur_thread() {
> >>            dead_thread_state->fast_state.SetIgnoreBit();
> >>            dead_thread_state->ignore_interceptors = 1;
> >>            dead_thread_state->is_dead = true;
> >> -        *const_cast<int*>(&dead_thread_state->tid) = -1;
> >> +        *const_cast<u32*>(&dead_thread_state->tid) = -1;
> >>            CHECK_EQ(0, internal_mprotect(dead_thread_state, sizeof(ThreadState),
> >>                                          PROT_READ));
> >>          }
> >> diff --git a/libsanitizer/tsan/tsan_platform_mac.cpp b/libsanitizer/tsan/tsan_platform_mac.cpp
> >> index ec2c5fb1621..d9719a136b2 100644
> >> --- a/libsanitizer/tsan/tsan_platform_mac.cpp
> >> +++ b/libsanitizer/tsan/tsan_platform_mac.cpp
> >> @@ -234,7 +234,7 @@ static void my_pthread_introspection_hook(unsigned int event, pthread_t thread,
> >>    #endif
> >>
> >>    void InitializePlatformEarly() {
> >> -#if !SANITIZER_GO && defined(__aarch64__)
> >> +#if !SANITIZER_GO && !HAS_48_BIT_ADDRESS_SPACE
> >>      uptr max_vm = GetMaxUserVirtualAddress() + 1;
> >>      if (max_vm != Mapping::kHiAppMemEnd) {
> >>        Printf("ThreadSanitizer: unsupported vm address limit %p, expected %p.\n",
> >> @@ -306,14 +306,13 @@ void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {
> >>    #if !SANITIZER_GO
> >>    // Note: this function runs with async signals enabled,
> >>    // so it must not touch any tsan state.
> >> -int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
> >> -    void *abstime), void *c, void *m, void *abstime,
> >> -    void(*cleanup)(void *arg), void *arg) {
> >> +int call_pthread_cancel_with_cleanup(int (*fn)(void *arg),
> >> +                                     void (*cleanup)(void *arg), void *arg) {
> >>      // pthread_cleanup_push/pop are hardcore macros mess.
> >>      // We can't intercept nor call them w/o including pthread.h.
> >>      int res;
> >>      pthread_cleanup_push(cleanup, arg);
> >> -  res = fn(c, m, abstime);
> >> +  res = fn(arg);
> >>      pthread_cleanup_pop(0);
> >>      return res;
> >>    }
> >> diff --git a/libsanitizer/tsan/tsan_platform_posix.cpp b/libsanitizer/tsan/tsan_platform_posix.cpp
> >> index d56b6c3b9c5..73e1d4577c2 100644
> >> --- a/libsanitizer/tsan/tsan_platform_posix.cpp
> >> +++ b/libsanitizer/tsan/tsan_platform_posix.cpp
> >> @@ -99,7 +99,7 @@ void CheckAndProtect() {
> >>        Die();
> >>      }
> >>
> >> -#if defined(__aarch64__) && defined(__APPLE__)
> >> +#if defined(__aarch64__) && defined(__APPLE__) && !HAS_48_BIT_ADDRESS_SPACE
> >>      ProtectRange(HeapMemEnd(), ShadowBeg());
> >>      ProtectRange(ShadowEnd(), MetaShadowBeg());
> >>      ProtectRange(MetaShadowEnd(), TraceMemBeg());
> >> diff --git a/libsanitizer/tsan/tsan_report.cpp b/libsanitizer/tsan/tsan_report.cpp
> >> index 968c7b97553..8ef9f0cd4fe 100644
> >> --- a/libsanitizer/tsan/tsan_report.cpp
> >> +++ b/libsanitizer/tsan/tsan_report.cpp
> >> @@ -69,7 +69,7 @@ ReportDesc::~ReportDesc() {
> >>
> >>    const int kThreadBufSize = 32;
> >>    const char *thread_name(char *buf, int tid) {
> >> -  if (tid == 0)
> >> +  if (tid == kMainTid)
> >>        return "main thread";
> >>      internal_snprintf(buf, kThreadBufSize, "thread T%d", tid);
> >>      return buf;
> >> @@ -127,7 +127,7 @@ void PrintStack(const ReportStack *ent) {
> >>      }
> >>      SymbolizedStack *frame = ent->frames;
> >>      for (int i = 0; frame && frame->info.address; frame = frame->next, i++) {
> >> -    InternalScopedString res(2 * GetPageSizeCached());
> >> +    InternalScopedString res;
> >>        RenderFrame(&res, common_flags()->stack_trace_format, i,
> >>                    frame->info.address, &frame->info,
> >>                    common_flags()->symbolize_vs_style,
> >> @@ -250,7 +250,7 @@ static void PrintMutex(const ReportMutex *rm) {
> >>
> >>    static void PrintThread(const ReportThread *rt) {
> >>      Decorator d;
> >> -  if (rt->id == 0)  // Little sense in describing the main thread.
> >> +  if (rt->id == kMainTid)  // Little sense in describing the main thread.
> >>        return;
> >>      Printf("%s", d.ThreadDescription());
> >>      Printf("  Thread T%d", rt->id);
> >> @@ -394,7 +394,7 @@ void PrintReport(const ReportDesc *rep) {
> >>
> >>    #else  // #if !SANITIZER_GO
> >>
> >> -const int kMainThreadId = 1;
> >> +const u32 kMainGoroutineId = 1;
> >>
> >>    void PrintStack(const ReportStack *ent) {
> >>      if (ent == 0 || ent->frames == 0) {
> >> @@ -415,7 +415,7 @@ static void PrintMop(const ReportMop *mop, bool first) {
> >>      Printf("%s at %p by ",
> >>          (first ? (mop->write ? "Write" : "Read")
> >>                 : (mop->write ? "Previous write" : "Previous read")), mop->addr);
> >> -  if (mop->tid == kMainThreadId)
> >> +  if (mop->tid == kMainGoroutineId)
> >>        Printf("main goroutine:\n");
> >>      else
> >>        Printf("goroutine %d:\n", mop->tid);
> >> @@ -428,7 +428,7 @@ static void PrintLocation(const ReportLocation *loc) {
> >>        Printf("\n");
> >>        Printf("Heap block of size %zu at %p allocated by ",
> >>            loc->heap_chunk_size, loc->heap_chunk_start);
> >> -    if (loc->tid == kMainThreadId)
> >> +    if (loc->tid == kMainGoroutineId)
> >>          Printf("main goroutine:\n");
> >>        else
> >>          Printf("goroutine %d:\n", loc->tid);
> >> @@ -448,7 +448,7 @@ static void PrintLocation(const ReportLocation *loc) {
> >>    }
> >>
> >>    static void PrintThread(const ReportThread *rt) {
> >> -  if (rt->id == kMainThreadId)
> >> +  if (rt->id == kMainGoroutineId)
> >>        return;
> >>      Printf("\n");
> >>      Printf("Goroutine %d (%s) created at:\n",
> >> diff --git a/libsanitizer/tsan/tsan_rtl.cpp b/libsanitizer/tsan/tsan_rtl.cpp
> >> index 3d721eb95a2..0efa99788ab 100644
> >> --- a/libsanitizer/tsan/tsan_rtl.cpp
> >> +++ b/libsanitizer/tsan/tsan_rtl.cpp
> >> @@ -11,17 +11,19 @@
> >>    // Main file (entry points) for the TSan run-time.
> >>    //===----------------------------------------------------------------------===//
> >>
> >> +#include "tsan_rtl.h"
> >> +
> >>    #include "sanitizer_common/sanitizer_atomic.h"
> >>    #include "sanitizer_common/sanitizer_common.h"
> >>    #include "sanitizer_common/sanitizer_file.h"
> >>    #include "sanitizer_common/sanitizer_libc.h"
> >> -#include "sanitizer_common/sanitizer_stackdepot.h"
> >>    #include "sanitizer_common/sanitizer_placement_new.h"
> >> +#include "sanitizer_common/sanitizer_stackdepot.h"
> >>    #include "sanitizer_common/sanitizer_symbolizer.h"
> >>    #include "tsan_defs.h"
> >> -#include "tsan_platform.h"
> >> -#include "tsan_rtl.h"
> >> +#include "tsan_interface.h"
> >>    #include "tsan_mman.h"
> >> +#include "tsan_platform.h"
> >>    #include "tsan_suppressions.h"
> >>    #include "tsan_symbolize.h"
> >>    #include "ubsan/ubsan_init.h"
> >> @@ -56,12 +58,23 @@ Context *ctx;
> >>    bool OnFinalize(bool failed);
> >>    void OnInitialize();
> >>    #else
> >> +#include <dlfcn.h>
> >>    SANITIZER_WEAK_CXX_DEFAULT_IMPL
> >>    bool OnFinalize(bool failed) {
> >> +#if !SANITIZER_GO
> >> +  if (auto *ptr = dlsym(RTLD_DEFAULT, "__tsan_on_finalize"))
> >> +    return reinterpret_cast<decltype(&__tsan_on_finalize)>(ptr)(failed);
> >> +#endif
> >>      return failed;
> >>    }
> >>    SANITIZER_WEAK_CXX_DEFAULT_IMPL
> >> -void OnInitialize() {}
> >> +void OnInitialize() {
> >> +#if !SANITIZER_GO
> >> +  if (auto *ptr = dlsym(RTLD_DEFAULT, "__tsan_on_initialize")) {
> >> +    return reinterpret_cast<decltype(&__tsan_on_initialize)>(ptr)();
> >> +  }
> >> +#endif
> >> +}
> >>    #endif
> >>
> >>    static char thread_registry_placeholder[sizeof(ThreadRegistry)];
> >> @@ -77,12 +90,19 @@ static ThreadContextBase *CreateThreadContext(u32 tid) {
> >>      new((void*)hdr) Trace();
> >>      // We are going to use only a small part of the trace with the default
> >>      // value of history_size. However, the constructor writes to the whole trace.
> >> -  // Unmap the unused part.
> >> +  // Release the unused part.
> >>      uptr hdr_end = hdr + sizeof(Trace);
> >>      hdr_end -= sizeof(TraceHeader) * (kTraceParts - TraceParts());
> >>      hdr_end = RoundUp(hdr_end, GetPageSizeCached());
> >> -  if (hdr_end < hdr + sizeof(Trace))
> >> -    UnmapOrDie((void*)hdr_end, hdr + sizeof(Trace) - hdr_end);
> >> +  if (hdr_end < hdr + sizeof(Trace)) {
> >> +    ReleaseMemoryPagesToOS(hdr_end, hdr + sizeof(Trace));
> >> +    uptr unused = hdr + sizeof(Trace) - hdr_end;
> >> +    if (hdr_end != (uptr)MmapFixedNoAccess(hdr_end, unused)) {
> >> +      Report("ThreadSanitizer: failed to mprotect(%p, %p)\n",
> >> +          hdr_end, unused);
> >> +      CHECK("unable to mprotect" && 0);
> >> +    }
> >> +  }
> >>      void *mem = internal_alloc(MBlockThreadContex, sizeof(ThreadContext));
> >>      return new(mem) ThreadContext(tid);
> >>    }
> >> @@ -94,42 +114,45 @@ static const u32 kThreadQuarantineSize = 64;
> >>    #endif
> >>
> >>    Context::Context()
> >> -  : initialized()
> >> -  , report_mtx(MutexTypeReport, StatMtxReport)
> >> -  , nreported()
> >> -  , nmissed_expected()
> >> -  , thread_registry(new(thread_registry_placeholder) ThreadRegistry(
> >> -      CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse))
> >> -  , racy_mtx(MutexTypeRacy, StatMtxRacy)
> >> -  , racy_stacks()
> >> -  , racy_addresses()
> >> -  , fired_suppressions_mtx(MutexTypeFired, StatMtxFired)
> >> -  , clock_alloc("clock allocator") {
> >> +    : initialized(),
> >> +      report_mtx(MutexTypeReport, StatMtxReport),
> >> +      nreported(),
> >> +      nmissed_expected(),
> >> +      thread_registry(new (thread_registry_placeholder) ThreadRegistry(
> >> +          CreateThreadContext, kMaxTid, kThreadQuarantineSize, kMaxTidReuse)),
> >> +      racy_mtx(MutexTypeRacy, StatMtxRacy),
> >> +      racy_stacks(),
> >> +      racy_addresses(),
> >> +      fired_suppressions_mtx(MutexTypeFired, StatMtxFired),
> >> +      clock_alloc(LINKER_INITIALIZED, "clock allocator") {
> >>      fired_suppressions.reserve(8);
> >>    }
> >>
> >>    // The objects are allocated in TLS, so one may rely on zero-initialization.
> >> -ThreadState::ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
> >> -                         unsigned reuse_count,
> >> -                         uptr stk_addr, uptr stk_size,
> >> +ThreadState::ThreadState(Context *ctx, u32 tid, int unique_id, u64 epoch,
> >> +                         unsigned reuse_count, uptr stk_addr, uptr stk_size,
> >>                             uptr tls_addr, uptr tls_size)
> >> -  : fast_state(tid, epoch)
> >> -  // Do not touch these, rely on zero initialization,
> >> -  // they may be accessed before the ctor.
> >> -  // , ignore_reads_and_writes()
> >> -  // , ignore_interceptors()
> >> -  , clock(tid, reuse_count)
> >> +    : fast_state(tid, epoch)
> >> +      // Do not touch these, rely on zero initialization,
> >> +      // they may be accessed before the ctor.
> >> +      // , ignore_reads_and_writes()
> >> +      // , ignore_interceptors()
> >> +      ,
> >> +      clock(tid, reuse_count)
> >>    #if !SANITIZER_GO
> >> -  , jmp_bufs()
> >> +      ,
> >> +      jmp_bufs()
> >>    #endif
> >> -  , tid(tid)
> >> -  , unique_id(unique_id)
> >> -  , stk_addr(stk_addr)
> >> -  , stk_size(stk_size)
> >> -  , tls_addr(tls_addr)
> >> -  , tls_size(tls_size)
> >> +      ,
> >> +      tid(tid),
> >> +      unique_id(unique_id),
> >> +      stk_addr(stk_addr),
> >> +      stk_size(stk_size),
> >> +      tls_addr(tls_addr),
> >> +      tls_size(tls_size)
> >>    #if !SANITIZER_GO
> >> -  , last_sleep_clock(tid)
> >> +      ,
> >> +      last_sleep_clock(tid)
> >>    #endif
> >>    {
> >>    }
> >> @@ -160,12 +183,12 @@ static void *BackgroundThread(void *arg) {
> >>        } else if (internal_strcmp(flags()->profile_memory, "stderr") == 0) {
> >>          mprof_fd = 2;
> >>        } else {
> >> -      InternalScopedString filename(kMaxPathLength);
> >> +      InternalScopedString filename;
> >>          filename.append("%s.%d", flags()->profile_memory, (int)internal_getpid());
> >>          fd_t fd = OpenFile(filename.data(), WrOnly);
> >>          if (fd == kInvalidFd) {
> >>            Printf("ThreadSanitizer: failed to open memory profile file '%s'\n",
> >> -            &filename[0]);
> >> +               filename.data());
> >>          } else {
> >>            mprof_fd = fd;
> >>          }
> >> @@ -351,6 +374,18 @@ static void TsanOnDeadlySignal(int signo, void *siginfo, void *context) {
> >>    }
> >>    #endif
> >>
> >> +void CheckUnwind() {
> >> +  // There is high probability that interceptors will check-fail as well,
> >> +  // on the other hand there is no sense in processing interceptors
> >> +  // since we are going to die soon.
> >> +  ScopedIgnoreInterceptors ignore;
> >> +#if !SANITIZER_GO
> >> +  cur_thread()->ignore_sync++;
> >> +  cur_thread()->ignore_reads_and_writes++;
> >> +#endif
> >> +  PrintCurrentStackSlow(StackTrace::GetCurrentPc());
> >> +}
> >> +
> >>    void Initialize(ThreadState *thr) {
> >>      // Thread safe because done before all threads exist.
> >>      static bool is_initialized = false;
> >> @@ -361,7 +396,7 @@ void Initialize(ThreadState *thr) {
> >>      ScopedIgnoreInterceptors ignore;
> >>      SanitizerToolName = "ThreadSanitizer";
> >>      // Install tool-specific callbacks in sanitizer_common.
> >> -  SetCheckFailedCallback(TsanCheckFailed);
> >> +  SetCheckUnwindCallback(CheckUnwind);
> >>
> >>      ctx = new(ctx_placeholder) Context;
> >>      const char *env_name = SANITIZER_GO ? "GORACE" : "TSAN_OPTIONS";
> >> @@ -499,23 +534,27 @@ 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,
> >> +  // Suppress all reports in the pthread_atfork callbacks.
> >> +  // Reports will deadlock on the report_mtx.
> >> +  // We could ignore 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);
> >> +  thr->suppress_reports++;
> >> +  // On OS X, REAL(fork) can call intercepted functions (OSSpinLockLock), and
> >> +  // we'll assert in CheckNoLocks() unless we ignore interceptors.
> >> +  thr->ignore_interceptors++;
> >>    }
> >>
> >>    void ForkParentAfter(ThreadState *thr, uptr pc) {
> >> -  ThreadIgnoreEnd(thr, pc);  // Begin is in ForkBefore.
> >> +  thr->suppress_reports--;  // Enabled in ForkBefore.
> >> +  thr->ignore_interceptors--;
> >>      ctx->report_mtx.Unlock();
> >>      ctx->thread_registry->Unlock();
> >>    }
> >>
> >>    void ForkChildAfter(ThreadState *thr, uptr pc) {
> >> -  ThreadIgnoreEnd(thr, pc);  // Begin is in ForkBefore.
> >> +  thr->suppress_reports--;  // Enabled in ForkBefore.
> >> +  thr->ignore_interceptors--;
> >>      ctx->report_mtx.Unlock();
> >>      ctx->thread_registry->Unlock();
> >>
> >> diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h
> >> index 04d474e044e..3ae519d34da 100644
> >> --- a/libsanitizer/tsan/tsan_rtl.h
> >> +++ b/libsanitizer/tsan/tsan_rtl.h
> >> @@ -84,9 +84,6 @@ typedef Allocator::AllocatorCache AllocatorCache;
> >>    Allocator *allocator();
> >>    #endif
> >>
> >> -void TsanCheckFailed(const char *file, int line, const char *cond,
> >> -                     u64 v1, u64 v2);
> >> -
> >>    const u64 kShadowRodata = (u64)-1;  // .rodata shadow marker
> >>
> >>    // FastState (from most significant bit):
> >> @@ -406,7 +403,7 @@ struct ThreadState {
> >>    #if TSAN_COLLECT_STATS
> >>      u64 stat[StatCnt];
> >>    #endif
> >> -  const int tid;
> >> +  const u32 tid;
> >>      const int unique_id;
> >>      bool in_symbolizer;
> >>      bool in_ignored_lib;
> >> @@ -447,9 +444,8 @@ struct ThreadState {
> >>
> >>      const ReportDesc *current_report;
> >>
> >> -  explicit ThreadState(Context *ctx, int tid, int unique_id, u64 epoch,
> >> -                       unsigned reuse_count,
> >> -                       uptr stk_addr, uptr stk_size,
> >> +  explicit ThreadState(Context *ctx, u32 tid, int unique_id, u64 epoch,
> >> +                       unsigned reuse_count, uptr stk_addr, uptr stk_size,
> >>                           uptr tls_addr, uptr tls_size);
> >>    };
> >>
> >> @@ -624,6 +620,7 @@ class ScopedReport : public ScopedReportBase {
> >>      ScopedErrorReportLock lock_;
> >>    };
> >>
> >> +bool ShouldReport(ThreadState *thr, ReportType typ);
> >>    ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack);
> >>    void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
> >>                      MutexSet *mset, uptr *tag = nullptr);
> >> diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cpp b/libsanitizer/tsan/tsan_rtl_mutex.cpp
> >> index 27897f0592b..0a8f3aa3ddb 100644
> >> --- a/libsanitizer/tsan/tsan_rtl_mutex.cpp
> >> +++ b/libsanitizer/tsan/tsan_rtl_mutex.cpp
> >> @@ -51,6 +51,8 @@ static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
> >>      // or false positives (e.g. unlock in a different thread).
> >>      if (SANITIZER_GO)
> >>        return;
> >> +  if (!ShouldReport(thr, typ))
> >> +    return;
> >>      ThreadRegistryLock l(ctx->thread_registry);
> >>      ScopedReport rep(typ);
> >>      rep.AddMutex(mid);
> >> @@ -96,9 +98,8 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
> >>        ctx->dd->MutexInit(&cb, &s->dd);
> >>      }
> >>      bool unlock_locked = false;
> >> -  if (flags()->report_destroy_locked
> >> -      && s->owner_tid != SyncVar::kInvalidTid
> >> -      && !s->IsFlagSet(MutexFlagBroken)) {
> >> +  if (flags()->report_destroy_locked && s->owner_tid != kInvalidTid &&
> >> +      !s->IsFlagSet(MutexFlagBroken)) {
> >>        s->SetFlags(MutexFlagBroken);
> >>        unlock_locked = true;
> >>      }
> >> @@ -107,7 +108,7 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
> >>      if (!unlock_locked)
> >>        s->Reset(thr->proc());  // must not reset it before the report is printed
> >>      s->mtx.Unlock();
> >> -  if (unlock_locked) {
> >> +  if (unlock_locked && ShouldReport(thr, ReportTypeMutexDestroyLocked)) {
> >>        ThreadRegistryLock l(ctx->thread_registry);
> >>        ScopedReport rep(ReportTypeMutexDestroyLocked);
> >>        rep.AddMutex(mid);
> >> @@ -169,7 +170,7 @@ void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz, int rec) {
> >>      thr->fast_state.IncrementEpoch();
> >>      TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
> >>      bool report_double_lock = false;
> >> -  if (s->owner_tid == SyncVar::kInvalidTid) {
> >> +  if (s->owner_tid == kInvalidTid) {
> >>        CHECK_EQ(s->recursion, 0);
> >>        s->owner_tid = thr->tid;
> >>        s->last_lock = thr->fast_state.raw();
> >> @@ -229,7 +230,7 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
> >>        s->recursion -= rec;
> >>        if (s->recursion == 0) {
> >>          StatInc(thr, StatMutexUnlock);
> >> -      s->owner_tid = SyncVar::kInvalidTid;
> >> +      s->owner_tid = kInvalidTid;
> >>          ReleaseStoreImpl(thr, pc, &s->clock);
> >>        } else {
> >>          StatInc(thr, StatMutexRecUnlock);
> >> @@ -275,7 +276,7 @@ void MutexPostReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
> >>      thr->fast_state.IncrementEpoch();
> >>      TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
> >>      bool report_bad_lock = false;
> >> -  if (s->owner_tid != SyncVar::kInvalidTid) {
> >> +  if (s->owner_tid != kInvalidTid) {
> >>        if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) {
> >>          s->SetFlags(MutexFlagBroken);
> >>          report_bad_lock = true;
> >> @@ -314,7 +315,7 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
> >>      thr->fast_state.IncrementEpoch();
> >>      TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
> >>      bool report_bad_unlock = false;
> >> -  if (s->owner_tid != SyncVar::kInvalidTid) {
> >> +  if (s->owner_tid != kInvalidTid) {
> >>        if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) {
> >>          s->SetFlags(MutexFlagBroken);
> >>          report_bad_unlock = true;
> >> @@ -344,7 +345,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
> >>      SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
> >>      bool write = true;
> >>      bool report_bad_unlock = false;
> >> -  if (s->owner_tid == SyncVar::kInvalidTid) {
> >> +  if (s->owner_tid == kInvalidTid) {
> >>        // Seems to be read unlock.
> >>        write = false;
> >>        StatInc(thr, StatMutexReadUnlock);
> >> @@ -359,7 +360,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
> >>        s->recursion--;
> >>        if (s->recursion == 0) {
> >>          StatInc(thr, StatMutexUnlock);
> >> -      s->owner_tid = SyncVar::kInvalidTid;
> >> +      s->owner_tid = kInvalidTid;
> >>          ReleaseStoreImpl(thr, pc, &s->clock);
> >>        } else {
> >>          StatInc(thr, StatMutexRecUnlock);
> >> @@ -387,7 +388,7 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
> >>    void MutexRepair(ThreadState *thr, uptr pc, uptr addr) {
> >>      DPrintf("#%d: MutexRepair %zx\n", thr->tid, addr);
> >>      SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
> >> -  s->owner_tid = SyncVar::kInvalidTid;
> >> +  s->owner_tid = kInvalidTid;
> >>      s->recursion = 0;
> >>      s->mtx.Unlock();
> >>    }
> >> @@ -534,7 +535,7 @@ void AcquireReleaseImpl(ThreadState *thr, uptr pc, SyncClock *c) {
> >>    }
> >>
> >>    void ReportDeadlock(ThreadState *thr, uptr pc, DDReport *r) {
> >> -  if (r == 0)
> >> +  if (r == 0 || !ShouldReport(thr, ReportTypeDeadlock))
> >>        return;
> >>      ThreadRegistryLock l(ctx->thread_registry);
> >>      ScopedReport rep(ReportTypeDeadlock);
> >> 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_report.cpp b/libsanitizer/tsan/tsan_rtl_report.cpp
> >> index 208d0df44df..706794fdad1 100644
> >> --- a/libsanitizer/tsan/tsan_rtl_report.cpp
> >> +++ b/libsanitizer/tsan/tsan_rtl_report.cpp
> >> @@ -31,23 +31,6 @@ using namespace __sanitizer;
> >>
> >>    static ReportStack *SymbolizeStack(StackTrace trace);
> >>
> >> -void TsanCheckFailed(const char *file, int line, const char *cond,
> >> -                     u64 v1, u64 v2) {
> >> -  // There is high probability that interceptors will check-fail as well,
> >> -  // on the other hand there is no sense in processing interceptors
> >> -  // since we are going to die soon.
> >> -  ScopedIgnoreInterceptors ignore;
> >> -#if !SANITIZER_GO
> >> -  cur_thread()->ignore_sync++;
> >> -  cur_thread()->ignore_reads_and_writes++;
> >> -#endif
> >> -  Printf("FATAL: ThreadSanitizer CHECK failed: "
> >> -         "%s:%d \"%s\" (0x%zx, 0x%zx)\n",
> >> -         file, line, cond, (uptr)v1, (uptr)v2);
> >> -  PrintCurrentStackSlow(StackTrace::GetCurrentPc());
> >> -  Die();
> >> -}
> >> -
> >>    // Can be overriden by an application/test to intercept reports.
> >>    #ifdef TSAN_EXTERNAL_HOOKS
> >>    bool OnReport(const ReportDesc *rep, bool suppressed);
> >> @@ -142,6 +125,34 @@ static ReportStack *SymbolizeStack(StackTrace trace) {
> >>      return stack;
> >>    }
> >>
> >> +bool ShouldReport(ThreadState *thr, ReportType typ) {
> >> +  // We set thr->suppress_reports in the fork context.
> >> +  // Taking any locking in the fork context can lead to deadlocks.
> >> +  // If any locks are already taken, it's too late to do this check.
> >> +  CheckNoLocks(thr);
> >> +  // For the same reason check we didn't lock thread_registry yet.
> >> +  if (SANITIZER_DEBUG)
> >> +    ThreadRegistryLock l(ctx->thread_registry);
> >> +  if (!flags()->report_bugs || thr->suppress_reports)
> >> +    return false;
> >> +  switch (typ) {
> >> +    case ReportTypeSignalUnsafe:
> >> +      return flags()->report_signal_unsafe;
> >> +    case ReportTypeThreadLeak:
> >> +#if !SANITIZER_GO
> >> +      // It's impossible to join phantom threads
> >> +      // in the child after fork.
> >> +      if (ctx->after_multithreaded_fork)
> >> +        return false;
> >> +#endif
> >> +      return flags()->report_thread_leaks;
> >> +    case ReportTypeMutexDestroyLocked:
> >> +      return flags()->report_destroy_locked;
> >> +    default:
> >> +      return true;
> >> +  }
> >> +}
> >> +
> >>    ScopedReportBase::ScopedReportBase(ReportType typ, uptr tag) {
> >>      ctx->thread_registry->CheckLocked();
> >>      void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc));
> >> @@ -497,8 +508,10 @@ static bool HandleRacyAddress(ThreadState *thr, uptr addr_min, uptr addr_max) {
> >>    }
> >>
> >>    bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
> >> -  if (!flags()->report_bugs || thr->suppress_reports)
> >> -    return false;
> >> +  // These should have been checked in ShouldReport.
> >> +  // It's too late to check them here, we have already taken locks.
> >> +  CHECK(flags()->report_bugs);
> >> +  CHECK(!thr->suppress_reports);
> >>      atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime());
> >>      const ReportDesc *rep = srep.GetReport();
> >>      CHECK_EQ(thr->current_report, nullptr);
> >> @@ -589,7 +602,7 @@ void ReportRace(ThreadState *thr) {
> >>      // at best it will cause deadlocks on internal mutexes.
> >>      ScopedIgnoreInterceptors ignore;
> >>
> >> -  if (!flags()->report_bugs)
> >> +  if (!ShouldReport(thr, ReportTypeRace))
> >>        return;
> >>      if (!flags()->report_atomic_races && !RaceBetweenAtomicAndFree(thr))
> >>        return;
> >> @@ -722,8 +735,7 @@ void PrintCurrentStack(ThreadState *thr, uptr pc) {
> >>    // However, this solution is not reliable enough, please see dvyukov's comment
> >>    // http://reviews.llvm.org/D19148#406208
> >>    // Also see PR27280 comment 2 and 3 for breaking examples and analysis.
> >> -ALWAYS_INLINE
> >> -void PrintCurrentStackSlow(uptr pc) {
> >> +ALWAYS_INLINE USED void PrintCurrentStackSlow(uptr pc) {
> >>    #if !SANITIZER_GO
> >>      uptr bp = GET_CURRENT_FRAME();
> >>      BufferedStackTrace *ptrace =
> >> diff --git a/libsanitizer/tsan/tsan_rtl_thread.cpp b/libsanitizer/tsan/tsan_rtl_thread.cpp
> >> index d80146735ea..6d1ccd8c9c7 100644
> >> --- a/libsanitizer/tsan/tsan_rtl_thread.cpp
> >> +++ b/libsanitizer/tsan/tsan_rtl_thread.cpp
> >> @@ -51,7 +51,7 @@ struct OnCreatedArgs {
> >>
> >>    void ThreadContext::OnCreated(void *arg) {
> >>      thr = 0;
> >> -  if (tid == 0)
> >> +  if (tid == kMainTid)
> >>        return;
> >>      OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
> >>      if (!args->thr)  // GCD workers don't have a parent thread.
> >> @@ -179,7 +179,7 @@ static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) {
> >>
> >>    #if !SANITIZER_GO
> >>    static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) {
> >> -  if (tctx->tid == 0) {
> >> +  if (tctx->tid == kMainTid) {
> >>        Printf("ThreadSanitizer: main thread finished with ignores enabled\n");
> >>      } else {
> >>        Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled,"
> >> @@ -210,7 +210,7 @@ static void ThreadCheckIgnore(ThreadState *thr) {}
> >>    void ThreadFinalize(ThreadState *thr) {
> >>      ThreadCheckIgnore(thr);
> >>    #if !SANITIZER_GO
> >> -  if (!flags()->report_thread_leaks)
> >> +  if (!ShouldReport(thr, ReportTypeThreadLeak))
> >>        return;
> >>      ThreadRegistryLock l(ctx->thread_registry);
> >>      Vector<ThreadLeak> leaks;
> >> @@ -250,9 +250,10 @@ void ThreadStart(ThreadState *thr, int tid, tid_t os_id,
> >>      uptr tls_size = 0;
> >>    #if !SANITIZER_GO
> >>      if (thread_type != ThreadType::Fiber)
> >> -    GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);
> >> +    GetThreadStackAndTls(tid == kMainTid, &stk_addr, &stk_size, &tls_addr,
> >> +                         &tls_size);
> >>
> >> -  if (tid) {
> >> +  if (tid != kMainTid) {
> >>        if (stk_addr && stk_size)
> >>          MemoryRangeImitateWrite(thr, /*pc=*/ 1, stk_addr, stk_size);
> >>
> >> @@ -313,7 +314,7 @@ static bool ConsumeThreadByUid(ThreadContextBase *tctx, void *arg) {
> >>    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;
> >> +  int tid = findCtx.tctx ? findCtx.tctx->tid : kInvalidTid;
> >>      DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, tid);
> >>      return tid;
> >>    }
> >> diff --git a/libsanitizer/tsan/tsan_sync.cpp b/libsanitizer/tsan/tsan_sync.cpp
> >> index 17ddd50f128..ba24f98ae9f 100644
> >> --- a/libsanitizer/tsan/tsan_sync.cpp
> >> +++ b/libsanitizer/tsan/tsan_sync.cpp
> >> @@ -53,8 +53,8 @@ void SyncVar::Reset(Processor *proc) {
> >>    }
> >>
> >>    MetaMap::MetaMap()
> >> -    : block_alloc_("heap block allocator")
> >> -    , sync_alloc_("sync allocator") {
> >> +    : block_alloc_(LINKER_INITIALIZED, "heap block allocator"),
> >> +      sync_alloc_(LINKER_INITIALIZED, "sync allocator") {
> >>      atomic_store(&uid_gen_, 0, memory_order_relaxed);
> >>    }
> >>
> >> diff --git a/libsanitizer/tsan/tsan_sync.h b/libsanitizer/tsan/tsan_sync.h
> >> index 47f2739d8de..c4056f684d7 100644
> >> --- a/libsanitizer/tsan/tsan_sync.h
> >> +++ b/libsanitizer/tsan/tsan_sync.h
> >> @@ -50,13 +50,11 @@ enum MutexFlags {
> >>    struct SyncVar {
> >>      SyncVar();
> >>
> >> -  static const int kInvalidTid = -1;
> >> -
> >>      uptr addr;  // overwritten by DenseSlabAlloc freelist
> >>      Mutex mtx;
> >>      u64 uid;  // Globally unique id.
> >>      u32 creation_stack_id;
> >> -  int owner_tid;  // Set only by exclusive owners.
> >> +  u32 owner_tid;  // Set only by exclusive owners.
> >>      u64 last_lock;
> >>      int recursion;
> >>      atomic_uint32_t flags;
> >> @@ -130,8 +128,8 @@ class MetaMap {
> >>      static const u32 kFlagMask  = 3u << 30;
> >>      static const u32 kFlagBlock = 1u << 30;
> >>      static const u32 kFlagSync  = 2u << 30;
> >> -  typedef DenseSlabAlloc<MBlock, 1<<16, 1<<12> BlockAlloc;
> >> -  typedef DenseSlabAlloc<SyncVar, 1<<16, 1<<10> SyncAlloc;
> >> +  typedef DenseSlabAlloc<MBlock, 1 << 18, 1 << 12, kFlagMask> BlockAlloc;
> >> +  typedef DenseSlabAlloc<SyncVar, 1 << 20, 1 << 10, kFlagMask> SyncAlloc;
> >>      BlockAlloc block_alloc_;
> >>      SyncAlloc sync_alloc_;
> >>      atomic_uint64_t uid_gen_;
> >> diff --git a/libsanitizer/ubsan/ubsan_diag.cpp b/libsanitizer/ubsan/ubsan_diag.cpp
> >> index 1b2828d236d..ef2e495cac8 100644
> >> --- a/libsanitizer/ubsan/ubsan_diag.cpp
> >> +++ b/libsanitizer/ubsan/ubsan_diag.cpp
> >> @@ -278,7 +278,7 @@ static void PrintMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
> >>      }
> >>
> >>      // Emit data.
> >> -  InternalScopedString Buffer(1024);
> >> +  InternalScopedString Buffer;
> >>      for (uptr P = Min; P != Max; ++P) {
> >>        unsigned char C = *reinterpret_cast<const unsigned char*>(P);
> >>        Buffer.append("%s%02x", (P % 8 == 0) ? "  " : " ", C);
> >> @@ -346,7 +346,7 @@ Diag::~Diag() {
> >>      // All diagnostics should be printed under report mutex.
> >>      ScopedReport::CheckLocked();
> >>      Decorator Decor;
> >> -  InternalScopedString Buffer(1024);
> >> +  InternalScopedString Buffer;
> >>
> >>      // Prepare a report that a monitor process can inspect.
> >>      if (Level == DL_Error) {
> >> @@ -388,6 +388,10 @@ ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc,
> >>    ScopedReport::~ScopedReport() {
> >>      MaybePrintStackTrace(Opts.pc, Opts.bp);
> >>      MaybeReportErrorSummary(SummaryLoc, Type);
> >> +
> >> +  if (common_flags()->print_module_map >= 2)
> >> +    DumpProcessMap();
> >> +
> >>      if (flags()->halt_on_error)
> >>        Die();
> >>    }
> >> diff --git a/libsanitizer/ubsan/ubsan_flags.cpp b/libsanitizer/ubsan/ubsan_flags.cpp
> >> index 9a66bd37518..25cefd46ce2 100644
> >> --- a/libsanitizer/ubsan/ubsan_flags.cpp
> >> +++ b/libsanitizer/ubsan/ubsan_flags.cpp
> >> @@ -50,7 +50,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 2184625aa6e..e201e6bba22 100644
> >> --- a/libsanitizer/ubsan/ubsan_handlers.cpp
> >> +++ b/libsanitizer/ubsan/ubsan_handlers.cpp
> >> @@ -894,21 +894,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 9f412353fc0..219fb15de55 100644
> >> --- a/libsanitizer/ubsan/ubsan_handlers.h
> >> +++ b/libsanitizer/ubsan/ubsan_handlers.h
> >> @@ -215,20 +215,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 e0be5a72ec4..9931d85bf40 100644
> >> --- a/libsanitizer/ubsan/ubsan_init.cpp
> >> +++ b/libsanitizer/ubsan/ubsan_init.cpp
> >> @@ -33,6 +33,11 @@ static void CommonInit() {
> >>      InitializeSuppressions();
> >>    }
> >>
> >> +static void UbsanDie() {
> >> +  if (common_flags()->print_module_map >= 1)
> >> +    DumpProcessMap();
> >> +}
> >> +
> >>    static void CommonStandaloneInit() {
> >>      SanitizerToolName = GetSanititizerToolName();
> >>      CacheBinaryName();
> >> @@ -42,6 +47,10 @@ static void CommonStandaloneInit() {
> >>      AndroidLogInit();
> >>      InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
> >>      CommonInit();
> >> +
> >> +  // Only add die callback when running in standalone mode to avoid printing
> >> +  // the same information from multiple sanitizers' output
> >> +  AddDieCallback(UbsanDie);
> >>      Symbolizer::LateInitialize();
> >>    }
> >>
> >> diff --git a/libsanitizer/ubsan/ubsan_monitor.cpp b/libsanitizer/ubsan/ubsan_monitor.cpp
> >> index d064e95f76f..69dd986f9bd 100644
> >> --- a/libsanitizer/ubsan/ubsan_monitor.cpp
> >> +++ b/libsanitizer/ubsan/ubsan_monitor.cpp
> >> @@ -17,7 +17,7 @@ using namespace __ubsan;
> >>    UndefinedBehaviorReport::UndefinedBehaviorReport(const char *IssueKind,
> >>                                                     Location &Loc,
> >>                                                     InternalScopedString &Msg)
> >> -    : IssueKind(IssueKind), Loc(Loc), Buffer(Msg.length() + 1) {
> >> +    : IssueKind(IssueKind), Loc(Loc) {
> >>      // We have the common sanitizer reporting lock, so it's safe to register a
> >>      // new UB report.
> >>      RegisterUndefinedBehaviorReport(this);
> >> @@ -52,9 +52,9 @@ void __ubsan::__ubsan_get_current_report_data(const char **OutIssueKind,
> >>
> >>      // Ensure that the first character of the diagnostic text can't start with a
> >>      // lowercase letter.
> >> -  char FirstChar = Buf.data()[0];
> >> +  char FirstChar = *Buf.data();
> >>      if (FirstChar >= 'a' && FirstChar <= 'z')
> >> -    Buf.data()[0] = FirstChar - 'a' + 'A';
> >> +    *Buf.data() += 'A' - 'a';
> >>
> >>      *OutIssueKind = CurrentUBR->IssueKind;
> >>      *OutMessage = Buf.data();
> >> diff --git a/libsanitizer/ubsan/ubsan_platform.h b/libsanitizer/ubsan/ubsan_platform.h
> >> index 98542fcea96..51e535d1e22 100644
> >> --- a/libsanitizer/ubsan/ubsan_platform.h
> >> +++ b/libsanitizer/ubsan/ubsan_platform.h
> >> @@ -12,16 +12,14 @@
> >>    #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(__NetBSD__) || defined(__DragonFly__) || \
> >>        (defined(__sun__) && defined(__svr4__)) || \
> >>        defined(_WIN32) || defined(__Fuchsia__) || defined(__rtems__)
> >>    # define CAN_SANITIZE_UB 1
> >>    #else
> >>    # define CAN_SANITIZE_UB 0
> >>    #endif
> >> -#endif //CAN_SANITIZE_UB
> >>
> >>    #endif
> >
> >> --
> >> 2.31.1
> >>
> >
> >
> > --
> > BR,
> > Hongtao
> >
>


-- 
BR,
Hongtao

  reply	other threads:[~2021-06-04  7:50 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-13  7:28 Martin Liška
2021-05-13 15:54 ` H.J. Lu
2021-05-13 17:27   ` Martin Liška
2021-05-13 20:01     ` H.J. Lu
2021-05-13 20:11       ` H.J. Lu
2021-05-14  1:26         ` [PATCH] libsanitizer: cherry-pick from upstream H.J. Lu
2021-06-04  7:32 ` [PATCH] libsanitizer: merge from master Hongtao Liu
2021-06-04  7:36   ` Martin Liška
2021-06-04  7:53     ` Hongtao Liu [this message]
  -- strict thread matches above, loose matches on Subject: below --
2020-06-02  6:00 [PATCH] Libsanitizer: " Martin Liška
2020-06-06 19:47 ` Andreas Schwab
2020-10-16  8:59 ` Martin Liška
2020-10-19  7:04   ` Tobias Burnus
2020-10-19  7:11     ` Martin Liška
2020-10-19  7:39       ` Tobias Burnus
2020-10-20  8:09         ` Tobias Burnus
2020-10-20  9:16           ` Martin Liška

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAMZc-bw6SjbrRCLYCeq1RN0e5qc5wsFK-qo1zE0cO5VnSSqeqQ@mail.gmail.com \
    --to=crazylht@gmail.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=mliska@suse.cz \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).