public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r14-263] libsanitizer: merge from upstream (3185e47b5a8444e9fd).
@ 2023-04-26 13:53 Martin Liska
  0 siblings, 0 replies; only message in thread
From: Martin Liska @ 2023-04-26 13:53 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:d53b3d94aaf211ffb2159614f5aaaf03ceb861cc

commit r14-263-gd53b3d94aaf211ffb2159614f5aaaf03ceb861cc
Author: Martin Liska <mliska@suse.cz>
Date:   Wed Apr 26 09:42:29 2023 +0200

    libsanitizer: merge from upstream (3185e47b5a8444e9fd).

Diff:
---
 libsanitizer/MERGE                                 |   2 +-
 libsanitizer/asan/asan_allocator.cpp               |  50 ++-
 libsanitizer/asan/asan_allocator.h                 |   8 +-
 libsanitizer/asan/asan_errors.cpp                  |  20 ++
 libsanitizer/asan/asan_errors.h                    |  67 +++--
 libsanitizer/asan/asan_globals.cpp                 |  19 ++
 libsanitizer/asan/asan_interceptors.cpp            |  59 ++--
 libsanitizer/asan/asan_interceptors.h              |   7 +-
 libsanitizer/asan/asan_internal.h                  |   2 +-
 libsanitizer/asan/asan_linux.cpp                   | 164 +++++-----
 libsanitizer/asan/asan_mac.cpp                     |   6 -
 libsanitizer/asan/asan_malloc_win.cpp              |   8 +-
 libsanitizer/asan/asan_mapping.h                   |   2 +-
 libsanitizer/asan/asan_memory_profile.cpp          |  19 +-
 libsanitizer/asan/asan_poisoning.cpp               | 334 +++++++++++++++------
 libsanitizer/asan/asan_report.cpp                  |  12 +
 libsanitizer/asan/asan_report.h                    |   4 +
 libsanitizer/asan/asan_thread.cpp                  |  86 +++++-
 libsanitizer/asan/asan_win.cpp                     |   6 -
 libsanitizer/builtins/assembly.h                   |   2 +-
 libsanitizer/hwasan/hwasan.cpp                     |  36 ++-
 libsanitizer/hwasan/hwasan.h                       |   2 +
 .../hwasan/hwasan_allocation_functions.cpp         |  26 +-
 libsanitizer/hwasan/hwasan_allocator.cpp           | 270 ++++++++++++++---
 libsanitizer/hwasan/hwasan_allocator.h             |  51 ++--
 libsanitizer/hwasan/hwasan_checks.h                |  78 +++--
 libsanitizer/hwasan/hwasan_flags.inc               |   3 +
 libsanitizer/hwasan/hwasan_fuchsia.cpp             |   8 +
 libsanitizer/hwasan/hwasan_interceptors.cpp        |  16 +-
 libsanitizer/hwasan/hwasan_linux.cpp               |  11 +
 libsanitizer/hwasan/hwasan_new_delete.cpp          |  24 ++
 libsanitizer/hwasan/hwasan_poisoning.cpp           |   8 +
 libsanitizer/hwasan/hwasan_registers.h             |  56 ++++
 libsanitizer/hwasan/hwasan_report.cpp              |  21 +-
 libsanitizer/hwasan/hwasan_setjmp_riscv64.S        |   2 +-
 libsanitizer/hwasan/hwasan_thread.cpp              |  58 ++++
 libsanitizer/hwasan/hwasan_thread.h                |  14 +-
 libsanitizer/hwasan/hwasan_thread_list.h           |  43 ++-
 .../include/sanitizer/allocator_interface.h        |   4 +
 .../include/sanitizer/common_interface_defs.h      |  73 +++++
 libsanitizer/include/sanitizer/dfsan_interface.h   |  20 ++
 libsanitizer/include/sanitizer/hwasan_interface.h  |   2 +-
 libsanitizer/include/sanitizer/tsan_interface.h    |   6 +
 .../interception/interception_type_test.cpp        |   4 +-
 libsanitizer/interception/interception_win.cpp     |   2 +-
 libsanitizer/lsan/lsan.cpp                         |   2 +-
 libsanitizer/lsan/lsan_allocator.cpp               |  29 +-
 libsanitizer/lsan/lsan_allocator.h                 |  10 +-
 libsanitizer/lsan/lsan_common.cpp                  |  61 ++--
 libsanitizer/lsan/lsan_common.h                    | 181 ++++++-----
 libsanitizer/lsan/lsan_common_fuchsia.cpp          |  13 +-
 libsanitizer/lsan/lsan_common_mac.cpp              |  20 +-
 libsanitizer/lsan/lsan_fuchsia.cpp                 |   7 +-
 libsanitizer/lsan/lsan_interceptors.cpp            |   2 +-
 libsanitizer/lsan/lsan_linux.cpp                   |   9 +-
 libsanitizer/lsan/lsan_mac.cpp                     |  19 +-
 libsanitizer/lsan/lsan_posix.cpp                   |   6 +-
 libsanitizer/lsan/lsan_thread.cpp                  |  47 +--
 libsanitizer/lsan/lsan_thread.h                    |  12 +-
 .../sanitizer_common/sanitizer_allocator.cpp       |   6 +-
 .../sanitizer_allocator_combined.h                 |   2 +-
 .../sanitizer_allocator_interface.h                |   2 +
 .../sanitizer_allocator_internal.h                 |   1 -
 .../sanitizer_allocator_secondary.h                |   2 +-
 libsanitizer/sanitizer_common/sanitizer_common.cpp |  20 ++
 libsanitizer/sanitizer_common/sanitizer_common.h   |   3 +
 .../sanitizer_common_interceptors.inc              | 156 +++-------
 .../sanitizer_common_interface.inc                 |   5 +
 .../sanitizer_common/sanitizer_common_syscalls.inc |  39 +--
 .../sanitizer_coverage_libcdep_new.cpp             |   9 +-
 .../sanitizer_common/sanitizer_errno_codes.h       |   1 +
 libsanitizer/sanitizer_common/sanitizer_file.h     |   1 +
 .../sanitizer_common/sanitizer_flag_parser.cpp     |   4 +-
 .../sanitizer_common/sanitizer_flag_parser.h       |   2 +-
 .../sanitizer_interceptors_ioctl_netbsd.inc        |   2 -
 .../sanitizer_interface_internal.h                 |  14 +-
 .../sanitizer_common/sanitizer_internal_defs.h     |   9 -
 libsanitizer/sanitizer_common/sanitizer_linux.cpp  |  43 ++-
 libsanitizer/sanitizer_common/sanitizer_linux.h    |   9 +-
 .../sanitizer_common/sanitizer_linux_libcdep.cpp   |  24 +-
 libsanitizer/sanitizer_common/sanitizer_mac.cpp    | 140 ++++-----
 libsanitizer/sanitizer_common/sanitizer_mac.h      |  20 --
 libsanitizer/sanitizer_common/sanitizer_mallinfo.h |  38 +++
 libsanitizer/sanitizer_common/sanitizer_platform.h |  11 +-
 .../sanitizer_platform_interceptors.h              |  20 +-
 .../sanitizer_platform_limits_linux.cpp            |   5 +-
 .../sanitizer_platform_limits_netbsd.cpp           |   2 -
 .../sanitizer_platform_limits_netbsd.h             |   2 -
 .../sanitizer_platform_limits_posix.cpp            |  47 ++-
 .../sanitizer_platform_limits_posix.h              |  46 +--
 libsanitizer/sanitizer_common/sanitizer_posix.cpp  |  19 +-
 libsanitizer/sanitizer_common/sanitizer_procmaps.h |  24 +-
 .../sanitizer_common/sanitizer_procmaps_bsd.cpp    |  16 +
 .../sanitizer_common/sanitizer_procmaps_common.cpp |   2 +
 .../sanitizer_common/sanitizer_procmaps_mac.cpp    |  78 ++++-
 .../sanitizer_common/sanitizer_stacktrace.cpp      |  17 +-
 .../sanitizer_common/sanitizer_stacktrace.h        |   4 +-
 .../sanitizer_stoptheworld_linux_libcdep.cpp       |  12 +-
 .../sanitizer_common/sanitizer_suppressions.cpp    |   1 +
 .../sanitizer_symbolizer_internal.h                |   2 +-
 .../sanitizer_symbolizer_libbacktrace.cpp          |   4 +-
 .../sanitizer_common/sanitizer_symbolizer_mac.cpp  |  20 +-
 .../sanitizer_symbolizer_posix_libcdep.cpp         |  38 +--
 .../sanitizer_symbolizer_report.cpp                |   3 +-
 .../sanitizer_common/sanitizer_symbolizer_win.cpp  |   6 +-
 .../sanitizer_common/sanitizer_thread_registry.cpp |   2 +-
 .../sanitizer_common/sanitizer_tls_get_addr.cpp    |  29 +-
 .../sanitizer_common/sanitizer_tls_get_addr.h      |  26 +-
 libsanitizer/sanitizer_common/sanitizer_win.cpp    |  13 +-
 libsanitizer/tsan/tsan_external.cpp                |  31 +-
 libsanitizer/tsan/tsan_flags.cpp                   |  10 +-
 libsanitizer/tsan/tsan_interceptors_mac.cpp        |   1 +
 libsanitizer/tsan/tsan_interceptors_posix.cpp      | 176 ++++++++---
 libsanitizer/tsan/tsan_interface.h                 |   5 +
 libsanitizer/tsan/tsan_mman.cpp                    |  19 ++
 libsanitizer/tsan/tsan_platform.h                  | 170 +++++++----
 libsanitizer/tsan/tsan_platform_linux.cpp          |  25 +-
 libsanitizer/tsan/tsan_platform_posix.cpp          |   2 +-
 libsanitizer/tsan/tsan_rtl.cpp                     |   3 +
 libsanitizer/tsan/tsan_rtl.h                       |  11 +-
 libsanitizer/tsan/tsan_rtl_aarch64.S               |  37 +--
 libsanitizer/tsan/tsan_rtl_loongarch64.S           | 196 ++++++++++++
 libsanitizer/tsan/tsan_rtl_ppc64.S                 |   1 -
 libsanitizer/tsan/tsan_rtl_report.cpp              |  10 +-
 libsanitizer/tsan/tsan_spinlock_defs_mac.h         |  45 +++
 libsanitizer/tsan/tsan_suppressions.cpp            |   5 +-
 libsanitizer/ubsan/ubsan_diag.cpp                  |   7 +-
 libsanitizer/ubsan/ubsan_flags.cpp                 |   1 -
 libsanitizer/ubsan/ubsan_handlers.cpp              |  15 -
 libsanitizer/ubsan/ubsan_handlers.h                |   8 -
 libsanitizer/ubsan/ubsan_platform.h                |   2 -
 libsanitizer/ubsan/ubsan_type_hash_itanium.cpp     |  23 +-
 132 files changed, 2772 insertions(+), 1165 deletions(-)

diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE
index 6bb19c7d5ba..cea6249d99c 100644
--- a/libsanitizer/MERGE
+++ b/libsanitizer/MERGE
@@ -1,4 +1,4 @@
-ae59131d3ef311fb4b1e50627c6457be00e60dc9
+3185e47b5a8444e9fd70b746a7ad679dd131ffe4
 
 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 52d7eff7281..19d7777c402 100644
--- a/libsanitizer/asan/asan_allocator.cpp
+++ b/libsanitizer/asan/asan_allocator.cpp
@@ -1094,10 +1094,16 @@ uptr PointsIntoChunk(void *p) {
 }
 
 uptr GetUserBegin(uptr chunk) {
+  // FIXME: All usecases provide chunk address, GetAsanChunkByAddrFastLocked is
+  // not needed.
   __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddrFastLocked(chunk);
   return m ? m->Beg() : 0;
 }
 
+uptr GetUserAddr(uptr chunk) {
+  return chunk;
+}
+
 LsanMetadata::LsanMetadata(uptr chunk) {
   metadata_ = chunk ? reinterpret_cast<void *>(chunk - __asan::kChunkHeaderSize)
                     : nullptr;
@@ -1138,7 +1144,7 @@ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
   __asan::get_allocator().ForEachChunk(callback, arg);
 }
 
-IgnoreObjectResult IgnoreObjectLocked(const void *p) {
+IgnoreObjectResult IgnoreObject(const void *p) {
   uptr addr = reinterpret_cast<uptr>(p);
   __asan::AsanChunk *m = __asan::instance.GetAsanChunkByAddr(addr);
   if (!m ||
@@ -1153,38 +1159,22 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
   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
 using namespace __asan;
 
+static const void *AllocationBegin(const void *p) {
+  AsanChunk *m = __asan::instance.GetAsanChunkByAddr((uptr)p);
+  if (!m)
+    return nullptr;
+  if (atomic_load(&m->chunk_state, memory_order_acquire) != CHUNK_ALLOCATED)
+    return nullptr;
+  if (m->UsedSize() == 0)
+    return nullptr;
+  return (const void *)(m->Beg());
+}
+
 // ASan allocator doesn't reserve extra bytes, so normally we would
 // just return "size". We don't want to expose our redzone sizes, etc here.
 uptr __sanitizer_get_estimated_allocated_size(uptr size) {
@@ -1208,6 +1198,10 @@ uptr __sanitizer_get_allocated_size(const void *p) {
   return allocated_size;
 }
 
+const void *__sanitizer_get_allocated_begin(const void *p) {
+  return AllocationBegin(p);
+}
+
 void __sanitizer_purge_allocator() {
   GET_STACK_TRACE_MALLOC;
   instance.Purge(&stack);
diff --git a/libsanitizer/asan/asan_allocator.h b/libsanitizer/asan/asan_allocator.h
index 0b4dbf03bb9..6a12a6c6025 100644
--- a/libsanitizer/asan/asan_allocator.h
+++ b/libsanitizer/asan/asan_allocator.h
@@ -143,11 +143,15 @@ typedef DefaultSizeClassMap SizeClassMap;
 const uptr kAllocatorSpace = ~(uptr)0;
 const uptr kAllocatorSize  =  0x8000000000ULL;  // 500G
 typedef DefaultSizeClassMap SizeClassMap;
-# else
+#  elif SANITIZER_APPLE
 const uptr kAllocatorSpace = 0x600000000000ULL;
 const uptr kAllocatorSize  =  0x40000000000ULL;  // 4T.
 typedef DefaultSizeClassMap SizeClassMap;
-# endif
+#  else
+const uptr kAllocatorSpace = 0x500000000000ULL;
+const uptr kAllocatorSize = 0x40000000000ULL;  // 4T.
+typedef DefaultSizeClassMap SizeClassMap;
+#  endif
 template <typename AddressSpaceViewTy>
 struct AP64 {  // Allocator64 parameters. Deliberately using a short name.
   static const uptr kSpaceBeg = kAllocatorSpace;
diff --git a/libsanitizer/asan/asan_errors.cpp b/libsanitizer/asan/asan_errors.cpp
index f3befdf3c2b..cc8dc26f5b7 100644
--- a/libsanitizer/asan/asan_errors.cpp
+++ b/libsanitizer/asan/asan_errors.cpp
@@ -334,6 +334,26 @@ void ErrorBadParamsToAnnotateContiguousContainer::Print() {
   ReportErrorSummary(scariness.GetDescription(), stack);
 }
 
+void ErrorBadParamsToAnnotateDoubleEndedContiguousContainer::Print() {
+  Report(
+      "ERROR: AddressSanitizer: bad parameters to "
+      "__sanitizer_annotate_double_ended_contiguous_container:\n"
+      "      storage_beg        : %p\n"
+      "      storage_end        : %p\n"
+      "      old_container_beg  : %p\n"
+      "      old_container_end  : %p\n"
+      "      new_container_beg  : %p\n"
+      "      new_container_end  : %p\n",
+      (void *)storage_beg, (void *)storage_end, (void *)old_container_beg,
+      (void *)old_container_end, (void *)new_container_beg,
+      (void *)new_container_end);
+  uptr granularity = ASAN_SHADOW_GRANULARITY;
+  if (!IsAligned(storage_beg, granularity))
+    Report("ERROR: storage_beg is not aligned by %zu\n", granularity);
+  stack->Print();
+  ReportErrorSummary(scariness.GetDescription(), stack);
+}
+
 void ErrorODRViolation::Print() {
   Decorator d;
   Printf("%s", d.Error());
diff --git a/libsanitizer/asan/asan_errors.h b/libsanitizer/asan/asan_errors.h
index c6ac88f6dc2..634f6da5443 100644
--- a/libsanitizer/asan/asan_errors.h
+++ b/libsanitizer/asan/asan_errors.h
@@ -331,6 +331,28 @@ struct ErrorBadParamsToAnnotateContiguousContainer : ErrorBase {
   void Print();
 };
 
+struct ErrorBadParamsToAnnotateDoubleEndedContiguousContainer : ErrorBase {
+  const BufferedStackTrace *stack;
+  uptr storage_beg, storage_end, old_container_beg, old_container_end,
+      new_container_beg, new_container_end;
+
+  ErrorBadParamsToAnnotateDoubleEndedContiguousContainer() = default;  // (*)
+  ErrorBadParamsToAnnotateDoubleEndedContiguousContainer(
+      u32 tid, BufferedStackTrace *stack_, uptr storage_beg_, uptr storage_end_,
+      uptr old_container_beg_, uptr old_container_end_, uptr new_container_beg_,
+      uptr new_container_end_)
+      : ErrorBase(tid, 10,
+                  "bad-__sanitizer_annotate_double_ended_contiguous_container"),
+        stack(stack_),
+        storage_beg(storage_beg_),
+        storage_end(storage_end_),
+        old_container_beg(old_container_beg_),
+        old_container_end(old_container_end_),
+        new_container_beg(new_container_beg_),
+        new_container_end(new_container_end_) {}
+  void Print();
+};
+
 struct ErrorODRViolation : ErrorBase {
   __asan_global global1, global2;
   u32 stack_id1, stack_id2;
@@ -378,28 +400,29 @@ struct ErrorGeneric : ErrorBase {
 };
 
 // clang-format off
-#define ASAN_FOR_EACH_ERROR_KIND(macro)         \
-  macro(DeadlySignal)                           \
-  macro(DoubleFree)                             \
-  macro(NewDeleteTypeMismatch)                  \
-  macro(FreeNotMalloced)                        \
-  macro(AllocTypeMismatch)                      \
-  macro(MallocUsableSizeNotOwned)               \
-  macro(SanitizerGetAllocatedSizeNotOwned)      \
-  macro(CallocOverflow)                         \
-  macro(ReallocArrayOverflow)                   \
-  macro(PvallocOverflow)                        \
-  macro(InvalidAllocationAlignment)             \
-  macro(InvalidAlignedAllocAlignment)           \
-  macro(InvalidPosixMemalignAlignment)          \
-  macro(AllocationSizeTooBig)                   \
-  macro(RssLimitExceeded)                       \
-  macro(OutOfMemory)                            \
-  macro(StringFunctionMemoryRangesOverlap)      \
-  macro(StringFunctionSizeOverflow)             \
-  macro(BadParamsToAnnotateContiguousContainer) \
-  macro(ODRViolation)                           \
-  macro(InvalidPointerPair)                     \
+#define ASAN_FOR_EACH_ERROR_KIND(macro)                    \
+  macro(DeadlySignal)                                      \
+  macro(DoubleFree)                                        \
+  macro(NewDeleteTypeMismatch)                             \
+  macro(FreeNotMalloced)                                   \
+  macro(AllocTypeMismatch)                                 \
+  macro(MallocUsableSizeNotOwned)                          \
+  macro(SanitizerGetAllocatedSizeNotOwned)                 \
+  macro(CallocOverflow)                                    \
+  macro(ReallocArrayOverflow)                              \
+  macro(PvallocOverflow)                                   \
+  macro(InvalidAllocationAlignment)                        \
+  macro(InvalidAlignedAllocAlignment)                      \
+  macro(InvalidPosixMemalignAlignment)                     \
+  macro(AllocationSizeTooBig)                              \
+  macro(RssLimitExceeded)                                  \
+  macro(OutOfMemory)                                       \
+  macro(StringFunctionMemoryRangesOverlap)                 \
+  macro(StringFunctionSizeOverflow)                        \
+  macro(BadParamsToAnnotateContiguousContainer)            \
+  macro(BadParamsToAnnotateDoubleEndedContiguousContainer) \
+  macro(ODRViolation)                                      \
+  macro(InvalidPointerPair)                                \
   macro(Generic)
 // clang-format on
 
diff --git a/libsanitizer/asan/asan_globals.cpp b/libsanitizer/asan/asan_globals.cpp
index 01a243927ca..4d391cb2a88 100644
--- a/libsanitizer/asan/asan_globals.cpp
+++ b/libsanitizer/asan/asan_globals.cpp
@@ -158,6 +158,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
@@ -203,6 +220,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 817008253fc..0f160055248 100644
--- a/libsanitizer/asan/asan_interceptors.cpp
+++ b/libsanitizer/asan/asan_interceptors.cpp
@@ -257,12 +257,36 @@ static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) {
   PoisonShadow(bottom, ssize, 0);
 }
 
-INTERCEPTOR(int, getcontext, struct ucontext_t *ucp) {
-  // API does not requires to have ucp clean, and sets only part of fields. We
-  // use ucp->uc_stack to unpoison new stack. We prefer to have zeroes then
-  // uninitialized bytes.
-  ResetContextStack(ucp);
-  return REAL(getcontext)(ucp);
+INTERCEPTOR(void, makecontext, struct ucontext_t *ucp, void (*func)(), int argc,
+            ...) {
+  va_list ap;
+  uptr args[64];
+  // We don't know a better way to forward ... into REAL function. We can
+  // increase args size if neccecary.
+  CHECK_LE(argc, ARRAY_SIZE(args));
+  internal_memset(args, 0, sizeof(args));
+  va_start(ap, argc);
+  for (int i = 0; i < argc; ++i) args[i] = va_arg(ap, uptr);
+  va_end(ap);
+
+#    define ENUMERATE_ARRAY_4(start) \
+      args[start], args[start + 1], args[start + 2], args[start + 3]
+#    define ENUMERATE_ARRAY_16(start)                         \
+      ENUMERATE_ARRAY_4(start), ENUMERATE_ARRAY_4(start + 4), \
+          ENUMERATE_ARRAY_4(start + 8), ENUMERATE_ARRAY_4(start + 12)
+#    define ENUMERATE_ARRAY_64()                                             \
+      ENUMERATE_ARRAY_16(0), ENUMERATE_ARRAY_16(16), ENUMERATE_ARRAY_16(32), \
+          ENUMERATE_ARRAY_16(48)
+
+  REAL(makecontext)
+  ((struct ucontext_t *)ucp, func, argc, ENUMERATE_ARRAY_64());
+
+#    undef ENUMERATE_ARRAY_4
+#    undef ENUMERATE_ARRAY_16
+#    undef ENUMERATE_ARRAY_64
+
+  // Sign the stack so we can identify it for unpoisoning.
+  SignContextStack(ucp);
 }
 
 INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
@@ -279,9 +303,6 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
   ReadContextStack(ucp, &stack, &ssize);
   ClearShadowMemoryForContextStack(stack, ssize);
 
-  // See getcontext interceptor.
-  ResetContextStack(oucp);
-
 #    if __has_attribute(__indirect_return__) && \
         (defined(__x86_64__) || defined(__i386__))
   int (*real_swapcontext)(struct ucontext_t *, struct ucontext_t *)
@@ -453,7 +474,9 @@ INTERCEPTOR(char*, strdup, const char *s) {
   }
   GET_STACK_TRACE_MALLOC;
   void *new_mem = asan_malloc(length + 1, &stack);
-  REAL(memcpy)(new_mem, s, length + 1);
+  if (new_mem) {
+    REAL(memcpy)(new_mem, s, length + 1);
+  }
   return reinterpret_cast<char*>(new_mem);
 }
 
@@ -469,7 +492,9 @@ INTERCEPTOR(char*, __strdup, const char *s) {
   }
   GET_STACK_TRACE_MALLOC;
   void *new_mem = asan_malloc(length + 1, &stack);
-  REAL(memcpy)(new_mem, s, length + 1);
+  if (new_mem) {
+    REAL(memcpy)(new_mem, s, length + 1);
+  }
   return reinterpret_cast<char*>(new_mem);
 }
 #endif // ASAN_INTERCEPT___STRDUP
@@ -658,11 +683,11 @@ void InitializeAsanInterceptors() {
   // Intecept jump-related functions.
   ASAN_INTERCEPT_FUNC(longjmp);
 
-#if ASAN_INTERCEPT_SWAPCONTEXT
-  ASAN_INTERCEPT_FUNC(getcontext);
+#  if ASAN_INTERCEPT_SWAPCONTEXT
   ASAN_INTERCEPT_FUNC(swapcontext);
-#endif
-#if ASAN_INTERCEPT__LONGJMP
+  ASAN_INTERCEPT_FUNC(makecontext);
+#  endif
+#  if ASAN_INTERCEPT__LONGJMP
   ASAN_INTERCEPT_FUNC(_longjmp);
 #endif
 #if ASAN_INTERCEPT___LONGJMP_CHK
@@ -681,11 +706,11 @@ void InitializeAsanInterceptors() {
 #endif
   // Indirectly intercept std::rethrow_exception.
 #if ASAN_INTERCEPT__UNWIND_RAISEEXCEPTION
-  INTERCEPT_FUNCTION(_Unwind_RaiseException);
+  ASAN_INTERCEPT_FUNC(_Unwind_RaiseException);
 #endif
   // Indirectly intercept std::rethrow_exception.
 #if ASAN_INTERCEPT__UNWIND_SJLJ_RAISEEXCEPTION
-  INTERCEPT_FUNCTION(_Unwind_SjLj_RaiseException);
+  ASAN_INTERCEPT_FUNC(_Unwind_SjLj_RaiseException);
 #endif
 
   // Intercept threading-related functions
diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h
index 9a6c22c764a..c4bf087ea17 100644
--- a/libsanitizer/asan/asan_interceptors.h
+++ b/libsanitizer/asan/asan_interceptors.h
@@ -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
diff --git a/libsanitizer/asan/asan_internal.h b/libsanitizer/asan/asan_internal.h
index 959fdec2604..a5348e35b29 100644
--- a/libsanitizer/asan/asan_internal.h
+++ b/libsanitizer/asan/asan_internal.h
@@ -105,8 +105,8 @@ void AsanApplyToGlobals(globals_op_fptr op, const void *needle);
 
 void AsanOnDeadlySignal(int, void *siginfo, void *context);
 
+void SignContextStack(void *context);
 void ReadContextStack(void *context, uptr *stack, uptr *ssize);
-void ResetContextStack(void *context);
 void StopInitOrderChecking();
 
 // Wrapper for TLS/TSD.
diff --git a/libsanitizer/asan/asan_linux.cpp b/libsanitizer/asan/asan_linux.cpp
index 89450fc120a..e19b4479aaf 100644
--- a/libsanitizer/asan/asan_linux.cpp
+++ b/libsanitizer/asan/asan_linux.cpp
@@ -15,55 +15,56 @@
 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
     SANITIZER_SOLARIS
 
-#include "asan_interceptors.h"
-#include "asan_internal.h"
-#include "asan_premap_shadow.h"
-#include "asan_thread.h"
-#include "sanitizer_common/sanitizer_flags.h"
-#include "sanitizer_common/sanitizer_freebsd.h"
-#include "sanitizer_common/sanitizer_libc.h"
-#include "sanitizer_common/sanitizer_procmaps.h"
-
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/mman.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <dlfcn.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <unwind.h>
-
-#if SANITIZER_FREEBSD
-#include <sys/link_elf.h>
-#endif
-
-#if SANITIZER_SOLARIS
-#include <link.h>
-#endif
-
-#if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS
-#include <ucontext.h>
-extern "C" void* _DYNAMIC;
-#elif SANITIZER_NETBSD
-#include <link_elf.h>
-#include <ucontext.h>
+#  include <dlfcn.h>
+#  include <fcntl.h>
+#  include <limits.h>
+#  include <pthread.h>
+#  include <stdio.h>
+#  include <sys/mman.h>
+#  include <sys/resource.h>
+#  include <sys/syscall.h>
+#  include <sys/time.h>
+#  include <sys/types.h>
+#  include <unistd.h>
+#  include <unwind.h>
+
+#  include "asan_interceptors.h"
+#  include "asan_internal.h"
+#  include "asan_premap_shadow.h"
+#  include "asan_thread.h"
+#  include "sanitizer_common/sanitizer_flags.h"
+#  include "sanitizer_common/sanitizer_freebsd.h"
+#  include "sanitizer_common/sanitizer_hash.h"
+#  include "sanitizer_common/sanitizer_libc.h"
+#  include "sanitizer_common/sanitizer_procmaps.h"
+
+#  if SANITIZER_FREEBSD
+#    include <sys/link_elf.h>
+#  endif
+
+#  if SANITIZER_SOLARIS
+#    include <link.h>
+#  endif
+
+#  if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS
+#    include <ucontext.h>
+extern "C" void *_DYNAMIC;
+#  elif SANITIZER_NETBSD
+#    include <link_elf.h>
+#    include <ucontext.h>
 extern Elf_Dyn _DYNAMIC;
-#else
-#include <sys/ucontext.h>
-#include <link.h>
+#  else
+#    include <link.h>
+#    include <sys/ucontext.h>
 extern ElfW(Dyn) _DYNAMIC[];
-#endif
+#  endif
 
 // x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
 // 32-bit mode.
-#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \
-  __FreeBSD_version <= 902001  // v9.2
-#define ucontext_t xucontext_t
-#endif
+#  if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32) && \
+      __FreeBSD_version <= 902001  // v9.2
+#    define ucontext_t xucontext_t
+#  endif
 
 typedef enum {
   ASAN_RT_VERSION_UNDEFINED = 0,
@@ -74,21 +75,21 @@ typedef enum {
 // FIXME: perhaps also store abi version here?
 extern "C" {
 SANITIZER_INTERFACE_ATTRIBUTE
-asan_rt_version_t  __asan_rt_version;
+asan_rt_version_t __asan_rt_version;
 }
 
 namespace __asan {
 
 void InitializePlatformInterceptors() {}
 void InitializePlatformExceptionHandlers() {}
-bool IsSystemHeapAddress (uptr addr) { return false; }
+bool IsSystemHeapAddress(uptr addr) { return false; }
 
 void *AsanDoesNotSupportStaticLinkage() {
   // This will fail to link with -static.
   return &_DYNAMIC;
 }
 
-#if ASAN_PREMAP_SHADOW
+#  if ASAN_PREMAP_SHADOW
 uptr FindPremappedShadowStart(uptr shadow_size_bytes) {
   uptr granularity = GetMmapGranularity();
   uptr shadow_start = reinterpret_cast<uptr>(&__asan_shadow);
@@ -98,14 +99,14 @@ uptr FindPremappedShadowStart(uptr shadow_size_bytes) {
   UnmapFromTo(shadow_start + shadow_size, shadow_start + premap_shadow_size);
   return shadow_start;
 }
-#endif
+#  endif
 
 uptr FindDynamicShadowStart() {
   uptr shadow_size_bytes = MemToShadowSize(kHighMemEnd);
-#if ASAN_PREMAP_SHADOW
+#  if ASAN_PREMAP_SHADOW
   if (!PremapShadowFailed())
     return FindPremappedShadowStart(shadow_size_bytes);
-#endif
+#  endif
 
   return MapDynamicShadow(shadow_size_bytes, ASAN_SHADOW_SCALE,
                           /*min_shadow_base_alignment*/ 0, kHighMemEnd);
@@ -121,11 +122,11 @@ void FlushUnneededASanShadowMemory(uptr p, uptr size) {
   ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
 }
 
-#if SANITIZER_ANDROID
+#  if SANITIZER_ANDROID
 // FIXME: should we do anything for Android?
 void AsanCheckDynamicRTPrereqs() {}
 void AsanCheckIncompatibleRT() {}
-#else
+#  else
 static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
                                 void *data) {
   VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n", info->dlpi_name,
@@ -154,7 +155,7 @@ static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
 
 static bool IsDynamicRTName(const char *libname) {
   return internal_strstr(libname, "libclang_rt.asan") ||
-    internal_strstr(libname, "libasan.so");
+         internal_strstr(libname, "libasan.so");
 }
 
 static void ReportIncompatibleRT() {
@@ -170,9 +171,10 @@ void AsanCheckDynamicRTPrereqs() {
   const char *first_dso_name = nullptr;
   dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name);
   if (first_dso_name && first_dso_name[0] && !IsDynamicRTName(first_dso_name)) {
-    Report("ASan runtime does not come first in initial library list; "
-           "you should either link runtime to your application or "
-           "manually preload it with LD_PRELOAD.\n");
+    Report(
+        "ASan runtime does not come first in initial library list; "
+        "you should either link runtime to your application or "
+        "manually preload it with LD_PRELOAD.\n");
     Die();
   }
 }
@@ -190,13 +192,14 @@ void AsanCheckIncompatibleRT() {
       // as early as possible, otherwise ASan interceptors could bind to
       // the functions in dynamic ASan runtime instead of the functions in
       // system libraries, causing crashes later in ASan initialization.
-      MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+      MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
       char filename[PATH_MAX];
       MemoryMappedSegment segment(filename, sizeof(filename));
       while (proc_maps.Next(&segment)) {
         if (IsDynamicRTName(segment.filename)) {
-          Report("Your application is linked against "
-                 "incompatible ASan runtimes.\n");
+          Report(
+              "Your application is linked against "
+              "incompatible ASan runtimes.\n");
           Die();
         }
       }
@@ -206,31 +209,36 @@ void AsanCheckIncompatibleRT() {
     }
   }
 }
-#endif // SANITIZER_ANDROID
+#  endif  // SANITIZER_ANDROID
 
-#if !SANITIZER_ANDROID
-void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
-  ucontext_t *ucp = (ucontext_t*)context;
-  *stack = (uptr)ucp->uc_stack.ss_sp;
-  *ssize = ucp->uc_stack.ss_size;
+#  if ASAN_INTERCEPT_SWAPCONTEXT
+constexpr u32 kAsanContextStackFlagsMagic = 0x51260eea;
+
+static int HashContextStack(const ucontext_t &ucp) {
+  MurMur2Hash64Builder hash(kAsanContextStackFlagsMagic);
+  hash.add(reinterpret_cast<uptr>(ucp.uc_stack.ss_sp));
+  hash.add(ucp.uc_stack.ss_size);
+  return static_cast<int>(hash.get());
 }
 
-void ResetContextStack(void *context) {
-  ucontext_t *ucp = (ucontext_t *)context;
-  ucp->uc_stack.ss_sp = nullptr;
-  ucp->uc_stack.ss_size = 0;
+void SignContextStack(void *context) {
+  ucontext_t *ucp = reinterpret_cast<ucontext_t *>(context);
+  ucp->uc_stack.ss_flags = HashContextStack(*ucp);
 }
-#  else
+
 void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
-  UNIMPLEMENTED();
+  const ucontext_t *ucp = reinterpret_cast<const ucontext_t *>(context);
+  if (HashContextStack(*ucp) == ucp->uc_stack.ss_flags) {
+    *stack = reinterpret_cast<uptr>(ucp->uc_stack.ss_sp);
+    *ssize = ucp->uc_stack.ss_size;
+    return;
+  }
+  *stack = 0;
+  *ssize = 0;
 }
+#  endif  // ASAN_INTERCEPT_SWAPCONTEXT
 
-void ResetContextStack(void *context) { UNIMPLEMENTED(); }
-#  endif
-
-void *AsanDlSymNext(const char *sym) {
-  return dlsym(RTLD_NEXT, sym);
-}
+void *AsanDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, sym); }
 
 bool HandleDlopenInit() {
   // Not supported on this platform.
@@ -239,7 +247,7 @@ bool HandleDlopenInit() {
   return false;
 }
 
-} // namespace __asan
+}  // namespace __asan
 
 #endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
         // SANITIZER_SOLARIS
diff --git a/libsanitizer/asan/asan_mac.cpp b/libsanitizer/asan/asan_mac.cpp
index a2d5c31a3f7..c9bd5fb8e1a 100644
--- a/libsanitizer/asan/asan_mac.cpp
+++ b/libsanitizer/asan/asan_mac.cpp
@@ -95,12 +95,6 @@ void FlushUnneededASanShadowMemory(uptr p, uptr size) {
   ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
 }
 
-void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
-  UNIMPLEMENTED();
-}
-
-void ResetContextStack(void *context) { UNIMPLEMENTED(); }
-
 // Support for the following functions from libdispatch on Mac OS:
 //   dispatch_async_f()
 //   dispatch_async()
diff --git a/libsanitizer/asan/asan_malloc_win.cpp b/libsanitizer/asan/asan_malloc_win.cpp
index 4b76d4ebd3e..ff78d7646a9 100644
--- a/libsanitizer/asan/asan_malloc_win.cpp
+++ b/libsanitizer/asan/asan_malloc_win.cpp
@@ -508,10 +508,10 @@ void ReplaceSystemMalloc() {
   TryToOverrideFunction("_expand_base", (uptr)_expand);
 
   if (flags()->windows_hook_rtl_allocators) {
-    INTERCEPT_FUNCTION(HeapSize);
-    INTERCEPT_FUNCTION(HeapFree);
-    INTERCEPT_FUNCTION(HeapReAlloc);
-    INTERCEPT_FUNCTION(HeapAlloc);
+    ASAN_INTERCEPT_FUNC(HeapSize);
+    ASAN_INTERCEPT_FUNC(HeapFree);
+    ASAN_INTERCEPT_FUNC(HeapReAlloc);
+    ASAN_INTERCEPT_FUNC(HeapAlloc);
 
     // Undocumented functions must be intercepted by name, not by symbol.
     __interception::OverrideFunction("RtlSizeHeap", (uptr)WRAP(RtlSizeHeap),
diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h
index 47ccf8444d3..c5f95c07a21 100644
--- a/libsanitizer/asan/asan_mapping.h
+++ b/libsanitizer/asan/asan_mapping.h
@@ -190,7 +190,7 @@
 #  elif defined(__aarch64__)
 #    define ASAN_SHADOW_OFFSET_CONST 0x0000001000000000
 #  elif defined(__powerpc64__)
-#    define ASAN_SHADOW_OFFSET_CONST 0x0000020000000000
+#    define ASAN_SHADOW_OFFSET_CONST 0x0000100000000000
 #  elif defined(__s390x__)
 #    define ASAN_SHADOW_OFFSET_CONST 0x0010000000000000
 #  elif SANITIZER_FREEBSD
diff --git a/libsanitizer/asan/asan_memory_profile.cpp b/libsanitizer/asan/asan_memory_profile.cpp
index 4fcd5600ed1..3396fc2bab9 100644
--- a/libsanitizer/asan/asan_memory_profile.cpp
+++ b/libsanitizer/asan/asan_memory_profile.cpp
@@ -11,12 +11,11 @@
 // This file implements __sanitizer_print_memory_profile.
 //===----------------------------------------------------------------------===//
 
+#include "asan/asan_allocator.h"
+#include "lsan/lsan_common.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
-#include "sanitizer_common/sanitizer_stoptheworld.h"
-#include "lsan/lsan_common.h"
-#include "asan/asan_allocator.h"
 
 #if CAN_SANITIZE_LEAKS
 
@@ -100,17 +99,16 @@ static void ChunkCallback(uptr chunk, void *arg) {
       FindHeapChunkByAllocBeg(chunk));
 }
 
-static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list,
-                            void *argument) {
+static void MemoryProfileCB(uptr top_percent, uptr max_number_of_contexts) {
   HeapProfile hp;
+  __lsan::LockAllocator();
   __lsan::ForEachChunk(ChunkCallback, &hp);
-  uptr *Arg = reinterpret_cast<uptr*>(argument);
-  hp.Print(Arg[0], Arg[1]);
+  __lsan::UnlockAllocator();
+  hp.Print(top_percent, max_number_of_contexts);
 
   if (Verbosity())
     __asan_print_accumulated_stats();
 }
-
 }  // namespace __asan
 
 #endif  // CAN_SANITIZE_LEAKS
@@ -120,10 +118,7 @@ SANITIZER_INTERFACE_ATTRIBUTE
 void __sanitizer_print_memory_profile(uptr top_percent,
                                       uptr max_number_of_contexts) {
 #if CAN_SANITIZE_LEAKS
-  uptr Arg[2];
-  Arg[0] = top_percent;
-  Arg[1] = max_number_of_contexts;
-  __sanitizer::StopTheWorld(__asan::MemoryProfileCB, Arg);
+  __asan::MemoryProfileCB(top_percent, max_number_of_contexts);
 #endif  // CAN_SANITIZE_LEAKS
 }
 }  // extern "C"
diff --git a/libsanitizer/asan/asan_poisoning.cpp b/libsanitizer/asan/asan_poisoning.cpp
index e4702563463..5164b7d860f 100644
--- a/libsanitizer/asan/asan_poisoning.cpp
+++ b/libsanitizer/asan/asan_poisoning.cpp
@@ -370,79 +370,77 @@ void __asan_unpoison_stack_memory(uptr addr, uptr size) {
   PoisonAlignedStackMemory(addr, size, false);
 }
 
+static void FixUnalignedStorage(uptr storage_beg, uptr storage_end,
+                                uptr &old_beg, uptr &old_end, uptr &new_beg,
+                                uptr &new_end) {
+  constexpr uptr granularity = ASAN_SHADOW_GRANULARITY;
+  if (UNLIKELY(!AddrIsAlignedByGranularity(storage_end))) {
+    uptr end_down = RoundDownTo(storage_end, granularity);
+    // Ignore the last unaligned granule if the storage is followed by
+    // unpoisoned byte, because we can't poison the prefix anyway. Don't call
+    // AddressIsPoisoned at all if container changes does not affect the last
+    // granule at all.
+    if ((((old_end != new_end) && Max(old_end, new_end) > end_down) ||
+         ((old_beg != new_beg) && Max(old_beg, new_beg) > end_down)) &&
+        !AddressIsPoisoned(storage_end)) {
+      old_beg = Min(end_down, old_beg);
+      old_end = Min(end_down, old_end);
+      new_beg = Min(end_down, new_beg);
+      new_end = Min(end_down, new_end);
+    }
+  }
+
+  // Handle misaligned begin and cut it off.
+  if (UNLIKELY(!AddrIsAlignedByGranularity(storage_beg))) {
+    uptr beg_up = RoundUpTo(storage_beg, granularity);
+    // The first unaligned granule needs special handling only if we had bytes
+    // there before and will have none after.
+    if ((new_beg == new_end || new_beg >= beg_up) && old_beg != old_end &&
+        old_beg < beg_up) {
+      // Keep granule prefix outside of the storage unpoisoned.
+      uptr beg_down = RoundDownTo(storage_beg, granularity);
+      *(u8 *)MemToShadow(beg_down) = storage_beg - beg_down;
+      old_beg = Max(beg_up, old_beg);
+      old_end = Max(beg_up, old_end);
+      new_beg = Max(beg_up, new_beg);
+      new_end = Max(beg_up, new_end);
+    }
+  }
+}
+
 void __sanitizer_annotate_contiguous_container(const void *beg_p,
                                                const void *end_p,
                                                const void *old_mid_p,
                                                const void *new_mid_p) {
-  if (!flags()->detect_container_overflow) return;
+  if (!flags()->detect_container_overflow)
+    return;
   VPrintf(2, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p,
           new_mid_p);
-  uptr beg = reinterpret_cast<uptr>(beg_p);
-  uptr end = reinterpret_cast<uptr>(end_p);
-  uptr old_mid = reinterpret_cast<uptr>(old_mid_p);
-  uptr new_mid = reinterpret_cast<uptr>(new_mid_p);
+  uptr storage_beg = reinterpret_cast<uptr>(beg_p);
+  uptr storage_end = reinterpret_cast<uptr>(end_p);
+  uptr old_end = reinterpret_cast<uptr>(old_mid_p);
+  uptr new_end = reinterpret_cast<uptr>(new_mid_p);
+  uptr old_beg = storage_beg;
+  uptr new_beg = storage_beg;
   uptr granularity = ASAN_SHADOW_GRANULARITY;
-  if (!(beg <= old_mid && beg <= new_mid && old_mid <= end && new_mid <= end)) {
+  if (!(storage_beg <= old_end && storage_beg <= new_end &&
+        old_end <= storage_end && new_end <= storage_end)) {
     GET_STACK_TRACE_FATAL_HERE;
-    ReportBadParamsToAnnotateContiguousContainer(beg, end, old_mid, new_mid,
-                                                 &stack);
+    ReportBadParamsToAnnotateContiguousContainer(storage_beg, storage_end,
+                                                 old_end, new_end, &stack);
   }
-  CHECK_LE(end - beg,
-           FIRST_32_SECOND_64(1UL << 30, 1ULL << 40)); // Sanity check.
+  CHECK_LE(storage_end - storage_beg,
+           FIRST_32_SECOND_64(1UL << 30, 1ULL << 40));  // Sanity check.
 
-  if (old_mid == new_mid)
+  if (old_end == new_end)
     return;  // Nothing to do here.
 
-  // Handle misaligned end and cut it off.
-  if (UNLIKELY(!AddrIsAlignedByGranularity(end))) {
-    uptr end_down = RoundDownTo(end, granularity);
-    // Either new or old mid must be in the granule to affect it.
-    if (new_mid > end_down) {
-      if (AddressIsPoisoned(end)) {
-        *(u8 *)MemToShadow(end_down) = static_cast<u8>(new_mid - end_down);
-      } else {
-        // Something after the container - don't touch.
-      }
-    } else if (old_mid > end_down) {
-      if (AddressIsPoisoned(end)) {
-        *(u8 *)MemToShadow(end_down) = kAsanContiguousContainerOOBMagic;
-      } else {
-        // Something after the container - don't touch.
-      }
-    }
+  FixUnalignedStorage(storage_beg, storage_end, old_beg, old_end, new_beg,
+                      new_end);
 
-    if (beg >= end_down)
-      return;  // Same granule.
-
-    old_mid = Min(end_down, old_mid);
-    new_mid = Min(end_down, new_mid);
-  }
-
-  // Handle misaligned begin and cut it off.
-  if (UNLIKELY(!AddrIsAlignedByGranularity(beg))) {
-    uptr beg_up = RoundUpTo(beg, granularity);
-    uptr beg_down = RoundDownTo(beg, granularity);
-    // As soon as we add first byte into container we will not be able to
-    // determine the state of the byte before the container. So we assume it's
-    // always unpoison.
-
-    // Either new or old mid must be in the granule to affect it.
-    if (new_mid < beg_up) {
-      *(u8 *)MemToShadow(beg_down) = static_cast<u8>(new_mid - beg_down);
-    } else if (old_mid < beg_up) {
-      *(u8 *)MemToShadow(beg_down) = 0;
-    }
-
-    old_mid = Max(beg_up, old_mid);
-    new_mid = Max(beg_up, new_mid);
-  }
-
-  if (old_mid == new_mid)
-    return;
-
-  uptr a = RoundDownTo(Min(old_mid, new_mid), granularity);
-  uptr c = RoundUpTo(Max(old_mid, new_mid), granularity);
-  uptr d1 = RoundDownTo(old_mid, granularity);
+  uptr a = RoundDownTo(Min(old_end, new_end), granularity);
+  uptr c = RoundUpTo(Max(old_end, new_end), granularity);
+  uptr d1 = RoundDownTo(old_end, granularity);
   // uptr d2 = RoundUpTo(old_mid, granularity);
   // Currently we should be in this state:
   // [a, d1) is good, [d2, c) is bad, [d1, d2) is partially good.
@@ -453,23 +451,148 @@ void __sanitizer_annotate_contiguous_container(const void *beg_p,
   // if (d1 != d2)
   //  CHECK_EQ(*(u8*)MemToShadow(d1), old_mid - d1);
   if (a + granularity <= d1)
-    CHECK_EQ(*(u8*)MemToShadow(a), 0);
+    CHECK_EQ(*(u8 *)MemToShadow(a), 0);
   // if (d2 + granularity <= c && c <= end)
   //   CHECK_EQ(*(u8 *)MemToShadow(c - granularity),
   //            kAsanContiguousContainerOOBMagic);
 
-  uptr b1 = RoundDownTo(new_mid, granularity);
-  uptr b2 = RoundUpTo(new_mid, granularity);
+  uptr b1 = RoundDownTo(new_end, granularity);
+  uptr b2 = RoundUpTo(new_end, granularity);
   // New state:
   // [a, b1) is good, [b2, c) is bad, [b1, b2) is partially good.
-  PoisonShadow(a, b1 - a, 0);
-  PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic);
+  if (b1 > a)
+    PoisonShadow(a, b1 - a, 0);
+  else if (c > b2)
+    PoisonShadow(b2, c - b2, kAsanContiguousContainerOOBMagic);
   if (b1 != b2) {
     CHECK_EQ(b2 - b1, granularity);
-    *(u8*)MemToShadow(b1) = static_cast<u8>(new_mid - b1);
+    *(u8 *)MemToShadow(b1) = static_cast<u8>(new_end - b1);
   }
 }
 
+// Annotates a double ended contiguous memory area like std::deque's chunk.
+// It allows detecting buggy accesses to allocated but not used begining
+// or end items of such a container.
+void __sanitizer_annotate_double_ended_contiguous_container(
+    const void *storage_beg_p, const void *storage_end_p,
+    const void *old_container_beg_p, const void *old_container_end_p,
+    const void *new_container_beg_p, const void *new_container_end_p) {
+  if (!flags()->detect_container_overflow)
+    return;
+
+  VPrintf(2, "contiguous_container: %p %p %p %p %p %p\n", storage_beg_p,
+          storage_end_p, old_container_beg_p, old_container_end_p,
+          new_container_beg_p, new_container_end_p);
+
+  uptr storage_beg = reinterpret_cast<uptr>(storage_beg_p);
+  uptr storage_end = reinterpret_cast<uptr>(storage_end_p);
+  uptr old_beg = reinterpret_cast<uptr>(old_container_beg_p);
+  uptr old_end = reinterpret_cast<uptr>(old_container_end_p);
+  uptr new_beg = reinterpret_cast<uptr>(new_container_beg_p);
+  uptr new_end = reinterpret_cast<uptr>(new_container_end_p);
+
+  constexpr uptr granularity = ASAN_SHADOW_GRANULARITY;
+
+  if (!(old_beg <= old_end && new_beg <= new_end) ||
+      !(storage_beg <= new_beg && new_end <= storage_end) ||
+      !(storage_beg <= old_beg && old_end <= storage_end)) {
+    GET_STACK_TRACE_FATAL_HERE;
+    ReportBadParamsToAnnotateDoubleEndedContiguousContainer(
+        storage_beg, storage_end, old_beg, old_end, new_beg, new_end, &stack);
+  }
+  CHECK_LE(storage_end - storage_beg,
+           FIRST_32_SECOND_64(1UL << 30, 1ULL << 40));  // Sanity check.
+
+  if ((old_beg == old_end && new_beg == new_end) ||
+      (old_beg == new_beg && old_end == new_end))
+    return;  // Nothing to do here.
+
+  FixUnalignedStorage(storage_beg, storage_end, old_beg, old_end, new_beg,
+                      new_end);
+
+  // Handle non-intersecting new/old containers separately have simpler
+  // intersecting case.
+  if (old_beg == old_end || new_beg == new_end || new_end <= old_beg ||
+      old_end <= new_beg) {
+    if (old_beg != old_end) {
+      // Poisoning the old container.
+      uptr a = RoundDownTo(old_beg, granularity);
+      uptr b = RoundUpTo(old_end, granularity);
+      PoisonShadow(a, b - a, kAsanContiguousContainerOOBMagic);
+    }
+
+    if (new_beg != new_end) {
+      // Unpoisoning the new container.
+      uptr a = RoundDownTo(new_beg, granularity);
+      uptr b = RoundDownTo(new_end, granularity);
+      PoisonShadow(a, b - a, 0);
+      if (!AddrIsAlignedByGranularity(new_end))
+        *(u8 *)MemToShadow(b) = static_cast<u8>(new_end - b);
+    }
+
+    return;
+  }
+
+  // Intersection of old and new containers is not empty.
+  CHECK_LT(new_beg, old_end);
+  CHECK_GT(new_end, old_beg);
+
+  if (new_beg < old_beg) {
+    // Round down because we can't poison prefixes.
+    uptr a = RoundDownTo(new_beg, granularity);
+    // Round down and ignore the [c, old_beg) as its state defined by unchanged
+    // [old_beg, old_end).
+    uptr c = RoundDownTo(old_beg, granularity);
+    PoisonShadow(a, c - a, 0);
+  } else if (new_beg > old_beg) {
+    // Round down and poison [a, old_beg) because it was unpoisoned only as a
+    // prefix.
+    uptr a = RoundDownTo(old_beg, granularity);
+    // Round down and ignore the [c, new_beg) as its state defined by unchanged
+    // [new_beg, old_end).
+    uptr c = RoundDownTo(new_beg, granularity);
+
+    PoisonShadow(a, c - a, kAsanContiguousContainerOOBMagic);
+  }
+
+  if (new_end > old_end) {
+    // Round down to poison the prefix.
+    uptr a = RoundDownTo(old_end, granularity);
+    // Round down and handle remainder below.
+    uptr c = RoundDownTo(new_end, granularity);
+    PoisonShadow(a, c - a, 0);
+    if (!AddrIsAlignedByGranularity(new_end))
+      *(u8 *)MemToShadow(c) = static_cast<u8>(new_end - c);
+  } else if (new_end < old_end) {
+    // Round up and handle remained below.
+    uptr a2 = RoundUpTo(new_end, granularity);
+    // Round up to poison entire granule as we had nothing in [old_end, c2).
+    uptr c2 = RoundUpTo(old_end, granularity);
+    PoisonShadow(a2, c2 - a2, kAsanContiguousContainerOOBMagic);
+
+    if (!AddrIsAlignedByGranularity(new_end)) {
+      uptr a = RoundDownTo(new_end, granularity);
+      *(u8 *)MemToShadow(a) = static_cast<u8>(new_end - a);
+    }
+  }
+}
+
+static const void *FindBadAddress(uptr begin, uptr end, bool poisoned) {
+  CHECK_LE(begin, end);
+  constexpr uptr kMaxRangeToCheck = 32;
+  if (end - begin > kMaxRangeToCheck * 2) {
+    if (auto *bad = FindBadAddress(begin, begin + kMaxRangeToCheck, poisoned))
+      return bad;
+    if (auto *bad = FindBadAddress(end - kMaxRangeToCheck, end, poisoned))
+      return bad;
+  }
+
+  for (uptr i = begin; i < end; ++i)
+    if (AddressIsPoisoned(i) != poisoned)
+      return reinterpret_cast<const void *>(i);
+  return nullptr;
+}
+
 const void *__sanitizer_contiguous_container_find_bad_address(
     const void *beg_p, const void *mid_p, const void *end_p) {
   if (!flags()->detect_container_overflow)
@@ -477,35 +600,22 @@ const void *__sanitizer_contiguous_container_find_bad_address(
   uptr granularity = ASAN_SHADOW_GRANULARITY;
   uptr beg = reinterpret_cast<uptr>(beg_p);
   uptr end = reinterpret_cast<uptr>(end_p);
+  uptr mid = reinterpret_cast<uptr>(mid_p);
+  CHECK_LE(beg, mid);
+  CHECK_LE(mid, end);
+  // If the byte after the storage is unpoisoned, everything in the granule
+  // before must stay unpoisoned.
   uptr annotations_end =
       (!AddrIsAlignedByGranularity(end) && !AddressIsPoisoned(end))
           ? RoundDownTo(end, granularity)
           : end;
-  uptr mid = reinterpret_cast<uptr>(mid_p);
-  CHECK_LE(beg, mid);
-  CHECK_LE(mid, end);
-  // Check some bytes starting from beg, some bytes around mid, and some bytes
-  // ending with end.
-  uptr kMaxRangeToCheck = 32;
-  uptr r1_beg = beg;
-  uptr r1_end = Min(beg + kMaxRangeToCheck, mid);
-  uptr r2_beg = Max(beg, mid - kMaxRangeToCheck);
-  uptr r2_end = Min(annotations_end, mid + kMaxRangeToCheck);
-  uptr r3_beg = Max(annotations_end - kMaxRangeToCheck, mid);
-  uptr r3_end = annotations_end;
-  for (uptr i = r1_beg; i < r1_end; i++)
-    if (AddressIsPoisoned(i))
-      return reinterpret_cast<const void *>(i);
-  for (uptr i = r2_beg; i < mid; i++)
-    if (AddressIsPoisoned(i))
-      return reinterpret_cast<const void *>(i);
-  for (uptr i = mid; i < r2_end; i++)
-    if (!AddressIsPoisoned(i))
-      return reinterpret_cast<const void *>(i);
-  for (uptr i = r3_beg; i < r3_end; i++)
-    if (!AddressIsPoisoned(i))
-      return reinterpret_cast<const void *>(i);
-  return nullptr;
+  beg = Min(beg, annotations_end);
+  mid = Min(mid, annotations_end);
+  if (auto *bad = FindBadAddress(beg, mid, false))
+    return bad;
+  if (auto *bad = FindBadAddress(mid, annotations_end, true))
+    return bad;
+  return FindBadAddress(annotations_end, end, false);
 }
 
 int __sanitizer_verify_contiguous_container(const void *beg_p,
@@ -515,6 +625,48 @@ int __sanitizer_verify_contiguous_container(const void *beg_p,
                                                            end_p) == nullptr;
 }
 
+const void *__sanitizer_double_ended_contiguous_container_find_bad_address(
+    const void *storage_beg_p, const void *container_beg_p,
+    const void *container_end_p, const void *storage_end_p) {
+  if (!flags()->detect_container_overflow)
+    return nullptr;
+  uptr granularity = ASAN_SHADOW_GRANULARITY;
+  uptr storage_beg = reinterpret_cast<uptr>(storage_beg_p);
+  uptr storage_end = reinterpret_cast<uptr>(storage_end_p);
+  uptr beg = reinterpret_cast<uptr>(container_beg_p);
+  uptr end = reinterpret_cast<uptr>(container_end_p);
+
+  // The prefix of the firs granule of the container is unpoisoned.
+  if (beg != end)
+    beg = Max(storage_beg, RoundDownTo(beg, granularity));
+
+  // If the byte after the storage is unpoisoned, the prefix of the last granule
+  // is unpoisoned.
+  uptr annotations_end = (!AddrIsAlignedByGranularity(storage_end) &&
+                          !AddressIsPoisoned(storage_end))
+                             ? RoundDownTo(storage_end, granularity)
+                             : storage_end;
+  storage_beg = Min(storage_beg, annotations_end);
+  beg = Min(beg, annotations_end);
+  end = Min(end, annotations_end);
+
+  if (auto *bad = FindBadAddress(storage_beg, beg, true))
+    return bad;
+  if (auto *bad = FindBadAddress(beg, end, false))
+    return bad;
+  if (auto *bad = FindBadAddress(end, annotations_end, true))
+    return bad;
+  return FindBadAddress(annotations_end, storage_end, false);
+}
+
+int __sanitizer_verify_double_ended_contiguous_container(
+    const void *storage_beg_p, const void *container_beg_p,
+    const void *container_end_p, const void *storage_end_p) {
+  return __sanitizer_double_ended_contiguous_container_find_bad_address(
+             storage_beg_p, container_beg_p, container_end_p, storage_end_p) ==
+         nullptr;
+}
+
 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
 void __asan_poison_intra_object_redzone(uptr ptr, uptr size) {
   AsanPoisonOrUnpoisonIntraObjectRedzone(ptr, size, true);
diff --git a/libsanitizer/asan/asan_report.cpp b/libsanitizer/asan/asan_report.cpp
index 2a55d6c0978..f2c04342e77 100644
--- a/libsanitizer/asan/asan_report.cpp
+++ b/libsanitizer/asan/asan_report.cpp
@@ -354,6 +354,18 @@ void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
   in_report.ReportError(error);
 }
 
+void ReportBadParamsToAnnotateDoubleEndedContiguousContainer(
+    uptr storage_beg, uptr storage_end, uptr old_container_beg,
+    uptr old_container_end, uptr new_container_beg, uptr new_container_end,
+    BufferedStackTrace *stack) {
+  ScopedInErrorReport in_report;
+  ErrorBadParamsToAnnotateDoubleEndedContiguousContainer error(
+      GetCurrentTidOrInvalid(), stack, storage_beg, storage_end,
+      old_container_beg, old_container_end, new_container_beg,
+      new_container_end);
+  in_report.ReportError(error);
+}
+
 void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
                         const __asan_global *g2, u32 stack_id2) {
   ScopedInErrorReport in_report;
diff --git a/libsanitizer/asan/asan_report.h b/libsanitizer/asan/asan_report.h
index dcf60894ef3..248e30dd42b 100644
--- a/libsanitizer/asan/asan_report.h
+++ b/libsanitizer/asan/asan_report.h
@@ -83,6 +83,10 @@ void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
 void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
                                                   uptr old_mid, uptr new_mid,
                                                   BufferedStackTrace *stack);
+void ReportBadParamsToAnnotateDoubleEndedContiguousContainer(
+    uptr storage_beg, uptr storage_end, uptr old_container_beg,
+    uptr old_container_end, uptr new_container_beg, uptr new_container_end,
+    BufferedStackTrace *stack);
 
 void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
                         const __asan_global *g2, u32 stack_id2);
diff --git a/libsanitizer/asan/asan_thread.cpp b/libsanitizer/asan/asan_thread.cpp
index c15963e1418..3f6e58e8775 100644
--- a/libsanitizer/asan/asan_thread.cpp
+++ b/libsanitizer/asan/asan_thread.cpp
@@ -10,17 +10,18 @@
 //
 // Thread-related code.
 //===----------------------------------------------------------------------===//
+#include "asan_thread.h"
+
 #include "asan_allocator.h"
 #include "asan_interceptors.h"
+#include "asan_mapping.h"
 #include "asan_poisoning.h"
 #include "asan_stack.h"
-#include "asan_thread.h"
-#include "asan_mapping.h"
+#include "lsan/lsan_common.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 #include "sanitizer_common/sanitizer_tls_get_addr.h"
-#include "lsan/lsan_common.h"
 
 namespace __asan {
 
@@ -306,6 +307,7 @@ void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
   GetThreadStackAndTls(tid() == kMainTid, &stack_bottom_, &stack_size,
                        &tls_begin_, &tls_size);
   stack_top_ = RoundDownTo(stack_bottom_ + stack_size, ASAN_SHADOW_GRANULARITY);
+  stack_bottom_ = RoundDownTo(stack_bottom_, ASAN_SHADOW_GRANULARITY);
   tls_end_ = tls_begin_ + tls_size;
   dtls_ = DTLS_Get();
 
@@ -478,6 +480,17 @@ __asan::AsanThread *GetAsanThreadByOsIDLocked(tid_t os_id) {
 
 // --- Implementation of LSan-specific functions --- {{{1
 namespace __lsan {
+void LockThreadRegistry() { __asan::asanThreadRegistry().Lock(); }
+
+void UnlockThreadRegistry() { __asan::asanThreadRegistry().Unlock(); }
+
+static ThreadRegistry *GetAsanThreadRegistryLocked() {
+  __asan::asanThreadRegistry().CheckLocked();
+  return &__asan::asanThreadRegistry();
+}
+
+void EnsureMainThreadIDIsCorrect() { __asan::EnsureMainThreadIDIsCorrect(); }
+
 bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
                            uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
                            uptr *cache_end, DTLS **dtls) {
@@ -496,33 +509,76 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
 
 void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {}
 
-void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
-                            void *arg) {
+void GetThreadExtraStackRangesLocked(tid_t os_id,
+                                     InternalMmapVector<Range> *ranges) {
   __asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
   if (!t)
     return;
   __asan::FakeStack *fake_stack = t->get_fake_stack();
   if (!fake_stack)
     return;
-  fake_stack->ForEachFakeFrame(callback, arg);
+
+  fake_stack->ForEachFakeFrame(
+      [](uptr begin, uptr end, void *arg) {
+        reinterpret_cast<InternalMmapVector<Range> *>(arg)->push_back(
+            {begin, end});
+      },
+      ranges);
 }
 
-void LockThreadRegistry() {
-  __asan::asanThreadRegistry().Lock();
+void GetThreadExtraStackRangesLocked(InternalMmapVector<Range> *ranges) {
+  GetAsanThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+      [](ThreadContextBase *tctx, void *arg) {
+        GetThreadExtraStackRangesLocked(
+            tctx->os_id, reinterpret_cast<InternalMmapVector<Range> *>(arg));
+      },
+      ranges);
 }
 
-void UnlockThreadRegistry() {
-  __asan::asanThreadRegistry().Unlock();
+void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs) {
+  GetAsanThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+      [](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 =
+            static_cast<__asan::AsanThreadContext *>(tctx);
+
+        // 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>(atctx->thread->get_arg());
+        if (!thread_arg)
+          return;
+
+        auto ptrsVec = reinterpret_cast<InternalMmapVector<uptr> *>(ptrs);
+        ptrsVec->push_back(thread_arg);
+      },
+      ptrs);
 }
 
-ThreadRegistry *GetThreadRegistryLocked() {
-  __asan::asanThreadRegistry().CheckLocked();
-  return &__asan::asanThreadRegistry();
+void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) {
+  GetAsanThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+      [](ThreadContextBase *tctx, void *threads) {
+        if (tctx->status == ThreadStatusRunning)
+          reinterpret_cast<InternalMmapVector<tid_t> *>(threads)->push_back(
+              tctx->os_id);
+      },
+      threads);
 }
 
-void EnsureMainThreadIDIsCorrect() {
-  __asan::EnsureMainThreadIDIsCorrect();
+void FinishThreadLocked(u32 tid) {
+  GetAsanThreadRegistryLocked()->FinishThread(tid);
 }
+
 } // namespace __lsan
 
 // ---------------------- Interface ---------------- {{{1
diff --git a/libsanitizer/asan/asan_win.cpp b/libsanitizer/asan/asan_win.cpp
index f11df0613d1..7dbd7ab98a1 100644
--- a/libsanitizer/asan/asan_win.cpp
+++ b/libsanitizer/asan/asan_win.cpp
@@ -263,12 +263,6 @@ void AsanCheckDynamicRTPrereqs() {}
 
 void AsanCheckIncompatibleRT() {}
 
-void ReadContextStack(void *context, uptr *stack, uptr *ssize) {
-  UNIMPLEMENTED();
-}
-
-void ResetContextStack(void *context) { UNIMPLEMENTED(); }
-
 void AsanOnDeadlySignal(int, void *siginfo, void *context) { UNIMPLEMENTED(); }
 
 bool PlatformUnpoisonStacks() { return false; }
diff --git a/libsanitizer/builtins/assembly.h b/libsanitizer/builtins/assembly.h
index 69a3d8620f9..169d49683f5 100644
--- a/libsanitizer/builtins/assembly.h
+++ b/libsanitizer/builtins/assembly.h
@@ -267,7 +267,7 @@
 #define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target)                         \
   .globl SYMBOL_NAME(name) SEPARATOR                                           \
   SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR                                  \
-  DECLARE_SYMBOL_VISIBILITY(SYMBOL_NAME(name)) SEPARATOR                       \
+  DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR                                    \
   .set SYMBOL_NAME(name), SYMBOL_NAME(target) SEPARATOR
 
 #if defined(__ARM_EABI__)
diff --git a/libsanitizer/hwasan/hwasan.cpp b/libsanitizer/hwasan/hwasan.cpp
index 9db4fb09409..097136fe548 100644
--- a/libsanitizer/hwasan/hwasan.cpp
+++ b/libsanitizer/hwasan/hwasan.cpp
@@ -86,6 +86,9 @@ static void InitializeFlags() {
     cf.clear_shadow_mmap_threshold = 4096 * (SANITIZER_ANDROID ? 2 : 8);
     // Sigtrap is used in error reporting.
     cf.handle_sigtrap = kHandleSignalExclusive;
+    // For now only tested on Linux. Other plantforms can be turned on as they
+    // become ready.
+    cf.detect_leaks = cf.detect_leaks && SANITIZER_LINUX && !SANITIZER_ANDROID;
 
 #if SANITIZER_ANDROID
     // Let platform handle other signals. It is better at reporting them then we
@@ -106,6 +109,15 @@ static void InitializeFlags() {
   RegisterHwasanFlags(&parser, f);
   RegisterCommonFlags(&parser);
 
+#if CAN_SANITIZE_LEAKS
+  __lsan::Flags *lf = __lsan::flags();
+  lf->SetDefaults();
+
+  FlagParser lsan_parser;
+  __lsan::RegisterLsanFlags(&lsan_parser, lf);
+  RegisterCommonFlags(&lsan_parser);
+#endif
+
 #if HWASAN_CONTAINS_UBSAN
   __ubsan::Flags *uf = __ubsan::flags();
   uf->SetDefaults();
@@ -118,12 +130,18 @@ static void InitializeFlags() {
   // Override from user-specified string.
   if (__hwasan_default_options)
     parser.ParseString(__hwasan_default_options());
+#if CAN_SANITIZE_LEAKS
+  lsan_parser.ParseString(__lsan_default_options());
+#endif
 #if HWASAN_CONTAINS_UBSAN
   const char *ubsan_default_options = __ubsan_default_options();
   ubsan_parser.ParseString(ubsan_default_options);
 #endif
 
   parser.ParseStringFromEnv("HWASAN_OPTIONS");
+#if CAN_SANITIZE_LEAKS
+  lsan_parser.ParseStringFromEnv("LSAN_OPTIONS");
+#endif
 #if HWASAN_CONTAINS_UBSAN
   ubsan_parser.ParseStringFromEnv("UBSAN_OPTIONS");
 #endif
@@ -133,6 +151,12 @@ static void InitializeFlags() {
   if (Verbosity()) ReportUnrecognizedFlags();
 
   if (common_flags()->help) parser.PrintFlagDescriptions();
+  // Flag validation:
+  if (!CAN_SANITIZE_LEAKS && common_flags()->detect_leaks) {
+    Report("%s: detect_leaks is not supported on this platform.\n",
+           SanitizerToolName);
+    Die();
+  }
 }
 
 static void CheckUnwind() {
@@ -368,10 +392,20 @@ __attribute__((constructor(0))) void __hwasan_init() {
   HwasanAllocatorInit();
   HwasanInstallAtForkHandler();
 
+  if (CAN_SANITIZE_LEAKS) {
+    __lsan::InitCommonLsan();
+    InstallAtExitCheckLeaks();
+  }
+
 #if HWASAN_CONTAINS_UBSAN
   __ubsan::InitAsPlugin();
 #endif
 
+  if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks) {
+    __lsan::ScopedInterceptorDisabler disabler;
+    Symbolizer::LateInitialize();
+  }
+
   VPrintf(1, "HWAddressSanitizer init done\n");
 
   hwasan_init_is_running = 0;
@@ -519,7 +553,7 @@ void __hwasan_store16_noabort(uptr p) {
 }
 
 void __hwasan_tag_memory(uptr p, u8 tag, uptr sz) {
-  TagMemoryAligned(p, sz, tag);
+  TagMemoryAligned(UntagAddr(p), sz, tag);
 }
 
 uptr __hwasan_tag_pointer(uptr p, u8 tag) {
diff --git a/libsanitizer/hwasan/hwasan.h b/libsanitizer/hwasan/hwasan.h
index ef4055a50ef..c3d71a28142 100644
--- a/libsanitizer/hwasan/hwasan.h
+++ b/libsanitizer/hwasan/hwasan.h
@@ -144,6 +144,8 @@ void HwasanOnDeadlySignal(int signo, void *info, void *context);
 
 void HwasanInstallAtForkHandler();
 
+void InstallAtExitCheckLeaks();
+
 void UpdateMemoryUsage();
 
 void AppendToErrorMessageBuffer(const char *buffer);
diff --git a/libsanitizer/hwasan/hwasan_allocation_functions.cpp b/libsanitizer/hwasan/hwasan_allocation_functions.cpp
index 9cd82dbabd1..59ad633879b 100644
--- a/libsanitizer/hwasan/hwasan_allocation_functions.cpp
+++ b/libsanitizer/hwasan/hwasan_allocation_functions.cpp
@@ -16,14 +16,25 @@
 #include "interception/interception.h"
 #include "sanitizer_common/sanitizer_allocator_dlsym.h"
 #include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "sanitizer_common/sanitizer_mallinfo.h"
 #include "sanitizer_common/sanitizer_tls_get_addr.h"
 
-#if !SANITIZER_FUCHSIA
-
 using namespace __hwasan;
 
 struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
   static bool UseImpl() { return !hwasan_inited; }
+  static void OnAllocate(const void *ptr, uptr size) {
+#  if CAN_SANITIZE_LEAKS
+    // Suppress leaks from dlerror(). Previously dlsym hack on global array was
+    // used by leak sanitizer as a root region.
+    __lsan_register_root_region(ptr, size);
+#  endif
+  }
+  static void OnFree(const void *ptr, uptr size) {
+#  if CAN_SANITIZE_LEAKS
+    __lsan_unregister_root_region(ptr, size);
+#  endif
+  }
 };
 
 extern "C" {
@@ -143,12 +154,19 @@ void *__sanitizer_malloc(uptr size) {
 
 }  // extern "C"
 
-#if HWASAN_WITH_INTERCEPTORS
+#if HWASAN_WITH_INTERCEPTORS || SANITIZER_FUCHSIA
+#if SANITIZER_FUCHSIA
+// Fuchsia does not use WRAP/wrappers used for the interceptor infrastructure.
+#  define INTERCEPTOR_ALIAS(RET, FN, ARGS...)                                 \
+    extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE RET FN( \
+        ARGS) ALIAS("__sanitizer_" #FN)
+#else
 #  define INTERCEPTOR_ALIAS(RET, FN, ARGS...)                                 \
     extern "C" SANITIZER_INTERFACE_ATTRIBUTE RET WRAP(FN)(ARGS)               \
         ALIAS("__sanitizer_" #FN);                                            \
     extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE RET FN( \
         ARGS) ALIAS("__sanitizer_" #FN)
+#endif
 
 INTERCEPTOR_ALIAS(int, posix_memalign, void **memptr, SIZE_T alignment,
                   SIZE_T size);
@@ -171,5 +189,3 @@ INTERCEPTOR_ALIAS(int, mallopt, int cmd, int value);
 INTERCEPTOR_ALIAS(void, malloc_stats, void);
 #  endif
 #endif  // #if HWASAN_WITH_INTERCEPTORS
-
-#endif  // SANITIZER_FUCHSIA
diff --git a/libsanitizer/hwasan/hwasan_allocator.cpp b/libsanitizer/hwasan/hwasan_allocator.cpp
index 842455150c7..d3cb5c84572 100644
--- a/libsanitizer/hwasan/hwasan_allocator.cpp
+++ b/libsanitizer/hwasan/hwasan_allocator.cpp
@@ -21,6 +21,7 @@
 #include "hwasan_malloc_bisect.h"
 #include "hwasan_thread.h"
 #include "hwasan_report.h"
+#include "lsan/lsan_common.h"
 
 namespace __hwasan {
 
@@ -32,40 +33,39 @@ static atomic_uint8_t hwasan_allocator_tagging_enabled;
 static constexpr tag_t kFallbackAllocTag = 0xBB & kTagMask;
 static constexpr tag_t kFallbackFreeTag = 0xBC;
 
-enum RightAlignMode {
-  kRightAlignNever,
-  kRightAlignSometimes,
-  kRightAlignAlways
+enum {
+  // Either just allocated by underlying allocator, but AsanChunk is not yet
+  // ready, or almost returned to undelying allocator and AsanChunk is already
+  // meaningless.
+  CHUNK_INVALID = 0,
+  // The chunk is allocated and not yet freed.
+  CHUNK_ALLOCATED = 1,
 };
 
+
 // Initialized in HwasanAllocatorInit, an never changed.
 static ALIGNED(16) u8 tail_magic[kShadowAlignment - 1];
+static uptr max_malloc_size;
 
 bool HwasanChunkView::IsAllocated() const {
-  return metadata_ && metadata_->alloc_context_id &&
-         metadata_->get_requested_size();
-}
-
-// Aligns the 'addr' right to the granule boundary.
-static uptr AlignRight(uptr addr, uptr requested_size) {
-  uptr tail_size = requested_size % kShadowAlignment;
-  if (!tail_size) return addr;
-  return addr + kShadowAlignment - tail_size;
+  return metadata_ && metadata_->IsAllocated();
 }
 
 uptr HwasanChunkView::Beg() const {
-  if (metadata_ && metadata_->right_aligned)
-    return AlignRight(block_, metadata_->get_requested_size());
   return block_;
 }
 uptr HwasanChunkView::End() const {
   return Beg() + UsedSize();
 }
 uptr HwasanChunkView::UsedSize() const {
-  return metadata_->get_requested_size();
+  return metadata_->GetRequestedSize();
 }
 u32 HwasanChunkView::GetAllocStackId() const {
-  return metadata_->alloc_context_id;
+  return metadata_->GetAllocStackId();
+}
+
+u32 HwasanChunkView::GetAllocThreadId() const {
+  return metadata_->GetAllocThreadId();
 }
 
 uptr HwasanChunkView::ActualSize() const {
@@ -76,10 +76,58 @@ bool HwasanChunkView::FromSmallHeap() const {
   return allocator.FromPrimary(reinterpret_cast<void *>(block_));
 }
 
+bool HwasanChunkView::AddrIsInside(uptr addr) const {
+  return (addr >= Beg()) && (addr < Beg() + UsedSize());
+}
+
+inline void Metadata::SetAllocated(u32 stack, u64 size) {
+  Thread *t = GetCurrentThread();
+  u64 context = t ? t->unique_id() : kMainTid;
+  context <<= 32;
+  context += stack;
+  requested_size_low = size & ((1ul << 32) - 1);
+  requested_size_high = size >> 32;
+  atomic_store(&alloc_context_id, context, memory_order_relaxed);
+  atomic_store(&chunk_state, CHUNK_ALLOCATED, memory_order_release);
+}
+
+inline void Metadata::SetUnallocated() {
+  atomic_store(&chunk_state, CHUNK_INVALID, memory_order_release);
+  requested_size_low = 0;
+  requested_size_high = 0;
+  atomic_store(&alloc_context_id, 0, memory_order_relaxed);
+}
+
+inline bool Metadata::IsAllocated() const {
+  return atomic_load(&chunk_state, memory_order_relaxed) == CHUNK_ALLOCATED;
+}
+
+inline u64 Metadata::GetRequestedSize() const {
+  return (static_cast<u64>(requested_size_high) << 32) + requested_size_low;
+}
+
+inline u32 Metadata::GetAllocStackId() const {
+  return atomic_load(&alloc_context_id, memory_order_relaxed);
+}
+
+inline u32 Metadata::GetAllocThreadId() const {
+  u64 context = atomic_load(&alloc_context_id, memory_order_relaxed);
+  u32 tid = context >> 32;
+  return tid;
+}
+
 void GetAllocatorStats(AllocatorStatCounters s) {
   allocator.GetStats(s);
 }
 
+inline void Metadata::SetLsanTag(__lsan::ChunkTag tag) {
+  lsan_tag = tag;
+}
+
+inline __lsan::ChunkTag Metadata::GetLsanTag() const {
+  return static_cast<__lsan::ChunkTag>(lsan_tag);
+}
+
 uptr GetAliasRegionStart() {
 #if defined(HWASAN_ALIASING_MODE)
   constexpr uptr kAliasRegionOffset = 1ULL << (kTaggableRegionCheckShift - 1);
@@ -105,6 +153,12 @@ void HwasanAllocatorInit() {
                  GetAliasRegionStart());
   for (uptr i = 0; i < sizeof(tail_magic); i++)
     tail_magic[i] = GetCurrentThread()->GenerateRandomTag();
+  if (common_flags()->max_allocation_size_mb) {
+    max_malloc_size = common_flags()->max_allocation_size_mb << 20;
+    max_malloc_size = Min(max_malloc_size, kMaxAllowedMallocSize);
+  } else {
+    max_malloc_size = kMaxAllowedMallocSize;
+  }
 }
 
 void HwasanAllocatorLock() { allocator.ForceLock(); }
@@ -124,13 +178,16 @@ static uptr TaggedSize(uptr size) {
 
 static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
                             bool zeroise) {
-  if (orig_size > kMaxAllowedMallocSize) {
+  // Keep this consistent with LSAN and ASAN behavior.
+  if (UNLIKELY(orig_size == 0))
+    orig_size = 1;
+  if (UNLIKELY(orig_size > max_malloc_size)) {
     if (AllocatorMayReturnNull()) {
       Report("WARNING: HWAddressSanitizer failed to allocate 0x%zx bytes\n",
              orig_size);
       return nullptr;
     }
-    ReportAllocationSizeTooBig(orig_size, kMaxAllowedMallocSize, stack);
+    ReportAllocationSizeTooBig(orig_size, max_malloc_size, stack);
   }
   if (UNLIKELY(IsRssLimitExceeded())) {
     if (AllocatorMayReturnNull())
@@ -155,11 +212,6 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
       return nullptr;
     ReportOutOfMemory(size, stack);
   }
-  Metadata *meta =
-      reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));
-  meta->set_requested_size(orig_size);
-  meta->alloc_context_id = StackDepotPut(*stack);
-  meta->right_aligned = false;
   if (zeroise) {
     internal_memset(allocated, 0, size);
   } else if (flags()->max_malloc_fill_size > 0) {
@@ -199,6 +251,13 @@ static void *HwasanAllocate(StackTrace *stack, uptr orig_size, uptr alignment,
     }
   }
 
+  Metadata *meta =
+      reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));
+#if CAN_SANITIZE_LEAKS
+  meta->SetLsanTag(__lsan::DisabledInThisThread() ? __lsan::kIgnored
+                                                  : __lsan::kDirectlyLeaked);
+#endif
+  meta->SetAllocated(StackDepotPut(*stack), orig_size);
   RunMallocHooks(user_ptr, size);
   return user_ptr;
 }
@@ -244,9 +303,10 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
     ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr));
     return;
   }
-  uptr orig_size = meta->get_requested_size();
+  uptr orig_size = meta->GetRequestedSize();
   u32 free_context_id = StackDepotPut(*stack);
-  u32 alloc_context_id = meta->alloc_context_id;
+  u32 alloc_context_id = meta->GetAllocStackId();
+  u32 alloc_thread_id = meta->GetAllocThreadId();
 
   // Check tail magic.
   uptr tagged_size = TaggedSize(orig_size);
@@ -265,8 +325,8 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
                             orig_size, tail_magic);
   }
 
-  meta->set_requested_size(0);
-  meta->alloc_context_id = 0;
+  // TODO(kstoimenov): consider meta->SetUnallocated(free_context_id).
+  meta->SetUnallocated();
   // This memory will not be reused by anyone else, so we are free to keep it
   // poisoned.
   Thread *t = GetCurrentThread();
@@ -298,8 +358,9 @@ static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
   if (t) {
     allocator.Deallocate(t->allocator_cache(), aligned_ptr);
     if (auto *ha = t->heap_allocations())
-      ha->push({reinterpret_cast<uptr>(tagged_ptr), alloc_context_id,
-                free_context_id, static_cast<u32>(orig_size)});
+      ha->push({reinterpret_cast<uptr>(tagged_ptr), alloc_thread_id,
+                alloc_context_id, free_context_id,
+                static_cast<u32>(orig_size)});
   } else {
     SpinMutexLock l(&fallback_mutex);
     AllocatorCache *cache = &fallback_allocator_cache;
@@ -322,7 +383,7 @@ static void *HwasanReallocate(StackTrace *stack, void *tagged_ptr_old,
         reinterpret_cast<Metadata *>(allocator.GetMetaData(untagged_ptr_old));
     internal_memcpy(
         UntagPtr(tagged_ptr_new), untagged_ptr_old,
-        Min(new_size, static_cast<uptr>(meta->get_requested_size())));
+        Min(new_size, static_cast<uptr>(meta->GetRequestedSize())));
     HwasanDeallocate(stack, tagged_ptr_old);
   }
   return tagged_ptr_new;
@@ -348,19 +409,30 @@ HwasanChunkView FindHeapChunkByAddress(uptr address) {
   return HwasanChunkView(reinterpret_cast<uptr>(block), metadata);
 }
 
+static const void *AllocationBegin(const void *p) {
+  const void *untagged_ptr = UntagPtr(p);
+  if (!untagged_ptr)
+    return nullptr;
+
+  const void *beg = allocator.GetBlockBegin(untagged_ptr);
+  if (!beg)
+    return nullptr;
+
+  Metadata *b = (Metadata *)allocator.GetMetaData(beg);
+  if (b->GetRequestedSize() == 0)
+    return nullptr;
+
+  tag_t tag = GetTagFromPointer((uptr)p);
+  return (const void *)AddTagToPointer((uptr)beg, tag);
+}
+
 static uptr AllocationSize(const void *tagged_ptr) {
   const void *untagged_ptr = UntagPtr(tagged_ptr);
   if (!untagged_ptr) return 0;
   const void *beg = allocator.GetBlockBegin(untagged_ptr);
   Metadata *b = (Metadata *)allocator.GetMetaData(untagged_ptr);
-  if (b->right_aligned) {
-    if (beg != reinterpret_cast<void *>(RoundDownTo(
-                   reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment)))
-      return 0;
-  } else {
-    if (beg != untagged_ptr) return 0;
-  }
-  return b->get_requested_size();
+  if (beg != untagged_ptr) return 0;
+  return b->GetRequestedSize();
 }
 
 void *hwasan_malloc(uptr size, StackTrace *stack) {
@@ -451,6 +523,122 @@ void hwasan_free(void *ptr, StackTrace *stack) {
 
 }  // namespace __hwasan
 
+// --- Implementation of LSan-specific functions --- {{{1
+namespace __lsan {
+
+void LockAllocator() {
+  __hwasan::HwasanAllocatorLock();
+}
+
+void UnlockAllocator() {
+  __hwasan::HwasanAllocatorUnlock();
+}
+
+void GetAllocatorGlobalRange(uptr *begin, uptr *end) {
+  *begin = (uptr)&__hwasan::allocator;
+  *end = *begin + sizeof(__hwasan::allocator);
+}
+
+uptr PointsIntoChunk(void *p) {
+  p = __hwasan::InTaggableRegion(reinterpret_cast<uptr>(p)) ? UntagPtr(p) : p;
+  uptr addr = reinterpret_cast<uptr>(p);
+  uptr chunk =
+      reinterpret_cast<uptr>(__hwasan::allocator.GetBlockBeginFastLocked(p));
+  if (!chunk)
+    return 0;
+  __hwasan::Metadata *metadata = reinterpret_cast<__hwasan::Metadata *>(
+      __hwasan::allocator.GetMetaData(reinterpret_cast<void *>(chunk)));
+  if (!metadata || !metadata->IsAllocated())
+    return 0;
+  if (addr < chunk + metadata->GetRequestedSize())
+    return chunk;
+  if (IsSpecialCaseOfOperatorNew0(chunk, metadata->GetRequestedSize(), addr))
+    return chunk;
+  return 0;
+}
+
+uptr GetUserBegin(uptr chunk) {
+  if (__hwasan::InTaggableRegion(chunk))
+    CHECK_EQ(UntagAddr(chunk), chunk);
+  void *block = __hwasan::allocator.GetBlockBeginFastLocked(
+      reinterpret_cast<void *>(chunk));
+  if (!block)
+    return 0;
+  __hwasan::Metadata *metadata = reinterpret_cast<__hwasan::Metadata *>(
+      __hwasan::allocator.GetMetaData(block));
+  if (!metadata || !metadata->IsAllocated())
+    return 0;
+
+  return reinterpret_cast<uptr>(block);
+}
+
+uptr GetUserAddr(uptr chunk) {
+  tag_t mem_tag = *(tag_t *)__hwasan::MemToShadow(chunk);
+  if (!__hwasan::InTaggableRegion(chunk))
+    return chunk;
+  return AddTagToPointer(chunk, mem_tag);
+}
+
+LsanMetadata::LsanMetadata(uptr chunk) {
+  if (__hwasan::InTaggableRegion(chunk))
+    CHECK_EQ(UntagAddr(chunk), chunk);
+  metadata_ =
+      chunk ? __hwasan::allocator.GetMetaData(reinterpret_cast<void *>(chunk))
+            : nullptr;
+}
+
+bool LsanMetadata::allocated() const {
+  if (!metadata_)
+    return false;
+  __hwasan::Metadata *m = reinterpret_cast<__hwasan::Metadata *>(metadata_);
+  return m->IsAllocated();
+}
+
+ChunkTag LsanMetadata::tag() const {
+  __hwasan::Metadata *m = reinterpret_cast<__hwasan::Metadata *>(metadata_);
+  return m->GetLsanTag();
+}
+
+void LsanMetadata::set_tag(ChunkTag value) {
+  __hwasan::Metadata *m = reinterpret_cast<__hwasan::Metadata *>(metadata_);
+  m->SetLsanTag(value);
+}
+
+uptr LsanMetadata::requested_size() const {
+  __hwasan::Metadata *m = reinterpret_cast<__hwasan::Metadata *>(metadata_);
+  return m->GetRequestedSize();
+}
+
+u32 LsanMetadata::stack_trace_id() const {
+  __hwasan::Metadata *m = reinterpret_cast<__hwasan::Metadata *>(metadata_);
+  return m->GetAllocStackId();
+}
+
+void ForEachChunk(ForEachChunkCallback callback, void *arg) {
+  __hwasan::allocator.ForEachChunk(callback, arg);
+}
+
+IgnoreObjectResult IgnoreObject(const void *p) {
+  p = __hwasan::InTaggableRegion(reinterpret_cast<uptr>(p)) ? UntagPtr(p) : p;
+  uptr addr = reinterpret_cast<uptr>(p);
+  uptr chunk = reinterpret_cast<uptr>(__hwasan::allocator.GetBlockBegin(p));
+  if (!chunk)
+    return kIgnoreObjectInvalid;
+  __hwasan::Metadata *metadata = reinterpret_cast<__hwasan::Metadata *>(
+      __hwasan::allocator.GetMetaData(reinterpret_cast<void *>(chunk)));
+  if (!metadata || !metadata->IsAllocated())
+    return kIgnoreObjectInvalid;
+  if (addr >= chunk + metadata->GetRequestedSize())
+    return kIgnoreObjectInvalid;
+  if (metadata->GetLsanTag() == kIgnored)
+    return kIgnoreObjectAlreadyIgnored;
+
+  metadata->SetLsanTag(kIgnored);
+  return kIgnoreObjectSuccess;
+}
+
+}  // namespace __lsan
+
 using namespace __hwasan;
 
 void __hwasan_enable_allocator_tagging() {
@@ -481,4 +669,8 @@ uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
 
 int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; }
 
+const void *__sanitizer_get_allocated_begin(const void *p) {
+  return AllocationBegin(p);
+}
+
 uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); }
diff --git a/libsanitizer/hwasan/hwasan_allocator.h b/libsanitizer/hwasan/hwasan_allocator.h
index bae53b56559..b7a06da0b65 100644
--- a/libsanitizer/hwasan/hwasan_allocator.h
+++ b/libsanitizer/hwasan/hwasan_allocator.h
@@ -17,6 +17,7 @@
 #include "hwasan_interface_internal.h"
 #include "hwasan_mapping.h"
 #include "hwasan_poisoning.h"
+#include "lsan/lsan_common.h"
 #include "sanitizer_common/sanitizer_allocator.h"
 #include "sanitizer_common/sanitizer_allocator_checks.h"
 #include "sanitizer_common/sanitizer_allocator_interface.h"
@@ -31,18 +32,25 @@
 namespace __hwasan {
 
 struct Metadata {
+ private:
+  atomic_uint64_t alloc_context_id;
   u32 requested_size_low;
-  u32 requested_size_high : 31;
-  u32 right_aligned : 1;
-  u32 alloc_context_id;
-  u64 get_requested_size() {
-    return (static_cast<u64>(requested_size_high) << 32) + requested_size_low;
-  }
-  void set_requested_size(u64 size) {
-    requested_size_low = size & ((1ul << 32) - 1);
-    requested_size_high = size >> 32;
-  }
+  u16 requested_size_high;
+  atomic_uint8_t chunk_state;
+  u8 lsan_tag;
+
+ public:
+  inline void SetAllocated(u32 stack, u64 size);
+  inline void SetUnallocated();
+
+  inline bool IsAllocated() const;
+  inline u64 GetRequestedSize() const;
+  inline u32 GetAllocStackId() const;
+  inline u32 GetAllocThreadId() const;
+  inline void SetLsanTag(__lsan::ChunkTag tag);
+  inline __lsan::ChunkTag GetLsanTag() const;
 };
+static_assert(sizeof(Metadata) == 16);
 
 struct HwasanMapUnmapCallback {
   void OnMap(uptr p, uptr size) const { UpdateMemoryUsage(); }
@@ -61,15 +69,21 @@ struct AP64 {
 
 #if defined(HWASAN_ALIASING_MODE)
   static const uptr kSpaceSize = 1ULL << kAddressTagShift;
+  typedef __sanitizer::DefaultSizeClassMap SizeClassMap;
+#elif SANITIZER_LINUX && !SANITIZER_ANDROID
+  static const uptr kSpaceSize = 0x40000000000ULL;  // 4T.
+  typedef __sanitizer::DefaultSizeClassMap SizeClassMap;
 #else
-  static const uptr kSpaceSize = 0x2000000000ULL;
+  static const uptr kSpaceSize = 0x2000000000ULL;  // 128G.
+  typedef __sanitizer::VeryDenseSizeClassMap SizeClassMap;
 #endif
+
   static const uptr kMetadataSize = sizeof(Metadata);
-  typedef __sanitizer::VeryDenseSizeClassMap SizeClassMap;
   using AddressSpaceView = LocalAddressSpaceView;
   typedef HwasanMapUnmapCallback MapUnmapCallback;
   static const uptr kFlags = 0;
 };
+
 typedef SizeClassAllocator64<AP64> PrimaryAllocator;
 typedef CombinedAllocator<PrimaryAllocator> Allocator;
 typedef Allocator::AllocatorCache AllocatorCache;
@@ -87,8 +101,12 @@ class HwasanChunkView {
   uptr UsedSize() const;       // Size requested by the user
   uptr ActualSize() const;     // Size allocated by the allocator.
   u32 GetAllocStackId() const;
+  u32 GetAllocThreadId() const;
   bool FromSmallHeap() const;
+  bool AddrIsInside(uptr addr) const;
+
  private:
+  friend class __lsan::LsanMetadata;
   uptr block_;
   Metadata *const metadata_;
 };
@@ -97,13 +115,12 @@ HwasanChunkView FindHeapChunkByAddress(uptr address);
 
 // Information about one (de)allocation that happened in the past.
 // These are recorded in a thread-local ring buffer.
-// TODO: this is currently 24 bytes (20 bytes + alignment).
-// Compress it to 16 bytes or extend it to be more useful.
 struct HeapAllocationRecord {
   uptr tagged_addr;
-  u32  alloc_context_id;
-  u32  free_context_id;
-  u32  requested_size;
+  u32 alloc_thread_id;
+  u32 alloc_context_id;
+  u32 free_context_id;
+  u32 requested_size;
 };
 
 typedef RingBuffer<HeapAllocationRecord> HeapAllocationsRingBuffer;
diff --git a/libsanitizer/hwasan/hwasan_checks.h b/libsanitizer/hwasan/hwasan_checks.h
index b0b37d7a2e2..514d351cf7d 100644
--- a/libsanitizer/hwasan/hwasan_checks.h
+++ b/libsanitizer/hwasan/hwasan_checks.h
@@ -15,17 +15,49 @@
 
 #include "hwasan_allocator.h"
 #include "hwasan_mapping.h"
+#include "hwasan_registers.h"
 #include "sanitizer_common/sanitizer_common.h"
 
 namespace __hwasan {
-template <unsigned X>
+
+enum class ErrorAction { Abort, Recover };
+enum class AccessType { Load, Store };
+
+// Used when the access size is known.
+constexpr unsigned SigTrapEncoding(ErrorAction EA, AccessType AT,
+                                   unsigned LogSize) {
+  return 0x20 * (EA == ErrorAction::Recover) +
+         0x10 * (AT == AccessType::Store) + LogSize;
+}
+
+// Used when the access size varies at runtime.
+constexpr unsigned SigTrapEncoding(ErrorAction EA, AccessType AT) {
+  return SigTrapEncoding(EA, AT, 0xf);
+}
+
+template <ErrorAction EA, AccessType AT, size_t LogSize>
 __attribute__((always_inline)) static void SigTrap(uptr p) {
-#if defined(__aarch64__)
+  // Other platforms like linux can use signals for intercepting an exception
+  // and dispatching to HandleTagMismatch. The fuchsias implementation doesn't
+  // use signals so we can call it here directly instead.
+#if CAN_GET_REGISTERS && SANITIZER_FUCHSIA
+  auto regs = GetRegisters();
+  size_t size = 2 << LogSize;
+  AccessInfo access_info = {
+      .addr = p,
+      .size = size,
+      .is_store = AT == AccessType::Store,
+      .is_load = AT == AccessType::Load,
+      .recover = EA == ErrorAction::Recover,
+  };
+  HandleTagMismatch(access_info, (uptr)__builtin_return_address(0),
+                    (uptr)__builtin_frame_address(0), /*uc=*/nullptr, regs.x);
+#elif defined(__aarch64__)
   (void)p;
   // 0x900 is added to do not interfere with the kernel use of lower values of
   // brk immediate.
   register uptr x0 asm("x0") = p;
-  asm("brk %1\n\t" ::"r"(x0), "n"(0x900 + X));
+  asm("brk %1\n\t" ::"r"(x0), "n"(0x900 + SigTrapEncoding(EA, AT, LogSize)));
 #elif defined(__x86_64__)
   // INT3 + NOP DWORD ptr [EAX + X] to pass X to our signal handler, 5 bytes
   // total. The pointer is passed via rdi.
@@ -34,7 +66,7 @@ __attribute__((always_inline)) static void SigTrap(uptr p) {
   // different nop command, the three bytes one).
   asm volatile(
       "int3\n"
-      "nopl %c0(%%rax)\n" ::"n"(0x40 + X),
+      "nopl %c0(%%rax)\n" ::"n"(0x40 + SigTrapEncoding(EA, AT, LogSize)),
       "D"(p));
 #elif SANITIZER_RISCV64
   // Put pointer into x10
@@ -44,7 +76,7 @@ __attribute__((always_inline)) static void SigTrap(uptr p) {
   asm volatile(
       "ebreak\n"
       "addiw x0, x0, %1\n" ::"r"(x10),
-      "I"(0x40 + X));
+      "I"(0x40 + SigTrapEncoding(EA, AT, LogSize)));
 #else
   // FIXME: not always sigill.
   __builtin_trap();
@@ -53,17 +85,31 @@ __attribute__((always_inline)) static void SigTrap(uptr p) {
 }
 
 // Version with access size which is not power of 2
-template <unsigned X>
+template <ErrorAction EA, AccessType AT>
 __attribute__((always_inline)) static void SigTrap(uptr p, uptr size) {
-#if defined(__aarch64__)
+  // Other platforms like linux can use signals for intercepting an exception
+  // and dispatching to HandleTagMismatch. The fuchsias implementation doesn't
+  // use signals so we can call it here directly instead.
+#if CAN_GET_REGISTERS && SANITIZER_FUCHSIA
+  auto regs = GetRegisters();
+  AccessInfo access_info = {
+      .addr = p,
+      .size = size,
+      .is_store = AT == AccessType::Store,
+      .is_load = AT == AccessType::Load,
+      .recover = EA == ErrorAction::Recover,
+  };
+  HandleTagMismatch(access_info, (uptr)__builtin_return_address(0),
+                    (uptr)__builtin_frame_address(0), /*uc=*/nullptr, regs.x);
+#elif defined(__aarch64__)
   register uptr x0 asm("x0") = p;
   register uptr x1 asm("x1") = size;
-  asm("brk %2\n\t" ::"r"(x0), "r"(x1), "n"(0x900 + X));
+  asm("brk %2\n\t" ::"r"(x0), "r"(x1), "n"(0x900 + SigTrapEncoding(EA, AT)));
 #elif defined(__x86_64__)
   // Size is stored in rsi.
   asm volatile(
       "int3\n"
-      "nopl %c0(%%rax)\n" ::"n"(0x40 + X),
+      "nopl %c0(%%rax)\n" ::"n"(0x40 + SigTrapEncoding(EA, AT)),
       "D"(p), "S"(size));
 #elif SANITIZER_RISCV64
   // Put access size into x11
@@ -72,7 +118,7 @@ __attribute__((always_inline)) static void SigTrap(uptr p, uptr size) {
   asm volatile(
       "ebreak\n"
       "addiw x0, x0, %2\n" ::"r"(x10),
-      "r"(x11), "I"(0x40 + X));
+      "r"(x11), "I"(0x40 + SigTrapEncoding(EA, AT)));
 #else
   __builtin_trap();
 #endif
@@ -94,9 +140,6 @@ __attribute__((always_inline, nodebug)) static bool PossiblyShortTagMatches(
   return *(u8 *)(ptr | (kShadowAlignment - 1)) == ptr_tag;
 }
 
-enum class ErrorAction { Abort, Recover };
-enum class AccessType { Load, Store };
-
 template <ErrorAction EA, AccessType AT, unsigned LogSize>
 __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
   if (!InTaggableRegion(p))
@@ -104,8 +147,7 @@ __attribute__((always_inline, nodebug)) static void CheckAddress(uptr p) {
   uptr ptr_raw = p & ~kAddressTagMask;
   tag_t mem_tag = *(tag_t *)MemToShadow(ptr_raw);
   if (UNLIKELY(!PossiblyShortTagMatches(mem_tag, p, 1 << LogSize))) {
-    SigTrap<0x20 * (EA == ErrorAction::Recover) +
-            0x10 * (AT == AccessType::Store) + LogSize>(p);
+    SigTrap<EA, AT, LogSize>(p);
     if (EA == ErrorAction::Abort)
       __builtin_unreachable();
   }
@@ -122,8 +164,7 @@ __attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
   tag_t *shadow_last = (tag_t *)MemToShadow(ptr_raw + sz);
   for (tag_t *t = shadow_first; t < shadow_last; ++t)
     if (UNLIKELY(ptr_tag != *t)) {
-      SigTrap<0x20 * (EA == ErrorAction::Recover) +
-              0x10 * (AT == AccessType::Store) + 0xf>(p, sz);
+      SigTrap<EA, AT>(p, sz);
       if (EA == ErrorAction::Abort)
         __builtin_unreachable();
     }
@@ -132,8 +173,7 @@ __attribute__((always_inline, nodebug)) static void CheckAddressSized(uptr p,
   if (UNLIKELY(tail_sz != 0 &&
                !PossiblyShortTagMatches(
                    *shadow_last, end & ~(kShadowAlignment - 1), tail_sz))) {
-    SigTrap<0x20 * (EA == ErrorAction::Recover) +
-            0x10 * (AT == AccessType::Store) + 0xf>(p, sz);
+    SigTrap<EA, AT>(p, sz);
     if (EA == ErrorAction::Abort)
       __builtin_unreachable();
   }
diff --git a/libsanitizer/hwasan/hwasan_flags.inc b/libsanitizer/hwasan/hwasan_flags.inc
index 4a226ee2ab8..978fa46b705 100644
--- a/libsanitizer/hwasan/hwasan_flags.inc
+++ b/libsanitizer/hwasan/hwasan_flags.inc
@@ -23,6 +23,9 @@ HWASAN_FLAG(bool, tag_in_free, true, "")
 HWASAN_FLAG(bool, print_stats, false, "")
 HWASAN_FLAG(bool, halt_on_error, true, "")
 HWASAN_FLAG(bool, atexit, false, "")
+HWASAN_FLAG(
+    bool, print_live_threads_info, true,
+    "If set, prints the remaining threads in report as an extra information.")
 
 // Test only flag to disable malloc/realloc/free memory tagging on startup.
 // Tagging can be reenabled with __hwasan_enable_allocator_tagging().
diff --git a/libsanitizer/hwasan/hwasan_fuchsia.cpp b/libsanitizer/hwasan/hwasan_fuchsia.cpp
index 858fac05af2..d1696f8aa79 100644
--- a/libsanitizer/hwasan/hwasan_fuchsia.cpp
+++ b/libsanitizer/hwasan/hwasan_fuchsia.cpp
@@ -185,6 +185,8 @@ void InstallAtExitHandler() {}
 
 void HwasanInstallAtForkHandler() {}
 
+void InstallAtExitCheckLeaks() {}
+
 void InitializeOsSupport() {
 #ifdef __aarch64__
   uint32_t features = 0;
@@ -202,6 +204,12 @@ void InitializeOsSupport() {
 
 }  // namespace __hwasan
 
+namespace __lsan {
+
+bool UseExitcodeOnLeak() { return __hwasan::flags()->halt_on_error; }
+
+}  // namespace __lsan
+
 extern "C" {
 
 void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
diff --git a/libsanitizer/hwasan/hwasan_interceptors.cpp b/libsanitizer/hwasan/hwasan_interceptors.cpp
index c67927dc9f6..16ac85eb858 100644
--- a/libsanitizer/hwasan/hwasan_interceptors.cpp
+++ b/libsanitizer/hwasan/hwasan_interceptors.cpp
@@ -39,11 +39,19 @@ static void *HwasanThreadStartFunc(void *arg) {
 
 INTERCEPTOR(int, pthread_create, void *th, void *attr, void *(*callback)(void*),
             void * param) {
-  ScopedTaggingDisabler disabler;
+  EnsureMainThreadIDIsCorrect();
+  ScopedTaggingDisabler tagging_disabler;
   ThreadStartArg *A = reinterpret_cast<ThreadStartArg *> (MmapOrDie(
       GetPageSizeCached(), "pthread_create"));
   *A = {callback, param};
-  int res = REAL(pthread_create)(th, attr, &HwasanThreadStartFunc, A);
+  int res;
+  {
+    // ASAN uses the same approach to disable leaks from pthread_create.
+#    if CAN_SANITIZE_LEAKS
+    __lsan::ScopedInterceptorDisabler lsan_disabler;
+#    endif
+    res = REAL(pthread_create)(th, attr, &HwasanThreadStartFunc, A);
+  }
   return res;
 }
 
@@ -220,6 +228,10 @@ INTERCEPTOR(void, longjmp, __hw_jmp_buf env, int val) {
 namespace __hwasan {
 
 int OnExit() {
+  if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks &&
+      __lsan::HasReportedLeaks()) {
+    return common_flags()->exitcode;
+  }
   // FIXME: ask frontend whether we need to return failure.
   return 0;
 }
diff --git a/libsanitizer/hwasan/hwasan_linux.cpp b/libsanitizer/hwasan/hwasan_linux.cpp
index 88ccfde007d..d3e4b5390e8 100644
--- a/libsanitizer/hwasan/hwasan_linux.cpp
+++ b/libsanitizer/hwasan/hwasan_linux.cpp
@@ -541,6 +541,17 @@ void HwasanInstallAtForkHandler() {
   pthread_atfork(before, after, after);
 }
 
+void InstallAtExitCheckLeaks() {
+  if (CAN_SANITIZE_LEAKS) {
+    if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
+      if (flags()->halt_on_error)
+        Atexit(__lsan::DoLeakCheck);
+      else
+        Atexit(__lsan::DoRecoverableLeakCheckVoid);
+    }
+  }
+}
+
 }  // namespace __hwasan
 
 #endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
diff --git a/libsanitizer/hwasan/hwasan_new_delete.cpp b/libsanitizer/hwasan/hwasan_new_delete.cpp
index 495046a754f..f0fd3726ef1 100644
--- a/libsanitizer/hwasan/hwasan_new_delete.cpp
+++ b/libsanitizer/hwasan/hwasan_new_delete.cpp
@@ -92,6 +92,14 @@ 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, size_t) NOEXCEPT {
+  OPERATOR_DELETE_BODY;
+}
+INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
+    void *ptr, size_t) NOEXCEPT {
+  OPERATOR_DELETE_BODY;
+}
 
 #endif  // OPERATOR_NEW_BODY
 
@@ -134,5 +142,21 @@ 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, size_t, std::align_val_t) NOEXCEPT {
+  OPERATOR_DELETE_BODY;
+}
+INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
+    void *ptr, size_t, std::align_val_t) NOEXCEPT {
+  OPERATOR_DELETE_BODY;
+}
+INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete(
+    void *ptr, size_t, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
+  OPERATOR_DELETE_BODY;
+}
+INTERCEPTOR_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void operator delete[](
+    void *ptr, size_t, std::align_val_t, std::nothrow_t const &) NOEXCEPT {
+  OPERATOR_DELETE_BODY;
+}
 
 #endif  // OPERATOR_NEW_ALIGN_BODY
diff --git a/libsanitizer/hwasan/hwasan_poisoning.cpp b/libsanitizer/hwasan/hwasan_poisoning.cpp
index 5aafdb1884b..a4e5935754a 100644
--- a/libsanitizer/hwasan/hwasan_poisoning.cpp
+++ b/libsanitizer/hwasan/hwasan_poisoning.cpp
@@ -26,3 +26,11 @@ uptr TagMemory(uptr p, uptr size, tag_t tag) {
 }
 
 }  // namespace __hwasan
+
+// --- Implementation of LSan-specific functions --- {{{1
+namespace __lsan {
+bool WordIsPoisoned(uptr addr) {
+  // Fixme: implement actual tag checking.
+  return false;
+}
+}  // namespace __lsan
diff --git a/libsanitizer/hwasan/hwasan_registers.h b/libsanitizer/hwasan/hwasan_registers.h
new file mode 100644
index 00000000000..48a140ffc92
--- /dev/null
+++ b/libsanitizer/hwasan/hwasan_registers.h
@@ -0,0 +1,56 @@
+//===-- hwasan_registers.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
+//
+//===----------------------------------------------------------------------===//
+//
+// This describes the register state retrieved by hwasan when error reporting.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef HWASAN_REGISTERS_H
+#define HWASAN_REGISTERS_H
+
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if defined(__aarch64__)
+
+#  define CAN_GET_REGISTERS 1
+
+struct Registers {
+  uptr x[32];
+};
+
+__attribute__((always_inline, unused)) static Registers GetRegisters() {
+  Registers regs;
+  __asm__ volatile(
+      "stp x0, x1, [%1, #(8 * 0)]\n"
+      "stp x2, x3, [%1, #(8 * 2)]\n"
+      "stp x4, x5, [%1, #(8 * 4)]\n"
+      "stp x6, x7, [%1, #(8 * 6)]\n"
+      "stp x8, x9, [%1, #(8 * 8)]\n"
+      "stp x10, x11, [%1, #(8 * 10)]\n"
+      "stp x12, x13, [%1, #(8 * 12)]\n"
+      "stp x14, x15, [%1, #(8 * 14)]\n"
+      "stp x16, x17, [%1, #(8 * 16)]\n"
+      "stp x18, x19, [%1, #(8 * 18)]\n"
+      "stp x20, x21, [%1, #(8 * 20)]\n"
+      "stp x22, x23, [%1, #(8 * 22)]\n"
+      "stp x24, x25, [%1, #(8 * 24)]\n"
+      "stp x26, x27, [%1, #(8 * 26)]\n"
+      "stp x28, x29, [%1, #(8 * 28)]\n"
+      : "=m"(regs)
+      : "r"(regs.x));
+  regs.x[30] = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
+  regs.x[31] = reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
+  return regs;
+}
+
+#else
+#  define CAN_GET_REGISTERS 0
+#endif
+
+#endif  // HWASAN_REGISTERS_H
diff --git a/libsanitizer/hwasan/hwasan_report.cpp b/libsanitizer/hwasan/hwasan_report.cpp
index de082150b70..8f9dc6cf13e 100644
--- a/libsanitizer/hwasan/hwasan_report.cpp
+++ b/libsanitizer/hwasan/hwasan_report.cpp
@@ -102,6 +102,15 @@ static StackTrace GetStackTraceFromId(u32 id) {
   return res;
 }
 
+static void MaybePrintAndroidHelpUrl() {
+#if SANITIZER_ANDROID
+  Printf(
+      "Learn more about HWASan reports: "
+      "https://source.android.com/docs/security/test/memory-safety/"
+      "hwasan-reports\n");
+#endif
+}
+
 // A RAII object that holds a copy of the current thread stack ring buffer.
 // The actual stack buffer may change while we are iterating over it (for
 // example, Printf may call syslog() which can itself be built with hwasan).
@@ -322,7 +331,7 @@ static void ShowHeapOrGlobalCandidate(uptr untagged_addr, tag_t *candidate,
            untagged_addr, offset, whence, chunk.UsedSize(), chunk.Beg(),
            chunk.End());
     Printf("%s", d.Allocation());
-    Printf("allocated here:\n");
+    Printf("allocated by thread T%u here:\n", chunk.GetAllocThreadId());
     Printf("%s", d.Default());
     GetStackTraceFromId(chunk.GetAllocStackId()).Print();
     return;
@@ -464,12 +473,12 @@ void PrintAddressDescription(
              har.requested_size, UntagAddr(har.tagged_addr),
              UntagAddr(har.tagged_addr) + har.requested_size);
       Printf("%s", d.Allocation());
-      Printf("freed by thread T%zd here:\n", t->unique_id());
+      Printf("freed by thread T%u here:\n", t->unique_id());
       Printf("%s", d.Default());
       GetStackTraceFromId(har.free_context_id).Print();
 
       Printf("%s", d.Allocation());
-      Printf("previously allocated here:\n", t);
+      Printf("previously allocated by thread T%u here:\n", har.alloc_thread_id);
       Printf("%s", d.Default());
       GetStackTraceFromId(har.alloc_context_id).Print();
 
@@ -492,7 +501,8 @@ void PrintAddressDescription(
   }
 
   // Print the remaining threads, as an extra information, 1 line per thread.
-  hwasanThreadList().VisitAllLiveThreads([&](Thread *t) { t->Announce(); });
+  if (flags()->print_live_threads_info)
+    hwasanThreadList().VisitAllLiveThreads([&](Thread *t) { t->Announce(); });
 
   if (!num_descriptions_printed)
     // We exhausted our possibilities. Bail out.
@@ -600,6 +610,7 @@ void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) {
   if (tag_ptr)
     PrintTagsAroundAddr(tag_ptr);
 
+  MaybePrintAndroidHelpUrl();
   ReportErrorSummary(bug_type, stack);
 }
 
@@ -673,6 +684,7 @@ void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size,
   tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
   PrintTagsAroundAddr(tag_ptr);
 
+  MaybePrintAndroidHelpUrl();
   ReportErrorSummary(bug_type, stack);
 }
 
@@ -742,6 +754,7 @@ void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
   if (registers_frame)
     ReportRegisters(registers_frame, pc);
 
+  MaybePrintAndroidHelpUrl();
   ReportErrorSummary(bug_type, stack);
 }
 
diff --git a/libsanitizer/hwasan/hwasan_setjmp_riscv64.S b/libsanitizer/hwasan/hwasan_setjmp_riscv64.S
index f33c4916df1..43f9c3c26b4 100644
--- a/libsanitizer/hwasan/hwasan_setjmp_riscv64.S
+++ b/libsanitizer/hwasan/hwasan_setjmp_riscv64.S
@@ -36,7 +36,7 @@ ASM_TYPE_FUNCTION(__interceptor_setjmp)
 __interceptor_setjmp:
   CFI_STARTPROC
   addi x11, x0, 0
-  j    __interceptor_sigsetjmp
+  tail __interceptor_sigsetjmp
   CFI_ENDPROC
 ASM_SIZE(__interceptor_setjmp)
 
diff --git a/libsanitizer/hwasan/hwasan_thread.cpp b/libsanitizer/hwasan/hwasan_thread.cpp
index c776ae179ce..3375782ef29 100644
--- a/libsanitizer/hwasan/hwasan_thread.cpp
+++ b/libsanitizer/hwasan/hwasan_thread.cpp
@@ -5,6 +5,7 @@
 #include "hwasan_interface_internal.h"
 #include "hwasan_mapping.h"
 #include "hwasan_poisoning.h"
+#include "hwasan_thread_list.h"
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_file.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
@@ -43,6 +44,8 @@ void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size,
 
   static atomic_uint64_t unique_id;
   unique_id_ = atomic_fetch_add(&unique_id, 1, memory_order_relaxed);
+  if (!IsMainThread())
+    os_id_ = GetTid();
 
   if (auto sz = flags()->heap_history_size)
     heap_allocations_ = HeapAllocationsRingBuffer::New(sz);
@@ -54,6 +57,7 @@ void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size,
   InitStackRingBuffer(stack_buffer_start, stack_buffer_size);
 #endif
   InitStackAndTls(state);
+  dtls_ = DTLS_Get();
 }
 
 void Thread::InitStackRingBuffer(uptr stack_buffer_start,
@@ -147,4 +151,58 @@ tag_t Thread::GenerateRandomTag(uptr num_bits) {
   return tag;
 }
 
+void EnsureMainThreadIDIsCorrect() {
+  auto *t = __hwasan::GetCurrentThread();
+  if (t && (t->IsMainThread()))
+    t->set_os_id(GetTid());
+}
+
 } // namespace __hwasan
+
+// --- Implementation of LSan-specific functions --- {{{1
+namespace __lsan {
+
+static __hwasan::HwasanThreadList *GetHwasanThreadListLocked() {
+  auto &tl = __hwasan::hwasanThreadList();
+  tl.CheckLocked();
+  return &tl;
+}
+
+static __hwasan::Thread *GetThreadByOsIDLocked(tid_t os_id) {
+  return GetHwasanThreadListLocked()->FindThreadLocked(
+      [os_id](__hwasan::Thread *t) { return t->os_id() == os_id; });
+}
+
+void LockThreadRegistry() { __hwasan::hwasanThreadList().Lock(); }
+
+void UnlockThreadRegistry() { __hwasan::hwasanThreadList().Unlock(); }
+
+void EnsureMainThreadIDIsCorrect() { __hwasan::EnsureMainThreadIDIsCorrect(); }
+
+bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
+                           uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
+                           uptr *cache_end, DTLS **dtls) {
+  auto *t = GetThreadByOsIDLocked(os_id);
+  if (!t)
+    return false;
+  *stack_begin = t->stack_bottom();
+  *stack_end = t->stack_top();
+  *tls_begin = t->tls_begin();
+  *tls_end = t->tls_end();
+  // Fixme: is this correct for HWASan.
+  *cache_begin = 0;
+  *cache_end = 0;
+  *dtls = t->dtls();
+  return true;
+}
+
+void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {}
+
+void GetThreadExtraStackRangesLocked(tid_t os_id,
+                                     InternalMmapVector<Range> *ranges) {}
+void GetThreadExtraStackRangesLocked(InternalMmapVector<Range> *ranges) {}
+
+void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs) {}
+void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) {}
+
+}  // namespace __lsan
diff --git a/libsanitizer/hwasan/hwasan_thread.h b/libsanitizer/hwasan/hwasan_thread.h
index 3db7c1a9454..9e1b438e48f 100644
--- a/libsanitizer/hwasan/hwasan_thread.h
+++ b/libsanitizer/hwasan/hwasan_thread.h
@@ -46,6 +46,7 @@ class Thread {
   uptr stack_size() { return stack_top() - stack_bottom(); }
   uptr tls_begin() { return tls_begin_; }
   uptr tls_end() { return tls_end_; }
+  DTLS *dtls() { return dtls_; }
   bool IsMainThread() { return unique_id_ == 0; }
 
   bool AddrIsInStack(uptr addr) {
@@ -61,13 +62,16 @@ class Thread {
   void DisableTagging() { tagging_disabled_++; }
   void EnableTagging() { tagging_disabled_--; }
 
-  u64 unique_id() const { return unique_id_; }
+  u32 unique_id() const { return unique_id_; }
   void Announce() {
     if (announced_) return;
     announced_ = true;
     Print("Thread: ");
   }
 
+  tid_t os_id() const { return os_id_; }
+  void set_os_id(tid_t os_id) { os_id_ = os_id; }
+
   uptr &vfork_spill() { return vfork_spill_; }
 
  private:
@@ -81,6 +85,7 @@ class Thread {
   uptr stack_bottom_;
   uptr tls_begin_;
   uptr tls_end_;
+  DTLS *dtls_;
 
   u32 random_state_;
   u32 random_buffer_;
@@ -89,7 +94,9 @@ class Thread {
   HeapAllocationsRingBuffer *heap_allocations_;
   StackAllocationsRingBuffer *stack_allocations_;
 
-  u64 unique_id_;  // counting from zero.
+  u32 unique_id_;  // counting from zero.
+
+  tid_t os_id_;
 
   u32 tagging_disabled_;  // if non-zero, malloc uses zero tag in this thread.
 
@@ -103,6 +110,9 @@ class Thread {
 Thread *GetCurrentThread();
 uptr *GetCurrentThreadLongPtr();
 
+// Used to handle fork().
+void EnsureMainThreadIDIsCorrect();
+
 struct ScopedTaggingDisabler {
   ScopedTaggingDisabler() { GetCurrentThread()->DisableTagging(); }
   ~ScopedTaggingDisabler() { GetCurrentThread()->EnableTagging(); }
diff --git a/libsanitizer/hwasan/hwasan_thread_list.h b/libsanitizer/hwasan/hwasan_thread_list.h
index 15916a802d6..97485b195b6 100644
--- a/libsanitizer/hwasan/hwasan_thread_list.h
+++ b/libsanitizer/hwasan/hwasan_thread_list.h
@@ -71,7 +71,7 @@ struct ThreadStats {
   uptr total_stack_size;
 };
 
-class HwasanThreadList {
+class SANITIZER_MUTEX HwasanThreadList {
  public:
   HwasanThreadList(uptr storage, uptr size)
       : free_space_(storage), free_space_end_(storage + size) {
@@ -85,7 +85,8 @@ class HwasanThreadList {
         RoundUpTo(ring_buffer_size_ + sizeof(Thread), ring_buffer_size_ * 2);
   }
 
-  Thread *CreateCurrentThread(const Thread::InitState *state = nullptr) {
+  Thread *CreateCurrentThread(const Thread::InitState *state = nullptr)
+      SANITIZER_EXCLUDES(free_list_mutex_, live_list_mutex_) {
     Thread *t = nullptr;
     {
       SpinMutexLock l(&free_list_mutex_);
@@ -114,7 +115,8 @@ class HwasanThreadList {
     ReleaseMemoryPagesToOS(start, start + thread_alloc_size_);
   }
 
-  void RemoveThreadFromLiveList(Thread *t) {
+  void RemoveThreadFromLiveList(Thread *t)
+      SANITIZER_EXCLUDES(live_list_mutex_) {
     SpinMutexLock l(&live_list_mutex_);
     for (Thread *&t2 : live_list_)
       if (t2 == t) {
@@ -127,7 +129,7 @@ class HwasanThreadList {
     CHECK(0 && "thread not found in live list");
   }
 
-  void ReleaseThread(Thread *t) {
+  void ReleaseThread(Thread *t) SANITIZER_EXCLUDES(free_list_mutex_) {
     RemoveThreadStats(t);
     t->Destroy();
     DontNeedThread(t);
@@ -149,30 +151,47 @@ class HwasanThreadList {
   }
 
   template <class CB>
-  void VisitAllLiveThreads(CB cb) {
+  void VisitAllLiveThreads(CB cb) SANITIZER_EXCLUDES(live_list_mutex_) {
     SpinMutexLock l(&live_list_mutex_);
     for (Thread *t : live_list_) cb(t);
   }
 
-  void AddThreadStats(Thread *t) {
+  template <class CB>
+  Thread *FindThreadLocked(CB cb) SANITIZER_CHECK_LOCKED(stats_mutex_) {
+    CheckLocked();
+    for (Thread *t : live_list_)
+      if (cb(t))
+        return t;
+    return nullptr;
+  }
+
+  void AddThreadStats(Thread *t) SANITIZER_EXCLUDES(stats_mutex_) {
     SpinMutexLock l(&stats_mutex_);
     stats_.n_live_threads++;
     stats_.total_stack_size += t->stack_size();
   }
 
-  void RemoveThreadStats(Thread *t) {
+  void RemoveThreadStats(Thread *t) SANITIZER_EXCLUDES(stats_mutex_) {
     SpinMutexLock l(&stats_mutex_);
     stats_.n_live_threads--;
     stats_.total_stack_size -= t->stack_size();
   }
 
-  ThreadStats GetThreadStats() {
+  ThreadStats GetThreadStats() SANITIZER_EXCLUDES(stats_mutex_) {
     SpinMutexLock l(&stats_mutex_);
     return stats_;
   }
 
   uptr GetRingBufferSize() const { return ring_buffer_size_; }
 
+  void Lock() SANITIZER_ACQUIRE(live_list_mutex_) { live_list_mutex_.Lock(); }
+  void CheckLocked() const SANITIZER_CHECK_LOCKED(live_list_mutex_) {
+    live_list_mutex_.CheckLocked();
+  }
+  void Unlock() SANITIZER_RELEASE(live_list_mutex_) {
+    live_list_mutex_.Unlock();
+  }
+
  private:
   Thread *AllocThread() {
     SpinMutexLock l(&free_space_mutex_);
@@ -191,12 +210,14 @@ class HwasanThreadList {
   uptr thread_alloc_size_;
 
   SpinMutex free_list_mutex_;
-  InternalMmapVector<Thread *> free_list_;
+  InternalMmapVector<Thread *> free_list_
+      SANITIZER_GUARDED_BY(free_list_mutex_);
   SpinMutex live_list_mutex_;
-  InternalMmapVector<Thread *> live_list_;
+  InternalMmapVector<Thread *> live_list_
+      SANITIZER_GUARDED_BY(live_list_mutex_);
 
-  ThreadStats stats_;
   SpinMutex stats_mutex_;
+  ThreadStats stats_ SANITIZER_GUARDED_BY(stats_mutex_);
 };
 
 void InitThreadList(uptr storage, uptr size);
diff --git a/libsanitizer/include/sanitizer/allocator_interface.h b/libsanitizer/include/sanitizer/allocator_interface.h
index 6226135ef84..d0cfce79c1a 100644
--- a/libsanitizer/include/sanitizer/allocator_interface.h
+++ b/libsanitizer/include/sanitizer/allocator_interface.h
@@ -26,6 +26,10 @@ extern "C" {
      is not yet freed. */
   int __sanitizer_get_ownership(const volatile void *p);
 
+  /* If a pointer lies within an allocation, it will return the start address
+     of the allocation. Otherwise, it returns nullptr. */
+  const void *__sanitizer_get_allocated_begin(const void *p);
+
   /* Returns the number of bytes reserved for the pointer p.
      Requires (get_ownership(p) == true) or (p == 0). */
   size_t __sanitizer_get_allocated_size(const volatile void *p);
diff --git a/libsanitizer/include/sanitizer/common_interface_defs.h b/libsanitizer/include/sanitizer/common_interface_defs.h
index ba58ad46f32..2f415bd9e85 100644
--- a/libsanitizer/include/sanitizer/common_interface_defs.h
+++ b/libsanitizer/include/sanitizer/common_interface_defs.h
@@ -159,6 +159,40 @@ void __sanitizer_annotate_contiguous_container(const void *beg,
                                                const void *old_mid,
                                                const void *new_mid);
 
+/// Similar to <c>__sanitizer_annotate_contiguous_container</c>.
+///
+/// Annotates the current state of a contiguous container memory,
+/// such as <c>std::deque</c>'s single chunk, when the boundries are moved.
+///
+/// A contiguous chunk is a chunk that keeps all of its elements
+/// in a contiguous region of memory. The container owns the region of memory
+/// <c>[storage_beg, storage_end)</c>; the memory <c>[container_beg,
+/// container_end)</c> is used to store the current elements, and the memory
+/// <c>[storage_beg, container_beg), [container_end, storage_end)</c> is
+/// reserved for future elements (<c>storage_beg <= container_beg <=
+/// container_end <= storage_end</c>). For example, in <c> std::deque </c>:
+/// - chunk with a frist deques element will have container_beg equal to address
+///  of the first element.
+/// - in every next chunk with elements, true is  <c> container_beg ==
+/// storage_beg </c>.
+///
+/// Argument requirements:
+/// During unpoisoning memory of empty container (before first element is
+/// added):
+/// - old_container_beg_p == old_container_end_p
+/// During poisoning after last element was removed:
+/// - new_container_beg_p == new_container_end_p
+/// \param storage_beg Beginning of memory region.
+/// \param storage_end End of memory region.
+/// \param old_container_beg Old beginning of used region.
+/// \param old_container_end End of used region.
+/// \param new_container_beg New beginning of used region.
+/// \param new_container_end New end of used region.
+void __sanitizer_annotate_double_ended_contiguous_container(
+    const void *storage_beg, const void *storage_end,
+    const void *old_container_beg, const void *old_container_end,
+    const void *new_container_beg, const void *new_container_end);
+
 /// Returns true if the contiguous container <c>[beg, end)</c> is properly
 /// poisoned.
 ///
@@ -178,6 +212,31 @@ void __sanitizer_annotate_contiguous_container(const void *beg,
 int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
                                             const void *end);
 
+/// Returns true if the double ended contiguous
+/// container <c>[storage_beg, storage_end)</c> is properly poisoned.
+///
+/// Proper poisoning could occur, for example, with
+/// <c>__sanitizer_annotate_double_ended_contiguous_container</c>), that is, if
+/// <c>[storage_beg, container_beg)</c> is not addressable, <c>[container_beg,
+/// container_end)</c> is addressable and <c>[container_end, end)</c> is
+/// unaddressable. Full verification requires O (<c>storage_end -
+/// storage_beg</c>) time; this function tries to avoid such complexity by
+/// touching only parts of the container around <c><i>storage_beg</i></c>,
+/// <c><i>container_beg</i></c>, <c><i>container_end</i></c>, and
+/// <c><i>storage_end</i></c>.
+///
+/// \param storage_beg Beginning of memory region.
+/// \param container_beg Beginning of used region.
+/// \param container_end End of used region.
+/// \param storage_end End of memory region.
+///
+/// \returns True if the double-ended contiguous container <c>[storage_beg,
+/// container_beg, container_end, end)</c> is properly poisoned - only
+/// [container_beg; container_end) is addressable.
+int __sanitizer_verify_double_ended_contiguous_container(
+    const void *storage_beg, const void *container_beg,
+    const void *container_end, const void *storage_end);
+
 /// Similar to <c>__sanitizer_verify_contiguous_container()</c> but also
 /// returns the address of the first improperly poisoned byte.
 ///
@@ -192,6 +251,20 @@ const void *__sanitizer_contiguous_container_find_bad_address(const void *beg,
                                                               const void *mid,
                                                               const void *end);
 
+/// returns the address of the first improperly poisoned byte.
+///
+/// Returns NULL if the area is poisoned properly.
+///
+/// \param storage_beg Beginning of memory region.
+/// \param container_beg Beginning of used region.
+/// \param container_end End of used region.
+/// \param storage_end End of memory region.
+///
+/// \returns The bad address or NULL.
+const void *__sanitizer_double_ended_contiguous_container_find_bad_address(
+    const void *storage_beg, const void *container_beg,
+    const void *container_end, const void *storage_end);
+
 /// Prints the stack trace leading to this call (useful for calling from the
 /// debugger).
 void __sanitizer_print_stack_trace(void);
diff --git a/libsanitizer/include/sanitizer/dfsan_interface.h b/libsanitizer/include/sanitizer/dfsan_interface.h
index 8e581a67572..519bfffa9a2 100644
--- a/libsanitizer/include/sanitizer/dfsan_interface.h
+++ b/libsanitizer/include/sanitizer/dfsan_interface.h
@@ -31,6 +31,14 @@ typedef void (*dfsan_write_callback_t)(int fd, const void *buf, size_t count);
 typedef void (*dfsan_conditional_callback_t)(dfsan_label label,
                                              dfsan_origin origin);
 
+/// Signature of the callback argument to dfsan_set_reaches_function_callback().
+/// The description is intended to hold the name of the variable.
+typedef void (*dfsan_reaches_function_callback_t)(dfsan_label label,
+                                                  dfsan_origin origin,
+                                                  const char *file,
+                                                  unsigned int line,
+                                                  const char *function);
+
 /// Computes the union of \c l1 and \c l2, resulting in a union label.
 dfsan_label dfsan_union(dfsan_label l1, dfsan_label l2);
 
@@ -91,6 +99,18 @@ void dfsan_set_conditional_callback(dfsan_conditional_callback_t callback);
 /// This function returns all label bits seen in signal handler conditions.
 dfsan_label dfsan_get_labels_in_signal_conditional();
 
+/// Sets a callback to be invoked when tainted data reaches a function.
+/// This could occur at function entry, or at a load instruction.
+/// These callbacks will only be added if -dfsan-reaches-function-callbacks=1.
+void dfsan_set_reaches_function_callback(
+    dfsan_reaches_function_callback_t callback);
+
+/// Making callbacks that handle signals well is tricky, so when
+/// -dfsan-reaches-function-callbacks=true, functions reached in signal
+/// handlers will add the labels they see into a global (bitwise-or together).
+/// This function returns all label bits seen during signal handlers.
+dfsan_label dfsan_get_labels_in_signal_reaches_function();
+
 /// Interceptor hooks.
 /// Whenever a dfsan's custom function is called the corresponding
 /// hook is called it non-zero. The hooks should be defined by the user.
diff --git a/libsanitizer/include/sanitizer/hwasan_interface.h b/libsanitizer/include/sanitizer/hwasan_interface.h
index 14035c05c63..ee742c7f303 100644
--- a/libsanitizer/include/sanitizer/hwasan_interface.h
+++ b/libsanitizer/include/sanitizer/hwasan_interface.h
@@ -1,4 +1,4 @@
-//===-- sanitizer/asan_interface.h ------------------------------*- C++ -*-===//
+//===-- sanitizer/hwasan_interface.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.
diff --git a/libsanitizer/include/sanitizer/tsan_interface.h b/libsanitizer/include/sanitizer/tsan_interface.h
index 2782e61fb8c..58f2513734e 100644
--- a/libsanitizer/include/sanitizer/tsan_interface.h
+++ b/libsanitizer/include/sanitizer/tsan_interface.h
@@ -172,6 +172,12 @@ int __tsan_on_finalize(int failed);
 // Release TSan internal memory in a best-effort manner.
 void __tsan_flush_memory();
 
+// User-provided default TSAN options.
+const char* __tsan_default_options(void);
+
+// User-provided default TSAN suppressions.
+const char* __tsan_default_suppressions(void);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/libsanitizer/interception/interception_type_test.cpp b/libsanitizer/interception/interception_type_test.cpp
index 2a118fb214f..7c3de82a1e8 100644
--- a/libsanitizer/interception/interception_type_test.cpp
+++ b/libsanitizer/interception/interception_type_test.cpp
@@ -24,9 +24,9 @@ COMPILER_CHECK(sizeof(::SSIZE_T) == sizeof(ssize_t));
 COMPILER_CHECK(sizeof(::PTRDIFF_T) == sizeof(ptrdiff_t));
 COMPILER_CHECK(sizeof(::INTMAX_T) == sizeof(intmax_t));
 
-#if !SANITIZER_APPLE
+#  if SANITIZER_GLIBC || SANITIZER_ANDROID
 COMPILER_CHECK(sizeof(::OFF64_T) == sizeof(off64_t));
-#endif
+#  endif
 
 // The following are the cases when pread (and friends) is used instead of
 // pread64. In those cases we need OFF_T to match off_t. We don't care about the
diff --git a/libsanitizer/interception/interception_win.cpp b/libsanitizer/interception/interception_win.cpp
index d0db981d519..faaa8ee1538 100644
--- a/libsanitizer/interception/interception_win.cpp
+++ b/libsanitizer/interception/interception_win.cpp
@@ -738,7 +738,7 @@ bool OverrideFunctionWithRedirectJump(
     return false;
 
   if (orig_old_func) {
-    uptr relative_offset = *(u32*)(old_func + 1);
+    sptr relative_offset = *(s32 *)(old_func + 1);
     uptr absolute_target = old_func + relative_offset + kJumpInstructionLength;
     *orig_old_func = absolute_target;
   }
diff --git a/libsanitizer/lsan/lsan.cpp b/libsanitizer/lsan/lsan.cpp
index 489c5ca01fe..319f399e60f 100644
--- a/libsanitizer/lsan/lsan.cpp
+++ b/libsanitizer/lsan/lsan.cpp
@@ -36,7 +36,7 @@ void __sanitizer::BufferedStackTrace::UnwindImpl(
     uptr pc, uptr bp, void *context, bool request_fast, u32 max_depth) {
   using namespace __lsan;
   uptr stack_top = 0, stack_bottom = 0;
-  if (ThreadContext *t = CurrentThreadContext()) {
+  if (ThreadContextLsanBase *t = GetCurrentThread()) {
     stack_top = t->stack_end();
     stack_bottom = t->stack_begin();
   }
diff --git a/libsanitizer/lsan/lsan_allocator.cpp b/libsanitizer/lsan/lsan_allocator.cpp
index 43928ad294e..ee7facac6ea 100644
--- a/libsanitizer/lsan/lsan_allocator.cpp
+++ b/libsanitizer/lsan/lsan_allocator.cpp
@@ -145,6 +145,22 @@ void GetAllocatorCacheRange(uptr *begin, uptr *end) {
   *end = *begin + sizeof(AllocatorCache);
 }
 
+static const void *GetMallocBegin(const void *p) {
+  if (!p)
+    return nullptr;
+  void *beg = allocator.GetBlockBegin(p);
+  if (!beg)
+    return nullptr;
+  ChunkMetadata *m = Metadata(beg);
+  if (!m)
+    return nullptr;
+  if (!m->allocated)
+    return nullptr;
+  if (m->requested_size == 0)
+    return nullptr;
+  return (const void *)beg;
+}
+
 uptr GetMallocUsableSize(const void *p) {
   if (!p)
     return 0;
@@ -275,6 +291,10 @@ uptr GetUserBegin(uptr chunk) {
   return chunk;
 }
 
+uptr GetUserAddr(uptr chunk) {
+  return chunk;
+}
+
 LsanMetadata::LsanMetadata(uptr chunk) {
   metadata_ = Metadata(reinterpret_cast<void *>(chunk));
   CHECK(metadata_);
@@ -304,7 +324,7 @@ void ForEachChunk(ForEachChunkCallback callback, void *arg) {
   allocator.ForEachChunk(callback, arg);
 }
 
-IgnoreObjectResult IgnoreObjectLocked(const void *p) {
+IgnoreObjectResult IgnoreObject(const void *p) {
   void *chunk = allocator.GetBlockBegin(p);
   if (!chunk || p < chunk) return kIgnoreObjectInvalid;
   ChunkMetadata *m = Metadata(chunk);
@@ -319,7 +339,7 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
   }
 }
 
-void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
+void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *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.
 
@@ -359,6 +379,11 @@ uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
 SANITIZER_INTERFACE_ATTRIBUTE
 int __sanitizer_get_ownership(const void *p) { return Metadata(p) != nullptr; }
 
+SANITIZER_INTERFACE_ATTRIBUTE
+const void * __sanitizer_get_allocated_begin(const void *p) {
+  return GetMallocBegin(p);
+}
+
 SANITIZER_INTERFACE_ATTRIBUTE
 uptr __sanitizer_get_allocated_size(const void *p) {
   return GetMallocUsableSize(p);
diff --git a/libsanitizer/lsan/lsan_allocator.h b/libsanitizer/lsan/lsan_allocator.h
index b67d9d7750e..10c1672ec5e 100644
--- a/libsanitizer/lsan/lsan_allocator.h
+++ b/libsanitizer/lsan/lsan_allocator.h
@@ -68,13 +68,13 @@ using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
 # if SANITIZER_FUCHSIA || defined(__powerpc64__)
 const uptr kAllocatorSpace = ~(uptr)0;
 const uptr kAllocatorSize  =  0x40000000000ULL;  // 4T.
-#elif defined(__s390x__)
-const uptr kAllocatorSpace = 0x40000000000ULL;
-const uptr kAllocatorSize = 0x40000000000ULL;  // 4T.
-# else
+#  elif SANITIZER_APPLE
 const uptr kAllocatorSpace = 0x600000000000ULL;
 const uptr kAllocatorSize  = 0x40000000000ULL;  // 4T.
-# endif
+#  else
+const uptr kAllocatorSpace = 0x500000000000ULL;
+const uptr kAllocatorSize = 0x40000000000ULL;  // 4T.
+#  endif
 template <typename AddressSpaceViewTy>
 struct AP64 {  // Allocator64 parameters. Deliberately using a short name.
   static const uptr kSpaceBeg = kAllocatorSpace;
diff --git a/libsanitizer/lsan/lsan_common.cpp b/libsanitizer/lsan/lsan_common.cpp
index 576274608c8..ae29e4a21fd 100644
--- a/libsanitizer/lsan/lsan_common.cpp
+++ b/libsanitizer/lsan/lsan_common.cpp
@@ -270,13 +270,20 @@ static inline bool MaybeUserPointer(uptr p) {
   if (p < kMinAddress)
     return false;
 #  if defined(__x86_64__)
+  // TODO: add logic similar to ARM when Intel LAM is available.
   // Accept only canonical form user-space addresses.
   return ((p >> 47) == 0);
 #  elif defined(__mips64)
   return ((p >> 40) == 0);
 #  elif defined(__aarch64__)
+  // TBI (Top Byte Ignore) feature of AArch64: bits [63:56] are ignored in
+  // address translation and can be used to store a tag.
+  constexpr uptr kPointerMask = 255ULL << 48;
   // Accept up to 48 bit VMA.
-  return ((p >> 48) == 0);
+  return ((p & kPointerMask) == 0);
+#  elif defined(__loongarch_lp64)
+  // Allow 47-bit user-space VMA at current.
+  return ((p >> 47) == 0);
 #  else
   return true;
 #  endif
@@ -350,9 +357,12 @@ void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier) {
   }
 }
 
-void ForEachExtraStackRangeCb(uptr begin, uptr end, void *arg) {
-  Frontier *frontier = reinterpret_cast<Frontier *>(arg);
-  ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable);
+void ScanExtraStackRanges(const InternalMmapVector<Range> &ranges,
+                          Frontier *frontier) {
+  for (uptr i = 0; i < ranges.size(); i++) {
+    ScanRangeForPointers(ranges[i].begin, ranges[i].end, frontier, "FAKE STACK",
+                         kReachable);
+  }
 }
 
 #  if SANITIZER_FUCHSIA
@@ -371,8 +381,7 @@ extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_iterate_dynamic_tls(
 
 static void ProcessThreadRegistry(Frontier *frontier) {
   InternalMmapVector<uptr> ptrs;
-  GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
-      GetAdditionalThreadContextPtrs, &ptrs);
+  GetAdditionalThreadContextPtrsLocked(&ptrs);
 
   for (uptr i = 0; i < ptrs.size(); ++i) {
     void *ptr = reinterpret_cast<void *>(ptrs[i]);
@@ -395,6 +404,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
                            Frontier *frontier, tid_t caller_tid,
                            uptr caller_sp) {
   InternalMmapVector<uptr> registers;
+  InternalMmapVector<Range> extra_ranges;
   for (uptr i = 0; i < suspended_threads.ThreadCount(); i++) {
     tid_t os_id = static_cast<tid_t>(suspended_threads.GetThreadID(i));
     LOG_THREADS("Processing thread %llu.\n", os_id);
@@ -455,7 +465,9 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
       }
       ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK",
                            kReachable);
-      ForEachExtraStackRange(os_id, ForEachExtraStackRangeCb, frontier);
+      extra_ranges.clear();
+      GetThreadExtraStackRangesLocked(os_id, &extra_ranges);
+      ScanExtraStackRanges(extra_ranges, frontier);
     }
 
     if (flags()->use_tls) {
@@ -669,18 +681,6 @@ void LeakSuppressionContext::PrintMatchedSuppressions() {
   Printf("%s\n\n", line);
 }
 
-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, tctx->os_id);
-    if (i >= suspended_threads.size() || suspended_threads[i] != tctx->os_id)
-      Report(
-          "Running thread %llu was not suspended. False leaks are possible.\n",
-          tctx->os_id);
-  }
-}
-
 #  if SANITIZER_FUCHSIA
 
 // Fuchsia provides a libc interface that guarantees all threads are
@@ -697,8 +697,16 @@ static void ReportUnsuspendedThreads(
 
   Sort(threads.data(), threads.size());
 
-  GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
-      &ReportIfNotSuspended, &threads);
+  InternalMmapVector<tid_t> unsuspended;
+  GetRunningThreadsLocked(&unsuspended);
+
+  for (auto os_id : unsuspended) {
+    uptr i = InternalLowerBound(threads, os_id);
+    if (i >= threads.size() || threads[i] != os_id)
+      Report(
+          "Running thread %zu was not suspended. False leaks are possible.\n",
+          os_id);
+  }
 }
 
 #  endif  // !SANITIZER_FUCHSIA
@@ -741,8 +749,11 @@ static bool PrintResults(LeakReport &report) {
 }
 
 static bool CheckForLeaks() {
-  if (&__lsan_is_turned_off && __lsan_is_turned_off())
+  if (&__lsan_is_turned_off && __lsan_is_turned_off()) {
+    VReport(1, "LeakSanitizer is disabled");
     return false;
+  }
+  VReport(1, "LeakSanitizer: checking for leaks");
   // 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.
@@ -852,7 +863,7 @@ void LeakReport::AddLeakedChunks(const LeakedChunks &chunks) {
       leaks_.push_back(leak);
     }
     if (flags()->report_objects) {
-      LeakedObject obj = {leaks_[i].id, chunk, leaked_size};
+      LeakedObject obj = {leaks_[i].id, GetUserAddr(chunk), leaked_size};
       leaked_objects_.push_back(obj);
     }
   }
@@ -937,7 +948,7 @@ void LeakReport::PrintSummary() {
 
 uptr LeakReport::ApplySuppressions() {
   LeakSuppressionContext *suppressions = GetSuppressionContext();
-  uptr new_suppressions = false;
+  uptr new_suppressions = 0;
   for (uptr i = 0; i < leaks_.size(); i++) {
     if (suppressions->Suppress(leaks_[i].stack_trace_id, leaks_[i].hit_count,
                                leaks_[i].total_size)) {
@@ -986,7 +997,7 @@ void __lsan_ignore_object(const void *p) {
   // Cannot use PointsIntoChunk or LsanMetadata here, since the allocator is not
   // locked.
   Lock l(&global_mutex);
-  IgnoreObjectResult res = IgnoreObjectLocked(p);
+  IgnoreObjectResult res = IgnoreObject(p);
   if (res == kIgnoreObjectInvalid)
     VReport(1, "__lsan_ignore_object(): no heap object found at %p\n", p);
   if (res == kIgnoreObjectAlreadyIgnored)
diff --git a/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h
index 20ef7c458b4..a1f2d1a349b 100644
--- a/libsanitizer/lsan/lsan_common.h
+++ b/libsanitizer/lsan/lsan_common.h
@@ -21,6 +21,7 @@
 #include "sanitizer_common/sanitizer_stackdepot.h"
 #include "sanitizer_common/sanitizer_stoptheworld.h"
 #include "sanitizer_common/sanitizer_symbolizer.h"
+#include "sanitizer_common/sanitizer_thread_registry.h"
 
 // LeakSanitizer relies on some Glibc's internals (e.g. TLS machinery) on Linux.
 // Also, LSan doesn't like 32 bit architectures
@@ -42,6 +43,8 @@
 #  define CAN_SANITIZE_LEAKS 1
 #elif defined(__arm__) && SANITIZER_LINUX
 #  define CAN_SANITIZE_LEAKS 1
+#elif SANITIZER_LOONGARCH64 && SANITIZER_LINUX
+#  define CAN_SANITIZE_LEAKS 1
 #elif SANITIZER_RISCV64 && SANITIZER_LINUX
 #  define CAN_SANITIZE_LEAKS 1
 #elif SANITIZER_NETBSD || SANITIZER_FUCHSIA
@@ -57,6 +60,9 @@ class ThreadContextBase;
 struct DTLS;
 }
 
+// This section defines function and class prototypes which must be implemented
+// by the parent tool linking in LSan. There are implementations provided by the
+// LSan library which will be linked in when LSan is used as a standalone tool.
 namespace __lsan {
 
 // Chunk tags.
@@ -67,6 +73,106 @@ enum ChunkTag {
   kIgnored = 3
 };
 
+enum IgnoreObjectResult {
+  kIgnoreObjectSuccess,
+  kIgnoreObjectAlreadyIgnored,
+  kIgnoreObjectInvalid
+};
+
+struct Range {
+  uptr begin;
+  uptr end;
+};
+
+//// --------------------------------------------------------------------------
+//// Poisoning prototypes.
+//// --------------------------------------------------------------------------
+
+// Returns true if [addr, addr + sizeof(void *)) is poisoned.
+bool WordIsPoisoned(uptr addr);
+
+//// --------------------------------------------------------------------------
+//// Thread prototypes.
+//// --------------------------------------------------------------------------
+
+// Wrappers for ThreadRegistry access.
+void LockThreadRegistry() SANITIZER_NO_THREAD_SAFETY_ANALYSIS;
+void UnlockThreadRegistry() SANITIZER_NO_THREAD_SAFETY_ANALYSIS;
+// If called from the main thread, updates the main thread's TID in the thread
+// registry. We need this to handle processes that fork() without a subsequent
+// exec(), which invalidates the recorded TID. To update it, we must call
+// gettid() from the main thread. Our solution is to call this function before
+// leak checking and also before every call to pthread_create() (to handle cases
+// where leak checking is initiated from a non-main thread).
+void EnsureMainThreadIDIsCorrect();
+
+bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
+                           uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
+                           uptr *cache_end, DTLS **dtls);
+void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches);
+void GetThreadExtraStackRangesLocked(InternalMmapVector<Range> *ranges);
+void GetThreadExtraStackRangesLocked(tid_t os_id,
+                                     InternalMmapVector<Range> *ranges);
+void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs);
+void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads);
+
+//// --------------------------------------------------------------------------
+//// Allocator prototypes.
+//// --------------------------------------------------------------------------
+
+// Wrappers for allocator's ForceLock()/ForceUnlock().
+void LockAllocator();
+void UnlockAllocator();
+
+// Returns the address range occupied by the global allocator object.
+void GetAllocatorGlobalRange(uptr *begin, uptr *end);
+// If p points into a chunk that has been allocated to the user, returns its
+// user-visible address. Otherwise, returns 0.
+uptr PointsIntoChunk(void *p);
+// Returns address of user-visible chunk contained in this allocator chunk.
+uptr GetUserBegin(uptr chunk);
+// Returns user-visible address for chunk. If memory tagging is used this
+// function will return the tagged address.
+uptr GetUserAddr(uptr chunk);
+
+// Wrapper for chunk metadata operations.
+class LsanMetadata {
+ public:
+  // Constructor accepts address of user-visible chunk.
+  explicit LsanMetadata(uptr chunk);
+  bool allocated() const;
+  ChunkTag tag() const;
+  void set_tag(ChunkTag value);
+  uptr requested_size() const;
+  u32 stack_trace_id() const;
+
+ private:
+  void *metadata_;
+};
+
+// Iterate over all existing chunks. Allocator must be locked.
+void ForEachChunk(ForEachChunkCallback callback, void *arg);
+
+// Helper for __lsan_ignore_object().
+IgnoreObjectResult IgnoreObject(const void *p);
+
+// The rest of the LSan interface which is implemented by library.
+
+struct ScopedStopTheWorldLock {
+  ScopedStopTheWorldLock() {
+    LockThreadRegistry();
+    LockAllocator();
+  }
+
+  ~ScopedStopTheWorldLock() {
+    UnlockAllocator();
+    UnlockThreadRegistry();
+  }
+
+  ScopedStopTheWorldLock &operator=(const ScopedStopTheWorldLock &) = delete;
+  ScopedStopTheWorldLock(const ScopedStopTheWorldLock &) = delete;
+};
+
 struct Flags {
 #define LSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
 #include "lsan_flags.inc"
@@ -153,8 +259,6 @@ struct CheckForLeaksParam {
 InternalMmapVectorNoCtor<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,
@@ -164,12 +268,8 @@ void ScanRangeForPointers(uptr begin, uptr end,
                           Frontier *frontier,
                           const char *region_type, ChunkTag tag);
 void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier);
-
-enum IgnoreObjectResult {
-  kIgnoreObjectSuccess,
-  kIgnoreObjectAlreadyIgnored,
-  kIgnoreObjectInvalid
-};
+void ScanExtraStackRanges(const InternalMmapVector<Range> &ranges,
+                          Frontier *frontier);
 
 // Functions called from the parent tool.
 const char *MaybeCallLsanDefaultOptions();
@@ -221,57 +321,6 @@ inline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size,
 #endif
 }
 
-// The following must be implemented in the parent tool.
-
-void ForEachChunk(ForEachChunkCallback callback, void *arg);
-// Returns the address range occupied by the global allocator object.
-void GetAllocatorGlobalRange(uptr *begin, uptr *end);
-// Wrappers for allocator's ForceLock()/ForceUnlock().
-void LockAllocator();
-void UnlockAllocator();
-// Returns true if [addr, addr + sizeof(void *)) is poisoned.
-bool WordIsPoisoned(uptr addr);
-// Wrappers for ThreadRegistry access.
-void LockThreadRegistry() SANITIZER_NO_THREAD_SAFETY_ANALYSIS;
-void UnlockThreadRegistry() SANITIZER_NO_THREAD_SAFETY_ANALYSIS;
-
-struct ScopedStopTheWorldLock {
-  ScopedStopTheWorldLock() {
-    LockThreadRegistry();
-    LockAllocator();
-  }
-
-  ~ScopedStopTheWorldLock() {
-    UnlockAllocator();
-    UnlockThreadRegistry();
-  }
-
-  ScopedStopTheWorldLock &operator=(const ScopedStopTheWorldLock &) = delete;
-  ScopedStopTheWorldLock(const ScopedStopTheWorldLock &) = delete;
-};
-
-ThreadRegistry *GetThreadRegistryLocked();
-bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
-                           uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
-                           uptr *cache_end, DTLS **dtls);
-void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches);
-void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
-                            void *arg);
-// If called from the main thread, updates the main thread's TID in the thread
-// registry. We need this to handle processes that fork() without a subsequent
-// exec(), which invalidates the recorded TID. To update it, we must call
-// gettid() from the main thread. Our solution is to call this function before
-// leak checking and also before every call to pthread_create() (to handle cases
-// where leak checking is initiated from a non-main thread).
-void EnsureMainThreadIDIsCorrect();
-// If p points into a chunk that has been allocated to the user, returns its
-// user-visible address. Otherwise, returns 0.
-uptr PointsIntoChunk(void *p);
-// Returns address of user-visible chunk contained in this allocator chunk.
-uptr GetUserBegin(uptr chunk);
-// Helper for __lsan_ignore_object().
-IgnoreObjectResult IgnoreObjectLocked(const void *p);
-
 // Return the linker module, if valid for the platform.
 LoadedModule *GetLinker();
 
@@ -281,20 +330,6 @@ bool HasReportedLeaks();
 // Run platform-specific leak handlers.
 void HandleLeaks();
 
-// Wrapper for chunk metadata operations.
-class LsanMetadata {
- public:
-  // Constructor accepts address of user-visible chunk.
-  explicit LsanMetadata(uptr chunk);
-  bool allocated() const;
-  ChunkTag tag() const;
-  void set_tag(ChunkTag value);
-  uptr requested_size() const;
-  u32 stack_trace_id() const;
- private:
-  void *metadata_;
-};
-
 }  // namespace __lsan
 
 extern "C" {
diff --git a/libsanitizer/lsan/lsan_common_fuchsia.cpp b/libsanitizer/lsan/lsan_common_fuchsia.cpp
index edb4ca6c857..bcad1c205fc 100644
--- a/libsanitizer/lsan/lsan_common_fuchsia.cpp
+++ b/libsanitizer/lsan/lsan_common_fuchsia.cpp
@@ -12,6 +12,7 @@
 //===---------------------------------------------------------------------===//
 
 #include "lsan_common.h"
+#include "lsan_thread.h"
 #include "sanitizer_common/sanitizer_platform.h"
 
 #if CAN_SANITIZE_LEAKS && SANITIZER_FUCHSIA
@@ -143,17 +144,13 @@ void LockStuffAndStopTheWorld(StopTheWorldCallback callback,
 
         // We don't use the thread registry at all for enumerating the threads
         // and their stacks, registers, and TLS regions.  So use it separately
-        // just for the allocator cache, and to call ForEachExtraStackRange,
+        // just for the allocator cache, and to call ScanExtraStackRanges,
         // which ASan needs.
         if (flags()->use_stacks) {
-          GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
-              [](ThreadContextBase *tctx, void *arg) {
-                ForEachExtraStackRange(tctx->os_id, ForEachExtraStackRangeCb,
-                                       arg);
-              },
-              &params->argument->frontier);
+          InternalMmapVector<Range> ranges;
+          GetThreadExtraStackRangesLocked(&ranges);
+          ScanExtraStackRanges(ranges, &params->argument->frontier);
         }
-
         params->callback(SuspendedThreadsListFuchsia(), params->argument);
       },
       &params);
diff --git a/libsanitizer/lsan/lsan_common_mac.cpp b/libsanitizer/lsan/lsan_common_mac.cpp
index b6b15095744..9ccf098a656 100644
--- a/libsanitizer/lsan/lsan_common_mac.cpp
+++ b/libsanitizer/lsan/lsan_common_mac.cpp
@@ -25,6 +25,8 @@
 #  include "sanitizer_common/sanitizer_allocator_internal.h"
 namespace __lsan {
 
+class ThreadContextLsanBase;
+
 enum class SeenRegion {
   None = 0,
   AllocOnce = 1 << 0,
@@ -50,18 +52,18 @@ struct RegionScanState {
 
 typedef struct {
   int disable_counter;
-  u32 current_thread_id;
+  ThreadContextLsanBase *current_thread;
   AllocatorCache cache;
 } thread_local_data_t;
 
 static pthread_key_t key;
 static pthread_once_t key_once = PTHREAD_ONCE_INIT;
 
-// The main thread destructor requires the current thread id,
-// so we can't destroy it until it's been used and reset to invalid tid
+// The main thread destructor requires the current thread,
+// so we can't destroy it until it's been used and reset.
 void restore_tid_data(void *ptr) {
   thread_local_data_t *data = (thread_local_data_t *)ptr;
-  if (data->current_thread_id != kInvalidTid)
+  if (data->current_thread)
     pthread_setspecific(key, data);
 }
 
@@ -76,7 +78,7 @@ static thread_local_data_t *get_tls_val(bool alloc) {
   if (ptr == NULL && alloc) {
     ptr = (thread_local_data_t *)InternalAlloc(sizeof(*ptr));
     ptr->disable_counter = 0;
-    ptr->current_thread_id = kInvalidTid;
+    ptr->current_thread = nullptr;
     ptr->cache = AllocatorCache();
     pthread_setspecific(key, ptr);
   }
@@ -99,12 +101,14 @@ void EnableInThisThread() {
   --*disable_counter;
 }
 
-u32 GetCurrentThread() {
+ThreadContextLsanBase *GetCurrentThread() {
   thread_local_data_t *data = get_tls_val(false);
-  return data ? data->current_thread_id : kInvalidTid;
+  return data ? data->current_thread : nullptr;
 }
 
-void SetCurrentThread(u32 tid) { get_tls_val(true)->current_thread_id = tid; }
+void SetCurrentThread(ThreadContextLsanBase *tctx) {
+  get_tls_val(true)->current_thread = tctx;
+}
 
 AllocatorCache *GetAllocatorCache() { return &get_tls_val(true)->cache; }
 
diff --git a/libsanitizer/lsan/lsan_fuchsia.cpp b/libsanitizer/lsan/lsan_fuchsia.cpp
index 2d96206754a..4edac9757a9 100644
--- a/libsanitizer/lsan/lsan_fuchsia.cpp
+++ b/libsanitizer/lsan/lsan_fuchsia.cpp
@@ -46,6 +46,7 @@ struct OnStartedArgs {
 };
 
 void ThreadContext::OnStarted(void *arg) {
+  ThreadContextLsanBase::OnStarted(arg);
   auto args = reinterpret_cast<const OnStartedArgs *>(arg);
   cache_begin_ = args->cache_begin;
   cache_end_ = args->cache_end;
@@ -68,7 +69,7 @@ void InitializeMainThread() {
 }
 
 void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {
-  GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+  GetLsanThreadRegistryLocked()->RunCallbackForEachThreadLocked(
       [](ThreadContextBase *tctx, void *arg) {
         auto ctx = static_cast<ThreadContext *>(tctx);
         static_cast<decltype(caches)>(arg)->push_back(ctx->cache_begin());
@@ -98,7 +99,7 @@ void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
   OnCreatedArgs args;
   args.stack_begin = reinterpret_cast<uptr>(stack_base);
   args.stack_end = args.stack_begin + stack_size;
-  u32 parent_tid = GetCurrentThread();
+  u32 parent_tid = GetCurrentThreadId();
   u32 tid = ThreadCreate(parent_tid, detached, &args);
   return reinterpret_cast<void *>(static_cast<uptr>(tid));
 }
@@ -110,7 +111,7 @@ void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
   // On success, there is nothing to do here.
   if (error != thrd_success) {
     // Clean up the thread registry for the thread creation that didn't happen.
-    GetThreadRegistryLocked()->FinishThread(tid);
+    GetLsanThreadRegistryLocked()->FinishThread(tid);
   }
 }
 
diff --git a/libsanitizer/lsan/lsan_interceptors.cpp b/libsanitizer/lsan/lsan_interceptors.cpp
index 3a1b2afdbb7..3f8ef3fe48c 100644
--- a/libsanitizer/lsan/lsan_interceptors.cpp
+++ b/libsanitizer/lsan/lsan_interceptors.cpp
@@ -468,7 +468,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr,
     res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p);
   }
   if (res == 0) {
-    int tid = ThreadCreate(GetCurrentThread(), IsStateDetached(detached));
+    int tid = ThreadCreate(GetCurrentThreadId(), IsStateDetached(detached));
     CHECK_NE(tid, kMainTid);
     atomic_store(&p.tid, tid, memory_order_release);
     while (atomic_load(&p.tid, memory_order_acquire) != 0)
diff --git a/libsanitizer/lsan/lsan_linux.cpp b/libsanitizer/lsan/lsan_linux.cpp
index 47c2f21b5a6..5074cee1296 100644
--- a/libsanitizer/lsan/lsan_linux.cpp
+++ b/libsanitizer/lsan/lsan_linux.cpp
@@ -14,13 +14,14 @@
 
 #if SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA
 
-#include "lsan_allocator.h"
+#  include "lsan_allocator.h"
+#  include "lsan_thread.h"
 
 namespace __lsan {
 
-static THREADLOCAL u32 current_thread_tid = kInvalidTid;
-u32 GetCurrentThread() { return current_thread_tid; }
-void SetCurrentThread(u32 tid) { current_thread_tid = tid; }
+static THREADLOCAL ThreadContextLsanBase *current_thread = nullptr;
+ThreadContextLsanBase *GetCurrentThread() { return current_thread; }
+void SetCurrentThread(ThreadContextLsanBase *tctx) { current_thread = tctx; }
 
 static THREADLOCAL AllocatorCache allocator_cache;
 AllocatorCache *GetAllocatorCache() { return &allocator_cache; }
diff --git a/libsanitizer/lsan/lsan_mac.cpp b/libsanitizer/lsan/lsan_mac.cpp
index 6964a9ba28d..2bcd0057f24 100644
--- a/libsanitizer/lsan/lsan_mac.cpp
+++ b/libsanitizer/lsan/lsan_mac.cpp
@@ -67,10 +67,9 @@ typedef struct {
 
 ALWAYS_INLINE
 void lsan_register_worker_thread(int parent_tid) {
-  if (GetCurrentThread() == kInvalidTid) {
+  if (GetCurrentThreadId() == kInvalidTid) {
     u32 tid = ThreadCreate(parent_tid, true);
     ThreadStart(tid, GetTid());
-    SetCurrentThread(tid);
   }
 }
 
@@ -101,7 +100,7 @@ extern "C" lsan_block_context_t *alloc_lsan_context(void *ctxt,
       (lsan_block_context_t *)lsan_malloc(sizeof(lsan_block_context_t), stack);
   lsan_ctxt->block = ctxt;
   lsan_ctxt->func = func;
-  lsan_ctxt->parent_tid = GetCurrentThread();
+  lsan_ctxt->parent_tid = GetCurrentThreadId();
   return lsan_ctxt;
 }
 
@@ -146,13 +145,13 @@ void dispatch_source_set_event_handler(dispatch_source_t ds,
                                        void (^work)(void));
 }
 
-#define GET_LSAN_BLOCK(work)                 \
-  void (^lsan_block)(void);                  \
-  int parent_tid = GetCurrentThread();       \
-  lsan_block = ^(void) {                     \
-    lsan_register_worker_thread(parent_tid); \
-    work();                                  \
-  }
+#    define GET_LSAN_BLOCK(work)                 \
+      void (^lsan_block)(void);                  \
+      int parent_tid = GetCurrentThreadId();     \
+      lsan_block = ^(void) {                     \
+        lsan_register_worker_thread(parent_tid); \
+        work();                                  \
+      }
 
 INTERCEPTOR(void, dispatch_async, dispatch_queue_t dq, void (^work)(void)) {
   GET_LSAN_BLOCK(work);
diff --git a/libsanitizer/lsan/lsan_posix.cpp b/libsanitizer/lsan/lsan_posix.cpp
index 8f277db2237..d99e1cc0105 100644
--- a/libsanitizer/lsan/lsan_posix.cpp
+++ b/libsanitizer/lsan/lsan_posix.cpp
@@ -16,6 +16,7 @@
 #if SANITIZER_POSIX
 #include "lsan.h"
 #include "lsan_allocator.h"
+#include "lsan_thread.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
 #include "sanitizer_common/sanitizer_tls_get_addr.h"
 
@@ -34,6 +35,7 @@ struct OnStartedArgs {
 };
 
 void ThreadContext::OnStarted(void *arg) {
+  ThreadContextLsanBase::OnStarted(arg);
   auto args = reinterpret_cast<const OnStartedArgs *>(arg);
   stack_begin_ = args->stack_begin;
   stack_end_ = args->stack_end;
@@ -61,7 +63,7 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
                            uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
                            uptr *cache_end, DTLS **dtls) {
   ThreadContext *context = static_cast<ThreadContext *>(
-      GetThreadRegistryLocked()->FindThreadContextByOsIDLocked(os_id));
+      GetLsanThreadRegistryLocked()->FindThreadContextByOsIDLocked(os_id));
   if (!context)
     return false;
   *stack_begin = context->stack_begin();
@@ -87,7 +89,7 @@ static void OnStackUnwind(const SignalContext &sig, const void *,
 }
 
 void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {
-  HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind,
+  HandleDeadlySignal(siginfo, context, GetCurrentThreadId(), &OnStackUnwind,
                      nullptr);
 }
 
diff --git a/libsanitizer/lsan/lsan_thread.cpp b/libsanitizer/lsan/lsan_thread.cpp
index ca3dfd03b10..9da42f32e06 100644
--- a/libsanitizer/lsan/lsan_thread.cpp
+++ b/libsanitizer/lsan/lsan_thread.cpp
@@ -25,9 +25,12 @@ namespace __lsan {
 
 static ThreadRegistry *thread_registry;
 
+static Mutex mu_for_thread_context;
+static LowLevelAllocator allocator_for_thread_context;
+
 static ThreadContextBase *CreateThreadContext(u32 tid) {
-  void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext");
-  return new (mem) ThreadContext(tid);
+  Lock lock(&mu_for_thread_context);
+  return new (allocator_for_thread_context) ThreadContext(tid);
 }
 
 void InitializeThreadRegistry() {
@@ -39,9 +42,12 @@ void InitializeThreadRegistry() {
 ThreadContextLsanBase::ThreadContextLsanBase(int tid)
     : ThreadContextBase(tid) {}
 
+void ThreadContextLsanBase::OnStarted(void *arg) { SetCurrentThread(this); }
+
 void ThreadContextLsanBase::OnFinished() {
   AllocatorThreadFinish();
   DTLS_Destroy();
+  SetCurrentThread(nullptr);
 }
 
 u32 ThreadCreate(u32 parent_tid, bool detached, void *arg) {
@@ -51,40 +57,39 @@ u32 ThreadCreate(u32 parent_tid, bool detached, void *arg) {
 void ThreadContextLsanBase::ThreadStart(u32 tid, tid_t os_id,
                                         ThreadType thread_type, void *arg) {
   thread_registry->StartThread(tid, os_id, thread_type, arg);
-  SetCurrentThread(tid);
 }
 
-void ThreadFinish() {
-  thread_registry->FinishThread(GetCurrentThread());
-  SetCurrentThread(kInvalidTid);
-}
-
-ThreadContext *CurrentThreadContext() {
-  if (!thread_registry)
-    return nullptr;
-  if (GetCurrentThread() == kInvalidTid)
-    return nullptr;
-  // No lock needed when getting current thread.
-  return (ThreadContext *)thread_registry->GetThreadLocked(GetCurrentThread());
-}
+void ThreadFinish() { thread_registry->FinishThread(GetCurrentThreadId()); }
 
 void EnsureMainThreadIDIsCorrect() {
-  if (GetCurrentThread() == kMainTid)
-    CurrentThreadContext()->os_id = GetTid();
+  if (GetCurrentThreadId() == kMainTid)
+    GetCurrentThread()->os_id = GetTid();
 }
 
 ///// Interface to the common LSan module. /////
 
-void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
-                            void *arg) {}
+void GetThreadExtraStackRangesLocked(tid_t os_id,
+                                     InternalMmapVector<Range> *ranges) {}
+void GetThreadExtraStackRangesLocked(InternalMmapVector<Range> *ranges) {}
 
 void LockThreadRegistry() { thread_registry->Lock(); }
 
 void UnlockThreadRegistry() { thread_registry->Unlock(); }
 
-ThreadRegistry *GetThreadRegistryLocked() {
+ThreadRegistry *GetLsanThreadRegistryLocked() {
   thread_registry->CheckLocked();
   return thread_registry;
 }
 
+void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) {
+  GetLsanThreadRegistryLocked()->RunCallbackForEachThreadLocked(
+      [](ThreadContextBase *tctx, void *threads) {
+        if (tctx->status == ThreadStatusRunning) {
+          reinterpret_cast<InternalMmapVector<tid_t> *>(threads)->push_back(
+              tctx->os_id);
+        }
+      },
+      threads);
+}
+
 }  // namespace __lsan
diff --git a/libsanitizer/lsan/lsan_thread.h b/libsanitizer/lsan/lsan_thread.h
index 6ab4172092a..709a02915c2 100644
--- a/libsanitizer/lsan/lsan_thread.h
+++ b/libsanitizer/lsan/lsan_thread.h
@@ -21,6 +21,7 @@ namespace __lsan {
 class ThreadContextLsanBase : public ThreadContextBase {
  public:
   explicit ThreadContextLsanBase(int tid);
+  void OnStarted(void *arg) override;
   void OnFinished() override;
   uptr stack_begin() { return stack_begin_; }
   uptr stack_end() { return stack_end_; }
@@ -45,12 +46,17 @@ class ThreadContext;
 void InitializeThreadRegistry();
 void InitializeMainThread();
 
+ThreadRegistry *GetLsanThreadRegistryLocked();
+
 u32 ThreadCreate(u32 tid, bool detached, void *arg = nullptr);
 void ThreadFinish();
 
-u32 GetCurrentThread();
-void SetCurrentThread(u32 tid);
-ThreadContext *CurrentThreadContext();
+ThreadContextLsanBase *GetCurrentThread();
+inline u32 GetCurrentThreadId() {
+  ThreadContextLsanBase *ctx = GetCurrentThread();
+  return ctx ? ctx->tid : kInvalidTid;
+}
+void SetCurrentThread(ThreadContextLsanBase *tctx);
 void EnsureMainThreadIDIsCorrect();
 
 }  // namespace __lsan
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.cpp b/libsanitizer/sanitizer_common/sanitizer_allocator.cpp
index 25a43a59f04..03392b61503 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator.cpp
@@ -146,12 +146,10 @@ void *LowLevelAllocator::Allocate(uptr size) {
   size = RoundUpTo(size, low_level_alloc_min_alignment);
   if (allocated_end_ - allocated_current_ < (sptr)size) {
     uptr size_to_allocate = RoundUpTo(size, GetPageSizeCached());
-    allocated_current_ =
-        (char*)MmapOrDie(size_to_allocate, __func__);
+    allocated_current_ = (char *)MmapOrDie(size_to_allocate, __func__);
     allocated_end_ = allocated_current_ + size_to_allocate;
     if (low_level_alloc_callback) {
-      low_level_alloc_callback((uptr)allocated_current_,
-                               size_to_allocate);
+      low_level_alloc_callback((uptr)allocated_current_, size_to_allocate);
     }
   }
   CHECK(allocated_end_ - allocated_current_ >= (sptr)size);
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h b/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
index b92cfa5bf4c..b76d36dcf5a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
@@ -134,7 +134,7 @@ class CombinedAllocator {
 
   // This function does the same as GetBlockBegin, but is much faster.
   // Must be called with the allocator locked.
-  void *GetBlockBeginFastLocked(void *p) {
+  void *GetBlockBeginFastLocked(const void *p) {
     if (primary_.PointerIsMine(p))
       return primary_.GetBlockBegin(p);
     return secondary_.GetBlockBeginFastLocked(p);
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h b/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h
index c1b27563e2f..8f3b71eb6ce 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h
@@ -21,6 +21,8 @@ extern "C" {
 SANITIZER_INTERFACE_ATTRIBUTE
 uptr __sanitizer_get_estimated_allocated_size(uptr size);
 SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_get_ownership(const void *p);
+SANITIZER_INTERFACE_ATTRIBUTE const void *__sanitizer_get_allocated_begin(
+    const void *p);
 SANITIZER_INTERFACE_ATTRIBUTE uptr
 __sanitizer_get_allocated_size(const void *p);
 SANITIZER_INTERFACE_ATTRIBUTE uptr __sanitizer_get_current_allocated_bytes();
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h b/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h
index 38994736877..62523c7ae18 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h
@@ -51,7 +51,6 @@ void InternalFree(void *p, InternalAllocatorCache *cache = nullptr);
 void InternalAllocatorLock();
 void InternalAllocatorUnlock();
 InternalAllocator *internal_allocator();
-
 } // namespace __sanitizer
 
 #endif // SANITIZER_ALLOCATOR_INTERNAL_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h b/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h
index 48afb2a2983..15764555560 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h
@@ -215,7 +215,7 @@ class LargeMmapAllocator {
 
   // This function does the same as GetBlockBegin, but is much faster.
   // Must be called with the allocator locked.
-  void *GetBlockBeginFastLocked(void *ptr) {
+  void *GetBlockBeginFastLocked(const void *ptr) {
     mutex_.CheckLocked();
     uptr p = reinterpret_cast<uptr>(ptr);
     uptr n = n_chunks_;
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cpp b/libsanitizer/sanitizer_common/sanitizer_common.cpp
index 82236453157..79b7748b8f6 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_common.cpp
@@ -61,6 +61,26 @@ void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
   UNREACHABLE("unable to mmap");
 }
 
+void NORETURN ReportMunmapFailureAndDie(void *addr, uptr size, error_t err,
+                                        bool raw_report) {
+  static int recursion_count;
+  if (raw_report || recursion_count) {
+    // If raw report is requested or we went into recursion just die.  The
+    // Report() and CHECK calls below may call munmap recursively and fail.
+    RawWrite("ERROR: Failed to munmap\n");
+    Die();
+  }
+  recursion_count++;
+  Report(
+      "ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p (error "
+      "code: %d)\n",
+      SanitizerToolName, size, size, addr, err);
+#if !SANITIZER_GO
+  DumpProcessMap();
+#endif
+  UNREACHABLE("unable to unmmap");
+}
+
 typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
 typedef bool U32ComparisonFunction(const u32 &a, const u32 &b);
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h
index b462e388c23..61d44020ed9 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.h
+++ b/libsanitizer/sanitizer_common/sanitizer_common.h
@@ -211,6 +211,7 @@ class LowLevelAllocator {
  public:
   // Requires an external lock.
   void *Allocate(uptr size);
+
  private:
   char *allocated_end_;
   char *allocated_current_;
@@ -315,6 +316,8 @@ CheckFailed(const char *file, int line, const char *cond, u64 v1, u64 v2);
 void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
                                       const char *mmap_type, error_t err,
                                       bool raw_report = false);
+void NORETURN ReportMunmapFailureAndDie(void *ptr, uptr size, error_t err,
+                                        bool raw_report = false);
 
 // Returns true if the platform-specific error reported is an OOM error.
 bool ErrorIsOOM(error_t err);
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
index ba4b80081f0..3bd73cf8748 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
@@ -23,10 +23,6 @@
 //   COMMON_INTERCEPTOR_SET_THREAD_NAME
 //   COMMON_INTERCEPTOR_DLOPEN
 //   COMMON_INTERCEPTOR_ON_EXIT
-//   COMMON_INTERCEPTOR_MUTEX_PRE_LOCK
-//   COMMON_INTERCEPTOR_MUTEX_POST_LOCK
-//   COMMON_INTERCEPTOR_MUTEX_UNLOCK
-//   COMMON_INTERCEPTOR_MUTEX_REPAIR
 //   COMMON_INTERCEPTOR_SET_PTHREAD_NAME
 //   COMMON_INTERCEPTOR_HANDLE_RECVMSG
 //   COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED
@@ -223,26 +219,6 @@ extern const short *_tolower_tab_;
 #define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) {}
 #endif
 
-#ifndef COMMON_INTERCEPTOR_MUTEX_PRE_LOCK
-#define COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m) {}
-#endif
-
-#ifndef COMMON_INTERCEPTOR_MUTEX_POST_LOCK
-#define COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m) {}
-#endif
-
-#ifndef COMMON_INTERCEPTOR_MUTEX_UNLOCK
-#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) {}
-#endif
-
-#ifndef COMMON_INTERCEPTOR_MUTEX_REPAIR
-#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) {}
-#endif
-
-#ifndef COMMON_INTERCEPTOR_MUTEX_INVALID
-#define COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m) {}
-#endif
-
 #ifndef COMMON_INTERCEPTOR_HANDLE_RECVMSG
 #define COMMON_INTERCEPTOR_HANDLE_RECVMSG(ctx, msg) ((void)(msg))
 #endif
@@ -1374,7 +1350,7 @@ INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3,
     char *name = (char *)arg5;
     COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1);
   }
-  int res = REAL(prctl(option, arg2, arg3, arg4, arg5));
+  int res = REAL(prctl)(option, arg2, arg3, arg4, arg5);
   if (option == PR_SET_NAME) {
     char buff[16];
     internal_strncpy(buff, (char *)arg2, 15);
@@ -4475,90 +4451,13 @@ INTERCEPTOR(void, _exit, int status) {
 #define INIT__EXIT
 #endif
 
-#if SANITIZER_INTERCEPT_PTHREAD_MUTEX
-INTERCEPTOR(int, pthread_mutex_lock, void *m) {
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_lock, m);
-  COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m);
-  int res = REAL(pthread_mutex_lock)(m);
-  if (res == errno_EOWNERDEAD)
-    COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m);
-  if (res == 0 || res == errno_EOWNERDEAD)
-    COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m);
-  if (res == errno_EINVAL)
-    COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m);
-  return res;
-}
-
-INTERCEPTOR(int, pthread_mutex_unlock, void *m) {
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_unlock, m);
-  COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m);
-  int res = REAL(pthread_mutex_unlock)(m);
-  if (res == errno_EINVAL)
-    COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m);
-  return res;
-}
-
-#define INIT_PTHREAD_MUTEX_LOCK COMMON_INTERCEPT_FUNCTION(pthread_mutex_lock)
-#define INIT_PTHREAD_MUTEX_UNLOCK \
-  COMMON_INTERCEPT_FUNCTION(pthread_mutex_unlock)
-#else
-#define INIT_PTHREAD_MUTEX_LOCK
-#define INIT_PTHREAD_MUTEX_UNLOCK
-#endif
-
-#if SANITIZER_INTERCEPT___PTHREAD_MUTEX
-INTERCEPTOR(int, __pthread_mutex_lock, void *m) {
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, __pthread_mutex_lock, m);
-  COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m);
-  int res = REAL(__pthread_mutex_lock)(m);
-  if (res == errno_EOWNERDEAD)
-    COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m);
-  if (res == 0 || res == errno_EOWNERDEAD)
-    COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m);
-  if (res == errno_EINVAL)
-    COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m);
-  return res;
-}
-
-INTERCEPTOR(int, __pthread_mutex_unlock, void *m) {
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, __pthread_mutex_unlock, m);
-  COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m);
-  int res = REAL(__pthread_mutex_unlock)(m);
-  if (res == errno_EINVAL)
-    COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m);
-  return res;
-}
-
-#define INIT___PTHREAD_MUTEX_LOCK \
-  COMMON_INTERCEPT_FUNCTION(__pthread_mutex_lock)
-#define INIT___PTHREAD_MUTEX_UNLOCK \
-  COMMON_INTERCEPT_FUNCTION(__pthread_mutex_unlock)
-#else
-#define INIT___PTHREAD_MUTEX_LOCK
-#define INIT___PTHREAD_MUTEX_UNLOCK
-#endif
-
 #if SANITIZER_INTERCEPT___LIBC_MUTEX
-INTERCEPTOR(int, __libc_mutex_lock, void *m)
-ALIAS(WRAPPER_NAME(pthread_mutex_lock));
-
-INTERCEPTOR(int, __libc_mutex_unlock, void *m)
-ALIAS(WRAPPER_NAME(pthread_mutex_unlock));
-
 INTERCEPTOR(int, __libc_thr_setcancelstate, int state, int *oldstate)
 ALIAS(WRAPPER_NAME(pthread_setcancelstate));
 
-#define INIT___LIBC_MUTEX_LOCK COMMON_INTERCEPT_FUNCTION(__libc_mutex_lock)
-#define INIT___LIBC_MUTEX_UNLOCK COMMON_INTERCEPT_FUNCTION(__libc_mutex_unlock)
 #define INIT___LIBC_THR_SETCANCELSTATE \
   COMMON_INTERCEPT_FUNCTION(__libc_thr_setcancelstate)
 #else
-#define INIT___LIBC_MUTEX_LOCK
-#define INIT___LIBC_MUTEX_UNLOCK
 #define INIT___LIBC_THR_SETCANCELSTATE
 #endif
 
@@ -5864,8 +5763,10 @@ INTERCEPTOR(int, capget, void *hdrp, void *datap) {
   // its metadata. See
   // https://github.com/google/sanitizers/issues/321.
   int res = REAL(capget)(hdrp, datap);
-  if (res == 0 && datap)
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datap, __user_cap_data_struct_sz);
+  if (res == 0 && datap) {
+    unsigned datasz = __user_cap_data_struct_sz(hdrp);
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datap, datasz);
+  }
   // We can also return -1 and write to hdrp->version if the version passed in
   // hdrp->version is unsupported. But that's not a trivial condition to check,
   // and anyway COMMON_INTERCEPTOR_READ_RANGE protects us to some extent.
@@ -5876,8 +5777,10 @@ INTERCEPTOR(int, capset, void *hdrp, const void *datap) {
   COMMON_INTERCEPTOR_ENTER(ctx, capset, hdrp, datap);
   if (hdrp)
     COMMON_INTERCEPTOR_READ_RANGE(ctx, hdrp, __user_cap_header_struct_sz);
-  if (datap)
-    COMMON_INTERCEPTOR_READ_RANGE(ctx, datap, __user_cap_data_struct_sz);
+  if (datap) {
+    unsigned datasz = __user_cap_data_struct_sz(hdrp);
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, datap, datasz);
+  }
   return REAL(capset)(hdrp, datap);
 }
 #define INIT_CAPGET                  \
@@ -10458,6 +10361,39 @@ INTERCEPTOR(int, __xuname, int size, void *utsname) {
 #define INIT___XUNAME
 #endif
 
+#if SANITIZER_INTERCEPT_HEXDUMP
+INTERCEPTOR(void, hexdump, const void *ptr, int length, const char *header, int flags) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, hexdump, ptr, length, header, flags);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, length);
+  COMMON_INTERCEPTOR_READ_RANGE(ctx, header, internal_strlen(header) + 1);
+  REAL(hexdump)(ptr, length, header, flags);
+}
+
+#define INIT_HEXDUMP COMMON_INTERCEPT_FUNCTION(hexdump);
+#else
+#define INIT_HEXDUMP
+#endif
+
+#if SANITIZER_INTERCEPT_ARGP_PARSE
+INTERCEPTOR(int, argp_parse, const struct argp *argp, int argc, char **argv,
+            unsigned flags, int *arg_index, void *input) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, argp_parse, argp, argc, argv, flags, arg_index,
+                           input);
+  for (int i = 0; i < argc; i++)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, argv[i], internal_strlen(argv[i]) + 1);
+  int res = REAL(argp_parse)(argp, argc, argv, flags, arg_index, input);
+  if (!res && arg_index)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, arg_index, sizeof(int));
+  return res;
+}
+
+#define INIT_ARGP_PARSE COMMON_INTERCEPT_FUNCTION(argp_parse);
+#else
+#define INIT_ARGP_PARSE
+#endif
+
 #include "sanitizer_common_interceptors_netbsd_compat.inc"
 
 static void InitializeCommonInterceptors() {
@@ -10604,12 +10540,6 @@ static void InitializeCommonInterceptors() {
   INIT_PTHREAD_SIGMASK;
   INIT_BACKTRACE;
   INIT__EXIT;
-  INIT_PTHREAD_MUTEX_LOCK;
-  INIT_PTHREAD_MUTEX_UNLOCK;
-  INIT___PTHREAD_MUTEX_LOCK;
-  INIT___PTHREAD_MUTEX_UNLOCK;
-  INIT___LIBC_MUTEX_LOCK;
-  INIT___LIBC_MUTEX_UNLOCK;
   INIT___LIBC_THR_SETCANCELSTATE;
   INIT_GETMNTENT;
   INIT_GETMNTENT_R;
@@ -10782,6 +10712,8 @@ static void InitializeCommonInterceptors() {
   INIT_PROCCTL
   INIT_UNAME;
   INIT___XUNAME;
+  INIT_HEXDUMP;
+  INIT_ARGP_PARSE;
 
   INIT___PRINTF_CHK;
 }
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
index 932e5478616..01be600e33b 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
@@ -9,12 +9,16 @@
 //===----------------------------------------------------------------------===//
 INTERFACE_FUNCTION(__sanitizer_acquire_crash_state)
 INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container)
+INTERFACE_FUNCTION(__sanitizer_annotate_double_ended_contiguous_container)
 INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
+INTERFACE_FUNCTION(
+    __sanitizer_double_ended_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_FUNCTION(__sanitizer_verify_double_ended_contiguous_container)
 INTERFACE_WEAK_FUNCTION(__sanitizer_on_print)
 INTERFACE_WEAK_FUNCTION(__sanitizer_report_error_summary)
 INTERFACE_WEAK_FUNCTION(__sanitizer_sandbox_on_notify)
@@ -28,6 +32,7 @@ INTERFACE_FUNCTION(__sanitizer_get_module_and_offset_for_pc)
 INTERFACE_FUNCTION(__sanitizer_symbolize_global)
 INTERFACE_FUNCTION(__sanitizer_symbolize_pc)
 // Allocator interface.
+INTERFACE_FUNCTION(__sanitizer_get_allocated_begin)
 INTERFACE_FUNCTION(__sanitizer_get_allocated_size)
 INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes)
 INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size)
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
index a38b134085a..93b988ba163 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
@@ -417,14 +417,14 @@ PRE_SYSCALL(capget)(void *header, void *dataptr) {
 POST_SYSCALL(capget)(long res, void *header, void *dataptr) {
   if (res >= 0)
     if (dataptr)
-      POST_WRITE(dataptr, __user_cap_data_struct_sz);
+      POST_WRITE(dataptr, __user_cap_data_struct_sz(header));
 }
 
 PRE_SYSCALL(capset)(void *header, const void *data) {
   if (header)
     PRE_READ(header, __user_cap_header_struct_sz);
   if (data)
-    PRE_READ(data, __user_cap_data_struct_sz);
+    PRE_READ(data, __user_cap_data_struct_sz(header));
 }
 
 POST_SYSCALL(capset)(long res, void *header, const void *data) {}
@@ -910,24 +910,26 @@ POST_SYSCALL(statfs)(long res, const void *path, void *buf) {
   }
 }
 
-PRE_SYSCALL(statfs64)(const void *path, long sz, void *buf) {
-  if (path)
-    PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
-}
+PRE_SYSCALL(fstatfs)(long fd, void *buf) {}
 
-POST_SYSCALL(statfs64)(long res, const void *path, long sz, void *buf) {
+POST_SYSCALL(fstatfs)(long res, long fd, void *buf) {
   if (res >= 0) {
     if (buf)
-      POST_WRITE(buf, struct_statfs64_sz);
+      POST_WRITE(buf, struct_statfs_sz);
   }
 }
+#  endif  // !SANITIZER_ANDROID
 
-PRE_SYSCALL(fstatfs)(long fd, void *buf) {}
+#  if SANITIZER_GLIBC
+PRE_SYSCALL(statfs64)(const void *path, long sz, void *buf) {
+  if (path)
+    PRE_READ(path, __sanitizer::internal_strlen((const char *)path) + 1);
+}
 
-POST_SYSCALL(fstatfs)(long res, long fd, void *buf) {
+POST_SYSCALL(statfs64)(long res, const void *path, long sz, void *buf) {
   if (res >= 0) {
     if (buf)
-      POST_WRITE(buf, struct_statfs_sz);
+      POST_WRITE(buf, struct_statfs64_sz);
   }
 }
 
@@ -939,7 +941,7 @@ POST_SYSCALL(fstatfs64)(long res, long fd, long sz, void *buf) {
       POST_WRITE(buf, struct_statfs64_sz);
   }
 }
-#  endif  // !SANITIZER_ANDROID
+#  endif  // SANITIZER_GLIBC
 
 PRE_SYSCALL(lstat)(const void *filename, void *statbuf) {
   if (filename)
@@ -998,7 +1000,7 @@ POST_SYSCALL(newfstat)(long res, long fd, void *statbuf) {
   }
 }
 
-#  if !SANITIZER_ANDROID
+#  if SANITIZER_GLIBC
 PRE_SYSCALL(ustat)(long dev, void *ubuf) {}
 
 POST_SYSCALL(ustat)(long res, long dev, void *ubuf) {
@@ -1007,7 +1009,7 @@ POST_SYSCALL(ustat)(long res, long dev, void *ubuf) {
       POST_WRITE(ubuf, struct_ustat_sz);
   }
 }
-#  endif  // !SANITIZER_ANDROID
+#  endif  // SANITIZER_GLIBC
 
 PRE_SYSCALL(stat64)(const void *filename, void *statbuf) {
   if (filename)
@@ -2106,6 +2108,7 @@ PRE_SYSCALL(epoll_wait)
 POST_SYSCALL(epoll_wait)
 (long res, long epfd, void *events, long maxevents, long timeout) {
   if (res >= 0) {
+    COMMON_SYSCALL_FD_ACQUIRE(epfd);
     if (events)
       POST_WRITE(events, res * struct_epoll_event_sz);
   }
@@ -2122,6 +2125,7 @@ POST_SYSCALL(epoll_pwait)
 (long res, long epfd, void *events, long maxevents, long timeout,
  const void *sigmask, long sigsetsize) {
   if (res >= 0) {
+    COMMON_SYSCALL_FD_ACQUIRE(epfd);
     if (events)
       POST_WRITE(events, res * struct_epoll_event_sz);
   }
@@ -2142,6 +2146,7 @@ POST_SYSCALL(epoll_pwait2)
  const sanitizer_kernel_timespec *timeout, const void *sigmask,
  long sigsetsize) {
   if (res >= 0) {
+    COMMON_SYSCALL_FD_ACQUIRE(epfd);
     if (events)
       POST_WRITE(events, res * struct_epoll_event_sz);
   }
@@ -2228,7 +2233,7 @@ POST_SYSCALL(setrlimit)(long res, long resource, void *rlim) {
   }
 }
 
-#  if !SANITIZER_ANDROID
+#  if SANITIZER_GLIBC
 PRE_SYSCALL(prlimit64)
 (long pid, long resource, const void *new_rlim, void *old_rlim) {
   if (new_rlim)
@@ -2512,7 +2517,7 @@ PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
 #  if !SANITIZER_ANDROID &&                                                   \
       (defined(__i386) || defined(__x86_64) || defined(__mips64) ||           \
        defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \
-       SANITIZER_RISCV64)
+       defined(__loongarch__) || SANITIZER_RISCV64)
   if (data) {
     if (request == ptrace_setregs) {
       PRE_READ((void *)data, struct_user_regs_struct_sz);
@@ -2534,7 +2539,7 @@ POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) {
 #  if !SANITIZER_ANDROID &&                                                   \
       (defined(__i386) || defined(__x86_64) || defined(__mips64) ||           \
        defined(__powerpc64__) || defined(__aarch64__) || defined(__s390__) || \
-       SANITIZER_RISCV64)
+       defined(__loongarch__) || SANITIZER_RISCV64)
   if (res >= 0 && data) {
     // Note that this is different from the interceptor in
     // sanitizer_common_interceptors.inc.
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
index 956b48e0b43..ce432696718 100644
--- a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
@@ -282,7 +282,14 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, const uptr* beg,
 // Weak definition for code instrumented with -fsanitize-coverage=stack-depth
 // and later linked with code containing a strong definition.
 // E.g., -fsanitize=fuzzer-no-link
+// FIXME: Update Apple deployment target so that thread_local is always
+// supported, and remove the #if.
+// FIXME: Figure out how this should work on Windows, exported thread_local
+// symbols are not supported:
+// "data with thread storage duration may not have dll interface"
+#if !SANITIZER_APPLE && !SANITIZER_WINDOWS
 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE uptr __sancov_lowest_stack;
+thread_local uptr __sancov_lowest_stack;
+#endif
 
 #endif  // !SANITIZER_FUCHSIA
diff --git a/libsanitizer/sanitizer_common/sanitizer_errno_codes.h b/libsanitizer/sanitizer_common/sanitizer_errno_codes.h
index 192e9392d49..3917b2817f2 100644
--- a/libsanitizer/sanitizer_common/sanitizer_errno_codes.h
+++ b/libsanitizer/sanitizer_common/sanitizer_errno_codes.h
@@ -25,6 +25,7 @@ namespace __sanitizer {
 #define errno_EBUSY 16
 #define errno_EINVAL 22
 #define errno_ENAMETOOLONG 36
+#define errno_ENOSYS 38
 
 // Those might not present or their value differ on different platforms.
 extern const int errno_EOWNERDEAD;
diff --git a/libsanitizer/sanitizer_common/sanitizer_file.h b/libsanitizer/sanitizer_common/sanitizer_file.h
index 810c1e452f6..9459c6b00ac 100644
--- a/libsanitizer/sanitizer_common/sanitizer_file.h
+++ b/libsanitizer/sanitizer_common/sanitizer_file.h
@@ -15,6 +15,7 @@
 #ifndef SANITIZER_FILE_H
 #define SANITIZER_FILE_H
 
+#include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_libc.h"
 #include "sanitizer_mutex.h"
diff --git a/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp b/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp
index 9e274268bf2..c620da7f220 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_flag_parser.cpp
@@ -13,9 +13,9 @@
 #include "sanitizer_flag_parser.h"
 
 #include "sanitizer_common.h"
-#include "sanitizer_libc.h"
-#include "sanitizer_flags.h"
 #include "sanitizer_flag_parser.h"
+#include "sanitizer_flags.h"
+#include "sanitizer_libc.h"
 
 namespace __sanitizer {
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_flag_parser.h b/libsanitizer/sanitizer_common/sanitizer_flag_parser.h
index 3ccc6a6fa53..ae49294dde9 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flag_parser.h
+++ b/libsanitizer/sanitizer_common/sanitizer_flag_parser.h
@@ -13,9 +13,9 @@
 #ifndef SANITIZER_FLAG_REGISTRY_H
 #define SANITIZER_FLAG_REGISTRY_H
 
+#include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_libc.h"
-#include "sanitizer_common.h"
 
 namespace __sanitizer {
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc b/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
index 9683b97ab91..16b2a10d8b0 100644
--- a/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_interceptors_ioctl_netbsd.inc
@@ -1267,8 +1267,6 @@ static void ioctl_table_fill() {
   _(TIOCGFLAGS, WRITE, sizeof(int));
   _(TIOCSFLAGS, READ, sizeof(int));
   _(TIOCDCDTIMESTAMP, WRITE, struct_timeval_sz);
-  _(TIOCRCVFRAME, READ, sizeof(uptr));
-  _(TIOCXMTFRAME, READ, sizeof(uptr));
   _(TIOCPTMGET, WRITE, struct_ptmget_sz);
   _(TIOCGRANTPT, NONE, 0);
   _(TIOCPTSNAME, WRITE, struct_ptmget_sz);
diff --git a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
index ad34e5e5ba5..cd0d45e2f3f 100644
--- a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
+++ b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
@@ -66,18 +66,30 @@ void __sanitizer_annotate_contiguous_container(const void *beg, const void *end,
                                                const void *old_mid,
                                                const void *new_mid);
 SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_annotate_double_ended_contiguous_container(
+    const void *storage_beg, const void *storage_end,
+    const void *old_container_beg, const void *old_container_end,
+    const void *new_container_beg, const void *new_container_end);
+SANITIZER_INTERFACE_ATTRIBUTE
 int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
                                             const void *end);
 SANITIZER_INTERFACE_ATTRIBUTE
+int __sanitizer_verify_double_ended_contiguous_container(
+    const void *storage_beg, const void *container_beg,
+    const void *container_end, const void *storage_end);
+SANITIZER_INTERFACE_ATTRIBUTE
 const void *__sanitizer_contiguous_container_find_bad_address(const void *beg,
                                                               const void *mid,
                                                               const void *end);
+SANITIZER_INTERFACE_ATTRIBUTE
+const void *__sanitizer_double_ended_contiguous_container_find_bad_address(
+    const void *storage_beg, const void *container_beg,
+    const void *container_end, const void *storage_end);
 
 SANITIZER_INTERFACE_ATTRIBUTE
 int __sanitizer_get_module_and_offset_for_pc(void *pc, char *module_path,
                                              __sanitizer::uptr module_path_len,
                                              void **pc_offset);
-
 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
 __sanitizer_cov_trace_cmp();
 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
index 6b800820ab8..98186c429e9 100644
--- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
+++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
@@ -37,15 +37,6 @@
 # define SANITIZER_WEAK_ATTRIBUTE  __attribute__((weak))
 #endif
 
-// TLS is handled differently on different platforms
-#if SANITIZER_LINUX || SANITIZER_NETBSD || \
-  SANITIZER_FREEBSD
-# define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE \
-    __attribute__((tls_model("initial-exec"))) thread_local
-#else
-# define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE
-#endif
-
 //--------------------------- WEAK FUNCTIONS ---------------------------------//
 // When working with weak functions, to simplify the code and make it more
 // portable, when possible define a default implementation using this macro:
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
index f23ea9da371..24c6acaa9e5 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
@@ -440,7 +440,7 @@ uptr internal_fstat(fd_t fd, void *buf) {
   return res;
 #      elif SANITIZER_LINUX && defined(__loongarch__)
   struct statx bufx;
-  int res = internal_syscall(SYSCALL(statx), fd, 0, AT_EMPTY_PATH,
+  int res = internal_syscall(SYSCALL(statx), fd, "", AT_EMPTY_PATH,
                              STATX_BASIC_STATS, (uptr)&bufx);
   statx_to_stat(&bufx, (struct stat *)buf);
   return res;
@@ -1502,6 +1502,47 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
                        : "x30", "memory");
   return res;
 }
+#elif SANITIZER_LOONGARCH64
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+                    int *parent_tidptr, void *newtls, int *child_tidptr) {
+  if (!fn || !child_stack)
+    return -EINVAL;
+
+  CHECK_EQ(0, (uptr)child_stack % 16);
+
+  register int res __asm__("$a0");
+  register int __flags __asm__("$a0") = flags;
+  register void *__stack __asm__("$a1") = child_stack;
+  register int *__ptid __asm__("$a2") = parent_tidptr;
+  register int *__ctid __asm__("$a3") = child_tidptr;
+  register void *__tls __asm__("$a4") = newtls;
+  register int (*__fn)(void *) __asm__("$a5") = fn;
+  register void *__arg __asm__("$a6") = arg;
+  register int nr_clone __asm__("$a7") = __NR_clone;
+
+  __asm__ __volatile__(
+      "syscall 0\n"
+
+      // if ($a0 != 0)
+      //   return $a0;
+      "bnez $a0, 1f\n"
+
+      // In the child, now. Call "fn(arg)".
+      "move $a0, $a6\n"
+      "jirl $ra, $a5, 0\n"
+
+      // Call _exit($a0).
+      "addi.d $a7, $zero, %9\n"
+      "syscall 0\n"
+
+      "1:\n"
+
+      : "=r"(res)
+      : "0"(__flags), "r"(__stack), "r"(__ptid), "r"(__ctid), "r"(__tls),
+        "r"(__fn), "r"(__arg), "r"(nr_clone), "i"(__NR_exit)
+      : "memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$t8");
+  return res;
+}
 #elif defined(__powerpc64__)
 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
                    int *parent_tidptr, void *newtls, int *child_tidptr) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h b/libsanitizer/sanitizer_common/sanitizer_linux.h
index 761c57d1b8e..c84c04a8775 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux.h
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.h
@@ -77,9 +77,9 @@ uptr internal_arch_prctl(int option, uptr arg2);
 // internal_sigaction instead.
 int internal_sigaction_norestorer(int signum, const void *act, void *oldact);
 void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
-#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \
-    defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \
-    defined(__arm__) || SANITIZER_RISCV64
+#    if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \
+        defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \
+        defined(__arm__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64
 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
                     int *parent_tidptr, void *newtls, int *child_tidptr);
 #endif
@@ -152,6 +152,9 @@ inline void ReleaseMemoryPagesToOSAndZeroFill(uptr beg, uptr end) {
                "rdhwr   %0,$29\n" \
                ".set    pop\n" : "=r"(__v)); \
        __v; })
+#elif defined (__riscv)
+# define __get_tls() \
+    ({ void** __v; __asm__("mv %0, tp" : "=r"(__v)); __v; })
 #elif defined(__i386__)
 # define __get_tls() \
     ({ void** __v; __asm__("movl %%gs:0, %0" : "=r"(__v)); __v; })
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
index 56d231643ba..37b2b57c0c8 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
@@ -205,7 +205,8 @@ void InitTlsSize() {
   g_use_dlpi_tls_data =
       GetLibcVersion(&major, &minor, &patch) && major == 2 && minor >= 25;
 
-#if defined(__aarch64__) || defined(__x86_64__) || defined(__powerpc64__)
+#if defined(__aarch64__) || defined(__x86_64__) || defined(__powerpc64__) || \
+    defined(__loongarch__)
   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);
@@ -265,6 +266,8 @@ static uptr ThreadDescriptorSizeFallback() {
 #elif defined(__mips__)
   // TODO(sagarthakur): add more values as per different glibc versions.
   val = FIRST_32_SECOND_64(1152, 1776);
+#elif SANITIZER_LOONGARCH64
+  val = 1856; // from glibc 2.36
 #elif SANITIZER_RISCV64
   int major;
   int minor;
@@ -304,7 +307,8 @@ uptr ThreadDescriptorSize() {
   return val;
 }
 
-#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
+#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64 || \
+    SANITIZER_LOONGARCH64
 // TlsPreTcbSize includes size of struct pthread_descr and size of tcb
 // head structure. It lies before the static tls blocks.
 static uptr TlsPreTcbSize() {
@@ -314,6 +318,8 @@ static uptr TlsPreTcbSize() {
   const uptr kTcbHead = 88; // sizeof (tcbhead_t)
 #elif SANITIZER_RISCV64
   const uptr kTcbHead = 16;  // sizeof (tcbhead_t)
+#elif SANITIZER_LOONGARCH64
+  const uptr kTcbHead = 16;  // sizeof (tcbhead_t)
 #endif
   const uptr kTlsAlign = 16;
   const uptr kTlsPreTcbSize =
@@ -500,6 +506,15 @@ static void GetTls(uptr *addr, uptr *size) {
   *addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
           ThreadDescriptorSize();
   *size = g_tls_size + ThreadDescriptorSize();
+#elif SANITIZER_GLIBC && defined(__loongarch__)
+#  ifdef __clang__
+  *addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
+          ThreadDescriptorSize();
+#  else
+  asm("or %0,$tp,$zero" : "=r"(*addr));
+  *addr -= ThreadDescriptorSize();
+#  endif
+  *size = g_tls_size + ThreadDescriptorSize();
 #elif SANITIZER_GLIBC && defined(__powerpc64__)
   // Workaround for glibc<2.25(?). 2.27 is known to not need this.
   uptr tp;
@@ -568,6 +583,7 @@ static void GetTls(uptr *addr, uptr *size) {
       *addr = (uptr)tcb->tcb_dtv[1];
     }
   }
+#else
 #error "Unknown OS"
 #endif
 }
@@ -822,13 +838,9 @@ u32 GetNumberOfCPUs() {
 #elif SANITIZER_SOLARIS
   return sysconf(_SC_NPROCESSORS_ONLN);
 #else
-#if defined(CPU_COUNT)
   cpu_set_t CPUs;
   CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0);
   return CPU_COUNT(&CPUs);
-#else
-  return 1;
-#endif
 #endif
 }
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
index a2591e996e7..24e3d111252 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mac.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
@@ -12,89 +12,81 @@
 
 #include "sanitizer_platform.h"
 #if SANITIZER_APPLE
-#include "sanitizer_mac.h"
-#include "interception/interception.h"
+#  include "interception/interception.h"
+#  include "sanitizer_mac.h"
 
 // Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so
 // the clients will most certainly use 64-bit ones as well.
-#ifndef _DARWIN_USE_64_BIT_INODE
-#define _DARWIN_USE_64_BIT_INODE 1
-#endif
-#include <stdio.h>
-
-#include "sanitizer_common.h"
-#include "sanitizer_file.h"
-#include "sanitizer_flags.h"
-#include "sanitizer_interface_internal.h"
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_libc.h"
-#include "sanitizer_platform_limits_posix.h"
-#include "sanitizer_procmaps.h"
-#include "sanitizer_ptrauth.h"
-
-#if !SANITIZER_IOS
-#include <crt_externs.h>  // for _NSGetEnviron
-#else
+#  ifndef _DARWIN_USE_64_BIT_INODE
+#    define _DARWIN_USE_64_BIT_INODE 1
+#  endif
+#  include <stdio.h>
+
+#  include "sanitizer_common.h"
+#  include "sanitizer_file.h"
+#  include "sanitizer_flags.h"
+#  include "sanitizer_interface_internal.h"
+#  include "sanitizer_internal_defs.h"
+#  include "sanitizer_libc.h"
+#  include "sanitizer_platform_limits_posix.h"
+#  include "sanitizer_procmaps.h"
+#  include "sanitizer_ptrauth.h"
+
+#  if !SANITIZER_IOS
+#    include <crt_externs.h>  // for _NSGetEnviron
+#  else
 extern char **environ;
-#endif
+#  endif
 
-#if defined(__has_include) && __has_include(<os/trace.h>) && defined(__BLOCKS__)
-#define SANITIZER_OS_TRACE 1
-#include <os/trace.h>
-#else
-#define SANITIZER_OS_TRACE 0
-#endif
+#  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 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
+#  if !SANITIZER_IOS
+#    include <crt_externs.h>  // for _NSGetArgv and _NSGetEnviron
+#  else
 extern "C" {
-  extern char ***_NSGetArgv(void);
+extern char ***_NSGetArgv(void);
 }
-#endif
+#  endif
 
-#include <asl.h>
-#include <dlfcn.h>  // for dladdr()
-#include <errno.h>
-#include <fcntl.h>
-#include <libkern/OSAtomic.h>
-#include <mach-o/dyld.h>
-#include <mach/mach.h>
-#include <mach/mach_time.h>
-#include <mach/vm_statistics.h>
-#include <malloc/malloc.h>
-#if defined(__has_builtin) && __has_builtin(__builtin_os_log_format)
-# include <os/log.h>
-#else
-   /* Without support for __builtin_os_log_format, fall back to the older
-      method.  */
-# define OS_LOG_DEFAULT 0
-# define os_log_error(A,B,C) \
-  asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", (C));
-#endif
-#include <pthread.h>
-#include <pthread/introspection.h>
-#include <sched.h>
-#include <signal.h>
-#include <spawn.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <sys/sysctl.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <util.h>
+#  include <asl.h>
+#  include <dlfcn.h>  // for dladdr()
+#  include <errno.h>
+#  include <fcntl.h>
+#  include <libkern/OSAtomic.h>
+#  include <mach-o/dyld.h>
+#  include <mach/mach.h>
+#  include <mach/mach_time.h>
+#  include <mach/vm_statistics.h>
+#  include <malloc/malloc.h>
+#  include <os/log.h>
+#  include <pthread.h>
+#  include <pthread/introspection.h>
+#  include <sched.h>
+#  include <signal.h>
+#  include <spawn.h>
+#  include <stdlib.h>
+#  include <sys/ioctl.h>
+#  include <sys/mman.h>
+#  include <sys/resource.h>
+#  include <sys/stat.h>
+#  include <sys/sysctl.h>
+#  include <sys/types.h>
+#  include <sys/wait.h>
+#  include <unistd.h>
+#  include <util.h>
 
 // From <crt_externs.h>, but we don't have that file on iOS.
 extern "C" {
@@ -997,7 +989,7 @@ static void VerifyInterceptorsWorking() {
   // "wrap_puts" within our own dylib.
   Dl_info info_puts, info_runtime;
   RAW_CHECK(dladdr(dlsym(RTLD_DEFAULT, "puts"), &info_puts));
-  RAW_CHECK(dladdr((void *)__sanitizer_report_error_summary, &info_runtime));
+  RAW_CHECK(dladdr((void *)&VerifyInterceptorsWorking, &info_runtime));
   if (internal_strcmp(info_puts.dli_fname, info_runtime.dli_fname) != 0) {
     Report(
         "ERROR: Interceptors are not working. This may be because %s is "
@@ -1047,7 +1039,7 @@ static void StripEnv() {
     return;
 
   Dl_info info;
-  RAW_CHECK(dladdr((void *)__sanitizer_report_error_summary, &info));
+  RAW_CHECK(dladdr((void *)&StripEnv, &info));
   const char *dylib_name = StripModuleName(info.dli_fname);
   bool lib_is_in_env = internal_strstr(dyld_insert_libraries, dylib_name);
   if (!lib_is_in_env)
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_mac.h
index 1cf2e298cc9..f0a97d098ee 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_APPLE
 #include "sanitizer_posix.h"
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_mallinfo.h b/libsanitizer/sanitizer_common/sanitizer_mallinfo.h
new file mode 100644
index 00000000000..4e58c02df83
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_mallinfo.h
@@ -0,0 +1,38 @@
+//===-- sanitizer_mallinfo.h ----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer common code.
+//
+// Definition for mallinfo on different platforms.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_MALLINFO_H
+#define SANITIZER_MALLINFO_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform.h"
+
+namespace __sanitizer {
+
+#if SANITIZER_ANDROID
+
+struct __sanitizer_struct_mallinfo {
+  uptr v[10];
+};
+
+#elif SANITIZER_LINUX || SANITIZER_APPLE || SANITIZER_FUCHSIA
+
+struct __sanitizer_struct_mallinfo {
+  int v[10];
+};
+
+#endif
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_MALLINFO_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform.h b/libsanitizer/sanitizer_common/sanitizer_platform.h
index 7ecc465bea9..764996e5735 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform.h
@@ -279,15 +279,14 @@
 #endif
 
 // By default we allow to use SizeClassAllocator64 on 64-bit platform.
-// But in some cases (e.g. AArch64's 39-bit address space) SizeClassAllocator64
-// does not work well and we need to fallback to SizeClassAllocator32.
+// But in some cases SizeClassAllocator64 does not work well and we need to
+// fallback to SizeClassAllocator32.
 // For such platforms build this code with -DSANITIZER_CAN_USE_ALLOCATOR64=0 or
 // change the definition of SANITIZER_CAN_USE_ALLOCATOR64 here.
 #ifndef SANITIZER_CAN_USE_ALLOCATOR64
-#  if (SANITIZER_ANDROID && defined(__aarch64__)) || SANITIZER_FUCHSIA
-#    define SANITIZER_CAN_USE_ALLOCATOR64 1
-#  elif defined(__mips64) || defined(__arm__) || defined(__i386__) || \
-      SANITIZER_RISCV64 || defined(__hexagon__)
+#  if SANITIZER_RISCV64 || SANITIZER_IOS
+#    define SANITIZER_CAN_USE_ALLOCATOR64 0
+#  elif defined(__mips64) || defined(__hexagon__)
 #    define SANITIZER_CAN_USE_ALLOCATOR64 0
 #  else
 #    define SANITIZER_CAN_USE_ALLOCATOR64 (SANITIZER_WORDSIZE == 64)
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
index 8307b1ec28b..eb39fabfd59 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
@@ -269,11 +269,11 @@
 #define SANITIZER_INTERCEPT_INET_ATON SI_POSIX
 #define SANITIZER_INTERCEPT_SYSINFO SI_LINUX
 #define SANITIZER_INTERCEPT_READDIR SI_POSIX
-#define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
+#define SANITIZER_INTERCEPT_READDIR64 SI_GLIBC || SI_SOLARIS32
 #if SI_LINUX_NOT_ANDROID &&                                                \
     (defined(__i386) || defined(__x86_64) || defined(__mips64) ||          \
      defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
-     defined(__s390__) || SANITIZER_RISCV64)
+     defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64)
 #define SANITIZER_INTERCEPT_PTRACE 1
 #else
 #define SANITIZER_INTERCEPT_PTRACE 0
@@ -308,7 +308,7 @@
 #define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_SCANDIR \
   (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID || SI_SOLARIS32
+#define SANITIZER_INTERCEPT_SCANDIR64 SI_GLIBC || SI_SOLARIS32
 #define SANITIZER_INTERCEPT_GETGROUPS SI_POSIX
 #define SANITIZER_INTERCEPT_POLL SI_POSIX
 #define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID || SI_SOLARIS
@@ -330,10 +330,10 @@
 #define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_STATFS \
   (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_STATFS64 SI_LINUX_NOT_ANDROID && SANITIZER_HAS_STATFS64
+#define SANITIZER_INTERCEPT_STATFS64 SI_GLIBC && SANITIZER_HAS_STATFS64
 #define SANITIZER_INTERCEPT_STATVFS \
   (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
-#define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STATVFS64 SI_GLIBC
 #define SANITIZER_INTERCEPT_INITGROUPS SI_POSIX
 #define SANITIZER_INTERCEPT_ETHER_NTOA_ATON SI_POSIX
 #define SANITIZER_INTERCEPT_ETHER_HOST \
@@ -396,8 +396,6 @@
 #define SANITIZER_INTERCEPT__EXIT \
   (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_MAC || SI_SOLARIS)
 
-#define SANITIZER_INTERCEPT_PTHREAD_MUTEX SI_POSIX
-#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_GLIBC || SI_SOLARIS)
@@ -471,9 +469,9 @@
 #define SANITIZER_INTERCEPT_LSTAT (SI_NETBSD || SI_FREEBSD || SI_STAT_LINUX)
 #define SANITIZER_INTERCEPT___XSTAT \
   ((!SANITIZER_INTERCEPT_STAT && SI_POSIX) || SI_STAT_LINUX)
-#define SANITIZER_INTERCEPT___XSTAT64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT___XSTAT64 SI_GLIBC
 #define SANITIZER_INTERCEPT___LXSTAT SANITIZER_INTERCEPT___XSTAT
-#define SANITIZER_INTERCEPT___LXSTAT64 SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT___LXSTAT64 SI_GLIBC
 
 #define SANITIZER_INTERCEPT_UTMP \
   (SI_POSIX && !SI_MAC && !SI_FREEBSD && !SI_NETBSD)
@@ -484,7 +482,7 @@
   (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD)
 
 #define SANITIZER_INTERCEPT_MMAP SI_POSIX
-#define SANITIZER_INTERCEPT_MMAP64 SI_LINUX_NOT_ANDROID || SI_SOLARIS
+#define SANITIZER_INTERCEPT_MMAP64 SI_GLIBC || SI_SOLARIS
 #define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO (SI_GLIBC || SI_ANDROID)
 #define SANITIZER_INTERCEPT_MEMALIGN (!SI_FREEBSD && !SI_MAC && !SI_NETBSD)
 #define SANITIZER_INTERCEPT___LIBC_MEMALIGN SI_GLIBC
@@ -593,6 +591,8 @@
 #define SANITIZER_INTERCEPT___XUNAME SI_FREEBSD
 #define SANITIZER_INTERCEPT_FLOPEN SI_FREEBSD
 #define SANITIZER_INTERCEPT_PROCCTL SI_FREEBSD
+#define SANITIZER_INTERCEPT_HEXDUMP SI_FREEBSD
+#define SANITIZER_INTERCEPT_ARGP_PARSE SI_GLIBC
 
 // This macro gives a way for downstream users to override the above
 // interceptor macros irrespective of the platform they are on. They have
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
index c278c8797f7..bf0f355847c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
@@ -26,10 +26,7 @@
 
 // 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__) || defined(__mips__) || defined(__hexagon__)
 #    include <sys/stat.h>
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
index 648e502b904..c40877ba48d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cpp
@@ -2342,8 +2342,6 @@ unsigned IOCTL_TIOCDRAIN = TIOCDRAIN;
 unsigned IOCTL_TIOCGFLAGS = TIOCGFLAGS;
 unsigned IOCTL_TIOCSFLAGS = TIOCSFLAGS;
 unsigned IOCTL_TIOCDCDTIMESTAMP = TIOCDCDTIMESTAMP;
-unsigned IOCTL_TIOCRCVFRAME = TIOCRCVFRAME;
-unsigned IOCTL_TIOCXMTFRAME = TIOCXMTFRAME;
 unsigned IOCTL_TIOCPTMGET = TIOCPTMGET;
 unsigned IOCTL_TIOCGRANTPT = TIOCGRANTPT;
 unsigned IOCTL_TIOCPTSNAME = TIOCPTSNAME;
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h
index dc6eb59b280..4c697b4d107 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h
@@ -2195,8 +2195,6 @@ extern unsigned IOCTL_TIOCDRAIN;
 extern unsigned IOCTL_TIOCGFLAGS;
 extern unsigned IOCTL_TIOCSFLAGS;
 extern unsigned IOCTL_TIOCDCDTIMESTAMP;
-extern unsigned IOCTL_TIOCRCVFRAME;
-extern unsigned IOCTL_TIOCXMTFRAME;
 extern unsigned IOCTL_TIOCPTMGET;
 extern unsigned IOCTL_TIOCGRANTPT;
 extern unsigned IOCTL_TIOCPTSNAME;
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
index c85cf1626a7..a04eed7aa5a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
@@ -18,6 +18,7 @@
 // depends on _FILE_OFFSET_BITS setting.
 // To get this "true" dirent definition, we undefine _FILE_OFFSET_BITS below.
 #undef _FILE_OFFSET_BITS
+#undef _TIME_BITS
 #endif
 
 // Must go after undef _FILE_OFFSET_BITS.
@@ -94,7 +95,7 @@
 # include <utime.h>
 # include <sys/ptrace.h>
 #    if defined(__mips64) || defined(__aarch64__) || defined(__arm__) || \
-        defined(__hexagon__) || SANITIZER_RISCV64
+        defined(__hexagon__) || defined(__loongarch__) ||SANITIZER_RISCV64
 #      include <asm/ptrace.h>
 #      ifdef __arm__
 typedef struct user_fpregs elf_fpregset_t;
@@ -247,7 +248,23 @@ namespace __sanitizer {
   unsigned struct_sysinfo_sz = sizeof(struct sysinfo);
   unsigned __user_cap_header_struct_sz =
       sizeof(struct __user_cap_header_struct);
-  unsigned __user_cap_data_struct_sz = sizeof(struct __user_cap_data_struct);
+  unsigned __user_cap_data_struct_sz(void *hdrp) {
+    int u32s = 0;
+    if (hdrp) {
+      switch (((struct __user_cap_header_struct *)hdrp)->version) {
+      case _LINUX_CAPABILITY_VERSION_1:
+        u32s = _LINUX_CAPABILITY_U32S_1;
+        break;
+      case _LINUX_CAPABILITY_VERSION_2:
+        u32s = _LINUX_CAPABILITY_U32S_2;
+        break;
+      case _LINUX_CAPABILITY_VERSION_3:
+        u32s = _LINUX_CAPABILITY_U32S_3;
+        break;
+      }
+    }
+    return sizeof(struct __user_cap_data_struct) * u32s;
+  }
   unsigned struct_new_utsname_sz = sizeof(struct new_utsname);
   unsigned struct_old_utsname_sz = sizeof(struct old_utsname);
   unsigned struct_oldold_utsname_sz = sizeof(struct oldold_utsname);
@@ -260,7 +277,7 @@ namespace __sanitizer {
   unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
 #endif // SANITIZER_LINUX
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC
   // Use pre-computed size of struct ustat to avoid <sys/ustat.h> which
   // has been removed from glibc 2.28.
 #if defined(__aarch64__) || defined(__s390x__) || defined(__mips64) ||     \
@@ -281,7 +298,7 @@ namespace __sanitizer {
   unsigned struct_ustat_sz = SIZEOF_STRUCT_USTAT;
   unsigned struct_rlimit64_sz = sizeof(struct rlimit64);
   unsigned struct_statvfs64_sz = sizeof(struct statvfs64);
-#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+#endif // SANITIZER_GLIBC
 
 #if SANITIZER_INTERCEPT_CRYPT_R
   unsigned struct_crypt_data_sz = sizeof(struct crypt_data);
@@ -352,7 +369,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
 #if SANITIZER_LINUX && !SANITIZER_ANDROID &&                               \
     (defined(__i386) || defined(__x86_64) || defined(__mips64) ||          \
      defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
-     defined(__s390__) || SANITIZER_RISCV64)
+     defined(__s390__) || defined(__loongarch__)|| SANITIZER_RISCV64)
 #if defined(__mips64) || defined(__powerpc64__) || defined(__arm__)
   unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs);
   unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t);
@@ -362,21 +379,24 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
 #elif defined(__aarch64__)
   unsigned struct_user_regs_struct_sz = sizeof(struct user_pt_regs);
   unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpsimd_state);
+#elif defined(__loongarch__)
+  unsigned struct_user_regs_struct_sz = sizeof(struct user_pt_regs);
+  unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fp_state);
 #elif defined(__s390__)
   unsigned struct_user_regs_struct_sz = sizeof(struct _user_regs_struct);
   unsigned struct_user_fpregs_struct_sz = sizeof(struct _user_fpregs_struct);
 #else
   unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct);
   unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct);
-#endif // __mips64 || __powerpc64__ || __aarch64__
+#endif // __mips64 || __powerpc64__ || __aarch64__ || __loongarch__
 #if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \
     defined(__aarch64__) || defined(__arm__) || defined(__s390__) ||    \
-    SANITIZER_RISCV64
+    defined(__loongarch__) || SANITIZER_RISCV64
   unsigned struct_user_fpxregs_struct_sz = 0;
 #else
   unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct);
 #endif // __x86_64 || __mips64 || __powerpc64__ || __aarch64__ || __arm__
-// || __s390__
+// || __s390__ || __loongarch__
 #ifdef __arm__
   unsigned struct_user_vfpregs_struct_sz = ARM_VFPREGS_SIZE;
 #else
@@ -1089,7 +1109,7 @@ CHECK_SIZE_AND_OFFSET(dirent, d_off);
 #endif
 CHECK_SIZE_AND_OFFSET(dirent, d_reclen);
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if SANITIZER_GLIBC
 COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64));
 CHECK_SIZE_AND_OFFSET(dirent64, d_ino);
 CHECK_SIZE_AND_OFFSET(dirent64, d_off);
@@ -1122,6 +1142,15 @@ CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags);
 CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_restorer);
 #endif
 
+#if SANITIZER_HAS_SIGINFO
+COMPILER_CHECK(alignof(siginfo_t) == alignof(__sanitizer_siginfo));
+using __sanitizer_siginfo_t = __sanitizer_siginfo;
+CHECK_TYPE_SIZE(siginfo_t);
+CHECK_SIZE_AND_OFFSET(siginfo_t, si_signo);
+CHECK_SIZE_AND_OFFSET(siginfo_t, si_errno);
+CHECK_SIZE_AND_OFFSET(siginfo_t, si_code);
+#endif
+
 #if SANITIZER_LINUX
 CHECK_TYPE_SIZE(__sysctl_args);
 CHECK_SIZE_AND_OFFSET(__sysctl_args, name);
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
index 44dd3d9e22d..cfca7bdedbe 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -18,6 +18,7 @@
 
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_platform.h"
+#include "sanitizer_mallinfo.h"
 
 #if SANITIZER_APPLE
 #include <sys/cdefs.h>
@@ -28,8 +29,7 @@
 #define SANITIZER_HAS_STAT64 0
 #define SANITIZER_HAS_STATFS64 0
 #endif
-#else
-// Must be SANITIZER_LINUX then
+#elif SANITIZER_GLIBC || SANITIZER_ANDROID
 #define SANITIZER_HAS_STAT64 1
 #define SANITIZER_HAS_STATFS64 1
 #endif
@@ -136,7 +136,7 @@ struct __sanitizer_perf_event_attr {
 extern unsigned struct_epoll_event_sz;
 extern unsigned struct_sysinfo_sz;
 extern unsigned __user_cap_header_struct_sz;
-extern unsigned __user_cap_data_struct_sz;
+extern unsigned __user_cap_data_struct_sz(void *hdrp);
 extern unsigned struct_new_utsname_sz;
 extern unsigned struct_old_utsname_sz;
 extern unsigned struct_oldold_utsname_sz;
@@ -205,17 +205,7 @@ struct __sanitizer_sem_t {
 };
 #endif // SANITIZER_LINUX
 
-#if SANITIZER_ANDROID
-struct __sanitizer_struct_mallinfo {
-  uptr v[10];
-};
-#endif
-
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
-struct __sanitizer_struct_mallinfo {
-  int v[10];
-};
-
 extern unsigned struct_ustat_sz;
 extern unsigned struct_rlimit64_sz;
 extern unsigned struct_statvfs64_sz;
@@ -517,7 +507,7 @@ struct __sanitizer_dirent {
 };
 #  endif
 
-#  if SANITIZER_LINUX && !SANITIZER_ANDROID
+#  if SANITIZER_GLIBC
 struct __sanitizer_dirent64 {
   unsigned long long d_ino;
   unsigned long long d_off;
@@ -587,10 +577,30 @@ struct __sanitizer_sigset_t {
 };
 #endif
 
-struct __sanitizer_siginfo {
-  // The size is determined by looking at sizeof of real siginfo_t on linux.
-  u64 opaque[128 / sizeof(u64)];
+struct __sanitizer_siginfo_pad {
+  // Require uptr, because siginfo_t is always pointer-size aligned on Linux.
+  uptr pad[128 / sizeof(uptr)];
+};
+
+#if SANITIZER_LINUX
+# define SANITIZER_HAS_SIGINFO 1
+union __sanitizer_siginfo {
+  struct {
+    int si_signo;
+# if SANITIZER_MIPS
+    int si_code;
+    int si_errno;
+# else
+    int si_errno;
+    int si_code;
+# endif
+  };
+  __sanitizer_siginfo_pad pad;
 };
+#else
+# define SANITIZER_HAS_SIGINFO 0
+typedef __sanitizer_siginfo_pad __sanitizer_siginfo;
+#endif
 
 using __sanitizer_sighandler_ptr = void (*)(int sig);
 using __sanitizer_sigactionhandler_ptr = void (*)(int sig,
@@ -843,7 +853,7 @@ typedef void __sanitizer_FILE;
 #if SANITIZER_LINUX && !SANITIZER_ANDROID &&                               \
     (defined(__i386) || defined(__x86_64) || defined(__mips64) ||          \
      defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
-     defined(__s390__) || SANITIZER_RISCV64)
+     defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64)
 extern unsigned struct_user_regs_struct_sz;
 extern unsigned struct_user_fpregs_struct_sz;
 extern unsigned struct_user_fpxregs_struct_sz;
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
index b0e32b50c07..f6b0bbd3a5d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
@@ -57,11 +57,9 @@ void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
 void UnmapOrDie(void *addr, uptr size) {
   if (!addr || !size) return;
   uptr res = internal_munmap(addr, size);
-  if (UNLIKELY(internal_iserror(res))) {
-    Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
-           SanitizerToolName, size, size, addr);
-    CHECK("unable to unmap" && 0);
-  }
+  int reserrno;
+  if (UNLIKELY(internal_iserror(res, &reserrno)))
+    ReportMunmapFailureAndDie(addr, size, reserrno);
   DecreaseTotalMmap(size);
 }
 
@@ -87,19 +85,26 @@ void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
   CHECK(IsPowerOfTwo(size));
   CHECK(IsPowerOfTwo(alignment));
   uptr map_size = size + alignment;
+  // mmap maps entire pages and rounds up map_size needs to be a an integral 
+  // number of pages. 
+  // We need to be aware of this size for calculating end and for unmapping
+  // fragments before and after the alignment region.
+  map_size = RoundUpTo(map_size, GetPageSizeCached());
   uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type);
   if (UNLIKELY(!map_res))
     return nullptr;
-  uptr map_end = map_res + map_size;
   uptr res = map_res;
   if (!IsAligned(res, alignment)) {
     res = (map_res + alignment - 1) & ~(alignment - 1);
     UnmapOrDie((void*)map_res, res - map_res);
   }
+  uptr map_end = map_res + map_size;
   uptr end = res + size;
   end = RoundUpTo(end, GetPageSizeCached());
-  if (end != map_end)
+  if (end != map_end) {
+    CHECK_LT(end, map_end);
     UnmapOrDie((void*)end, map_end - end);
+  }
   return (void*)res;
 }
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps.h b/libsanitizer/sanitizer_common/sanitizer_procmaps.h
index 19bad158387..bf3c2c28e32 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps.h
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps.h
@@ -65,6 +65,8 @@ class MemoryMappedSegment {
   MemoryMappedSegmentData *data_;
 };
 
+struct ImageHeader;
+
 class MemoryMappingLayoutBase {
  public:
   virtual bool Next(MemoryMappedSegment *segment) { UNIMPLEMENTED(); }
@@ -75,10 +77,22 @@ class MemoryMappingLayoutBase {
   ~MemoryMappingLayoutBase() {}
 };
 
-class MemoryMappingLayout final : public MemoryMappingLayoutBase {
+class MemoryMappingLayout : public MemoryMappingLayoutBase {
  public:
   explicit MemoryMappingLayout(bool cache_enabled);
+
+// This destructor cannot be virtual, as it would cause an operator new() linking
+// failures in hwasan test cases. However non-virtual destructors emit warnings
+// in macOS build, hence disabling those
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
+#endif
   ~MemoryMappingLayout();
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
   virtual bool Next(MemoryMappedSegment *segment) override;
   virtual bool Error() const override;
   virtual void Reset() override;
@@ -90,10 +104,14 @@ class MemoryMappingLayout final : public MemoryMappingLayoutBase {
   // Adds all mapped objects into a vector.
   void DumpListOfModules(InternalMmapVectorNoCtor<LoadedModule> *modules);
 
+ protected:
+#if SANITIZER_APPLE
+  virtual const ImageHeader *CurrentImageHeader();
+#endif
+  MemoryMappingLayoutData data_;
+
  private:
   void LoadFromCache();
-
-  MemoryMappingLayoutData data_;
 };
 
 // Returns code range for the specified module.
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_bsd.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_bsd.cpp
index 1f489b71ad9..36a82c4ac96 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_bsd.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_bsd.cpp
@@ -39,6 +39,22 @@
 
 namespace __sanitizer {
 
+#if SANITIZER_FREEBSD
+void GetMemoryProfile(fill_profile_f cb, uptr *stats) {
+  const int Mib[] = {
+    CTL_KERN,
+    KERN_PROC,
+    KERN_PROC_PID,
+    getpid()
+  }; 
+
+  struct kinfo_proc InfoProc;
+  uptr Len = sizeof(InfoProc);
+  CHECK_EQ(internal_sysctl(Mib, ARRAY_SIZE(Mib), nullptr, (uptr *)&InfoProc, &Len, 0), 0);
+  cb(0, InfoProc.ki_rssize * GetPageSizeCached(), false, stats);
+}
+#endif
+
 void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
   const int Mib[] = {
 #if SANITIZER_FREEBSD
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
index eb351b0f06f..a7805ad1b08 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
@@ -145,6 +145,7 @@ void MemoryMappingLayout::DumpListOfModules(
   }
 }
 
+#if SANITIZER_LINUX || SANITIZER_ANDROID || SANITIZER_SOLARIS || SANITIZER_NETBSD
 void GetMemoryProfile(fill_profile_f cb, uptr *stats) {
   char *smaps = nullptr;
   uptr smaps_cap = 0;
@@ -184,6 +185,7 @@ void ParseUnixMemoryProfile(fill_profile_f cb, uptr *stats, char *smaps,
     while (*pos++ != '\n') {}
   }
 }
+#endif
 
 } // namespace __sanitizer
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
index ba4259acd46..b44e016a0e5 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
@@ -146,13 +146,8 @@ static bool IsDyldHdr(const mach_header *hdr) {
 // until we hit a Mach header matching dyld instead. These recurse
 // calls are expensive, but the first memory map generation occurs
 // early in the process, when dyld is one of the only images loaded,
-// so it will be hit after only a few iterations.  These assumptions don't
-// hold on macOS 13+ anymore (dyld itself has moved into the shared cache).
-
-// FIXME: Unfortunately, the upstream revised version to deal with macOS 13+
-// is incompatible with GCC and also uses APIs not available on earlier
-// systems which we support; backed out for now.
-
+// so it will be hit after only a few iterations.  These assumptions don't hold
+// on macOS 13+ anymore (dyld itself has moved into the shared cache).
 static mach_header *GetDyldImageHeaderViaVMRegion() {
   vm_address_t address = 0;
 
@@ -176,17 +171,64 @@ static mach_header *GetDyldImageHeaderViaVMRegion() {
   }
 }
 
+extern "C" {
+struct dyld_shared_cache_dylib_text_info {
+  uint64_t version;  // current version 2
+  // following fields all exist in version 1
+  uint64_t loadAddressUnslid;
+  uint64_t textSegmentSize;
+  uuid_t dylibUuid;
+  const char *path;  // pointer invalid at end of iterations
+  // following fields all exist in version 2
+  uint64_t textSegmentOffset;  // offset from start of cache
+};
+typedef struct dyld_shared_cache_dylib_text_info
+    dyld_shared_cache_dylib_text_info;
+
+extern bool _dyld_get_shared_cache_uuid(uuid_t uuid);
+extern const void *_dyld_get_shared_cache_range(size_t *length);
+extern int dyld_shared_cache_iterate_text(
+    const uuid_t cacheUuid,
+    void (^callback)(const dyld_shared_cache_dylib_text_info *info));
+}  // extern "C"
+
+static mach_header *GetDyldImageHeaderViaSharedCache() {
+  uuid_t uuid;
+  bool hasCache = _dyld_get_shared_cache_uuid(uuid);
+  if (!hasCache)
+    return nullptr;
+
+  size_t cacheLength;
+  __block uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength);
+  CHECK(cacheStart && cacheLength);
+
+  __block mach_header *dyldHdr = nullptr;
+  int res = dyld_shared_cache_iterate_text(
+      uuid, ^(const dyld_shared_cache_dylib_text_info *info) {
+        CHECK_GE(info->version, 2);
+        mach_header *hdr =
+            (mach_header *)(cacheStart + info->textSegmentOffset);
+        if (IsDyldHdr(hdr))
+          dyldHdr = hdr;
+      });
+  CHECK_EQ(res, 0);
+
+  return dyldHdr;
+}
+
 const mach_header *get_dyld_hdr() {
   if (!dyld_hdr) {
     // On macOS 13+, dyld itself has moved into the shared cache.  Looking it up
     // via vm_region_recurse_64() causes spins/hangs/crashes.
-    // FIXME: find a way to do this compatible with GCC.
     if (GetMacosAlignedVersion() >= MacosVersion(13, 0)) {
+      dyld_hdr = GetDyldImageHeaderViaSharedCache();
+      if (!dyld_hdr) {
         VReport(1,
-                "looking up the dyld image header in the shared cache on "
-                "macOS 13+ is not yet supported.  Falling back to "
+                "Failed to lookup the dyld image header in the shared cache on "
+                "macOS 13+ (or no shared cache in use).  Falling back to "
                 "lookup via vm_region_recurse_64().\n");
         dyld_hdr = GetDyldImageHeaderViaVMRegion();
+      }
     } else {
       dyld_hdr = GetDyldImageHeaderViaVMRegion();
     }
@@ -208,7 +250,9 @@ static bool NextSegmentLoad(MemoryMappedSegment *segment,
                             MemoryMappedSegmentData *seg_data,
                             MemoryMappingLayoutData *layout_data) {
   const char *lc = layout_data->current_load_cmd_addr;
+
   layout_data->current_load_cmd_addr += ((const load_command *)lc)->cmdsize;
+  layout_data->current_load_cmd_count--;
   if (((const load_command *)lc)->cmd == kLCSegment) {
     const SegmentCommand* sc = (const SegmentCommand *)lc;
     uptr base_virt_addr, addr_mask;
@@ -316,11 +360,16 @@ static bool IsModuleInstrumented(const load_command *first_lc) {
   return false;
 }
 
+const ImageHeader *MemoryMappingLayout::CurrentImageHeader() {
+  const mach_header *hdr = (data_.current_image == kDyldImageIdx)
+                                ? get_dyld_hdr()
+                                : _dyld_get_image_header(data_.current_image);
+  return (const ImageHeader *)hdr;
+}
+
 bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
   for (; data_.current_image >= kDyldImageIdx; data_.current_image--) {
-    const mach_header *hdr = (data_.current_image == kDyldImageIdx)
-                                 ? get_dyld_hdr()
-                                 : _dyld_get_image_header(data_.current_image);
+    const mach_header *hdr = (const mach_header *)CurrentImageHeader();
     if (!hdr) continue;
     if (data_.current_load_cmd_count < 0) {
       // Set up for this image;
@@ -350,7 +399,7 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
           (const load_command *)data_.current_load_cmd_addr);
     }
 
-    for (; data_.current_load_cmd_count >= 0; data_.current_load_cmd_count--) {
+    while (data_.current_load_cmd_count > 0) {
       switch (data_.current_magic) {
         // data_.current_magic may be only one of MH_MAGIC, MH_MAGIC_64.
 #ifdef MH_MAGIC_64
@@ -371,6 +420,7 @@ bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
     }
     // If we get here, no more load_cmd's in this image talk about
     // segments.  Go on to the next image.
+    data_.current_load_cmd_count = -1; // This will trigger loading next image
   }
   return false;
 }
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
index 661495e2340..d24fae98213 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
@@ -87,8 +87,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
@@ -111,21 +111,14 @@ void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top,
          IsAligned((uptr)frame, sizeof(*frame)) &&
          size < max_depth) {
 #ifdef __powerpc__
-    // PowerPC ABIs specify that the return address is saved on the
-    // *caller's* stack frame.  Thus we must dereference the back chain
-    // to find the caller frame before extracting it.
+    // PowerPC ABIs specify that the return address is saved at offset
+    // 16 of the *caller's* stack frame.  Thus we must dereference the
+    // back chain to find the caller frame before extracting it.
     uhwptr *caller_frame = (uhwptr*)frame[0];
     if (!IsValidFrame((uptr)caller_frame, stack_top, bottom) ||
         !IsAligned((uptr)caller_frame, sizeof(uhwptr)))
       break;
-    // For most ABIs the offset where the return address is saved is two
-    // register sizes.  The exception is the SVR4 ABI, which uses an
-    // offset of only one register size.
-#ifdef _CALL_SYSV
-    uhwptr pc1 = caller_frame[1];
-#else
     uhwptr pc1 = caller_frame[2];
-#endif
 #elif defined(__s390__)
     uhwptr pc1 = frame[14];
 #elif defined(__loongarch__) || defined(__riscv)
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
index ee996c3e07e..47aed488c71 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
@@ -91,10 +91,10 @@ uptr StackTrace::GetPreviousInstructionPc(uptr pc) {
 #elif defined(__sparc__) || defined(__mips__)
   return pc - 8;
 #elif SANITIZER_RISCV64
-  // RV-64 has variable instruciton length...
+  // RV-64 has variable instruction length...
   // C extentions gives us 2-byte instructoins
   // RV-64 has 4-byte instructions
-  // + RISCV architecture allows instructions up to 8 bytes
+  // + RISC-V architecture allows instructions up to 8 bytes
   // It seems difficult to figure out the exact instruction length -
   // pc - 2 seems like a safe option for the purposes of stack tracing
   return pc - 2;
diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
index 403bda1174c..13b90ce9bf5 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
@@ -16,7 +16,7 @@
 #if SANITIZER_LINUX &&                                                   \
     (defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) || \
      defined(__powerpc64__) || defined(__s390__) || defined(__i386__) || \
-     defined(__arm__) || SANITIZER_RISCV64)
+     defined(__arm__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64)
 
 #include "sanitizer_stoptheworld.h"
 
@@ -31,7 +31,8 @@
 #include <sys/types.h> // for pid_t
 #include <sys/uio.h> // for iovec
 #include <elf.h> // for NT_PRSTATUS
-#if (defined(__aarch64__) || SANITIZER_RISCV64) && !SANITIZER_ANDROID
+#if (defined(__aarch64__) || SANITIZER_RISCV64 || SANITIZER_LOONGARCH64) && \
+     !SANITIZER_ANDROID
 // GLIBC 2.20+ sys/user does not include asm/ptrace.h
 # include <asm/ptrace.h>
 #endif
@@ -514,6 +515,12 @@ typedef struct user_pt_regs regs_struct;
 static constexpr uptr kExtraRegs[] = {0};
 #define ARCH_IOVEC_FOR_GETREGSET
 
+#elif defined(__loongarch__)
+typedef struct user_pt_regs regs_struct;
+#define REG_SP regs[3]
+static constexpr uptr kExtraRegs[] = {0};
+#define ARCH_IOVEC_FOR_GETREGSET
+
 #elif SANITIZER_RISCV64
 typedef struct user_regs_struct regs_struct;
 // sys/ucontext.h already defines REG_SP as 2. Undefine it first.
@@ -621,3 +628,4 @@ PtraceRegistersStatus SuspendedThreadsListLinux::GetRegistersAndSP(
 #endif  // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)
         // || defined(__aarch64__) || defined(__powerpc64__)
         // || defined(__s390__) || defined(__i386__) || defined(__arm__)
+        // || SANITIZER_LOONGARCH64
diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp b/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
index a674034b8e2..f3818526baa 100644
--- a/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
@@ -86,6 +86,7 @@ void SuppressionContext::ParseFromFile(const char *filename) {
   }
 
   Parse(file_contents);
+  UnmapOrDie(file_contents, contents_size);
 }
 
 bool SuppressionContext::Match(const char *str, const char *type,
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
index 29a08386d0b..3ec4d80105a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
@@ -13,8 +13,8 @@
 #ifndef SANITIZER_SYMBOLIZER_INTERNAL_H
 #define SANITIZER_SYMBOLIZER_INTERNAL_H
 
-#include "sanitizer_symbolizer.h"
 #include "sanitizer_file.h"
+#include "sanitizer_symbolizer.h"
 #include "sanitizer_vector.h"
 
 namespace __sanitizer {
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cpp
index 27ed222745e..cc02c77bccd 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cpp
@@ -11,11 +11,11 @@
 // Libbacktrace implementation of symbolizer parts.
 //===----------------------------------------------------------------------===//
 
-#include "sanitizer_platform.h"
+#include "sanitizer_symbolizer_libbacktrace.h"
 
 #include "sanitizer_internal_defs.h"
+#include "sanitizer_platform.h"
 #include "sanitizer_symbolizer.h"
-#include "sanitizer_symbolizer_libbacktrace.h"
 
 #if SANITIZER_LIBBACKTRACE
 # include "backtrace-supported.h"
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
index f4f2a036a1e..a9c958b2d10 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
@@ -14,16 +14,16 @@
 #include "sanitizer_platform.h"
 #if SANITIZER_APPLE
 
-#include "sanitizer_allocator_internal.h"
-#include "sanitizer_mac.h"
-#include "sanitizer_symbolizer_mac.h"
+#  include <dlfcn.h>
+#  include <errno.h>
+#  include <stdlib.h>
+#  include <sys/wait.h>
+#  include <unistd.h>
+#  include <util.h>
 
-#include <dlfcn.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <util.h>
+#  include "sanitizer_allocator_internal.h"
+#  include "sanitizer_mac.h"
+#  include "sanitizer_symbolizer_mac.h"
 
 namespace __sanitizer {
 
@@ -163,7 +163,7 @@ bool AtosSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
   uptr start_address = AddressInfo::kUnknown;
   if (!ParseCommandOutput(buf, addr, &stack->info.function, &stack->info.module,
                           &stack->info.file, &line, &start_address)) {
-    process_ = nullptr;
+    Report("WARNING: atos failed to symbolize address \"0x%zx\"\n", addr);
     return false;
   }
   stack->info.line = (int)line;
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
index b223f6cd01e..1a5e38faea8 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
@@ -13,25 +13,25 @@
 
 #include "sanitizer_platform.h"
 #if SANITIZER_POSIX
-#include "sanitizer_allocator_internal.h"
-#include "sanitizer_common.h"
-#include "sanitizer_file.h"
-#include "sanitizer_flags.h"
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_linux.h"
-#include "sanitizer_placement_new.h"
-#include "sanitizer_posix.h"
-#include "sanitizer_procmaps.h"
-#include "sanitizer_symbolizer_internal.h"
-#include "sanitizer_symbolizer_libbacktrace.h"
-#include "sanitizer_symbolizer_mac.h"
-
-#include <dlfcn.h>   // for dlsym()
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/wait.h>
-#include <unistd.h>
+#  include <dlfcn.h>  // for dlsym()
+#  include <errno.h>
+#  include <stdint.h>
+#  include <stdlib.h>
+#  include <sys/wait.h>
+#  include <unistd.h>
+
+#  include "sanitizer_allocator_internal.h"
+#  include "sanitizer_common.h"
+#  include "sanitizer_file.h"
+#  include "sanitizer_flags.h"
+#  include "sanitizer_internal_defs.h"
+#  include "sanitizer_linux.h"
+#  include "sanitizer_placement_new.h"
+#  include "sanitizer_posix.h"
+#  include "sanitizer_procmaps.h"
+#  include "sanitizer_symbolizer_internal.h"
+#  include "sanitizer_symbolizer_libbacktrace.h"
+#  include "sanitizer_symbolizer_mac.h"
 
 // C++ demangling function, as required by Itanium C++ ABI. This is weak,
 // because we do not require a C++ ABI library to be linked to a program
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
index d5c028e3640..73915715c5b 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
@@ -107,8 +107,7 @@ void ReportMmapWriteExec(int prot, int flags) {
   stack->Reset();
   uptr top = 0;
   uptr bottom = 0;
-  GET_CALLER_PC_BP_SP;
-  (void)sp;
+  GET_CALLER_PC_BP;
   bool fast = common_flags()->fast_unwind_on_fatal;
   if (StackTrace::WillUseFastUnwind(fast)) {
     GetThreadStackTopAndBottom(false, &top, &bottom);
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
index c647ab107ec..2a7137fe1f8 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
@@ -14,8 +14,8 @@
 #include "sanitizer_platform.h"
 #if SANITIZER_WINDOWS
 
-#include "sanitizer_dbghelp.h"
-#include "sanitizer_symbolizer_internal.h"
+#  include "sanitizer_dbghelp.h"
+#  include "sanitizer_symbolizer_internal.h"
 
 namespace __sanitizer {
 
@@ -231,8 +231,6 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
     // Check that tool command lines are simple and that complete escaping is
     // unnecessary.
     CHECK(!internal_strchr(arg, '"') && "quotes in args unsupported");
-    CHECK(!internal_strstr(arg, "\\\\") &&
-          "double backslashes in args unsupported");
     CHECK(arglen > 0 && arg[arglen - 1] != '\\' &&
           "args ending in backslash and empty args unsupported");
     command_line.append("\"%s\" ", arg);
diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
index 278f6defca9..741e0731c41 100644
--- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
@@ -335,7 +335,7 @@ void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) {
 
 ThreadContextBase *ThreadRegistry::QuarantinePop() {
   if (invalid_threads_.size() == 0)
-    return 0;
+    return nullptr;
   ThreadContextBase *tctx = invalid_threads_.front();
   invalid_threads_.pop_front();
   return tctx;
diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
index b13e2dc9e33..252979f1c2b 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_allocator_interface.h"
 #include "sanitizer_atomic.h"
 #include "sanitizer_flags.h"
 #include "sanitizer_platform_interceptors.h"
@@ -26,13 +27,6 @@ struct TlsGetAddrParam {
   uptr offset;
 };
 
-// Glibc starting from 2.19 allocates tls using __signal_safe_memalign,
-// which has such header.
-struct Glibc_2_19_tls_header {
-  uptr size;
-  uptr start;
-};
-
 // This must be static TLS
 __attribute__((tls_model("initial-exec")))
 static __thread DTLS dtls;
@@ -108,6 +102,14 @@ static const uptr kDtvOffset = 0x800;
 static const uptr kDtvOffset = 0;
 #endif
 
+extern "C" {
+SANITIZER_WEAK_ATTRIBUTE
+uptr __sanitizer_get_allocated_size(const void *p);
+
+SANITIZER_WEAK_ATTRIBUTE
+const void *__sanitizer_get_allocated_begin(const void *p);
+}
+
 DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
                                 uptr static_tls_begin, uptr static_tls_end) {
   if (!common_flags()->intercept_tls_get_addr) return 0;
@@ -125,19 +127,18 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
           atomic_load(&number_of_live_dtls, memory_order_relaxed));
   if (dtls.last_memalign_ptr == tls_beg) {
     tls_size = dtls.last_memalign_size;
-    VReport(2, "__tls_get_addr: glibc <=2.18 suspected; tls={0x%zx,0x%zx}\n",
+    VReport(2, "__tls_get_addr: glibc <=2.24 suspected; tls={0x%zx,0x%zx}\n",
             tls_beg, tls_size);
   } else if (tls_beg >= static_tls_begin && tls_beg < static_tls_end) {
     // This is the static TLS block which was initialized / unpoisoned at thread
     // creation.
     VReport(2, "__tls_get_addr: static tls: 0x%zx\n", tls_beg);
     tls_size = 0;
-  } else if ((tls_beg % 4096) == sizeof(Glibc_2_19_tls_header)) {
-    // We may want to check gnu_get_libc_version().
-    Glibc_2_19_tls_header *header = (Glibc_2_19_tls_header *)tls_beg - 1;
-    tls_size = header->size;
-    tls_beg = header->start;
-    VReport(2, "__tls_get_addr: glibc >=2.19 suspected; tls={0x%zx 0x%zx}\n",
+  } else if (const void *start =
+                 __sanitizer_get_allocated_begin((void *)tls_beg)) {
+    tls_beg = (uptr)start;
+    tls_size = __sanitizer_get_allocated_size(start);
+    VReport(2, "__tls_get_addr: glibc >=2.25 suspected; tls={0x%zx,0x%zx}\n",
             tls_beg, tls_size);
   } else {
     VReport(2, "__tls_get_addr: Can't guess glibc version\n");
diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
index a599c0bbc75..0ddab61deb1 100644
--- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
+++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
@@ -12,16 +12,24 @@
 // the lack of interface that would tell us about the Dynamic TLS (DTLS).
 // https://sourceware.org/bugzilla/show_bug.cgi?id=16291
 //
-// The matters get worse because the glibc implementation changed between
-// 2.18 and 2.19:
-// https://groups.google.com/forum/#!topic/address-sanitizer/BfwYD8HMxTM
-//
-// Before 2.19, every DTLS chunk is allocated with __libc_memalign,
+// Before 2.25: every DTLS chunk is allocated with __libc_memalign,
 // which we intercept and thus know where is the DTLS.
-// Since 2.19, DTLS chunks are allocated with __signal_safe_memalign,
-// which is an internal function that wraps a mmap call, neither of which
-// we can intercept. Luckily, __signal_safe_memalign has a simple parseable
-// header which we can use.
+//
+// Since 2.25: DTLS chunks are allocated with malloc. We could co-opt
+// the malloc interceptor to keep track of the last allocation, similar
+// to how we handle __libc_memalign; however, this adds some overhead
+// (since malloc, unlike __libc_memalign, is commonly called), and
+// requires care to avoid false negatives for LeakSanitizer.
+// Instead, we rely on our internal allocators - which keep track of all
+// its allocations - to determine if an address points to a malloc
+// allocation.
+//
+// There exists a since-deprecated version of Google's internal glibc fork
+// that used __signal_safe_memalign. DTLS_on_tls_get_addr relied on a
+// heuristic check (is the allocation 16 bytes from the start of a page
+// boundary?), which was sometimes erroneous:
+//     https://bugs.chromium.org/p/chromium/issues/detail?id=1275223#c15
+// Since that check has no practical use anymore, we have removed it.
 //
 //===----------------------------------------------------------------------===//
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_win.cpp
index e0568c9b62d..1c9b2dd8a5e 100644
--- a/libsanitizer/sanitizer_common/sanitizer_win.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_win.cpp
@@ -718,13 +718,24 @@ void ListOfModules::fallbackInit() { clear(); }
 // atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers).
 InternalMmapVectorNoCtor<void (*)(void)> atexit_functions;
 
-int Atexit(void (*function)(void)) {
+static int queueAtexit(void (*function)(void)) {
   atexit_functions.push_back(function);
   return 0;
 }
 
+// If Atexit() is being called after RunAtexit() has already been run, it needs
+// to be able to call atexit() directly. Here we use a function ponter to
+// switch out its behaviour.
+// An example of where this is needed is the asan_dynamic runtime on MinGW-w64.
+// On this environment, __asan_init is called during global constructor phase,
+// way after calling the .CRT$XID initializer.
+static int (*volatile queueOrCallAtExit)(void (*)(void)) = &queueAtexit;
+
+int Atexit(void (*function)(void)) { return queueOrCallAtExit(function); }
+
 static int RunAtexit() {
   TraceLoggingUnregister(g_asan_provider);
+  queueOrCallAtExit = &atexit;
   int ret = 0;
   for (uptr i = 0; i < atexit_functions.size(); ++i) {
     ret |= atexit(atexit_functions[i]);
diff --git a/libsanitizer/tsan/tsan_external.cpp b/libsanitizer/tsan/tsan_external.cpp
index 19ae174f20a..98abff54e2b 100644
--- a/libsanitizer/tsan/tsan_external.cpp
+++ b/libsanitizer/tsan/tsan_external.cpp
@@ -46,10 +46,6 @@ const char *GetReportHeaderFromTag(uptr tag) {
   return tag_data ? tag_data->header : nullptr;
 }
 
-void InsertShadowStackFrameForTag(ThreadState *thr, uptr tag) {
-  FuncEntry(thr, (uptr)&registered_tags[tag]);
-}
-
 uptr TagFromShadowStackFrame(uptr pc) {
   uptr tag_count = atomic_load(&used_tags, memory_order_relaxed);
   void *pc_ptr = (void *)pc;
@@ -60,15 +56,26 @@ uptr TagFromShadowStackFrame(uptr pc) {
 
 #if !SANITIZER_GO
 
-void ExternalAccess(void *addr, uptr caller_pc, void *tag, AccessType typ) {
+// We need to track tags for individual memory accesses, but there is no space
+// in the shadow cells for them.  Instead we push/pop them onto the thread
+// traces and ignore the extra tag frames when printing reports.
+static void PushTag(ThreadState *thr, uptr tag) {
+  FuncEntry(thr, (uptr)&registered_tags[tag]);
+}
+static void PopTag(ThreadState *thr) { FuncExit(thr); }
+
+static void ExternalAccess(void *addr, uptr caller_pc, uptr tsan_caller_pc,
+                           void *tag, AccessType typ) {
   CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed));
+  bool in_ignored_lib;
+  if (caller_pc && libignore()->IsIgnored(caller_pc, &in_ignored_lib))
+    return;
+
   ThreadState *thr = cur_thread();
   if (caller_pc) FuncEntry(thr, caller_pc);
-  InsertShadowStackFrameForTag(thr, (uptr)tag);
-  bool in_ignored_lib;
-  if (!caller_pc || !libignore()->IsIgnored(caller_pc, &in_ignored_lib))
-    MemoryAccess(thr, CALLERPC, (uptr)addr, 1, typ);
-  FuncExit(thr);
+  PushTag(thr, (uptr)tag);
+  MemoryAccess(thr, tsan_caller_pc, (uptr)addr, 1, typ);
+  PopTag(thr);
   if (caller_pc) FuncExit(thr);
 }
 
@@ -112,12 +119,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_PAC_PC(caller_pc), tag, kAccessRead);
+  ExternalAccess(addr, STRIP_PAC_PC(caller_pc), CALLERPC, tag, kAccessRead);
 }
 
 SANITIZER_INTERFACE_ATTRIBUTE
 void __tsan_external_write(void *addr, void *caller_pc, void *tag) {
-  ExternalAccess(addr, STRIP_PAC_PC(caller_pc), tag, kAccessWrite);
+  ExternalAccess(addr, STRIP_PAC_PC(caller_pc), CALLERPC, tag, kAccessWrite);
 }
 }  // extern "C"
 
diff --git a/libsanitizer/tsan/tsan_flags.cpp b/libsanitizer/tsan/tsan_flags.cpp
index ee78f25cc65..3fd58f46983 100644
--- a/libsanitizer/tsan/tsan_flags.cpp
+++ b/libsanitizer/tsan/tsan_flags.cpp
@@ -10,19 +10,21 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "sanitizer_common/sanitizer_flags.h"
+#include "tsan_flags.h"
+
 #include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_libc.h"
-#include "tsan_flags.h"
-#include "tsan_rtl.h"
+#include "tsan_interface.h"
 #include "tsan_mman.h"
+#include "tsan_rtl.h"
 #include "ubsan/ubsan_flags.h"
 
 namespace __tsan {
 
 // Can be overriden in frontend.
 #ifdef TSAN_EXTERNAL_HOOKS
-extern "C" const char* __tsan_default_options();
+extern "C" const char *__tsan_default_options();
 #else
 SANITIZER_WEAK_DEFAULT_IMPL
 const char *__tsan_default_options() {
diff --git a/libsanitizer/tsan/tsan_interceptors_mac.cpp b/libsanitizer/tsan/tsan_interceptors_mac.cpp
index 1ee47bcd123..e4f9e2915ce 100644
--- a/libsanitizer/tsan/tsan_interceptors_mac.cpp
+++ b/libsanitizer/tsan/tsan_interceptors_mac.cpp
@@ -18,6 +18,7 @@
 #include "tsan_interceptors.h"
 #include "tsan_interface.h"
 #include "tsan_interface_ann.h"
+#include "tsan_spinlock_defs_mac.h"
 #include "sanitizer_common/sanitizer_addrhashmap.h"
 
 #include <errno.h>
diff --git a/libsanitizer/tsan/tsan_interceptors_posix.cpp b/libsanitizer/tsan/tsan_interceptors_posix.cpp
index c557d5ddc6a..6ac6ac6a7fb 100644
--- a/libsanitizer/tsan/tsan_interceptors_posix.cpp
+++ b/libsanitizer/tsan/tsan_interceptors_posix.cpp
@@ -76,6 +76,8 @@ struct ucontext_t {
 #define PTHREAD_ABI_BASE  "GLIBC_2.3.2"
 #elif defined(__aarch64__) || SANITIZER_PPC64V2
 #define PTHREAD_ABI_BASE  "GLIBC_2.17"
+#elif SANITIZER_LOONGARCH64
+#define PTHREAD_ABI_BASE  "GLIBC_2.36"
 #endif
 
 extern "C" int pthread_attr_init(void *attr);
@@ -126,6 +128,7 @@ const int SIGSYS = 12;
 const int SIGBUS = 7;
 const int SIGSYS = 31;
 #endif
+const int SI_TIMER = -2;
 void *const MAP_FAILED = (void*)-1;
 #if SANITIZER_NETBSD
 const int PTHREAD_BARRIER_SERIAL_THREAD = 1234567;
@@ -247,13 +250,21 @@ SANITIZER_WEAK_CXX_DEFAULT_IMPL void OnPotentiallyBlockingRegionEnd() {}
 }  // namespace __tsan
 
 static ThreadSignalContext *SigCtx(ThreadState *thr) {
-  ThreadSignalContext *ctx = (ThreadSignalContext*)thr->signal_ctx;
+  // This function may be called reentrantly if it is interrupted by a signal
+  // handler. Use CAS to handle the race.
+  uptr ctx = atomic_load(&thr->signal_ctx, memory_order_relaxed);
   if (ctx == 0 && !thr->is_dead) {
-    ctx = (ThreadSignalContext*)MmapOrDie(sizeof(*ctx), "ThreadSignalContext");
-    MemoryResetRange(thr, (uptr)&SigCtx, (uptr)ctx, sizeof(*ctx));
-    thr->signal_ctx = ctx;
+    uptr pctx =
+        (uptr)MmapOrDie(sizeof(ThreadSignalContext), "ThreadSignalContext");
+    MemoryResetRange(thr, (uptr)&SigCtx, pctx, sizeof(ThreadSignalContext));
+    if (atomic_compare_exchange_strong(&thr->signal_ctx, &ctx, pctx,
+                                       memory_order_relaxed)) {
+      ctx = pctx;
+    } else {
+      UnmapOrDie((ThreadSignalContext *)pctx, sizeof(ThreadSignalContext));
+    }
   }
-  return ctx;
+  return (ThreadSignalContext *)ctx;
 }
 
 ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
@@ -968,9 +979,10 @@ void DestroyThreadState() {
 }
 
 void PlatformCleanUpThreadState(ThreadState *thr) {
-  ThreadSignalContext *sctx = thr->signal_ctx;
+  ThreadSignalContext *sctx = (ThreadSignalContext *)atomic_load(
+      &thr->signal_ctx, memory_order_relaxed);
   if (sctx) {
-    thr->signal_ctx = 0;
+    atomic_store(&thr->signal_ctx, 0, memory_order_relaxed);
     UnmapOrDie(sctx, sizeof(*sctx));
   }
 }
@@ -1351,6 +1363,19 @@ TSAN_INTERCEPTOR(int, pthread_mutex_destroy, void *m) {
   return res;
 }
 
+TSAN_INTERCEPTOR(int, pthread_mutex_lock, void *m) {
+  SCOPED_TSAN_INTERCEPTOR(pthread_mutex_lock, m);
+  MutexPreLock(thr, pc, (uptr)m);
+  int res = REAL(pthread_mutex_lock)(m);
+  if (res == errno_EOWNERDEAD)
+    MutexRepair(thr, pc, (uptr)m);
+  if (res == 0 || res == errno_EOWNERDEAD)
+    MutexPostLock(thr, pc, (uptr)m);
+  if (res == errno_EINVAL)
+    MutexInvalidAccess(thr, pc, (uptr)m);
+  return res;
+}
+
 TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) {
   SCOPED_TSAN_INTERCEPTOR(pthread_mutex_trylock, m);
   int res = REAL(pthread_mutex_trylock)(m);
@@ -1372,6 +1397,43 @@ TSAN_INTERCEPTOR(int, pthread_mutex_timedlock, void *m, void *abstime) {
 }
 #endif
 
+TSAN_INTERCEPTOR(int, pthread_mutex_unlock, void *m) {
+  SCOPED_TSAN_INTERCEPTOR(pthread_mutex_unlock, m);
+  MutexUnlock(thr, pc, (uptr)m);
+  int res = REAL(pthread_mutex_unlock)(m);
+  if (res == errno_EINVAL)
+    MutexInvalidAccess(thr, pc, (uptr)m);
+  return res;
+}
+
+#if SANITIZER_GLIBC
+#  if !__GLIBC_PREREQ(2, 34)
+// glibc 2.34 applies a non-default version for the two functions. They are no
+// longer expected to be intercepted by programs.
+TSAN_INTERCEPTOR(int, __pthread_mutex_lock, void *m) {
+  SCOPED_TSAN_INTERCEPTOR(__pthread_mutex_lock, m);
+  MutexPreLock(thr, pc, (uptr)m);
+  int res = REAL(__pthread_mutex_lock)(m);
+  if (res == errno_EOWNERDEAD)
+    MutexRepair(thr, pc, (uptr)m);
+  if (res == 0 || res == errno_EOWNERDEAD)
+    MutexPostLock(thr, pc, (uptr)m);
+  if (res == errno_EINVAL)
+    MutexInvalidAccess(thr, pc, (uptr)m);
+  return res;
+}
+
+TSAN_INTERCEPTOR(int, __pthread_mutex_unlock, void *m) {
+  SCOPED_TSAN_INTERCEPTOR(__pthread_mutex_unlock, m);
+  MutexUnlock(thr, pc, (uptr)m);
+  int res = REAL(__pthread_mutex_unlock)(m);
+  if (res == errno_EINVAL)
+    MutexInvalidAccess(thr, pc, (uptr)m);
+  return res;
+}
+#  endif
+#endif
+
 #if !SANITIZER_APPLE
 TSAN_INTERCEPTOR(int, pthread_spin_init, void *m, int pshared) {
   SCOPED_TSAN_INTERCEPTOR(pthread_spin_init, m, pshared);
@@ -1943,12 +2005,34 @@ TSAN_INTERCEPTOR(int, epoll_pwait, int epfd, void *ev, int cnt, int timeout,
   return res;
 }
 
-#define TSAN_MAYBE_INTERCEPT_EPOLL \
-    TSAN_INTERCEPT(epoll_create); \
-    TSAN_INTERCEPT(epoll_create1); \
-    TSAN_INTERCEPT(epoll_ctl); \
-    TSAN_INTERCEPT(epoll_wait); \
-    TSAN_INTERCEPT(epoll_pwait)
+TSAN_INTERCEPTOR(int, epoll_pwait2, int epfd, void *ev, int cnt, void *timeout,
+                 void *sigmask) {
+  SCOPED_INTERCEPTOR_RAW(epoll_pwait2, epfd, ev, cnt, timeout, sigmask);
+  // This function is new and may not be present in libc and/or kernel.
+  // Since we effectively add it to libc (as will be probed by the program
+  // using dlsym or a weak function pointer) we need to handle the case
+  // when it's not present in the actual libc.
+  if (!REAL(epoll_pwait2)) {
+    errno = errno_ENOSYS;
+    return -1;
+  }
+  if (MustIgnoreInterceptor(thr))
+    REAL(epoll_pwait2)(epfd, ev, cnt, timeout, sigmask);
+  if (epfd >= 0)
+    FdAccess(thr, pc, epfd);
+  int res = BLOCK_REAL(epoll_pwait2)(epfd, ev, cnt, timeout, sigmask);
+  if (res > 0 && epfd >= 0)
+    FdAcquire(thr, pc, epfd);
+  return res;
+}
+
+#  define TSAN_MAYBE_INTERCEPT_EPOLL \
+    TSAN_INTERCEPT(epoll_create);    \
+    TSAN_INTERCEPT(epoll_create1);   \
+    TSAN_INTERCEPT(epoll_ctl);       \
+    TSAN_INTERCEPT(epoll_wait);      \
+    TSAN_INTERCEPT(epoll_pwait);     \
+    TSAN_INTERCEPT(epoll_pwait2)
 #else
 #define TSAN_MAYBE_INTERCEPT_EPOLL
 #endif
@@ -2082,11 +2166,19 @@ void ProcessPendingSignalsImpl(ThreadState *thr) {
 
 }  // namespace __tsan
 
-static bool is_sync_signal(ThreadSignalContext *sctx, int sig) {
+static bool is_sync_signal(ThreadSignalContext *sctx, int sig,
+                           __sanitizer_siginfo *info) {
+  // If we are sending signal to ourselves, we must process it now.
+  if (sctx && sig == sctx->int_signal_send)
+    return true;
+#if SANITIZER_HAS_SIGINFO
+  // POSIX timers can be configured to send any kind of signal; however, it
+  // doesn't make any sense to consider a timer signal as synchronous!
+  if (info->si_code == SI_TIMER)
+    return false;
+#endif
   return sig == SIGSEGV || sig == SIGBUS || sig == SIGILL || sig == SIGTRAP ||
-         sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS ||
-         // If we are sending signal to ourselves, we must process it now.
-         (sctx && sig == sctx->int_signal_send);
+         sig == SIGABRT || sig == SIGFPE || sig == SIGPIPE || sig == SIGSYS;
 }
 
 void sighandler(int sig, __sanitizer_siginfo *info, void *ctx) {
@@ -2097,7 +2189,7 @@ void sighandler(int sig, __sanitizer_siginfo *info, void *ctx) {
     return;
   }
   // Don't mess with synchronous signals.
-  const bool sync = is_sync_signal(sctx, sig);
+  const bool sync = is_sync_signal(sctx, sig, info);
   if (sync ||
       // If we are in blocking function, we can safely process it now
       // (but check if we are in a recursive interceptor,
@@ -2405,11 +2497,21 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc,
     res;                                          \
   })
 
+// Ignore interceptors in OnLibraryLoaded()/Unloaded().  These hooks use code
+// (ListOfModules::init, MemoryMappingLayout::DumpListOfModules) that make
+// intercepted calls, which can cause deadlockes with ReportRace() which also
+// uses this code.
 #define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \
-  libignore()->OnLibraryLoaded(filename)
+  ({                                                        \
+    ScopedIgnoreInterceptors ignore_interceptors;           \
+    libignore()->OnLibraryLoaded(filename);                 \
+  })
 
-#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() \
-  libignore()->OnLibraryUnloaded()
+#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED()     \
+  ({                                              \
+    ScopedIgnoreInterceptors ignore_interceptors; \
+    libignore()->OnLibraryUnloaded();             \
+  })
 
 #define COMMON_INTERCEPTOR_ACQUIRE(ctx, u) \
   Acquire(((TsanInterceptorContext *) ctx)->thr, pc, u)
@@ -2446,26 +2548,6 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc,
 #define COMMON_INTERCEPTOR_ON_EXIT(ctx) \
   OnExit(((TsanInterceptorContext *) ctx)->thr)
 
-#define COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m) \
-  MutexPreLock(((TsanInterceptorContext *)ctx)->thr, \
-            ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
-
-#define COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m) \
-  MutexPostLock(((TsanInterceptorContext *)ctx)->thr, \
-            ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
-
-#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) \
-  MutexUnlock(((TsanInterceptorContext *)ctx)->thr, \
-            ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
-
-#define COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m) \
-  MutexRepair(((TsanInterceptorContext *)ctx)->thr, \
-            ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
-
-#define COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m) \
-  MutexInvalidAccess(((TsanInterceptorContext *)ctx)->thr, \
-                     ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
-
 #define COMMON_INTERCEPTOR_MMAP_IMPL(ctx, mmap, addr, sz, prot, flags, fd,  \
                                      off)                                   \
   do {                                                                      \
@@ -2762,7 +2844,9 @@ TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_wait, void *c, void *m)
 TSAN_INTERCEPTOR_NETBSD_ALIAS(int, cond_destroy, void *c)
 TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_init, void *m, void *a)
 TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_destroy, void *m)
+TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_lock, void *m)
 TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_trylock, void *m)
+TSAN_INTERCEPTOR_NETBSD_ALIAS(int, mutex_unlock, void *m)
 TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_init, void *m, void *a)
 TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_destroy, void *m)
 TSAN_INTERCEPTOR_NETBSD_ALIAS(int, rwlock_rdlock, void *m)
@@ -2864,8 +2948,16 @@ void InitializeInterceptors() {
 
   TSAN_INTERCEPT(pthread_mutex_init);
   TSAN_INTERCEPT(pthread_mutex_destroy);
+  TSAN_INTERCEPT(pthread_mutex_lock);
   TSAN_INTERCEPT(pthread_mutex_trylock);
   TSAN_INTERCEPT(pthread_mutex_timedlock);
+  TSAN_INTERCEPT(pthread_mutex_unlock);
+#if SANITIZER_GLIBC
+#  if !__GLIBC_PREREQ(2, 34)
+  TSAN_INTERCEPT(__pthread_mutex_lock);
+  TSAN_INTERCEPT(__pthread_mutex_unlock);
+#  endif
+#endif
 
   TSAN_INTERCEPT(pthread_spin_init);
   TSAN_INTERCEPT(pthread_spin_destroy);
@@ -3010,7 +3102,9 @@ void InitializeInterceptors() {
   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(cond_destroy);
   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_init);
   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_destroy);
+  TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_lock);
   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_trylock);
+  TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(mutex_unlock);
   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_init);
   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_destroy);
   TSAN_MAYBE_INTERCEPT_NETBSD_ALIAS(rwlock_rdlock);
diff --git a/libsanitizer/tsan/tsan_interface.h b/libsanitizer/tsan/tsan_interface.h
index 5b9d664e503..d53c1e3935d 100644
--- a/libsanitizer/tsan/tsan_interface.h
+++ b/libsanitizer/tsan/tsan_interface.h
@@ -32,6 +32,9 @@ extern "C" {
 // before any instrumented code is executed and before any call to malloc.
 SANITIZER_INTERFACE_ATTRIBUTE void __tsan_init();
 
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char *
+__tsan_default_options();
+
 SANITIZER_INTERFACE_ATTRIBUTE void __tsan_flush_memory();
 
 SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read1(void *addr);
@@ -85,6 +88,8 @@ SANITIZER_INTERFACE_ATTRIBUTE void __tsan_func_exit();
 SANITIZER_INTERFACE_ATTRIBUTE void __tsan_ignore_thread_begin();
 SANITIZER_INTERFACE_ATTRIBUTE void __tsan_ignore_thread_end();
 
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_on_thread_idle();
+
 SANITIZER_INTERFACE_ATTRIBUTE
 void *__tsan_external_register_tag(const char *object_type);
 SANITIZER_INTERFACE_ATTRIBUTE
diff --git a/libsanitizer/tsan/tsan_mman.cpp b/libsanitizer/tsan/tsan_mman.cpp
index 0937e521193..e5271cf5697 100644
--- a/libsanitizer/tsan/tsan_mman.cpp
+++ b/libsanitizer/tsan/tsan_mman.cpp
@@ -15,6 +15,7 @@
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_errno.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
+#include "tsan_interface.h"
 #include "tsan_mman.h"
 #include "tsan_rtl.h"
 #include "tsan_report.h"
@@ -351,6 +352,20 @@ void *user_pvalloc(ThreadState *thr, uptr pc, uptr sz) {
   return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, PageSize));
 }
 
+static const void *user_alloc_begin(const void *p) {
+  if (p == nullptr || !IsAppMem((uptr)p))
+    return nullptr;
+  void *beg = allocator()->GetBlockBegin(p);
+  if (!beg)
+    return nullptr;
+
+  MBlock *b = ctx->metamap.GetBlock((uptr)beg);
+  if (!b)
+    return nullptr;  // Not a valid pointer.
+
+  return (const void *)beg;
+}
+
 uptr user_alloc_usable_size(const void *p) {
   if (p == 0 || !IsAppMem((uptr)p))
     return 0;
@@ -429,6 +444,10 @@ int __sanitizer_get_ownership(const void *p) {
   return allocator()->GetBlockBegin(p) != 0;
 }
 
+const void *__sanitizer_get_allocated_begin(const void *p) {
+  return user_alloc_begin(p);
+}
+
 uptr __sanitizer_get_allocated_size(const void *p) {
   return user_alloc_usable_size(p);
 }
diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h
index 7c13c733513..f0cdaf48eaa 100644
--- a/libsanitizer/tsan/tsan_platform.h
+++ b/libsanitizer/tsan/tsan_platform.h
@@ -34,6 +34,14 @@ enum {
   // This is bad and can lead to unpredictable memory corruptions, etc
   // because range access functions assume linearity.
   kBrokenLinearity = 1 << 2,
+  // Meta for an app region overlaps with the meta of another app region.
+  // This is determined by recomputing the individual meta regions for
+  // each app region.
+  //
+  // N.B. There is no "kBrokenReverseMetaMapping" constant because there
+  // is no MetaToMem function. However, note that (!kBrokenLinearity
+  // && !kBrokenAliasedMetas) implies that MemToMeta is invertible.
+  kBrokenAliasedMetas = 1 << 3,
 };
 
 /*
@@ -42,8 +50,8 @@ C/C++ on linux/x86_64 and freebsd/x86_64
 0040 0000 0000 - 0100 0000 0000: -
 0100 0000 0000 - 1000 0000 0000: shadow
 1000 0000 0000 - 3000 0000 0000: -
-3000 0000 0000 - 4000 0000 0000: metainfo (memory blocks and sync objects)
-4000 0000 0000 - 5500 0000 0000: -
+3000 0000 0000 - 3400 0000 0000: metainfo (memory blocks and sync objects)
+3400 0000 0000 - 5500 0000 0000: -
 5500 0000 0000 - 5680 0000 0000: pie binaries without ASLR or on 4.1+ kernels
 5680 0000 0000 - 7d00 0000 0000: -
 7b00 0000 0000 - 7c00 0000 0000: heap
@@ -147,88 +155,133 @@ struct MappingAppleAarch64 {
 
 /*
 C/C++ on linux/aarch64 (39-bit VMA)
-0000 0010 00 - 0100 0000 00: main binary
-0100 0000 00 - 0400 0000 00: -
-0400 0000 00 - 1000 0000 00: shadow memory
-2000 0000 00 - 3100 0000 00: -
-3100 0000 00 - 3400 0000 00: metainfo
-3400 0000 00 - 5500 0000 00: -
-5500 0000 00 - 5600 0000 00: main binary (PIE)
+0000 0010 00 - 0500 0000 00: main binary                    (20 GB)
+0100 0000 00 - 2000 0000 00: -
+2000 0000 00 - 4000 0000 00: shadow memory                 (128 GB)
+4000 0000 00 - 4800 0000 00: metainfo                       (32 GB)
+4800 0000 00 - 5500 0000 00: -
+5500 0000 00 - 5a00 0000 00: main binary (PIE)              (20 GB)
 5600 0000 00 - 7c00 0000 00: -
-7c00 0000 00 - 7d00 0000 00: heap
-7d00 0000 00 - 7fff ffff ff: modules and main thread stack
+7a00 0000 00 - 7d00 0000 00: heap                           (12 GB)
+7d00 0000 00 - 7fff ffff ff: modules and main thread stack  (12 GB)
 */
 struct MappingAarch64_39 {
   static const uptr kLoAppMemBeg   = 0x0000001000ull;
-  static const uptr kLoAppMemEnd   = 0x0100000000ull;
-  static const uptr kShadowBeg = 0x0400000000ull;
-  static const uptr kShadowEnd = 0x1000000000ull;
-  static const uptr kMetaShadowBeg = 0x3100000000ull;
-  static const uptr kMetaShadowEnd = 0x3400000000ull;
+  static const uptr kLoAppMemEnd   = 0x0500000000ull;
+  static const uptr kShadowBeg     = 0x2000000000ull;
+  static const uptr kShadowEnd     = 0x4000000000ull;
+  static const uptr kMetaShadowBeg = 0x4000000000ull;
+  static const uptr kMetaShadowEnd = 0x4800000000ull;
   static const uptr kMidAppMemBeg  = 0x5500000000ull;
-  static const uptr kMidAppMemEnd = 0x5600000000ull;
-  static const uptr kHeapMemBeg    = 0x7c00000000ull;
+  static const uptr kMidAppMemEnd  = 0x5a00000000ull;
+  static const uptr kHeapMemBeg    = 0x7a00000000ull;
   static const uptr kHeapMemEnd    = 0x7d00000000ull;
-  static const uptr kHiAppMemBeg   = 0x7e00000000ull;
+  static const uptr kHiAppMemBeg   = 0x7d00000000ull;
   static const uptr kHiAppMemEnd   = 0x7fffffffffull;
-  static const uptr kShadowMsk = 0x7800000000ull;
-  static const uptr kShadowXor = 0x0200000000ull;
-  static const uptr kShadowAdd = 0x0000000000ull;
+  static const uptr kShadowMsk     = 0x7000000000ull;
+  static const uptr kShadowXor     = 0x1000000000ull;
+  static const uptr kShadowAdd     = 0x0000000000ull;
   static const uptr kVdsoBeg       = 0x7f00000000ull;
 };
 
 /*
 C/C++ on linux/aarch64 (42-bit VMA)
-00000 0010 00 - 01000 0000 00: main binary
-01000 0000 00 - 08000 0000 00: -
-08000 0000 00 - 10000 0000 00: shadow memory
-10000 0000 00 - 26000 0000 00: -
-26000 0000 00 - 28000 0000 00: metainfo
-28000 0000 00 - 2aa00 0000 00: -
-2aa00 0000 00 - 2ab00 0000 00: main binary (PIE)
-2ab00 0000 00 - 3e000 0000 00: -
-3e000 0000 00 - 3f000 0000 00: heap
-3f000 0000 00 - 3ffff ffff ff: modules and main thread stack
+00000 0010 00 - 02000 0000 00: main binary                   (128 GB)
+02000 0000 00 - 08000 0000 00: -
+10000 0000 00 - 20000 0000 00: shadow memory                (1024 GB)
+20000 0000 00 - 24000 0000 00: metainfo                      (256 GB)
+24000 0000 00 - 2aa00 0000 00: -
+2aa00 0000 00 - 2c000 0000 00: main binary (PIE)              (88 GB)
+2c000 0000 00 - 3c000 0000 00: -
+3c000 0000 00 - 3f000 0000 00: heap                          (192 GB)
+3f000 0000 00 - 3ffff ffff ff: modules and main thread stack  (64 GB)
 */
 struct MappingAarch64_42 {
-  static const uptr kBroken = kBrokenReverseMapping;
   static const uptr kLoAppMemBeg   = 0x00000001000ull;
-  static const uptr kLoAppMemEnd   = 0x01000000000ull;
-  static const uptr kShadowBeg = 0x08000000000ull;
-  static const uptr kShadowEnd = 0x10000000000ull;
-  static const uptr kMetaShadowBeg = 0x26000000000ull;
-  static const uptr kMetaShadowEnd = 0x28000000000ull;
+  static const uptr kLoAppMemEnd   = 0x02000000000ull;
+  static const uptr kShadowBeg     = 0x10000000000ull;
+  static const uptr kShadowEnd     = 0x20000000000ull;
+  static const uptr kMetaShadowBeg = 0x20000000000ull;
+  static const uptr kMetaShadowEnd = 0x24000000000ull;
   static const uptr kMidAppMemBeg  = 0x2aa00000000ull;
-  static const uptr kMidAppMemEnd = 0x2ab00000000ull;
-  static const uptr kHeapMemBeg    = 0x3e000000000ull;
+  static const uptr kMidAppMemEnd  = 0x2c000000000ull;
+  static const uptr kHeapMemBeg    = 0x3c000000000ull;
   static const uptr kHeapMemEnd    = 0x3f000000000ull;
   static const uptr kHiAppMemBeg   = 0x3f000000000ull;
   static const uptr kHiAppMemEnd   = 0x3ffffffffffull;
-  static const uptr kShadowMsk = 0x3c000000000ull;
-  static const uptr kShadowXor = 0x04000000000ull;
-  static const uptr kShadowAdd = 0x00000000000ull;
+  static const uptr kShadowMsk     = 0x38000000000ull;
+  static const uptr kShadowXor     = 0x08000000000ull;
+  static const uptr kShadowAdd     = 0x00000000000ull;
   static const uptr kVdsoBeg       = 0x37f00000000ull;
 };
 
+/*
+C/C++ on linux/aarch64 (48-bit VMA)
+0000 0000 1000 - 0a00 0000 0000: main binary                   (10240 GB)
+0a00 0000 1000 - 1554 0000 0000: -
+1554 0000 1000 - 5400 0000 0000: shadow memory                 (64176 GB)
+5400 0000 1000 - 8000 0000 0000: -
+8000 0000 1000 - 0a00 0000 0000: metainfo                      (32768 GB)
+a000 0000 1000 - aaaa 0000 0000: -
+aaaa 0000 1000 - ac00 0000 0000: main binary (PIE)              (1368 GB)
+ac00 0000 1000 - fc00 0000 0000: -
+fc00 0000 1000 - ffff ffff ffff: modules and main thread stack  (4096 GB)
+
+N.B. the shadow memory region has a strange start address, because it
+contains the shadows for the mid, high and low app regions (in this
+unusual order).
+*/
 struct MappingAarch64_48 {
   static const uptr kLoAppMemBeg   = 0x0000000001000ull;
-  static const uptr kLoAppMemEnd   = 0x0000200000000ull;
-  static const uptr kShadowBeg = 0x0001000000000ull;
-  static const uptr kShadowEnd = 0x0002000000000ull;
-  static const uptr kMetaShadowBeg = 0x0005000000000ull;
-  static const uptr kMetaShadowEnd = 0x0006000000000ull;
+  static const uptr kLoAppMemEnd   = 0x00a0000000000ull;
+  static const uptr kShadowBeg     = 0x0155400000000ull;
+  static const uptr kShadowEnd     = 0x0540000000000ull;
+  static const uptr kMetaShadowBeg = 0x0800000000000ull;
+  static const uptr kMetaShadowEnd = 0x0a00000000000ull;
   static const uptr kMidAppMemBeg  = 0x0aaaa00000000ull;
-  static const uptr kMidAppMemEnd = 0x0aaaf00000000ull;
-  static const uptr kHeapMemBeg    = 0x0ffff00000000ull;
-  static const uptr kHeapMemEnd    = 0x0ffff00000000ull;
-  static const uptr kHiAppMemBeg   = 0x0ffff00000000ull;
+  static const uptr kMidAppMemEnd  = 0x0ac0000000000ull;
+  static const uptr kHiAppMemBeg   = 0x0fc0000000000ull;
   static const uptr kHiAppMemEnd   = 0x1000000000000ull;
-  static const uptr kShadowMsk = 0x0fff800000000ull;
-  static const uptr kShadowXor = 0x0000800000000ull;
-  static const uptr kShadowAdd = 0x0000000000000ull;
+  static const uptr kHeapMemBeg    = 0x0fc0000000000ull;
+  static const uptr kHeapMemEnd    = 0x0fc0000000000ull;
+  static const uptr kShadowMsk     = 0x0c00000000000ull;
+  static const uptr kShadowXor     = 0x0200000000000ull;
+  static const uptr kShadowAdd     = 0x0000000000000ull;
   static const uptr kVdsoBeg       = 0xffff000000000ull;
 };
 
+/* C/C++ on linux/loongarch64 (47-bit VMA)
+0000 0000 4000 - 0080 0000 0000: main binary
+0080 0000 0000 - 0100 0000 0000: -
+0100 0000 0000 - 1000 0000 0000: shadow memory
+1000 0000 0000 - 3000 0000 0000: -
+3000 0000 0000 - 3400 0000 0000: metainfo
+3400 0000 0000 - 5555 0000 0000: -
+5555 0000 0000 - 5556 0000 0000: main binary (PIE)
+5556 0000 0000 - 7ffe 0000 0000: -
+7ffe 0000 0000 - 7fff 0000 0000: heap
+7fff 0000 0000 - 7fff 8000 0000: -
+7fff 8000 0000 - 8000 0000 0000: modules and main thread stack
+*/
+struct MappingLoongArch64_47 {
+  static const uptr kMetaShadowBeg = 0x300000000000ull;
+  static const uptr kMetaShadowEnd = 0x340000000000ull;
+  static const uptr kShadowBeg     = 0x010000000000ull;
+  static const uptr kShadowEnd     = 0x100000000000ull;
+  static const uptr kHeapMemBeg    = 0x7ffe00000000ull;
+  static const uptr kHeapMemEnd    = 0x7fff00000000ull;
+  static const uptr kLoAppMemBeg   = 0x000000004000ull;
+  static const uptr kLoAppMemEnd   = 0x008000000000ull;
+  static const uptr kMidAppMemBeg  = 0x555500000000ull;
+  static const uptr kMidAppMemEnd  = 0x555600000000ull;
+  static const uptr kHiAppMemBeg   = 0x7fff80000000ull;
+  static const uptr kHiAppMemEnd   = 0x800000000000ull;
+  static const uptr kShadowMsk     = 0x780000000000ull;
+  static const uptr kShadowXor     = 0x040000000000ull;
+  static const uptr kShadowAdd     = 0x000000000000ull;
+  static const uptr kVdsoBeg       = 0x7fffffffc000ull;
+};
+
 /*
 C/C++ on linux/powerpc64 (44-bit VMA)
 0000 0000 0100 - 0001 0000 0000: main binary
@@ -242,8 +295,8 @@ C/C++ on linux/powerpc64 (44-bit VMA)
 0f60 0000 0000 - 1000 0000 0000: modules and main thread stack
 */
 struct MappingPPC64_44 {
-  static const uptr kBroken =
-      kBrokenMapping | kBrokenReverseMapping | kBrokenLinearity;
+  static const uptr kBroken = kBrokenMapping | kBrokenReverseMapping |
+                              kBrokenLinearity | kBrokenAliasedMetas;
   static const uptr kMetaShadowBeg = 0x0b0000000000ull;
   static const uptr kMetaShadowEnd = 0x0d0000000000ull;
   static const uptr kShadowBeg     = 0x000100000000ull;
@@ -599,6 +652,8 @@ ALWAYS_INLINE auto SelectMapping(Arg arg) {
     case 48:
       return Func::template Apply<MappingAarch64_48>(arg);
   }
+#  elif SANITIZER_LOONGARCH64
+  return Func::template Apply<MappingLoongArch64_47>(arg);
 #  elif defined(__powerpc64__)
   switch (vmaSize) {
     case 44:
@@ -627,6 +682,7 @@ void ForEachMapping() {
   Func::template Apply<MappingAarch64_39>();
   Func::template Apply<MappingAarch64_42>();
   Func::template Apply<MappingAarch64_48>();
+  Func::template Apply<MappingLoongArch64_47>();
   Func::template Apply<MappingPPC64_44>();
   Func::template Apply<MappingPPC64_46>();
   Func::template Apply<MappingPPC64_47>();
diff --git a/libsanitizer/tsan/tsan_platform_linux.cpp b/libsanitizer/tsan/tsan_platform_linux.cpp
index 807f6be2eee..384a443c16b 100644
--- a/libsanitizer/tsan/tsan_platform_linux.cpp
+++ b/libsanitizer/tsan/tsan_platform_linux.cpp
@@ -66,7 +66,8 @@ extern "C" void *__libc_stack_end;
 void *__libc_stack_end = 0;
 #endif
 
-#if SANITIZER_LINUX && defined(__aarch64__) && !SANITIZER_GO
+#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__loongarch_lp64)) && \
+    !SANITIZER_GO
 # define INIT_LONGJMP_XOR_KEY 1
 #else
 # define INIT_LONGJMP_XOR_KEY 0
@@ -230,6 +231,14 @@ void InitializePlatformEarly() {
     Die();
   }
 #endif
+#elif SANITIZER_LOONGARCH64
+# if !SANITIZER_GO
+  if (vmaSize != 47) {
+    Printf("FATAL: ThreadSanitizer: unsupported VMA range\n");
+    Printf("FATAL: Found %zd - Supported 47\n", vmaSize);
+    Die();
+  }
+# endif
 #elif defined(__powerpc64__)
 # if !SANITIZER_GO
   if (vmaSize != 44 && vmaSize != 46 && vmaSize != 47) {
@@ -290,11 +299,12 @@ void InitializePlatform() {
       SetAddressSpaceUnlimited();
       reexec = true;
     }
-#if SANITIZER_LINUX && defined(__aarch64__)
+#if SANITIZER_ANDROID && (defined(__aarch64__) || defined(__x86_64__))
     // After patch "arm64: mm: support ARCH_MMAP_RND_BITS." is introduced in
     // linux kernel, the random gap between stack and mapped area is increased
     // from 128M to 36G on 39-bit aarch64. As it is almost impossible to cover
     // this big range, we should disable randomized virtual space on aarch64.
+    // ASLR personality check.
     int old_personality = personality(0xffffffff);
     if (old_personality != -1 && (old_personality & ADDR_NO_RANDOMIZE) == 0) {
       VReport(1, "WARNING: Program is run with randomized virtual address "
@@ -303,6 +313,9 @@ void InitializePlatform() {
       CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
       reexec = true;
     }
+
+#endif
+#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__loongarch_lp64))
     // Initialize the xor key used in {sig}{set,long}jump.
     InitializeLongjmpXorKey();
 #endif
@@ -375,6 +388,8 @@ static uptr UnmangleLongJmpSp(uptr mangled_sp) {
 # else
   return mangled_sp;
 # endif
+#elif defined(__loongarch_lp64)
+  return mangled_sp ^ longjmp_xor_key;
 #elif defined(__powerpc64__)
   // Reverse of:
   //   ld   r4, -28696(r13)
@@ -410,6 +425,8 @@ static uptr UnmangleLongJmpSp(uptr mangled_sp) {
 #elif SANITIZER_LINUX
 # ifdef __aarch64__
 #  define LONG_JMP_SP_ENV_SLOT 13
+# elif defined(__loongarch__)
+#  define LONG_JMP_SP_ENV_SLOT 1
 # elif defined(__mips64)
 #  define LONG_JMP_SP_ENV_SLOT 1
 # elif defined(__s390x__)
@@ -436,7 +453,11 @@ static void InitializeLongjmpXorKey() {
 
   // 2. Retrieve vanilla/mangled SP.
   uptr sp;
+#ifdef __loongarch__
+  asm("move  %0, $sp" : "=r" (sp));
+#else
   asm("mov  %0, sp" : "=r" (sp));
+#endif
   uptr mangled_sp = ((uptr *)&env)[LONG_JMP_SP_ENV_SLOT];
 
   // 3. xor SPs to obtain key.
diff --git a/libsanitizer/tsan/tsan_platform_posix.cpp b/libsanitizer/tsan/tsan_platform_posix.cpp
index 71874aad8dc..e7dcd664dc0 100644
--- a/libsanitizer/tsan/tsan_platform_posix.cpp
+++ b/libsanitizer/tsan/tsan_platform_posix.cpp
@@ -32,7 +32,7 @@ static const char kShadowMemoryMappingHint[] =
     "TSAN_OPTIONS=%s=0\n";
 
 #  if !SANITIZER_GO
-static void DontDumpShadow(uptr addr, uptr size) {
+void DontDumpShadow(uptr addr, uptr size) {
   if (common_flags()->use_madv_dontdump)
     if (!DontDumpShadowMemory(addr, size)) {
       Printf(kShadowMemoryMappingWarning, SanitizerToolName, addr, addr + size,
diff --git a/libsanitizer/tsan/tsan_rtl.cpp b/libsanitizer/tsan/tsan_rtl.cpp
index db3d94518b8..6b1ec1d04fd 100644
--- a/libsanitizer/tsan/tsan_rtl.cpp
+++ b/libsanitizer/tsan/tsan_rtl.cpp
@@ -213,6 +213,9 @@ static void DoResetImpl(uptr epoch) {
 #else
   auto resetFailed =
       !MmapFixedSuperNoReserve(shadow_begin, shadow_end-shadow_begin, "shadow");
+#  if !SANITIZER_GO
+  DontDumpShadow(shadow_begin, shadow_end - shadow_begin);
+#  endif
 #endif
   if (resetFailed) {
     Printf("failed to reset shadow memory\n");
diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h
index f0918d86d4e..a5606dbc7f8 100644
--- a/libsanitizer/tsan/tsan_rtl.h
+++ b/libsanitizer/tsan/tsan_rtl.h
@@ -56,7 +56,8 @@ namespace __tsan {
 
 #if !SANITIZER_GO
 struct MapUnmapCallback;
-#if defined(__mips64) || defined(__aarch64__) || defined(__powerpc__)
+#if defined(__mips64) || defined(__aarch64__) || defined(__loongarch__) || \
+    defined(__powerpc__)
 
 struct AP32 {
   static const uptr kSpaceBeg = 0;
@@ -219,7 +220,7 @@ struct ThreadState {
 #endif
 
   atomic_uintptr_t in_signal_handler;
-  ThreadSignalContext *signal_ctx;
+  atomic_uintptr_t signal_ctx;
 
 #if !SANITIZER_GO
   StackID last_sleep_stack_id;
@@ -483,6 +484,7 @@ void MapThreadTrace(uptr addr, uptr size, const char *name);
 void DontNeedShadowFor(uptr addr, uptr size);
 void UnmapShadow(ThreadState *thr, uptr addr, uptr size);
 void InitializeShadowMemory();
+void DontDumpShadow(uptr addr, uptr size);
 void InitializeInterceptors();
 void InitializeLibIgnore();
 void InitializeDynamicAnnotations();
@@ -678,8 +680,9 @@ ALWAYS_INLINE
 void LazyInitialize(ThreadState *thr) {
   // If we can use .preinit_array, assume that __tsan_init
   // called from .preinit_array initializes runtime before
-  // any instrumented code except ANDROID.
-#if (!SANITIZER_CAN_USE_PREINIT_ARRAY || defined(__ANDROID__))
+  // any instrumented code except when tsan is used as a 
+  // shared library.
+#if (!SANITIZER_CAN_USE_PREINIT_ARRAY || defined(SANITIZER_SHARED))
   if (UNLIKELY(!is_initialized))
     Initialize(thr);
 #endif
diff --git a/libsanitizer/tsan/tsan_rtl_aarch64.S b/libsanitizer/tsan/tsan_rtl_aarch64.S
index e0b4c71dfed..c6162659b87 100644
--- a/libsanitizer/tsan/tsan_rtl_aarch64.S
+++ b/libsanitizer/tsan/tsan_rtl_aarch64.S
@@ -3,28 +3,6 @@
 
 #include "sanitizer_common/sanitizer_asm.h"
 
-#if defined(__APPLE__)
-.align  2
-
-.section  __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers
-.long _setjmp$non_lazy_ptr
-_setjmp$non_lazy_ptr:
-.indirect_symbol _setjmp
-.long 0
-
-.section  __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers
-.long __setjmp$non_lazy_ptr
-__setjmp$non_lazy_ptr:
-.indirect_symbol __setjmp
-.long 0
-
-.section  __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers
-.long _sigsetjmp$non_lazy_ptr
-_sigsetjmp$non_lazy_ptr:
-.indirect_symbol _sigsetjmp
-.long 0
-#endif
-
 #if !defined(__APPLE__)
 .section .text
 #else
@@ -75,9 +53,8 @@ ASM_SYMBOL_INTERCEPTOR(setjmp):
   ldr     x1, [x1, #:got_lo12:_ZN14__interception11real_setjmpE]
   ldr     x1, [x1]
 #else
-  adrp    x1, _setjmp$non_lazy_ptr@page
-  add     x1, x1, _setjmp$non_lazy_ptr@pageoff
-  ldr     x1, [x1]
+  adrp    x1, _setjmp@GOTPAGE
+  ldr     x1, [x1, _setjmp@GOTPAGEOFF]
 #endif
   br      x1
 
@@ -126,9 +103,8 @@ ASM_SYMBOL_INTERCEPTOR(_setjmp):
   ldr     x1, [x1, #:got_lo12:_ZN14__interception12real__setjmpE]
   ldr     x1, [x1]
 #else
-  adrp    x1, __setjmp$non_lazy_ptr@page
-  add     x1, x1, __setjmp$non_lazy_ptr@pageoff
-  ldr     x1, [x1]
+  adrp    x1, __setjmp@GOTPAGE
+  ldr     x1, [x1, __setjmp@GOTPAGEOFF]
 #endif
   br      x1
 
@@ -179,9 +155,8 @@ ASM_SYMBOL_INTERCEPTOR(sigsetjmp):
   ldr     x2, [x2, #:got_lo12:_ZN14__interception14real_sigsetjmpE]
   ldr     x2, [x2]
 #else
-  adrp    x2, _sigsetjmp$non_lazy_ptr@page
-  add     x2, x2, _sigsetjmp$non_lazy_ptr@pageoff
-  ldr     x2, [x2]
+  adrp    x2, _sigsetjmp@GOTPAGE
+  ldr     x2, [x2, _sigsetjmp@GOTPAGEOFF]
 #endif
   br      x2
   CFI_ENDPROC
diff --git a/libsanitizer/tsan/tsan_rtl_loongarch64.S b/libsanitizer/tsan/tsan_rtl_loongarch64.S
new file mode 100644
index 00000000000..12856bd110c
--- /dev/null
+++ b/libsanitizer/tsan/tsan_rtl_loongarch64.S
@@ -0,0 +1,196 @@
+#include "sanitizer_common/sanitizer_asm.h"
+
+.section .text
+
+ASM_HIDDEN(__tsan_setjmp)
+.comm _ZN14__interception11real_setjmpE,8,8
+.globl ASM_SYMBOL_INTERCEPTOR(setjmp)
+ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(setjmp))
+ASM_SYMBOL_INTERCEPTOR(setjmp):
+  CFI_STARTPROC
+
+  // Save frame pointer and return address register
+  addi.d $sp, $sp, -32
+  st.d $ra, $sp, 24
+  st.d $fp, $sp, 16
+  CFI_DEF_CFA_OFFSET (32)
+  CFI_OFFSET (1, -8)
+  CFI_OFFSET (22, -16)
+
+  // Adjust the SP for previous frame
+  addi.d $fp, $sp, 32
+  CFI_DEF_CFA_REGISTER (22)
+
+  // Save env parameter
+  st.d $a0, $sp, 8
+  CFI_OFFSET (4, -24)
+
+  // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)`
+  addi.d  $a0, $fp, 0
+
+  // call tsan interceptor
+  bl      ASM_SYMBOL(__tsan_setjmp)
+
+  // Restore env parameter
+  ld.d $a0, $sp, 8
+  CFI_RESTORE (4)
+
+  // Restore frame/link register
+  ld.d $fp, $sp, 16
+  ld.d $ra, $sp, 24
+  addi.d $sp, $sp, 32
+  CFI_RESTORE (22)
+  CFI_RESTORE (1)
+  CFI_DEF_CFA (3, 0)
+
+  // tail jump to libc setjmp
+  la.local $a1, _ZN14__interception11real_setjmpE
+  ld.d $a1, $a1, 0
+  jr $a1
+
+  CFI_ENDPROC
+ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(setjmp))
+
+.comm _ZN14__interception12real__setjmpE,8,8
+.globl ASM_SYMBOL_INTERCEPTOR(_setjmp)
+ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(_setjmp))
+ASM_SYMBOL_INTERCEPTOR(_setjmp):
+  CFI_STARTPROC
+
+  // Save frame pointer and return address register
+  addi.d $sp, $sp, -32
+  st.d $ra, $sp, 24
+  st.d $fp, $sp, 16
+  CFI_DEF_CFA_OFFSET (32)
+  CFI_OFFSET (1, -8)
+  CFI_OFFSET (22, -16)
+
+  // Adjust the SP for previous frame
+  addi.d $fp, $sp, 32
+  CFI_DEF_CFA_REGISTER (22)
+
+  // Save env parameter
+  st.d $a0, $sp, 8
+  CFI_OFFSET (4, -24)
+
+  // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)`
+  addi.d  $a0, $fp, 0
+
+  // call tsan interceptor
+  bl      ASM_SYMBOL(__tsan_setjmp)
+
+  // Restore env parameter
+  ld.d $a0, $sp, 8
+  CFI_RESTORE (4)
+
+  // Restore frame/link register
+  ld.d $fp, $sp, 16
+  ld.d $ra, $sp, 24
+  addi.d $sp, $sp, 32
+  CFI_RESTORE (22)
+  CFI_RESTORE (1)
+  CFI_DEF_CFA (3, 0)
+
+  // tail jump to libc setjmp
+  la.local $a1, _ZN14__interception12real__setjmpE
+  ld.d $a1, $a1, 0
+  jr $a1
+
+  CFI_ENDPROC
+ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(_setjmp))
+
+.comm _ZN14__interception14real_sigsetjmpE,8,8
+.globl ASM_SYMBOL_INTERCEPTOR(sigsetjmp)
+ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(sigsetjmp))
+ASM_SYMBOL_INTERCEPTOR(sigsetjmp):
+  CFI_STARTPROC
+
+  // Save frame pointer and return address register
+  addi.d $sp, $sp, -32
+  st.d $ra, $sp, 24
+  st.d $fp, $sp, 16
+  CFI_DEF_CFA_OFFSET (32)
+  CFI_OFFSET (1, -8)
+  CFI_OFFSET (22, -16)
+
+  // Adjust the SP for previous frame
+  addi.d $fp, $sp, 32
+  CFI_DEF_CFA_REGISTER (22)
+
+  // Save env parameter
+  st.d $a0, $sp, 8
+  CFI_OFFSET (4, -24)
+
+  // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)`
+  addi.d  $a0, $fp, 0
+
+  // call tsan interceptor
+  bl      ASM_SYMBOL(__tsan_setjmp)
+
+  // Restore env parameter
+  ld.d $a0, $sp, 8
+  CFI_RESTORE (4)
+
+  // Restore frame/link register
+  ld.d $fp, $sp, 16
+  ld.d $ra, $sp, 24
+  addi.d $sp, $sp, 32
+  CFI_RESTORE (22)
+  CFI_RESTORE (1)
+  CFI_DEF_CFA (3, 0)
+
+  // tail jump to libc setjmp
+  la.local $a1, _ZN14__interception14real_sigsetjmpE
+  ld.d $a1, $a1, 0
+  jr $a1
+
+  CFI_ENDPROC
+ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(sigsetjmp))
+
+.comm _ZN14__interception16real___sigsetjmpE,8,8
+.globl ASM_SYMBOL_INTERCEPTOR(__sigsetjmp)
+ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp))
+ASM_SYMBOL_INTERCEPTOR(__sigsetjmp):
+  CFI_STARTPROC
+
+  // Save frame pointer and return address register
+  addi.d $sp, $sp, -32
+  st.d $ra, $sp, 24
+  st.d $fp, $sp, 16
+  CFI_DEF_CFA_OFFSET (32)
+  CFI_OFFSET (1, -8)
+  CFI_OFFSET (22, -16)
+
+  // Adjust the SP for previous frame
+  addi.d $fp, $sp, 32
+  CFI_DEF_CFA_REGISTER (22)
+
+  // Save env parameter
+  st.d $a0, $sp, 8
+  CFI_OFFSET (4, -24)
+
+  // Obtain SP, first argument to `void __tsan_setjmp(uptr sp)`
+  addi.d  $a0, $fp, 0
+
+  // call tsan interceptor
+  bl      ASM_SYMBOL(__tsan_setjmp)
+
+  // Restore env parameter
+  ld.d $a0, $sp, 8
+  CFI_RESTORE (4)
+
+  // Restore frame/link register
+  ld.d $fp, $sp, 16
+  ld.d $ra, $sp, 24
+  addi.d $sp, $sp, 32
+  CFI_RESTORE (22)
+  CFI_RESTORE (1)
+  CFI_DEF_CFA (3, 0)
+
+  // tail jump to libc setjmp
+  la.local $a1, _ZN14__interception16real___sigsetjmpE
+  ld.d $a1, $a1, 0
+  jr $a1
+
+  CFI_ENDPROC
+ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp))
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 c2cff60e2da..0311df553fd 100644
--- a/libsanitizer/tsan/tsan_rtl_report.cpp
+++ b/libsanitizer/tsan/tsan_rtl_report.cpp
@@ -10,20 +10,20 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
-#include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
+#include "tsan_fd.h"
+#include "tsan_flags.h"
+#include "tsan_mman.h"
 #include "tsan_platform.h"
+#include "tsan_report.h"
 #include "tsan_rtl.h"
 #include "tsan_suppressions.h"
 #include "tsan_symbolize.h"
-#include "tsan_report.h"
 #include "tsan_sync.h"
-#include "tsan_mman.h"
-#include "tsan_flags.h"
-#include "tsan_fd.h"
 
 namespace __tsan {
 
diff --git a/libsanitizer/tsan/tsan_spinlock_defs_mac.h b/libsanitizer/tsan/tsan_spinlock_defs_mac.h
new file mode 100644
index 00000000000..1a99a81c030
--- /dev/null
+++ b/libsanitizer/tsan/tsan_spinlock_defs_mac.h
@@ -0,0 +1,45 @@
+//===-- tsan_spinlock_defs_mac.h -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+// Mac-specific forward-declared function defintions that may be
+// deprecated in later versions of the OS.
+// These are needed for interceptors.
+//
+//===----------------------------------------------------------------------===//
+
+#if SANITIZER_APPLE
+
+#ifndef TSAN_SPINLOCK_DEFS_MAC_H
+#define TSAN_SPINLOCK_DEFS_MAC_H
+
+#include <stdint.h>
+
+extern "C" {
+
+/*
+Provides forward declarations related to OSSpinLocks on Darwin. These functions are
+deprecated on macOS version 10.12 and later,
+and are no longer included in the system headers.
+
+However, the symbols are still available on the system, so we provide these forward
+declarations to prevent compilation errors in tsan_interceptors_mac.cpp, which
+references these functions when defining TSAN interceptor functions.
+*/
+
+typedef int32_t OSSpinLock;
+
+void OSSpinLockLock(volatile OSSpinLock *__lock);
+void OSSpinLockUnlock(volatile OSSpinLock *__lock);
+bool OSSpinLockTry(volatile OSSpinLock *__lock);
+
+}
+
+#endif //TSAN_SPINLOCK_DEFS_MAC_H
+#endif // SANITIZER_APPLE
diff --git a/libsanitizer/tsan/tsan_suppressions.cpp b/libsanitizer/tsan/tsan_suppressions.cpp
index a1c1bf81bf6..9cdfa32a934 100644
--- a/libsanitizer/tsan/tsan_suppressions.cpp
+++ b/libsanitizer/tsan/tsan_suppressions.cpp
@@ -10,15 +10,16 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "tsan_suppressions.h"
+
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_suppressions.h"
-#include "tsan_suppressions.h"
-#include "tsan_rtl.h"
 #include "tsan_flags.h"
 #include "tsan_mman.h"
 #include "tsan_platform.h"
+#include "tsan_rtl.h"
 
 #if !SANITIZER_GO
 // Suppressions for true/false positives in standard libraries.
diff --git a/libsanitizer/ubsan/ubsan_diag.cpp b/libsanitizer/ubsan/ubsan_diag.cpp
index 3673e66539d..dd99613abbe 100644
--- a/libsanitizer/ubsan/ubsan_diag.cpp
+++ b/libsanitizer/ubsan/ubsan_diag.cpp
@@ -214,7 +214,12 @@ static void RenderText(InternalScopedString *Buffer, const char *Message,
       //        printf, and stop using snprintf here.
       char FloatBuffer[32];
 #if SANITIZER_WINDOWS
-      sprintf_s(FloatBuffer, sizeof(FloatBuffer), "%Lg", (long double)A.Float);
+      // On MSVC platforms, long doubles are equal to regular doubles.
+      // In MinGW environments on x86, long doubles are 80 bit, but here,
+      // we're calling an MS CRT provided printf function which considers
+      // long doubles to be 64 bit. Just cast the float value to a regular
+      // double to avoid the potential ambiguity in MinGW mode.
+      sprintf_s(FloatBuffer, sizeof(FloatBuffer), "%g", (double)A.Float);
 #else
       snprintf(FloatBuffer, sizeof(FloatBuffer), "%Lg", (long double)A.Float);
 #endif
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 970075e69a6..410292a0d53 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_platform.h b/libsanitizer/ubsan/ubsan_platform.h
index ad3e883f0f3..d2cc2e10bd2 100644
--- a/libsanitizer/ubsan/ubsan_platform.h
+++ b/libsanitizer/ubsan/ubsan_platform.h
@@ -12,7 +12,6 @@
 #ifndef UBSAN_PLATFORM_H
 #define UBSAN_PLATFORM_H
 
-#ifndef CAN_SANITIZE_UB
 // Other platforms should be easy to add, and probably work as-is.
 #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) ||        \
     defined(__NetBSD__) || defined(__DragonFly__) ||                           \
@@ -22,6 +21,5 @@
 #else
 # define CAN_SANITIZE_UB 0
 #endif
-#endif //CAN_SANITIZE_UB
 
 #endif
diff --git a/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp b/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp
index d82b542a020..468a8fcd603 100644
--- a/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp
+++ b/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp
@@ -17,6 +17,7 @@
 
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_ptrauth.h"
+#include <stdint.h>
 
 // The following are intended to be binary compatible with the definitions
 // given in the Itanium ABI. We make no attempt to be ODR-compatible with
@@ -25,9 +26,20 @@
 namespace std {
   class type_info {
   public:
+    typedef const char *__type_name_t;
     virtual ~type_info();
 
     const char *__type_name;
+
+    __type_name_t name() const {
+#if defined(__APPLE__) && defined(__LP64__) && !defined(__x86_64__)
+      uintptr_t __non_unique_rtti_bit =
+          (1ULL << ((__CHAR_BIT__ * sizeof(__type_name_t)) - 1));
+      return (__type_name_t)((uintptr_t)__type_name & ~__non_unique_rtti_bit);
+#else
+      return __type_name;
+#endif
+    }
   };
 }
 
@@ -117,7 +129,7 @@ static __ubsan::HashValue *getTypeCacheHashTableBucket(__ubsan::HashValue V) {
 static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived,
                                   const abi::__class_type_info *Base,
                                   sptr Offset) {
-  if (Derived->__type_name == Base->__type_name ||
+  if (Derived->name() == Base->name() ||
       __ubsan::checkTypeInfoEquality(Derived, Base))
     return Offset == 0;
 
@@ -254,17 +266,16 @@ __ubsan::getDynamicTypeInfoFromVtable(void *VtablePtr) {
   const abi::__class_type_info *ObjectType = findBaseAtOffset(
     static_cast<const abi::__class_type_info*>(Vtable->TypeInfo),
     -Vtable->Offset);
-  return DynamicTypeInfo(Vtable->TypeInfo->__type_name, -Vtable->Offset,
-                         ObjectType ? ObjectType->__type_name : "<unknown>");
+  return DynamicTypeInfo(Vtable->TypeInfo->name(), -Vtable->Offset,
+                         ObjectType ? ObjectType->name() : "<unknown>");
 }
 
 bool __ubsan::checkTypeInfoEquality(const void *TypeInfo1,
                                     const void *TypeInfo2) {
   auto TI1 = static_cast<const std::type_info *>(TypeInfo1);
   auto TI2 = static_cast<const std::type_info *>(TypeInfo2);
-  return SANITIZER_NON_UNIQUE_TYPEINFO && TI1->__type_name[0] != '*' &&
-         TI2->__type_name[0] != '*' &&
-         !internal_strcmp(TI1->__type_name, TI2->__type_name);
+  return SANITIZER_NON_UNIQUE_TYPEINFO && TI1->name()[0] != '*' &&
+         TI2->name()[0] != '*' && !internal_strcmp(TI1->name(), TI2->name());
 }
 
 #endif  // CAN_SANITIZE_UB && !SANITIZER_WINDOWS

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-04-26 13:53 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-04-26 13:53 [gcc r14-263] libsanitizer: merge from upstream (3185e47b5a8444e9fd) Martin Liska

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).