diff mbox series

[1/4] libsanitizer: merge from upstream (61a6439f35b6de28)

Message ID 20241107063538.4172543-2-kito.cheng@sifive.com
State New
Headers show
Series libsanitizer: merge from upstream | expand

Commit Message

Kito Cheng Nov. 7, 2024, 6:35 a.m. UTC
---
 libsanitizer/MERGE                            |    2 +-
 libsanitizer/asan/Makefile.am                 |    1 -
 libsanitizer/asan/Makefile.in                 |    5 +-
 libsanitizer/asan/asan_allocator.cpp          |   10 +-
 libsanitizer/asan/asan_allocator.h            |   36 +-
 libsanitizer/asan/asan_descriptions.cpp       |   52 +-
 libsanitizer/asan/asan_descriptions.h         |    2 -
 libsanitizer/asan/asan_errors.cpp             |   20 +-
 libsanitizer/asan/asan_errors.h               |   19 +
 libsanitizer/asan/asan_flags.cpp              |   96 +-
 libsanitizer/asan/asan_fuchsia.cpp            |    7 +-
 libsanitizer/asan/asan_globals.cpp            |  278 ++-
 libsanitizer/asan/asan_globals_win.cpp        |   12 +-
 libsanitizer/asan/asan_interceptors.cpp       |  139 +-
 libsanitizer/asan/asan_interceptors.h         |   15 +-
 libsanitizer/asan/asan_internal.h             |    4 +-
 libsanitizer/asan/asan_linux.cpp              |   29 +-
 libsanitizer/asan/asan_lock.h                 |    0
 libsanitizer/asan/asan_mac.cpp                |   12 +-
 libsanitizer/asan/asan_malloc_linux.cpp       |   16 +-
 libsanitizer/asan/asan_malloc_mac.cpp         |    5 +-
 libsanitizer/asan/asan_malloc_win.cpp         |   97 +-
 libsanitizer/asan/asan_malloc_win_thunk.cpp   |  229 ++
 libsanitizer/asan/asan_mapping.h              |    9 +-
 libsanitizer/asan/asan_new_delete.cpp         |    9 -
 libsanitizer/asan/asan_poisoning.cpp          |  184 +-
 libsanitizer/asan/asan_posix.cpp              |   47 +-
 libsanitizer/asan/asan_preinit.cpp            |   10 +-
 libsanitizer/asan/asan_premap_shadow.cpp      |    3 +-
 libsanitizer/asan/asan_report.cpp             |   43 +-
 libsanitizer/asan/asan_report.h               |    3 +
 libsanitizer/asan/asan_rtl.cpp                |   65 +-
 libsanitizer/asan/asan_rtl_x86_64.S           |   10 +
 libsanitizer/asan/asan_suppressions.cpp       |   12 +-
 libsanitizer/asan/asan_thread.cpp             |   40 +-
 libsanitizer/asan/asan_thread.h               |   11 +-
 libsanitizer/asan/asan_win.cpp                |   12 +-
 .../asan/asan_win_common_runtime_thunk.cpp    |  112 +
 .../asan/asan_win_common_runtime_thunk.h      |   38 +
 libsanitizer/asan/asan_win_dll_thunk.cpp      |  165 --
 .../asan/asan_win_dynamic_runtime_thunk.cpp   |  104 +-
 .../asan/asan_win_static_runtime_thunk.cpp    |  113 +
 .../asan/asan_win_weak_interception.cpp       |   22 -
 libsanitizer/builtins/assembly.h              |    5 +-
 libsanitizer/hwasan/hwasan.cpp                |    8 +-
 libsanitizer/hwasan/hwasan.h                  |   10 +-
 .../hwasan/hwasan_allocation_functions.cpp    |    8 +-
 libsanitizer/hwasan/hwasan_allocator.cpp      |    7 +-
 libsanitizer/hwasan/hwasan_checks.h           |    1 -
 libsanitizer/hwasan/hwasan_dynamic_shadow.cpp |   17 +-
 libsanitizer/hwasan/hwasan_flags.inc          |    7 +
 libsanitizer/hwasan/hwasan_interceptors.cpp   |    7 +-
 .../hwasan/hwasan_interface_internal.h        |    3 +
 libsanitizer/hwasan/hwasan_linux.cpp          |  108 +-
 libsanitizer/hwasan/hwasan_preinit.cpp        |   10 +-
 libsanitizer/hwasan/hwasan_report.cpp         |  161 +-
 libsanitizer/hwasan/hwasan_thread.cpp         |    8 +-
 libsanitizer/hwasan/hwasan_thread_list.cpp    |    9 +-
 libsanitizer/hwasan/hwasan_thread_list.h      |    8 +-
 .../include/sanitizer/allocator_interface.h   |   15 +-
 .../include/sanitizer/common_interface_defs.h |   39 +-
 .../include/sanitizer/hwasan_interface.h      |    4 +
 .../include/sanitizer/linux_syscall_hooks.h   |   16 +-
 .../include/sanitizer/memprof_interface.h     |    6 +
 .../include/sanitizer/nsan_interface.h        |   75 +
 .../include/sanitizer/rtsan_interface.h       |   75 +
 .../include/sanitizer/ubsan_interface.h       |    2 +
 libsanitizer/interception/interception.h      |   35 +-
 .../interception/interception_linux.h         |   16 +-
 .../interception/interception_type_test.cpp   |   31 +-
 .../interception/interception_win.cpp         |  237 +-
 libsanitizer/lsan/lsan.cpp                    |    3 +-
 libsanitizer/lsan/lsan.h                      |    1 +
 libsanitizer/lsan/lsan_allocator.cpp          |    2 +-
 libsanitizer/lsan/lsan_common.cpp             |  355 ++-
 libsanitizer/lsan/lsan_common.h               |    5 +
 libsanitizer/lsan/lsan_common_linux.cpp       |    2 +-
 libsanitizer/lsan/lsan_flags.inc              |    7 +
 libsanitizer/lsan/lsan_fuchsia.cpp            |    1 +
 libsanitizer/lsan/lsan_interceptors.cpp       |   12 +-
 libsanitizer/lsan/lsan_posix.cpp              |   45 +-
 libsanitizer/lsan/lsan_preinit.cpp            |    8 +-
 libsanitizer/lsan/lsan_thread.cpp             |   13 +-
 libsanitizer/sanitizer_common/Makefile.am     |    6 +-
 libsanitizer/sanitizer_common/Makefile.in     |   20 +-
 .../sanitizer_common/sancov_flags.cpp         |    6 +-
 .../sanitizer_common/sanitizer_allocator.cpp  |    7 +-
 .../sanitizer_allocator_dlsym.h               |   13 +-
 .../sanitizer_allocator_interface.h           |    2 +
 .../sanitizer_allocator_primary32.h           |    2 +-
 .../sanitizer_allocator_primary64.h           |   13 +-
 .../sanitizer_common/sanitizer_atomic.h       |   14 +-
 .../sanitizer_common/sanitizer_atomic_clang.h |   85 +-
 .../sanitizer_atomic_clang_mips.h             |  117 -
 .../sanitizer_atomic_clang_other.h            |   85 -
 .../sanitizer_atomic_clang_x86.h              |  113 -
 .../sanitizer_common/sanitizer_atomic_msvc.h  |    8 +-
 .../sanitizer_common/sanitizer_bitvector.h    |    8 +-
 .../sanitizer_chained_origin_depot.cpp        |    6 +-
 .../sanitizer_chained_origin_depot.h          |    4 +-
 .../sanitizer_common/sanitizer_common.cpp     |   15 +-
 .../sanitizer_common/sanitizer_common.h       |   61 +-
 .../sanitizer_common_interceptors.inc         |  457 ++--
 .../sanitizer_common_interface.inc            |    9 +
 .../sanitizer_common_libcdep.cpp              |   34 +-
 .../sanitizer_common_nolibc.cpp               |    7 +-
 .../sanitizer_common_syscalls.inc             |   68 +-
 .../sanitizer_coverage_fuchsia.cpp            |    2 +-
 .../sanitizer_coverage_libcdep_new.cpp        |    3 +-
 .../sanitizer_coverage_win_dll_thunk.cpp      |   20 -
 ... sanitizer_coverage_win_runtime_thunk.cpp} |   21 +-
 ...nitizer_coverage_win_weak_interception.cpp |   23 -
 .../sanitizer_common/sanitizer_dense_map.h    |   70 +-
 .../sanitizer_common/sanitizer_errno.cpp      |    1 +
 .../sanitizer_common/sanitizer_errno_codes.h  |    1 +
 .../sanitizer_common/sanitizer_file.cpp       |    4 +-
 .../sanitizer_common/sanitizer_flags.inc      |    7 +
 .../sanitizer_common/sanitizer_flat_map.h     |    4 +
 .../sanitizer_common/sanitizer_freebsd.h      |  137 --
 .../sanitizer_common/sanitizer_fuchsia.cpp    |  107 +-
 .../sanitizer_common/sanitizer_hash.h         |    2 +-
 .../sanitizer_interface_internal.h            |   10 +
 .../sanitizer_internal_defs.h                 |   45 +-
 .../sanitizer_common/sanitizer_libignore.cpp  |   32 +-
 .../sanitizer_common/sanitizer_libignore.h    |   35 +-
 .../sanitizer_common/sanitizer_linux.cpp      | 2137 ++++++++++-------
 .../sanitizer_common/sanitizer_linux.h        |  122 +-
 .../sanitizer_linux_libcdep.cpp               |  728 +++---
 .../sanitizer_common/sanitizer_linux_s390.cpp |  164 +-
 .../sanitizer_common/sanitizer_mac.cpp        |   58 +-
 libsanitizer/sanitizer_common/sanitizer_mac.h |   20 -
 .../sanitizer_common/sanitizer_mallinfo.h     |    4 +
 .../sanitizer_common/sanitizer_mutex.cpp      |    6 +-
 .../sanitizer_placement_new.h                 |    4 +-
 .../sanitizer_common/sanitizer_platform.h     |   17 +-
 .../sanitizer_platform_interceptors.h         |   54 +-
 .../sanitizer_platform_limits_freebsd.cpp     |    2 +
 .../sanitizer_platform_limits_freebsd.h       |   24 +-
 .../sanitizer_platform_limits_linux.cpp       |    5 +-
 .../sanitizer_platform_limits_openbsd.cpp     |    0
 .../sanitizer_platform_limits_openbsd.h       |    0
 .../sanitizer_platform_limits_posix.cpp       |   57 +-
 .../sanitizer_platform_limits_posix.h         |   32 +-
 .../sanitizer_common/sanitizer_posix.cpp      |   22 +-
 .../sanitizer_common/sanitizer_posix.h        |   32 +-
 .../sanitizer_posix_libcdep.cpp               |  133 +-
 .../sanitizer_common/sanitizer_printf.cpp     |    2 +-
 .../sanitizer_procmaps_bsd.cpp                |   47 +-
 .../sanitizer_procmaps_common.cpp             |    2 +-
 .../sanitizer_procmaps_mac.cpp                |   66 +-
 .../sanitizer_procmaps_solaris.cpp            |    4 +
 .../sanitizer_common/sanitizer_ptrauth.h      |   46 +-
 .../sanitizer_redefine_builtins.h             |   12 +-
 .../sanitizer_stack_store.cpp                 |    9 +-
 .../sanitizer_common/sanitizer_stackdepot.cpp |    8 +-
 .../sanitizer_common/sanitizer_stackdepot.h   |    4 +-
 .../sanitizer_stackdepotbase.h                |   31 +-
 .../sanitizer_common/sanitizer_stacktrace.cpp |   17 +-
 .../sanitizer_stacktrace_libcdep.cpp          |   20 +-
 .../sanitizer_stacktrace_printer.cpp          |   45 +-
 .../sanitizer_stacktrace_printer.h            |   48 +-
 .../sanitizer_stacktrace_sparc.cpp            |   11 +-
 .../sanitizer_stoptheworld_linux_libcdep.cpp  |   19 +-
 .../sanitizer_stoptheworld_netbsd_libcdep.cpp |    4 +-
 .../sanitizer_suppressions.cpp                |    7 +-
 .../sanitizer_common/sanitizer_symbolizer.h   |   30 +-
 .../sanitizer_symbolizer_libcdep.cpp          |    7 +
 .../sanitizer_symbolizer_mac.cpp              |    4 +-
 .../sanitizer_symbolizer_markup.cpp           |  234 +-
 .../sanitizer_symbolizer_markup.h             |   79 +
 ...> sanitizer_symbolizer_markup_constants.h} |   19 +-
 .../sanitizer_symbolizer_markup_fuchsia.cpp   |   85 +
 .../sanitizer_symbolizer_posix_libcdep.cpp    |   34 +-
 .../sanitizer_symbolizer_report.cpp           |   77 +-
 .../sanitizer_symbolizer_report_fuchsia.cpp   |   33 +
 .../sanitizer_symbolizer_win.cpp              |   13 +-
 .../sanitizer_thread_arg_retval.cpp           |   23 +-
 .../sanitizer_thread_arg_retval.h             |    1 +
 .../sanitizer_thread_history.cpp              |   72 +
 .../sanitizer_thread_history.h                |   24 +
 .../sanitizer_thread_registry.cpp             |   51 +-
 .../sanitizer_thread_registry.h               |   11 +-
 .../sanitizer_tls_get_addr.cpp                |   81 +-
 .../sanitizer_common/sanitizer_tls_get_addr.h |    4 -
 .../sanitizer_unwind_fuchsia.cpp              |   66 +
 .../sanitizer_common/sanitizer_unwind_win.cpp |    7 +
 .../sanitizer_common/sanitizer_win.cpp        |  107 +-
 .../sanitizer_win_dll_thunk.cpp               |  101 -
 .../sanitizer_win_dll_thunk.h                 |  181 --
 .../sanitizer_win_dynamic_runtime_thunk.cpp   |   26 -
 .../sanitizer_win_immortalize.h               |   71 +
 .../sanitizer_win_interception.cpp            |  156 ++
 .../sanitizer_win_interception.h              |   32 +
 .../sanitizer_win_thunk_interception.cpp      |  110 +
 .../sanitizer_win_thunk_interception.h        |   88 +
 .../sanitizer_win_weak_interception.cpp       |   94 -
 .../sanitizer_win_weak_interception.h         |   32 -
 libsanitizer/tsan/tsan_defs.h                 |    2 +-
 libsanitizer/tsan/tsan_dispatch_defs.h        |    7 -
 libsanitizer/tsan/tsan_interceptors_mac.cpp   |    8 +
 libsanitizer/tsan/tsan_interceptors_posix.cpp |  187 +-
 libsanitizer/tsan/tsan_interface_ann.cpp      |    2 +-
 libsanitizer/tsan/tsan_mman.cpp               |   31 +-
 libsanitizer/tsan/tsan_mman.h                 |    4 +-
 libsanitizer/tsan/tsan_platform.h             |   42 +-
 libsanitizer/tsan/tsan_platform_linux.cpp     |  171 +-
 libsanitizer/tsan/tsan_platform_mac.cpp       |    9 +-
 libsanitizer/tsan/tsan_platform_posix.cpp     |   43 +-
 libsanitizer/tsan/tsan_preinit.cpp            |   10 +-
 libsanitizer/tsan/tsan_report.cpp             |   26 +-
 libsanitizer/tsan/tsan_rtl.cpp                |   24 +-
 libsanitizer/tsan/tsan_rtl.h                  |    8 +-
 libsanitizer/tsan/tsan_rtl_aarch64.S          |    7 +
 libsanitizer/tsan/tsan_rtl_access.cpp         |   22 +-
 libsanitizer/tsan/tsan_rtl_mutex.cpp          |    2 +-
 libsanitizer/tsan/tsan_rtl_ppc64.S            |    1 -
 libsanitizer/tsan/tsan_rtl_thread.cpp         |   20 +-
 libsanitizer/tsan/tsan_suppressions.cpp       |    2 +-
 libsanitizer/tsan/tsan_vector_clock.h         |    2 +-
 libsanitizer/ubsan/ubsan_diag.cpp             |    6 +-
 libsanitizer/ubsan/ubsan_diag.h               |   20 -
 libsanitizer/ubsan/ubsan_diag_standalone.cpp  |    2 +-
 libsanitizer/ubsan/ubsan_flags.cpp            |    1 -
 libsanitizer/ubsan/ubsan_handlers.cpp         |   53 +-
 libsanitizer/ubsan/ubsan_handlers.h           |   10 +-
 libsanitizer/ubsan/ubsan_handlers_cxx.cpp     |   44 -
 libsanitizer/ubsan/ubsan_handlers_cxx.h       |   13 -
 libsanitizer/ubsan/ubsan_init.cpp             |    2 +-
 .../ubsan/ubsan_init_standalone_preinit.cpp   |    4 +-
 libsanitizer/ubsan/ubsan_interface.inc        |    2 -
 libsanitizer/ubsan/ubsan_platform.h           |    2 -
 .../ubsan/ubsan_signals_standalone.cpp        |    5 +
 .../ubsan/ubsan_type_hash_itanium.cpp         |    2 +-
 libsanitizer/ubsan/ubsan_value.cpp            |   17 +-
 libsanitizer/ubsan/ubsan_value.h              |   33 +-
 libsanitizer/ubsan/ubsan_win_dll_thunk.cpp    |   20 -
 ..._thunk.cpp => ubsan_win_runtime_thunk.cpp} |   11 +-
 .../ubsan/ubsan_win_weak_interception.cpp     |   23 -
 238 files changed, 7276 insertions(+), 4764 deletions(-)
 delete mode 100644 libsanitizer/asan/asan_lock.h
 create mode 100644 libsanitizer/asan/asan_malloc_win_thunk.cpp
 create mode 100644 libsanitizer/asan/asan_win_common_runtime_thunk.cpp
 create mode 100644 libsanitizer/asan/asan_win_common_runtime_thunk.h
 delete mode 100644 libsanitizer/asan/asan_win_dll_thunk.cpp
 create mode 100644 libsanitizer/asan/asan_win_static_runtime_thunk.cpp
 delete mode 100644 libsanitizer/asan/asan_win_weak_interception.cpp
 create mode 100644 libsanitizer/include/sanitizer/nsan_interface.h
 create mode 100644 libsanitizer/include/sanitizer/rtsan_interface.h
 delete mode 100644 libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
 delete mode 100644 libsanitizer/sanitizer_common/sanitizer_atomic_clang_other.h
 delete mode 100644 libsanitizer/sanitizer_common/sanitizer_atomic_clang_x86.h
 delete mode 100644 libsanitizer/sanitizer_common/sanitizer_coverage_win_dll_thunk.cpp
 rename libsanitizer/sanitizer_common/{sanitizer_coverage_win_dynamic_runtime_thunk.cpp => sanitizer_coverage_win_runtime_thunk.cpp} (59%)
 delete mode 100644 libsanitizer/sanitizer_common/sanitizer_coverage_win_weak_interception.cpp
 delete mode 100644 libsanitizer/sanitizer_common/sanitizer_freebsd.h
 delete mode 100644 libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp
 delete mode 100644 libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h
 create mode 100644 libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.h
 rename libsanitizer/sanitizer_common/{sanitizer_symbolizer_fuchsia.h => sanitizer_symbolizer_markup_constants.h} (69%)
 create mode 100644 libsanitizer/sanitizer_common/sanitizer_symbolizer_markup_fuchsia.cpp
 create mode 100644 libsanitizer/sanitizer_common/sanitizer_symbolizer_report_fuchsia.cpp
 create mode 100644 libsanitizer/sanitizer_common/sanitizer_thread_history.cpp
 create mode 100644 libsanitizer/sanitizer_common/sanitizer_thread_history.h
 create mode 100644 libsanitizer/sanitizer_common/sanitizer_unwind_fuchsia.cpp
 delete mode 100644 libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.cpp
 delete mode 100644 libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.h
 delete mode 100644 libsanitizer/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cpp
 create mode 100644 libsanitizer/sanitizer_common/sanitizer_win_immortalize.h
 create mode 100644 libsanitizer/sanitizer_common/sanitizer_win_interception.cpp
 create mode 100644 libsanitizer/sanitizer_common/sanitizer_win_interception.h
 create mode 100644 libsanitizer/sanitizer_common/sanitizer_win_thunk_interception.cpp
 create mode 100644 libsanitizer/sanitizer_common/sanitizer_win_thunk_interception.h
 delete mode 100644 libsanitizer/sanitizer_common/sanitizer_win_weak_interception.cpp
 delete mode 100644 libsanitizer/sanitizer_common/sanitizer_win_weak_interception.h
 delete mode 100644 libsanitizer/ubsan/ubsan_win_dll_thunk.cpp
 rename libsanitizer/ubsan/{ubsan_win_dynamic_runtime_thunk.cpp => ubsan_win_runtime_thunk.cpp} (62%)
 delete mode 100644 libsanitizer/ubsan/ubsan_win_weak_interception.cpp
diff mbox series

Patch

diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE
index 2ee0843e704e..a223feef2f54 100644
--- a/libsanitizer/MERGE
+++ b/libsanitizer/MERGE
@@ -1,4 +1,4 @@ 
-c425db2eb558c26377edc04e062c0c1f999b2770
+61a6439f35b6de28ff4aff4450d6fca970292fd5
 
 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/Makefile.am b/libsanitizer/asan/Makefile.am
index 6af250e99d9e..5c77b3b2c672 100644
--- a/libsanitizer/asan/Makefile.am
+++ b/libsanitizer/asan/Makefile.am
@@ -46,7 +46,6 @@  asan_files = \
 	asan_suppressions.cpp \
 	asan_thread.cpp \
 	asan_win.cpp \
-	asan_win_dll_thunk.cpp \
 	asan_win_dynamic_runtime_thunk.cpp \
   asan_interceptors_vfork.S
 
diff --git a/libsanitizer/asan/Makefile.in b/libsanitizer/asan/Makefile.in
index ac72e13830fe..ef4b65dda975 100644
--- a/libsanitizer/asan/Makefile.in
+++ b/libsanitizer/asan/Makefile.in
@@ -160,8 +160,7 @@  am__objects_1 = asan_activation.lo asan_allocator.lo asan_debugging.lo \
 	asan_posix.lo asan_premap_shadow.lo asan_report.lo asan_rtl.lo \
 	asan_shadow_setup.lo asan_stack.lo asan_stats.lo \
 	asan_suppressions.lo asan_thread.lo asan_win.lo \
-	asan_win_dll_thunk.lo asan_win_dynamic_runtime_thunk.lo \
-	asan_interceptors_vfork.lo
+	asan_win_dynamic_runtime_thunk.lo asan_interceptors_vfork.lo
 am_libasan_la_OBJECTS = $(am__objects_1)
 libasan_la_OBJECTS = $(am_libasan_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
@@ -457,7 +456,6 @@  asan_files = \
 	asan_suppressions.cpp \
 	asan_thread.cpp \
 	asan_win.cpp \
-	asan_win_dll_thunk.cpp \
 	asan_win_dynamic_runtime_thunk.cpp \
   asan_interceptors_vfork.S
 
@@ -619,7 +617,6 @@  distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_suppressions.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_thread.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_win.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_win_dll_thunk.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_win_dynamic_runtime_thunk.Plo@am__quote@
 
 .S.o:
diff --git a/libsanitizer/asan/asan_allocator.cpp b/libsanitizer/asan/asan_allocator.cpp
index 22dcf6132707..9e66f77217ec 100644
--- a/libsanitizer/asan/asan_allocator.cpp
+++ b/libsanitizer/asan/asan_allocator.cpp
@@ -717,7 +717,15 @@  struct Allocator {
       return;
     }
 
-    RunFreeHooks(ptr);
+    if (RunFreeHooks(ptr)) {
+      // Someone used __sanitizer_ignore_free_hook() and decided that they
+      // didn't want the memory to __sanitizer_ignore_free_hook freed right now.
+      // When they call free() on this pointer again at a later time, we should
+      // ignore the alloc-type mismatch and allow them to deallocate the pointer
+      // through free(), rather than the initial alloc type.
+      m->alloc_type = FROM_MALLOC;
+      return;
+    }
 
     // Must mark the chunk as quarantined before any changes to its metadata.
     // Do not quarantine given chunk if we failed to set CHUNK_QUARANTINE flag.
diff --git a/libsanitizer/asan/asan_allocator.h b/libsanitizer/asan/asan_allocator.h
index c3c4fae85b12..db8dc3bebfc6 100644
--- a/libsanitizer/asan/asan_allocator.h
+++ b/libsanitizer/asan/asan_allocator.h
@@ -182,42 +182,44 @@  static_assert(SizeClassMap::kNumClassesRounded <= 32,
               "allocator size and SizeClassMap tunings that allows us to "
               "reliably run all bringup tests in a sanitized environment.");
 
-#    else
+#    else   // SANITIZER_RISCV64
 // These are the default allocator tunings for non-RISCV environments where the
 // VMA is usually 48 bits and we have lots of space.
 const uptr kAllocatorSize = 0x40000000000ULL;  // 4T.
 typedef DefaultSizeClassMap SizeClassMap;
-#    endif
-#  elif defined(__powerpc64__)
+#    endif  // SANITIZER_RISCV64
+#  else     // SANITIZER_FUCHSIA
+
+#    if SANITIZER_APPLE
+const uptr kAllocatorSpace = 0x600000000000ULL;
+#    else   // SANITIZER_APPLE
 const uptr kAllocatorSpace = ~(uptr)0;
+#    endif  // SANITIZER_APPLE
+
+#    if defined(__powerpc64__)
 const uptr kAllocatorSize  =  0x20000000000ULL;  // 2T.
 typedef DefaultSizeClassMap SizeClassMap;
-#  elif defined(__aarch64__) && SANITIZER_ANDROID
+#    elif defined(__aarch64__) && SANITIZER_ANDROID
 // Android needs to support 39, 42 and 48 bit VMA.
-const uptr kAllocatorSpace =  ~(uptr)0;
 const uptr kAllocatorSize  =  0x2000000000ULL;  // 128G.
 typedef VeryCompactSizeClassMap SizeClassMap;
-#  elif SANITIZER_RISCV64
-const uptr kAllocatorSpace = ~(uptr)0;
+#    elif SANITIZER_RISCV64
 const uptr kAllocatorSize = 0x2000000000ULL;  // 128G.
 typedef VeryDenseSizeClassMap SizeClassMap;
-#  elif defined(__sparc__)
-const uptr kAllocatorSpace = ~(uptr)0;
+#    elif defined(__sparc__)
 const uptr kAllocatorSize = 0x20000000000ULL;  // 2T.
 typedef DefaultSizeClassMap SizeClassMap;
-#  elif SANITIZER_WINDOWS
-const uptr kAllocatorSpace = ~(uptr)0;
+#    elif SANITIZER_WINDOWS
 const uptr kAllocatorSize  =  0x8000000000ULL;  // 500G
 typedef DefaultSizeClassMap SizeClassMap;
-#  elif SANITIZER_APPLE
-const uptr kAllocatorSpace = 0x600000000000ULL;
+#    elif SANITIZER_APPLE
 const uptr kAllocatorSize  =  0x40000000000ULL;  // 4T.
 typedef DefaultSizeClassMap SizeClassMap;
-#  else
-const uptr kAllocatorSpace = 0x500000000000ULL;
+#    else
 const uptr kAllocatorSize = 0x40000000000ULL;  // 4T.
 typedef DefaultSizeClassMap SizeClassMap;
-#  endif
+#    endif  // defined(__powerpc64__) etc.
+#  endif    // SANITIZER_FUCHSIA
 template <typename AddressSpaceViewTy>
 struct AP64 {  // Allocator64 parameters. Deliberately using a short name.
   static const uptr kSpaceBeg = kAllocatorSpace;
@@ -232,7 +234,7 @@  struct AP64 {  // Allocator64 parameters. Deliberately using a short name.
 template <typename AddressSpaceView>
 using PrimaryAllocatorASVT = SizeClassAllocator64<AP64<AddressSpaceView>>;
 using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
-#else  // Fallback to SizeClassAllocator32.
+#else   // SANITIZER_CAN_USE_ALLOCATOR64. Fallback to SizeClassAllocator32.
 typedef CompactSizeClassMap SizeClassMap;
 template <typename AddressSpaceViewTy>
 struct AP32 {
diff --git a/libsanitizer/asan/asan_descriptions.cpp b/libsanitizer/asan/asan_descriptions.cpp
index ef6f3e0a096f..caec79313e22 100644
--- a/libsanitizer/asan/asan_descriptions.cpp
+++ b/libsanitizer/asan/asan_descriptions.cpp
@@ -20,24 +20,20 @@ 
 namespace __asan {
 
 AsanThreadIdAndName::AsanThreadIdAndName(AsanThreadContext *t) {
-  Init(t->tid, t->name);
-}
-
-AsanThreadIdAndName::AsanThreadIdAndName(u32 tid) {
-  if (tid == kInvalidTid) {
-    Init(tid, "");
-  } else {
-    asanThreadRegistry().CheckLocked();
-    AsanThreadContext *t = GetThreadContextByTidLocked(tid);
-    Init(tid, t->name);
+  if (!t) {
+    internal_snprintf(name, sizeof(name), "T-1");
+    return;
   }
+  int len = internal_snprintf(name, sizeof(name), "T%llu", t->unique_id);
+  CHECK(((unsigned int)len) < sizeof(name));
+  if (internal_strlen(t->name))
+    internal_snprintf(&name[len], sizeof(name) - len, " (%s)", t->name);
 }
 
-void AsanThreadIdAndName::Init(u32 tid, const char *tname) {
-  int len = internal_snprintf(name, sizeof(name), "T%d", tid);
-  CHECK(((unsigned int)len) < sizeof(name));
-  if (tname[0] != '\0')
-    internal_snprintf(&name[len], sizeof(name) - len, " (%s)", tname);
+AsanThreadIdAndName::AsanThreadIdAndName(u32 tid)
+    : AsanThreadIdAndName(
+          tid == kInvalidTid ? nullptr : GetThreadContextByTidLocked(tid)) {
+  asanThreadRegistry().CheckLocked();
 }
 
 void DescribeThread(AsanThreadContext *context) {
@@ -48,9 +44,20 @@  void DescribeThread(AsanThreadContext *context) {
     return;
   }
   context->announced = true;
+
+  AsanThreadContext *parent_context =
+      context->parent_tid == kInvalidTid
+          ? nullptr
+          : GetThreadContextByTidLocked(context->parent_tid);
+
+  // `context->parent_tid` may point to reused slot. Check `unique_id` which
+  // is always smaller for the parent, always greater for a new user.
+  if (context->unique_id <= parent_context->unique_id)
+    parent_context = nullptr;
+
   InternalScopedString str;
   str.AppendF("Thread %s", AsanThreadIdAndName(context).c_str());
-  if (context->parent_tid == kInvalidTid) {
+  if (!parent_context) {
     str.Append(" created by unknown thread\n");
     Printf("%s", str.data());
     return;
@@ -60,11 +67,8 @@  void DescribeThread(AsanThreadContext *context) {
   Printf("%s", str.data());
   StackDepotGet(context->stack_id).Print();
   // Recursively described parent thread if needed.
-  if (flags()->print_full_thread_history) {
-    AsanThreadContext *parent_context =
-        GetThreadContextByTidLocked(context->parent_tid);
+  if (flags()->print_full_thread_history)
     DescribeThread(parent_context);
-  }
 }
 
 // Shadow descriptions
@@ -245,11 +249,11 @@  static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
   InternalScopedString str;
   str.AppendF("    [%zd, %zd)", var.beg, var_end);
   // Render variable name.
-  str.AppendF(" '");
+  str.Append(" '");
   for (uptr i = 0; i < var.name_len; ++i) {
     str.AppendF("%c", var.name_pos[i]);
   }
-  str.AppendF("'");
+  str.Append("'");
   if (var.line > 0) {
     str.AppendF(" (line %zd)", var.line);
   }
@@ -260,7 +264,7 @@  static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
     str.AppendF("%s <== Memory access at offset %zd %s this variable%s\n",
                 d.Location(), addr, pos_descr, d.Default());
   } else {
-    str.AppendF("\n");
+    str.Append("\n");
   }
   Printf("%s", str.data());
 }
@@ -292,7 +296,7 @@  static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
   str.AppendF(" global variable '%s' defined in '",
               MaybeDemangleGlobalName(g.name));
   PrintGlobalLocation(&str, g, /*print_module_name=*/false);
-  str.AppendF("' (0x%zx) of size %zu\n", g.beg, g.size);
+  str.AppendF("' (%p) of size %zu\n", (void *)g.beg, g.size);
   str.Append(d.Default());
   PrintGlobalNameIfASCII(&str, g);
   Printf("%s", str.data());
diff --git a/libsanitizer/asan/asan_descriptions.h b/libsanitizer/asan/asan_descriptions.h
index 650e2eb9173a..a614f47d461b 100644
--- a/libsanitizer/asan/asan_descriptions.h
+++ b/libsanitizer/asan/asan_descriptions.h
@@ -35,8 +35,6 @@  class AsanThreadIdAndName {
   const char *c_str() const { return &name[0]; }
 
  private:
-  void Init(u32 tid, const char *tname);
-
   char name[128];
 };
 
diff --git a/libsanitizer/asan/asan_errors.cpp b/libsanitizer/asan/asan_errors.cpp
index 3f2d13e31464..4f112cc5d1bc 100644
--- a/libsanitizer/asan/asan_errors.cpp
+++ b/libsanitizer/asan/asan_errors.cpp
@@ -327,9 +327,6 @@  void ErrorBadParamsToAnnotateContiguousContainer::Print() {
       "      old_mid : %p\n"
       "      new_mid : %p\n",
       (void *)beg, (void *)end, (void *)old_mid, (void *)new_mid);
-  uptr granularity = ASAN_SHADOW_GRANULARITY;
-  if (!IsAligned(beg, granularity))
-    Report("ERROR: beg is not aligned by %zu\n", granularity);
   stack->Print();
   ReportErrorSummary(scariness.GetDescription(), stack);
 }
@@ -347,9 +344,20 @@  void ErrorBadParamsToAnnotateDoubleEndedContiguousContainer::Print() {
       (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 ErrorBadParamsToCopyContiguousContainerAnnotations::Print() {
+  Report(
+      "ERROR: AddressSanitizer: bad parameters to "
+      "__sanitizer_copy_contiguous_container_annotations:\n"
+      "      src_storage_beg : %p\n"
+      "      src_storage_end : %p\n"
+      "      dst_storage_beg : %p\n"
+      "      new_storage_end : %p\n",
+      (void *)old_storage_beg, (void *)old_storage_end, (void *)new_storage_beg,
+      (void *)new_storage_end);
   stack->Print();
   ReportErrorSummary(scariness.GetDescription(), stack);
 }
diff --git a/libsanitizer/asan/asan_errors.h b/libsanitizer/asan/asan_errors.h
index 634f6da54435..b3af655e6663 100644
--- a/libsanitizer/asan/asan_errors.h
+++ b/libsanitizer/asan/asan_errors.h
@@ -353,6 +353,24 @@  struct ErrorBadParamsToAnnotateDoubleEndedContiguousContainer : ErrorBase {
   void Print();
 };
 
+struct ErrorBadParamsToCopyContiguousContainerAnnotations : ErrorBase {
+  const BufferedStackTrace *stack;
+  uptr old_storage_beg, old_storage_end, new_storage_beg, new_storage_end;
+
+  ErrorBadParamsToCopyContiguousContainerAnnotations() = default;  // (*)
+  ErrorBadParamsToCopyContiguousContainerAnnotations(
+      u32 tid, BufferedStackTrace *stack_, uptr old_storage_beg_,
+      uptr old_storage_end_, uptr new_storage_beg_, uptr new_storage_end_)
+      : ErrorBase(tid, 10,
+                  "bad-__sanitizer_annotate_double_ended_contiguous_container"),
+        stack(stack_),
+        old_storage_beg(old_storage_beg_),
+        old_storage_end(old_storage_end_),
+        new_storage_beg(new_storage_beg_),
+        new_storage_end(new_storage_end_) {}
+  void Print();
+};
+
 struct ErrorODRViolation : ErrorBase {
   __asan_global global1, global2;
   u32 stack_id1, stack_id2;
@@ -421,6 +439,7 @@  struct ErrorGeneric : ErrorBase {
   macro(StringFunctionSizeOverflow)                        \
   macro(BadParamsToAnnotateContiguousContainer)            \
   macro(BadParamsToAnnotateDoubleEndedContiguousContainer) \
+  macro(BadParamsToCopyContiguousContainerAnnotations)     \
   macro(ODRViolation)                                      \
   macro(InvalidPointerPair)                                \
   macro(Generic)
diff --git a/libsanitizer/asan/asan_flags.cpp b/libsanitizer/asan/asan_flags.cpp
index 239898433232..56deb1b0d082 100644
--- a/libsanitizer/asan/asan_flags.cpp
+++ b/libsanitizer/asan/asan_flags.cpp
@@ -11,14 +11,16 @@ 
 // ASan flag parsing logic.
 //===----------------------------------------------------------------------===//
 
-#include "asan_activation.h"
 #include "asan_flags.h"
+
+#include "asan_activation.h"
 #include "asan_interface_internal.h"
 #include "asan_stack.h"
 #include "lsan/lsan_common.h"
 #include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_flag_parser.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_win_interception.h"
 #include "ubsan/ubsan_flags.h"
 #include "ubsan/ubsan_platform.h"
 
@@ -47,7 +49,21 @@  static void RegisterAsanFlags(FlagParser *parser, Flags *f) {
 #undef ASAN_FLAG
 }
 
-void InitializeFlags() {
+static void DisplayHelpMessages(FlagParser *parser) {
+  // TODO(eugenis): dump all flags at verbosity>=2?
+  if (Verbosity()) {
+    ReportUnrecognizedFlags();
+  }
+
+  if (common_flags()->help) {
+    parser->PrintFlagDescriptions();
+  }
+}
+
+static void InitializeDefaultFlags() {
+  Flags *f = flags();
+  FlagParser asan_parser;
+
   // Set the default values and prepare for parsing ASan and common flags.
   SetCommonFlagsDefaults();
   {
@@ -60,10 +76,8 @@  void InitializeFlags() {
     cf.exitcode = 1;
     OverrideCommonFlags(cf);
   }
-  Flags *f = flags();
   f->SetDefaults();
 
-  FlagParser asan_parser;
   RegisterAsanFlags(&asan_parser, f);
   RegisterCommonFlags(&asan_parser);
 
@@ -126,13 +140,12 @@  void InitializeFlags() {
 
   InitializeCommonFlags();
 
-  // TODO(eugenis): dump all flags at verbosity>=2?
-  if (Verbosity()) ReportUnrecognizedFlags();
+  // TODO(samsonov): print all of the flags (ASan, LSan, common).
+  DisplayHelpMessages(&asan_parser);
+}
 
-  if (common_flags()->help) {
-    // TODO(samsonov): print all of the flags (ASan, LSan, common).
-    asan_parser.PrintFlagDescriptions();
-  }
+static void ProcessFlags() {
+  Flags *f = flags();
 
   // Flag validation:
   if (!CAN_SANITIZE_LEAKS && common_flags()->detect_leaks) {
@@ -199,6 +212,67 @@  void InitializeFlags() {
   }
 }
 
+void InitializeFlags() {
+  InitializeDefaultFlags();
+  ProcessFlags();
+
+#if SANITIZER_WINDOWS
+  // On Windows, weak symbols are emulated by having the user program
+  // register which weak functions are defined.
+  // The ASAN DLL will initialize flags prior to user module initialization,
+  // so __asan_default_options will not point to the user definition yet.
+  // We still want to ensure we capture when options are passed via
+  // __asan_default_options, so we add a callback to be run
+  // when it is registered with the runtime.
+
+  // There is theoretically time between the initial ProcessFlags and
+  // registering the weak callback where a weak function could be added and we
+  // would miss it, but in practice, InitializeFlags will always happen under
+  // the loader lock (if built as a DLL) and so will any calls to
+  // __sanitizer_register_weak_function.
+  AddRegisterWeakFunctionCallback(
+      reinterpret_cast<uptr>(__asan_default_options), []() {
+        FlagParser asan_parser;
+
+        RegisterAsanFlags(&asan_parser, flags());
+        RegisterCommonFlags(&asan_parser);
+        asan_parser.ParseString(__asan_default_options());
+
+        DisplayHelpMessages(&asan_parser);
+        ProcessFlags();
+      });
+
+#  if CAN_SANITIZE_UB
+  AddRegisterWeakFunctionCallback(
+      reinterpret_cast<uptr>(__ubsan_default_options), []() {
+        FlagParser ubsan_parser;
+
+        __ubsan::RegisterUbsanFlags(&ubsan_parser, __ubsan::flags());
+        RegisterCommonFlags(&ubsan_parser);
+        ubsan_parser.ParseString(__ubsan_default_options());
+
+        // To match normal behavior, do not print UBSan help.
+        ProcessFlags();
+      });
+#  endif
+
+#  if CAN_SANITIZE_LEAKS
+  AddRegisterWeakFunctionCallback(
+      reinterpret_cast<uptr>(__lsan_default_options), []() {
+        FlagParser lsan_parser;
+
+        __lsan::RegisterLsanFlags(&lsan_parser, __lsan::flags());
+        RegisterCommonFlags(&lsan_parser);
+        lsan_parser.ParseString(__lsan_default_options());
+
+        // To match normal behavior, do not print LSan help.
+        ProcessFlags();
+      });
+#  endif
+
+#endif
+}
+
 }  // namespace __asan
 
 SANITIZER_INTERFACE_WEAK_DEF(const char*, __asan_default_options, void) {
diff --git a/libsanitizer/asan/asan_fuchsia.cpp b/libsanitizer/asan/asan_fuchsia.cpp
index 2b15504123be..96c41e9d42ba 100644
--- a/libsanitizer/asan/asan_fuchsia.cpp
+++ b/libsanitizer/asan/asan_fuchsia.cpp
@@ -57,8 +57,6 @@  void AsanCheckDynamicRTPrereqs() {}
 void AsanCheckIncompatibleRT() {}
 void InitializeAsanInterceptors() {}
 
-void *AsanDoesNotSupportStaticLinkage() { return nullptr; }
-
 void InitializePlatformExceptionHandlers() {}
 void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
   UNIMPLEMENTED();
@@ -123,8 +121,7 @@  static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid,
   // In lieu of AsanThread::Create.
   AsanThread *thread = (AsanThread *)MmapOrDie(AsanThreadMmapSize(), __func__);
 
-  AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
-  u32 tid = asanThreadRegistry().CreateThread(0, detached, parent_tid, &args);
+  u32 tid = asanThreadRegistry().CreateThread(0, detached, parent_tid, thread);
   asanThreadRegistry().SetThreadName(tid, name);
 
   return thread;
@@ -240,6 +237,8 @@  void FlushUnneededASanShadowMemory(uptr p, uptr size) {
 // So this doesn't install any atexit hook like on other platforms.
 void InstallAtExitCheckLeaks() {}
 
+void InstallAtForkHandler() {}
+
 }  // namespace __asan
 
 namespace __lsan {
diff --git a/libsanitizer/asan/asan_globals.cpp b/libsanitizer/asan/asan_globals.cpp
index 1b419928c36e..c83b782cb85f 100644
--- a/libsanitizer/asan/asan_globals.cpp
+++ b/libsanitizer/asan/asan_globals.cpp
@@ -21,31 +21,32 @@ 
 #include "asan_suppressions.h"
 #include "asan_thread.h"
 #include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_dense_map.h"
+#include "sanitizer_common/sanitizer_list.h"
 #include "sanitizer_common/sanitizer_mutex.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 #include "sanitizer_common/sanitizer_symbolizer.h"
+#include "sanitizer_common/sanitizer_thread_safety.h"
 
 namespace __asan {
 
 typedef __asan_global Global;
 
-struct ListOfGlobals {
-  const Global *g;
-  ListOfGlobals *next;
+struct GlobalListNode {
+  const Global *g = nullptr;
+  GlobalListNode *next = nullptr;
 };
+typedef IntrusiveList<GlobalListNode> ListOfGlobals;
 
 static Mutex mu_for_globals;
-static ListOfGlobals *list_of_all_globals;
+static ListOfGlobals list_of_all_globals SANITIZER_GUARDED_BY(mu_for_globals);
 
-static const int kDynamicInitGlobalsInitialCapacity = 512;
 struct DynInitGlobal {
-  Global g;
-  bool initialized;
+  Global g = {};
+  bool initialized = false;
+  DynInitGlobal *next = nullptr;
 };
-typedef InternalMmapVector<DynInitGlobal> VectorOfGlobals;
-// Lazy-initialized and never deleted.
-static VectorOfGlobals *dynamic_init_globals;
 
 // We want to remember where a certain range of globals was registered.
 struct GlobalRegistrationSite {
@@ -55,6 +56,39 @@  struct GlobalRegistrationSite {
 typedef InternalMmapVector<GlobalRegistrationSite> GlobalRegistrationSiteVector;
 static GlobalRegistrationSiteVector *global_registration_site_vector;
 
+static ListOfGlobals &GlobalsByIndicator(uptr odr_indicator)
+    SANITIZER_REQUIRES(mu_for_globals) {
+  using MapOfGlobals = DenseMap<uptr, ListOfGlobals>;
+
+  static MapOfGlobals *globals_by_indicator = nullptr;
+  if (!globals_by_indicator) {
+    alignas(
+        alignof(MapOfGlobals)) static char placeholder[sizeof(MapOfGlobals)];
+    globals_by_indicator = new (placeholder) MapOfGlobals();
+  }
+
+  return (*globals_by_indicator)[odr_indicator];
+}
+
+static const char *current_dynamic_init_module_name
+    SANITIZER_GUARDED_BY(mu_for_globals) = nullptr;
+
+using DynInitGlobalsByModule =
+    DenseMap<const char *, IntrusiveList<DynInitGlobal>>;
+
+// TODO: Add a NoDestroy helper, this patter is very common in sanitizers.
+static DynInitGlobalsByModule &DynInitGlobals()
+    SANITIZER_REQUIRES(mu_for_globals) {
+  static DynInitGlobalsByModule *globals_by_module = nullptr;
+  if (!globals_by_module) {
+    alignas(alignof(DynInitGlobalsByModule)) static char
+        placeholder[sizeof(DynInitGlobalsByModule)];
+    globals_by_module = new (placeholder) DynInitGlobalsByModule();
+  }
+
+  return *globals_by_module;
+}
+
 ALWAYS_INLINE void PoisonShadowForGlobal(const Global *g, u8 value) {
   FastPoisonShadow(g->beg, g->size_with_redzone, value);
 }
@@ -73,6 +107,35 @@  ALWAYS_INLINE void PoisonRedZones(const Global &g) {
 
 const uptr kMinimalDistanceFromAnotherGlobal = 64;
 
+static void AddGlobalToList(ListOfGlobals &list, const Global *g) {
+  list.push_front(new (GetGlobalLowLevelAllocator()) GlobalListNode{g});
+}
+
+static void UnpoisonDynamicGlobals(IntrusiveList<DynInitGlobal> &dyn_globals,
+                                   bool mark_initialized) {
+  for (auto &dyn_g : dyn_globals) {
+    const Global *g = &dyn_g.g;
+    if (dyn_g.initialized)
+      continue;
+    // Unpoison the whole global.
+    PoisonShadowForGlobal(g, 0);
+    // Poison redzones back.
+    PoisonRedZones(*g);
+    if (mark_initialized)
+      dyn_g.initialized = true;
+  }
+}
+
+static void PoisonDynamicGlobals(
+    const IntrusiveList<DynInitGlobal> &dyn_globals) {
+  for (auto &dyn_g : dyn_globals) {
+    const Global *g = &dyn_g.g;
+    if (dyn_g.initialized)
+      continue;
+    PoisonShadowForGlobal(g, kAsanInitializationOrderMagic);
+  }
+}
+
 static bool IsAddressNearGlobal(uptr addr, const __asan_global &g) {
   if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
   if (addr >= g.beg + g.size_with_redzone) return false;
@@ -114,8 +177,8 @@  int GetGlobalsForAddress(uptr addr, Global *globals, u32 *reg_sites,
   if (!flags()->report_globals) return 0;
   Lock lock(&mu_for_globals);
   int res = 0;
-  for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
-    const Global &g = *l->g;
+  for (const auto &l : list_of_all_globals) {
+    const Global &g = *l.g;
     if (flags()->report_globals >= 2)
       ReportGlobal(g, "Search");
     if (IsAddressNearGlobal(addr, g)) {
@@ -138,23 +201,47 @@  enum GlobalSymbolState {
 // Check ODR violation for given global G via special ODR indicator. We use
 // this method in case compiler instruments global variables through their
 // local aliases.
-static void CheckODRViolationViaIndicator(const Global *g) {
+static void CheckODRViolationViaIndicator(const Global *g)
+    SANITIZER_REQUIRES(mu_for_globals) {
   // Instrumentation requests to skip ODR check.
   if (g->odr_indicator == UINTPTR_MAX)
     return;
+
+  ListOfGlobals &relevant_globals = GlobalsByIndicator(g->odr_indicator);
+
   u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator);
-  if (*odr_indicator == UNREGISTERED) {
+  if (*odr_indicator == REGISTERED) {
+    // If *odr_indicator is REGISTERED, some module have already registered
+    // externally visible symbol with the same name. This is an ODR violation.
+    for (const auto &l : relevant_globals) {
+      if ((flags()->detect_odr_violation >= 2 || g->size != l.g->size) &&
+          !IsODRViolationSuppressed(g->name))
+        ReportODRViolation(g, FindRegistrationSite(g), l.g,
+                           FindRegistrationSite(l.g));
+    }
+  } else {  // UNREGISTERED
     *odr_indicator = REGISTERED;
-    return;
   }
-  // If *odr_indicator is DEFINED, some module have already registered
-  // externally visible symbol with the same name. This is an ODR violation.
-  for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
-    if (g->odr_indicator == l->g->odr_indicator &&
-        (flags()->detect_odr_violation >= 2 || g->size != l->g->size) &&
-        !IsODRViolationSuppressed(g->name))
-      ReportODRViolation(g, FindRegistrationSite(g),
-                         l->g, FindRegistrationSite(l->g));
+
+  AddGlobalToList(relevant_globals, 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)
+    SANITIZER_REQUIRES(mu_for_globals) {
+  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 (const auto &l : list_of_all_globals) {
+      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));
+      }
+    }
   }
 }
 
@@ -181,7 +268,7 @@  static inline bool UseODRIndicator(const Global *g) {
 // Register a global variable.
 // This function may be called more than once for every global
 // so we store the globals in a map.
-static void RegisterGlobal(const Global *g) {
+static void RegisterGlobal(const Global *g) SANITIZER_REQUIRES(mu_for_globals) {
   CHECK(AsanInited());
   if (flags()->report_globals >= 2)
     ReportGlobal(*g, "Added");
@@ -203,24 +290,22 @@  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);
-  ListOfGlobals *l = new (GetGlobalLowLevelAllocator()) ListOfGlobals;
-  l->g = g;
-  l->next = list_of_all_globals;
-  list_of_all_globals = l;
+
+  AddGlobalToList(list_of_all_globals, g);
+
   if (g->has_dynamic_init) {
-    if (!dynamic_init_globals) {
-      dynamic_init_globals = new (GetGlobalLowLevelAllocator()) VectorOfGlobals;
-      dynamic_init_globals->reserve(kDynamicInitGlobalsInitialCapacity);
-    }
-    DynInitGlobal dyn_global = { *g, false };
-    dynamic_init_globals->push_back(dyn_global);
+    DynInitGlobals()[g->module_name].push_back(
+        new (GetGlobalLowLevelAllocator()) DynInitGlobal{*g, false});
   }
 }
 
-static void UnregisterGlobal(const Global *g) {
+static void UnregisterGlobal(const Global *g)
+    SANITIZER_REQUIRES(mu_for_globals) {
   CHECK(AsanInited());
   if (flags()->report_globals >= 2)
     ReportGlobal(*g, "Removed");
@@ -242,18 +327,14 @@  static void UnregisterGlobal(const Global *g) {
 }
 
 void StopInitOrderChecking() {
-  Lock lock(&mu_for_globals);
-  if (!flags()->check_initialization_order || !dynamic_init_globals)
+  if (!flags()->check_initialization_order)
     return;
+  Lock lock(&mu_for_globals);
   flags()->check_initialization_order = false;
-  for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
-    DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
-    const Global *g = &dyn_g.g;
-    // Unpoison the whole global.
-    PoisonShadowForGlobal(g, 0);
-    // Poison redzones back.
-    PoisonRedZones(*g);
-  }
+  DynInitGlobals().forEach([&](auto &kv) {
+    UnpoisonDynamicGlobals(kv.second, /*mark_initialized=*/false);
+    return true;
+  });
 }
 
 static bool IsASCII(unsigned char c) { return /*0x00 <= c &&*/ c <= 0x7F; }
@@ -325,8 +406,8 @@  void __asan_unregister_image_globals(uptr *flag) {
 }
 
 void __asan_register_elf_globals(uptr *flag, void *start, void *stop) {
-  if (*flag) return;
-  if (!start) return;
+  if (*flag || start == stop)
+    return;
   CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global));
   __asan_global *globals_start = (__asan_global*)start;
   __asan_global *globals_stop = (__asan_global*)stop;
@@ -335,8 +416,8 @@  void __asan_register_elf_globals(uptr *flag, void *start, void *stop) {
 }
 
 void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop) {
-  if (!*flag) return;
-  if (!start) return;
+  if (!*flag || start == stop)
+    return;
   CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global));
   __asan_global *globals_start = (__asan_global*)start;
   __asan_global *globals_stop = (__asan_global*)stop;
@@ -408,47 +489,94 @@  void __asan_unregister_globals(__asan_global *globals, uptr n) {
 // poisons all global variables not defined in this TU, so that a dynamic
 // initializer can only touch global variables in the same TU.
 void __asan_before_dynamic_init(const char *module_name) {
-  if (!flags()->check_initialization_order ||
-      !CanPoisonMemory() ||
-      !dynamic_init_globals)
+  if (!flags()->check_initialization_order || !CanPoisonMemory())
     return;
   bool strict_init_order = flags()->strict_init_order;
   CHECK(module_name);
   CHECK(AsanInited());
   Lock lock(&mu_for_globals);
+  if (current_dynamic_init_module_name == module_name)
+    return;
   if (flags()->report_globals >= 3)
     Printf("DynInitPoison module: %s\n", module_name);
-  for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
-    DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
-    const Global *g = &dyn_g.g;
-    if (dyn_g.initialized)
-      continue;
-    if (g->module_name != module_name)
-      PoisonShadowForGlobal(g, kAsanInitializationOrderMagic);
-    else if (!strict_init_order)
-      dyn_g.initialized = true;
+
+  if (current_dynamic_init_module_name == nullptr) {
+    // First call, poison all globals from other modules.
+    DynInitGlobals().forEach([&](auto &kv) {
+      if (kv.first != module_name) {
+        PoisonDynamicGlobals(kv.second);
+      } else {
+        UnpoisonDynamicGlobals(kv.second,
+                               /*mark_initialized=*/!strict_init_order);
+      }
+      return true;
+    });
+  } else {
+    // Module changed.
+    PoisonDynamicGlobals(DynInitGlobals()[current_dynamic_init_module_name]);
+    UnpoisonDynamicGlobals(DynInitGlobals()[module_name],
+                           /*mark_initialized=*/!strict_init_order);
   }
+  current_dynamic_init_module_name = module_name;
 }
 
+// Maybe SANITIZER_CAN_USE_PREINIT_ARRAY is to conservative for `.init_array`,
+// however we should not make mistake here. If `UnpoisonBeforeMain` was not
+// executed at all we will have false reports on globals.
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+// This optimization aims to reduce the overhead of `__asan_after_dynamic_init`
+// calls by leveraging incremental unpoisoning/poisoning in
+// `__asan_before_dynamic_init`. We expect most `__asan_after_dynamic_init
+// calls` to be no-ops. However, to ensure all globals are unpoisoned before the
+// `main`, we force `UnpoisonBeforeMain` to fully execute
+// `__asan_after_dynamic_init`.
+
+// With lld, `UnpoisonBeforeMain` runs after standard `.init_array`, making it
+// the final `__asan_after_dynamic_init` call for the static runtime. In
+// contrast, GNU ld executes it earlier, causing subsequent
+// `__asan_after_dynamic_init` calls to perform full unpoisoning, losing the
+// optimization.
+bool allow_after_dynamic_init SANITIZER_GUARDED_BY(mu_for_globals) = false;
+
+static void UnpoisonBeforeMain(void) {
+  {
+    Lock lock(&mu_for_globals);
+    if (allow_after_dynamic_init)
+      return;
+    allow_after_dynamic_init = true;
+  }
+  if (flags()->report_globals >= 3)
+    Printf("UnpoisonBeforeMain\n");
+  __asan_after_dynamic_init();
+}
+
+__attribute__((section(".init_array.65537"), used)) static void (
+    *asan_after_init_array)(void) = UnpoisonBeforeMain;
+#else
+// Incremental poisoning is disabled, unpoison globals immediately.
+static constexpr bool allow_after_dynamic_init = true;
+#endif  // SANITIZER_CAN_USE_PREINIT_ARRAY
+
 // This method runs immediately after dynamic initialization in each TU, when
 // all dynamically initialized globals except for those defined in the current
 // TU are poisoned.  It simply unpoisons all dynamically initialized globals.
 void __asan_after_dynamic_init() {
-  if (!flags()->check_initialization_order ||
-      !CanPoisonMemory() ||
-      !dynamic_init_globals)
+  if (!flags()->check_initialization_order || !CanPoisonMemory())
     return;
   CHECK(AsanInited());
   Lock lock(&mu_for_globals);
-  // FIXME: Optionally report that we're unpoisoning globals from a module.
-  for (uptr i = 0, n = dynamic_init_globals->size(); i < n; ++i) {
-    DynInitGlobal &dyn_g = (*dynamic_init_globals)[i];
-    const Global *g = &dyn_g.g;
-    if (!dyn_g.initialized) {
-      // Unpoison the whole global.
-      PoisonShadowForGlobal(g, 0);
-      // Poison redzones back.
-      PoisonRedZones(*g);
-    }
-  }
+  if (!allow_after_dynamic_init)
+    return;
+  if (!current_dynamic_init_module_name)
+    return;
+
+  if (flags()->report_globals >= 3)
+    Printf("DynInitUnpoison\n");
+
+  DynInitGlobals().forEach([&](auto &kv) {
+    UnpoisonDynamicGlobals(kv.second, /*mark_initialized=*/false);
+    return true;
+  });
+
+  current_dynamic_init_module_name = nullptr;
 }
diff --git a/libsanitizer/asan/asan_globals_win.cpp b/libsanitizer/asan/asan_globals_win.cpp
index 19af88ab12b4..2b59595dcd3b 100644
--- a/libsanitizer/asan/asan_globals_win.cpp
+++ b/libsanitizer/asan/asan_globals_win.cpp
@@ -17,10 +17,10 @@  namespace __asan {
 
 #pragma section(".ASAN$GA", read, write)
 #pragma section(".ASAN$GZ", read, write)
-extern "C" __declspec(allocate(".ASAN$GA"))
-    ALIGNED(sizeof(__asan_global)) __asan_global __asan_globals_start = {};
-extern "C" __declspec(allocate(".ASAN$GZ"))
-    ALIGNED(sizeof(__asan_global)) __asan_global __asan_globals_end = {};
+extern "C" alignas(sizeof(__asan_global))
+    __declspec(allocate(".ASAN$GA")) __asan_global __asan_globals_start = {};
+extern "C" alignas(sizeof(__asan_global))
+    __declspec(allocate(".ASAN$GZ")) __asan_global __asan_globals_end = {};
 #pragma comment(linker, "/merge:.ASAN=.data")
 
 static void call_on_globals(void (*hook)(__asan_global *, uptr)) {
@@ -28,7 +28,9 @@  static void call_on_globals(void (*hook)(__asan_global *, uptr)) {
   __asan_global *end = &__asan_globals_end;
   uptr bytediff = (uptr)end - (uptr)start;
   if (bytediff % sizeof(__asan_global) != 0) {
-#if defined(SANITIZER_DLL_THUNK) || defined(SANITIZER_DYNAMIC_RUNTIME_THUNK)
+#  if defined(SANITIZER_DLL_THUNK) ||             \
+      defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) || \
+      defined(SANITIZER_STATIC_RUNTIME_THUNK)
     __debugbreak();
 #else
     CHECK("corrupt asan global array");
diff --git a/libsanitizer/asan/asan_interceptors.cpp b/libsanitizer/asan/asan_interceptors.cpp
index 635546b525ce..c13bcf2382b0 100644
--- a/libsanitizer/asan/asan_interceptors.cpp
+++ b/libsanitizer/asan/asan_interceptors.cpp
@@ -96,14 +96,16 @@  DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
   ASAN_WRITE_RANGE(ctx, ptr, size)
 #define COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, size) \
   ASAN_READ_RANGE(ctx, ptr, size)
-#  define COMMON_INTERCEPTOR_ENTER(ctx, func, ...)    \
-    ASAN_INTERCEPTOR_ENTER(ctx, func);                \
-    do {                                              \
-      if (AsanInitIsRunning())                        \
-        return REAL(func)(__VA_ARGS__);               \
-      if (SANITIZER_APPLE && UNLIKELY(!AsanInited())) \
-        return REAL(func)(__VA_ARGS__);               \
-      ENSURE_ASAN_INITED();                           \
+#  define COMMON_INTERCEPTOR_ENTER(ctx, func, ...) \
+    ASAN_INTERCEPTOR_ENTER(ctx, func);             \
+    do {                                           \
+      if constexpr (SANITIZER_APPLE) {             \
+        if (UNLIKELY(!AsanInited()))               \
+          return REAL(func)(__VA_ARGS__);          \
+      } else {                                     \
+        if (!TryAsanInitFromRtl())                 \
+          return REAL(func)(__VA_ARGS__);          \
+      }                                            \
     } while (false)
 #define COMMON_INTERCEPTOR_DIR_ACQUIRE(ctx, path) \
   do {                                            \
@@ -194,10 +196,13 @@  static int munmap_interceptor(Munmap real_munmap, void *addr, SIZE_T length) {
   __lsan::ScopedInterceptorDisabler disabler
 #endif
 
-#define SIGNAL_INTERCEPTOR_ENTER() ENSURE_ASAN_INITED()
+#  define SIGNAL_INTERCEPTOR_ENTER() \
+    do {                             \
+      AsanInitFromRtl();             \
+    } while (false)
 
-#include "sanitizer_common/sanitizer_common_interceptors.inc"
-#include "sanitizer_common/sanitizer_signal_interceptors.inc"
+#  include "sanitizer_common/sanitizer_common_interceptors.inc"
+#  include "sanitizer_common/sanitizer_signal_interceptors.inc"
 
 // Syscall interceptors don't have contexts, we don't support suppressions
 // for them.
@@ -328,7 +333,7 @@  INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,
 }
 #    endif
 
-DEFINE_REAL_PTHREAD_FUNCTIONS
+DEFINE_INTERNAL_PTHREAD_FUNCTIONS
 #endif  // ASAN_INTERCEPT_PTHREAD_CREATE
 
 #if ASAN_INTERCEPT_SWAPCONTEXT
@@ -506,7 +511,7 @@  DEFINE_REAL(char*, index, const char *string, int c)
   INTERCEPTOR(char *, strcat, char *to, const char *from) {
     void *ctx;
     ASAN_INTERCEPTOR_ENTER(ctx, strcat);
-    ENSURE_ASAN_INITED();
+    AsanInitFromRtl();
     if (flags()->replace_str) {
       uptr from_length = internal_strlen(from);
       ASAN_READ_RANGE(ctx, from, from_length + 1);
@@ -527,7 +532,7 @@  DEFINE_REAL(char*, index, const char *string, int c)
 INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
   void *ctx;
   ASAN_INTERCEPTOR_ENTER(ctx, strncat);
-  ENSURE_ASAN_INITED();
+  AsanInitFromRtl();
   if (flags()->replace_str) {
     uptr from_length = MaybeRealStrnlen(from, size);
     uptr copy_length = Min(size, from_length + 1);
@@ -546,16 +551,16 @@  INTERCEPTOR(char*, strncat, char *to, const char *from, uptr size) {
 INTERCEPTOR(char *, strcpy, char *to, const char *from) {
   void *ctx;
   ASAN_INTERCEPTOR_ENTER(ctx, strcpy);
-#if SANITIZER_APPLE
-  if (UNLIKELY(!AsanInited()))
-    return REAL(strcpy)(to, from);
-#endif
-  // strcpy is called from malloc_default_purgeable_zone()
-  // in __asan::ReplaceSystemAlloc() on Mac.
-  if (AsanInitIsRunning()) {
-    return REAL(strcpy)(to, from);
+  if constexpr (SANITIZER_APPLE) {
+    // strcpy is called from malloc_default_purgeable_zone()
+    // in __asan::ReplaceSystemAlloc() on Mac.
+    if (UNLIKELY(!AsanInited()))
+      return REAL(strcpy)(to, from);
+  } else {
+    if (!TryAsanInitFromRtl())
+      return REAL(strcpy)(to, from);
   }
-  ENSURE_ASAN_INITED();
+
   if (flags()->replace_str) {
     uptr from_size = internal_strlen(from) + 1;
     CHECK_RANGES_OVERLAP("strcpy", to, from_size, from, from_size);
@@ -565,12 +570,22 @@  INTERCEPTOR(char *, strcpy, char *to, const char *from) {
   return REAL(strcpy)(to, from);
 }
 
+// Windows doesn't always define the strdup identifier,
+// and when it does it's a macro defined to either _strdup
+// or _strdup_dbg, _strdup_dbg ends up calling _strdup, so
+// we want to intercept that. push/pop_macro are used to avoid problems
+// if this file ends up including <string.h> in the future.
+#  if SANITIZER_WINDOWS
+#    pragma push_macro("strdup")
+#    undef strdup
+#    define strdup _strdup
+#  endif
+
 INTERCEPTOR(char*, strdup, const char *s) {
   void *ctx;
   ASAN_INTERCEPTOR_ENTER(ctx, strdup);
-  if (UNLIKELY(!AsanInited()))
+  if (UNLIKELY(!TryAsanInitFromRtl()))
     return internal_strdup(s);
-  ENSURE_ASAN_INITED();
   uptr length = internal_strlen(s);
   if (flags()->replace_str) {
     ASAN_READ_RANGE(ctx, s, length + 1);
@@ -583,13 +598,12 @@  INTERCEPTOR(char*, strdup, const char *s) {
   return reinterpret_cast<char*>(new_mem);
 }
 
-#if ASAN_INTERCEPT___STRDUP
+#  if ASAN_INTERCEPT___STRDUP
 INTERCEPTOR(char*, __strdup, const char *s) {
   void *ctx;
   ASAN_INTERCEPTOR_ENTER(ctx, strdup);
-  if (UNLIKELY(!AsanInited()))
+  if (UNLIKELY(!TryAsanInitFromRtl()))
     return internal_strdup(s);
-  ENSURE_ASAN_INITED();
   uptr length = internal_strlen(s);
   if (flags()->replace_str) {
     ASAN_READ_RANGE(ctx, s, length + 1);
@@ -606,7 +620,7 @@  INTERCEPTOR(char*, __strdup, const char *s) {
 INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
   void *ctx;
   ASAN_INTERCEPTOR_ENTER(ctx, strncpy);
-  ENSURE_ASAN_INITED();
+  AsanInitFromRtl();
   if (flags()->replace_str) {
     uptr from_size = Min(size, MaybeRealStrnlen(from, size) + 1);
     CHECK_RANGES_OVERLAP("strncpy", to, from_size, from, from_size);
@@ -632,13 +646,38 @@  static ALWAYS_INLINE auto StrtolImpl(void *ctx, Fn real, const char *nptr,
     INTERCEPTOR(ret_type, func, const char *nptr, char **endptr, int base) { \
       void *ctx;                                                             \
       ASAN_INTERCEPTOR_ENTER(ctx, func);                                     \
-      ENSURE_ASAN_INITED();                                                  \
+      AsanInitFromRtl();                                                     \
       return StrtolImpl(ctx, REAL(func), nptr, endptr, base);                \
     }
 
-INTERCEPTOR_STRTO_BASE(long, strtol)
 INTERCEPTOR_STRTO_BASE(long long, strtoll)
 
+#  if SANITIZER_WINDOWS
+INTERCEPTOR(long, strtol, const char *nptr, char **endptr, int base) {
+  // REAL(strtol) may be ntdll!strtol, which doesn't set errno. Instead,
+  // call REAL(strtoll) and do the range check ourselves.
+  COMPILER_CHECK(sizeof(long) == sizeof(u32));
+
+  void *ctx;
+  ASAN_INTERCEPTOR_ENTER(ctx, strtol);
+  AsanInitFromRtl();
+
+  long long result = StrtolImpl(ctx, REAL(strtoll), nptr, endptr, base);
+
+  if (result > INT32_MAX) {
+    errno = errno_ERANGE;
+    return INT32_MAX;
+  }
+  if (result < INT32_MIN) {
+    errno = errno_ERANGE;
+    return INT32_MIN;
+  }
+  return (long)result;
+}
+#  else
+INTERCEPTOR_STRTO_BASE(long, strtol)
+#  endif
+
 #  if SANITIZER_GLIBC
 INTERCEPTOR_STRTO_BASE(long, __isoc23_strtol)
 INTERCEPTOR_STRTO_BASE(long long, __isoc23_strtoll)
@@ -647,11 +686,9 @@  INTERCEPTOR_STRTO_BASE(long long, __isoc23_strtoll)
 INTERCEPTOR(int, atoi, const char *nptr) {
   void *ctx;
   ASAN_INTERCEPTOR_ENTER(ctx, atoi);
-#if SANITIZER_APPLE
-  if (UNLIKELY(!AsanInited()))
+  if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))
     return REAL(atoi)(nptr);
-#  endif
-  ENSURE_ASAN_INITED();
+  AsanInitFromRtl();
   if (!flags()->replace_str) {
     return REAL(atoi)(nptr);
   }
@@ -669,11 +706,9 @@  INTERCEPTOR(int, atoi, const char *nptr) {
 INTERCEPTOR(long, atol, const char *nptr) {
   void *ctx;
   ASAN_INTERCEPTOR_ENTER(ctx, atol);
-#if SANITIZER_APPLE
-  if (UNLIKELY(!AsanInited()))
+  if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))
     return REAL(atol)(nptr);
-#  endif
-  ENSURE_ASAN_INITED();
+  AsanInitFromRtl();
   if (!flags()->replace_str) {
     return REAL(atol)(nptr);
   }
@@ -687,7 +722,7 @@  INTERCEPTOR(long, atol, const char *nptr) {
 INTERCEPTOR(long long, atoll, const char *nptr) {
   void *ctx;
   ASAN_INTERCEPTOR_ENTER(ctx, atoll);
-  ENSURE_ASAN_INITED();
+  AsanInitFromRtl();
   if (!flags()->replace_str) {
     return REAL(atoll)(nptr);
   }
@@ -708,12 +743,10 @@  static void AtCxaAtexit(void *unused) {
 #if ASAN_INTERCEPT___CXA_ATEXIT
 INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
             void *dso_handle) {
-#if SANITIZER_APPLE
-  if (UNLIKELY(!AsanInited()))
+  if (SANITIZER_APPLE && UNLIKELY(!AsanInited()))
     return REAL(__cxa_atexit)(func, arg, dso_handle);
-#    endif
-  ENSURE_ASAN_INITED();
-#if CAN_SANITIZE_LEAKS
+  AsanInitFromRtl();
+#    if CAN_SANITIZE_LEAKS
   __lsan::ScopedInterceptorDisabler disabler;
 #endif
   int res = REAL(__cxa_atexit)(func, arg, dso_handle);
@@ -724,8 +757,8 @@  INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
 
 #if ASAN_INTERCEPT_ATEXIT
 INTERCEPTOR(int, atexit, void (*func)()) {
-  ENSURE_ASAN_INITED();
-#if CAN_SANITIZE_LEAKS
+  AsanInitFromRtl();
+#    if CAN_SANITIZE_LEAKS
   __lsan::ScopedInterceptorDisabler disabler;
 #endif
   // Avoid calling real atexit as it is unreachable on at least on Linux.
@@ -739,7 +772,7 @@  INTERCEPTOR(int, atexit, void (*func)()) {
 extern "C" {
 extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
                            void (*child)());
-};
+}
 
 INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
             void (*child)()) {
@@ -753,8 +786,8 @@  INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
 #endif
 
 #if ASAN_INTERCEPT_VFORK
-DEFINE_REAL(int, vfork)
-DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork)
+DEFINE_REAL(int, vfork,)
+DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork,)
 #endif
 
 // ---------------------- InitializeAsanInterceptors ---------------- {{{1
@@ -773,7 +806,7 @@  void InitializeAsanInterceptors() {
   ASAN_INTERCEPT_FUNC(strncat);
   ASAN_INTERCEPT_FUNC(strncpy);
   ASAN_INTERCEPT_FUNC(strdup);
-#if ASAN_INTERCEPT___STRDUP
+#  if ASAN_INTERCEPT___STRDUP
   ASAN_INTERCEPT_FUNC(__strdup);
 #endif
 #if ASAN_INTERCEPT_INDEX && ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
@@ -869,6 +902,10 @@  void InitializeAsanInterceptors() {
   VReport(1, "AddressSanitizer: libc interceptors initialized\n");
 }
 
+#  if SANITIZER_WINDOWS
+#    pragma pop_macro("strdup")
+#  endif
+
 } // namespace __asan
 
 #endif  // !SANITIZER_FUCHSIA
diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h
index 8e9ed5d1ef4e..826b45f5ada8 100644
--- a/libsanitizer/asan/asan_interceptors.h
+++ b/libsanitizer/asan/asan_interceptors.h
@@ -24,14 +24,6 @@  namespace __asan {
 void InitializeAsanInterceptors();
 void InitializePlatformInterceptors();
 
-#define ENSURE_ASAN_INITED()       \
-  do {                             \
-    CHECK(!AsanInitIsRunning());   \
-    if (UNLIKELY(!AsanInited())) { \
-      AsanInitFromRtl();           \
-    }                              \
-  } while (0)
-
 }  // namespace __asan
 
 // There is no general interception at all on Fuchsia.
@@ -79,12 +71,7 @@  void InitializePlatformInterceptors();
 #if ASAN_HAS_EXCEPTIONS && !SANITIZER_SOLARIS && !SANITIZER_NETBSD && \
     (!SANITIZER_WINDOWS || (defined(__MINGW32__) && defined(__i386__)))
 # 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 e2b1e9800f5b..06dfc4b17733 100644
--- a/libsanitizer/asan/asan_internal.h
+++ b/libsanitizer/asan/asan_internal.h
@@ -60,6 +60,7 @@  class AsanThread;
 using __sanitizer::StackTrace;
 
 void AsanInitFromRtl();
+bool TryAsanInitFromRtl();
 
 // asan_win.cpp
 void InitializePlatformExceptionHandlers();
@@ -79,7 +80,6 @@  void ReplaceSystemMalloc();
 
 // asan_linux.cpp / asan_mac.cpp / asan_win.cpp
 uptr FindDynamicShadowStart();
-void *AsanDoesNotSupportStaticLinkage();
 void AsanCheckDynamicRTPrereqs();
 void AsanCheckIncompatibleRT();
 
@@ -125,13 +125,13 @@  void *AsanDlSymNext(const char *sym);
 bool HandleDlopenInit();
 
 void InstallAtExitCheckLeaks();
+void InstallAtForkHandler();
 
 #define ASAN_ON_ERROR() \
   if (&__asan_on_error) \
   __asan_on_error()
 
 bool AsanInited();
-bool AsanInitIsRunning();  // Used to avoid infinite recursion in __asan_init().
 extern bool replace_intrin_cached;
 extern void (*death_callback)(void);
 // These magic values are written to shadow for better error
diff --git a/libsanitizer/asan/asan_linux.cpp b/libsanitizer/asan/asan_linux.cpp
index e19b4479aaf3..4cabca388ca9 100644
--- a/libsanitizer/asan/asan_linux.cpp
+++ b/libsanitizer/asan/asan_linux.cpp
@@ -33,7 +33,6 @@ 
 #  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"
@@ -48,22 +47,12 @@ 
 
 #  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 <link.h>
 #    include <sys/ucontext.h>
-extern ElfW(Dyn) _DYNAMIC[];
-#  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
 
 typedef enum {
@@ -84,11 +73,6 @@  void InitializePlatformInterceptors() {}
 void InitializePlatformExceptionHandlers() {}
 bool IsSystemHeapAddress(uptr addr) { return false; }
 
-void *AsanDoesNotSupportStaticLinkage() {
-  // This will fail to link with -static.
-  return &_DYNAMIC;
-}
-
 #  if ASAN_PREMAP_SHADOW
 uptr FindPremappedShadowStart(uptr shadow_size_bytes) {
   uptr granularity = GetMmapGranularity();
@@ -109,7 +93,8 @@  uptr FindDynamicShadowStart() {
 #  endif
 
   return MapDynamicShadow(shadow_size_bytes, ASAN_SHADOW_SCALE,
-                          /*min_shadow_base_alignment*/ 0, kHighMemEnd);
+                          /*min_shadow_base_alignment*/ 0, kHighMemEnd,
+                          GetMmapGranularity());
 }
 
 void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
@@ -148,6 +133,11 @@  static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
       internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
     return 0;
 #    endif
+#    if SANITIZER_FREEBSD
+  // Ignore vDSO.
+  if (internal_strcmp(info->dlpi_name, "[vdso]") == 0)
+    return 0;
+#    endif
 
   *name = info->dlpi_name;
   return 1;
@@ -197,10 +187,7 @@  void AsanCheckIncompatibleRT() {
       MemoryMappedSegment segment(filename, sizeof(filename));
       while (proc_maps.Next(&segment)) {
         if (IsDynamicRTName(segment.filename)) {
-          Report(
-              "Your application is linked against "
-              "incompatible ASan runtimes.\n");
-          Die();
+          ReportIncompatibleRT();
         }
       }
       __asan_rt_version = ASAN_RT_VERSION_STATIC;
diff --git a/libsanitizer/asan/asan_lock.h b/libsanitizer/asan/asan_lock.h
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/libsanitizer/asan/asan_mac.cpp b/libsanitizer/asan/asan_mac.cpp
index 6252fa20d5e7..bfc349223258 100644
--- a/libsanitizer/asan/asan_mac.cpp
+++ b/libsanitizer/asan/asan_mac.cpp
@@ -49,14 +49,10 @@  void InitializePlatformInterceptors() {}
 void InitializePlatformExceptionHandlers() {}
 bool IsSystemHeapAddress (uptr addr) { return false; }
 
-// No-op. Mac does not support static linkage anyway.
-void *AsanDoesNotSupportStaticLinkage() {
-  return 0;
-}
-
 uptr FindDynamicShadowStart() {
   return MapDynamicShadow(MemToShadowSize(kHighMemEnd), ASAN_SHADOW_SCALE,
-                          /*min_shadow_base_alignment*/ 0, kHighMemEnd);
+                          /*min_shadow_base_alignment*/ 0, kHighMemEnd,
+                          GetMmapGranularity());
 }
 
 // No-op. Mac does not support static linkage anyway.
@@ -139,11 +135,11 @@  typedef void (*dispatch_mach_handler_function_t)(void *context,
                                                  dispatch_mach_reason reason,
                                                  dispatch_mach_msg_t message,
                                                  mach_error_t error);
-#if !defined(MISSING_BLOCKS_SUPPORT)
+#  if !defined(MISSING_BLOCKS_SUPPORT)
 typedef void (^dispatch_mach_handler_t)(dispatch_mach_reason reason,
                                         dispatch_mach_msg_t message,
                                         mach_error_t error);
-#endif
+#  endif
 
 // A wrapper for the ObjC blocks used to support libdispatch.
 typedef struct {
diff --git a/libsanitizer/asan/asan_malloc_linux.cpp b/libsanitizer/asan/asan_malloc_linux.cpp
index 0ba74c5d7143..3d6b03fefab7 100644
--- a/libsanitizer/asan/asan_malloc_linux.cpp
+++ b/libsanitizer/asan/asan_malloc_linux.cpp
@@ -25,13 +25,12 @@ 
 #  include "sanitizer_common/sanitizer_allocator_checks.h"
 #  include "sanitizer_common/sanitizer_allocator_dlsym.h"
 #  include "sanitizer_common/sanitizer_errno.h"
-#  include "sanitizer_common/sanitizer_tls_get_addr.h"
 
 // ---------------------- Replacement functions ---------------- {{{1
 using namespace __asan;
 
 struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
-  static bool UseImpl() { return AsanInitIsRunning(); }
+  static bool UseImpl() { return !TryAsanInitFromRtl(); }
   static void OnAllocate(const void *ptr, uptr size) {
 #  if CAN_SANITIZE_LEAKS
     // Suppress leaks from dlerror(). Previously dlsym hack on global array was
@@ -65,7 +64,6 @@  INTERCEPTOR(void, cfree, void *ptr) {
 INTERCEPTOR(void*, malloc, uptr size) {
   if (DlsymAlloc::Use())
     return DlsymAlloc::Allocate(size);
-  ENSURE_ASAN_INITED();
   GET_STACK_TRACE_MALLOC;
   return asan_malloc(size, &stack);
 }
@@ -73,7 +71,6 @@  INTERCEPTOR(void*, malloc, uptr size) {
 INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
   if (DlsymAlloc::Use())
     return DlsymAlloc::Callocate(nmemb, size);
-  ENSURE_ASAN_INITED();
   GET_STACK_TRACE_MALLOC;
   return asan_calloc(nmemb, size, &stack);
 }
@@ -81,14 +78,13 @@  INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
 INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
   if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(ptr))
     return DlsymAlloc::Realloc(ptr, size);
-  ENSURE_ASAN_INITED();
   GET_STACK_TRACE_MALLOC;
   return asan_realloc(ptr, size, &stack);
 }
 
 #if SANITIZER_INTERCEPT_REALLOCARRAY
 INTERCEPTOR(void*, reallocarray, void *ptr, uptr nmemb, uptr size) {
-  ENSURE_ASAN_INITED();
+  AsanInitFromRtl();
   GET_STACK_TRACE_MALLOC;
   return asan_reallocarray(ptr, nmemb, size, &stack);
 }
@@ -102,9 +98,7 @@  INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {
 
 INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {
   GET_STACK_TRACE_MALLOC;
-  void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC);
-  DTLS_on_libc_memalign(res, size);
-  return res;
+  return asan_memalign(boundary, size, &stack, FROM_MALLOC);
 }
 #endif // SANITIZER_INTERCEPT_MEMALIGN
 
@@ -188,11 +182,11 @@  struct MallocDebugL {
   void* (*valloc)(uptr size);
 };
 
-ALIGNED(32) const MallocDebugK asan_malloc_dispatch_k = {
+alignas(32) const MallocDebugK asan_malloc_dispatch_k = {
     WRAP(malloc),  WRAP(free),     WRAP(calloc),
     WRAP(realloc), WRAP(memalign), WRAP(malloc_usable_size)};
 
-ALIGNED(32) const MallocDebugL asan_malloc_dispatch_l = {
+alignas(32) const MallocDebugL asan_malloc_dispatch_l = {
     WRAP(calloc),         WRAP(free),               WRAP(mallinfo),
     WRAP(malloc),         WRAP(malloc_usable_size), WRAP(memalign),
     WRAP(posix_memalign), WRAP(pvalloc),            WRAP(realloc),
diff --git a/libsanitizer/asan/asan_malloc_mac.cpp b/libsanitizer/asan/asan_malloc_mac.cpp
index d2380ee62bf3..f25d7e190153 100644
--- a/libsanitizer/asan/asan_malloc_mac.cpp
+++ b/libsanitizer/asan/asan_malloc_mac.cpp
@@ -22,7 +22,10 @@ 
 
 using namespace __asan;
 #define COMMON_MALLOC_ZONE_NAME "asan"
-#define COMMON_MALLOC_ENTER() ENSURE_ASAN_INITED()
+#  define COMMON_MALLOC_ENTER() \
+    do {                        \
+      AsanInitFromRtl();        \
+    } while (false)
 #  define COMMON_MALLOC_SANITIZER_INITIALIZED AsanInited()
 #  define COMMON_MALLOC_FORCE_LOCK() asan_mz_force_lock()
 #  define COMMON_MALLOC_FORCE_UNLOCK() asan_mz_force_unlock()
diff --git a/libsanitizer/asan/asan_malloc_win.cpp b/libsanitizer/asan/asan_malloc_win.cpp
index 7e1d04c36dd5..3278f0721987 100644
--- a/libsanitizer/asan/asan_malloc_win.cpp
+++ b/libsanitizer/asan/asan_malloc_win.cpp
@@ -58,97 +58,69 @@  using namespace __asan;
 // MD: Memory allocation functions are defined in the CRT .dll,
 // so we have to intercept them before they are called for the first time.
 
-#if ASAN_DYNAMIC
-# define ALLOCATION_FUNCTION_ATTRIBUTE
-#else
-# define ALLOCATION_FUNCTION_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
-#endif
-
 extern "C" {
-ALLOCATION_FUNCTION_ATTRIBUTE
-size_t _msize(void *ptr) {
+__declspec(noinline) size_t _msize(void *ptr) {
   GET_CURRENT_PC_BP_SP;
   (void)sp;
   return asan_malloc_usable_size(ptr, pc, bp);
 }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-size_t _msize_base(void *ptr) {
-  return _msize(ptr);
-}
+__declspec(noinline) size_t _msize_base(void *ptr) { return _msize(ptr); }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void free(void *ptr) {
+__declspec(noinline) void free(void *ptr) {
   GET_STACK_TRACE_FREE;
   return asan_free(ptr, &stack, FROM_MALLOC);
 }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void _free_dbg(void *ptr, int) {
-  free(ptr);
-}
+__declspec(noinline) void _free_dbg(void *ptr, int) { free(ptr); }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void _free_base(void *ptr) {
-  free(ptr);
-}
+__declspec(noinline) void _free_base(void *ptr) { free(ptr); }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void *malloc(size_t size) {
+__declspec(noinline) void *malloc(size_t size) {
   GET_STACK_TRACE_MALLOC;
   return asan_malloc(size, &stack);
 }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void *_malloc_base(size_t size) {
-  return malloc(size);
-}
+__declspec(noinline) void *_malloc_base(size_t size) { return malloc(size); }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void *_malloc_dbg(size_t size, int, const char *, int) {
+__declspec(noinline) void *_malloc_dbg(size_t size, int, const char *, int) {
   return malloc(size);
 }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void *calloc(size_t nmemb, size_t size) {
+__declspec(noinline) void *calloc(size_t nmemb, size_t size) {
   GET_STACK_TRACE_MALLOC;
   return asan_calloc(nmemb, size, &stack);
 }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void *_calloc_base(size_t nmemb, size_t size) {
+__declspec(noinline) void *_calloc_base(size_t nmemb, size_t size) {
   return calloc(nmemb, size);
 }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void *_calloc_dbg(size_t nmemb, size_t size, int, const char *, int) {
+__declspec(noinline) void *_calloc_dbg(size_t nmemb, size_t size, int,
+                                       const char *, int) {
   return calloc(nmemb, size);
 }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void *_calloc_impl(size_t nmemb, size_t size, int *errno_tmp) {
+__declspec(noinline) void *_calloc_impl(size_t nmemb, size_t size,
+                                        int *errno_tmp) {
   return calloc(nmemb, size);
 }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void *realloc(void *ptr, size_t size) {
+__declspec(noinline) void *realloc(void *ptr, size_t size) {
   GET_STACK_TRACE_MALLOC;
   return asan_realloc(ptr, size, &stack);
 }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void *_realloc_dbg(void *ptr, size_t size, int) {
+__declspec(noinline) void *_realloc_dbg(void *ptr, size_t size, int) {
   UNREACHABLE("_realloc_dbg should not exist!");
   return 0;
 }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void *_realloc_base(void *ptr, size_t size) {
+__declspec(noinline) void *_realloc_base(void *ptr, size_t size) {
   return realloc(ptr, size);
 }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void *_recalloc(void *p, size_t n, size_t elem_size) {
+__declspec(noinline) void *_recalloc(void *p, size_t n, size_t elem_size) {
   if (!p)
     return calloc(n, elem_size);
   const size_t size = n * elem_size;
@@ -166,23 +138,41 @@  void *_recalloc(void *p, size_t n, size_t elem_size) {
   return new_alloc;
 }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void *_recalloc_base(void *p, size_t n, size_t elem_size) {
+__declspec(noinline) void *_recalloc_base(void *p, size_t n, size_t elem_size) {
   return _recalloc(p, n, elem_size);
 }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void *_expand(void *memblock, size_t size) {
+__declspec(noinline) void *_expand(void *memblock, size_t size) {
   // _expand is used in realloc-like functions to resize the buffer if possible.
   // We don't want memory to stand still while resizing buffers, so return 0.
   return 0;
 }
 
-ALLOCATION_FUNCTION_ATTRIBUTE
-void *_expand_dbg(void *memblock, size_t size) {
+__declspec(noinline) void *_expand_dbg(void *memblock, size_t size) {
   return _expand(memblock, size);
 }
 
+__declspec(dllexport) size_t __cdecl __asan_msize(void *ptr) {
+  return _msize(ptr);
+}
+__declspec(dllexport) void __cdecl __asan_free(void *const ptr) { free(ptr); }
+__declspec(dllexport) void *__cdecl __asan_malloc(const size_t size) {
+  return malloc(size);
+}
+__declspec(dllexport) void *__cdecl __asan_calloc(const size_t nmemb,
+                                                  const size_t size) {
+  return calloc(nmemb, size);
+}
+__declspec(dllexport) void *__cdecl __asan_realloc(void *const ptr,
+                                                   const size_t size) {
+  return realloc(ptr, size);
+}
+__declspec(dllexport) void *__cdecl __asan_recalloc(void *const ptr,
+                                                    const size_t nmemb,
+                                                    const size_t size) {
+  return _recalloc(ptr, nmemb, size);
+}
+
 // TODO(timurrrr): Might want to add support for _aligned_* allocation
 // functions to detect a bit more bugs.  Those functions seem to wrap malloc().
 
@@ -487,7 +477,6 @@  static void TryToOverrideFunction(const char *fname, uptr new_func) {
 }
 
 void ReplaceSystemMalloc() {
-#if defined(ASAN_DYNAMIC)
   TryToOverrideFunction("free", (uptr)free);
   TryToOverrideFunction("_free_base", (uptr)free);
   TryToOverrideFunction("malloc", (uptr)malloc);
@@ -543,8 +532,6 @@  void ReplaceSystemMalloc() {
   // allocation API will be directed to ASan's heap. We don't currently
   // intercept all calls to HeapAlloc. If we did, we would have to check on
   // HeapFree whether the pointer came from ASan of from the system.
-
-#endif  // defined(ASAN_DYNAMIC)
 }
 }  // namespace __asan
 
diff --git a/libsanitizer/asan/asan_malloc_win_thunk.cpp b/libsanitizer/asan/asan_malloc_win_thunk.cpp
new file mode 100644
index 000000000000..9cc00913177e
--- /dev/null
+++ b/libsanitizer/asan/asan_malloc_win_thunk.cpp
@@ -0,0 +1,229 @@ 
+//===-- asan_malloc_win_thunk.cpp
+//-----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Windows-specific malloc interception.
+// This is included statically for projects statically linking
+// with the C Runtime (/MT, /MTd) in order to provide ASAN-aware
+// versions of the C allocation functions.
+//===----------------------------------------------------------------------===//
+
+#ifdef SANITIZER_STATIC_RUNTIME_THUNK
+#  include "..\sanitizer_common\sanitizer_allocator_interface.h"
+// #include "asan_win_thunk_common.h"
+
+// Preserve stack traces with noinline.
+#  define STATIC_MALLOC_INTERFACE __declspec(noinline)
+
+extern "C" {
+__declspec(dllimport) size_t __cdecl __asan_msize(void *ptr);
+__declspec(dllimport) void __cdecl __asan_free(void *const ptr);
+__declspec(dllimport) void *__cdecl __asan_malloc(const size_t size);
+__declspec(dllimport) void *__cdecl __asan_calloc(const size_t nmemb,
+                                                  const size_t size);
+__declspec(dllimport) void *__cdecl __asan_realloc(void *const ptr,
+                                                   const size_t size);
+__declspec(dllimport) void *__cdecl __asan_recalloc(void *const ptr,
+                                                    const size_t nmemb,
+                                                    const size_t size);
+
+// Avoid tailcall optimization to preserve stack frames.
+#  pragma optimize("", off)
+
+// _msize
+STATIC_MALLOC_INTERFACE size_t _msize(void *ptr) { return __asan_msize(ptr); }
+
+STATIC_MALLOC_INTERFACE size_t _msize_base(void *ptr) {
+  return __asan_msize(ptr);
+}
+
+STATIC_MALLOC_INTERFACE size_t _msize_dbg(void *ptr) {
+  return __asan_msize(ptr);
+}
+
+// free
+STATIC_MALLOC_INTERFACE void free(void *const ptr) { return __asan_free(ptr); }
+
+STATIC_MALLOC_INTERFACE void _free_base(void *const ptr) {
+  return __asan_free(ptr);
+}
+
+STATIC_MALLOC_INTERFACE void _free_dbg(void *const ptr) {
+  return __asan_free(ptr);
+}
+
+// malloc
+STATIC_MALLOC_INTERFACE void *malloc(const size_t size) {
+  return __asan_malloc(size);
+}
+
+STATIC_MALLOC_INTERFACE void *_malloc_base(const size_t size) {
+  return __asan_malloc(size);
+}
+
+STATIC_MALLOC_INTERFACE void *_malloc_dbg(const size_t size) {
+  return __asan_malloc(size);
+}
+
+// calloc
+STATIC_MALLOC_INTERFACE void *calloc(const size_t nmemb, const size_t size) {
+  return __asan_calloc(nmemb, size);
+}
+
+STATIC_MALLOC_INTERFACE void *_calloc_base(const size_t nmemb,
+                                           const size_t size) {
+  return __asan_calloc(nmemb, size);
+}
+
+STATIC_MALLOC_INTERFACE void *_calloc_impl(const size_t nmemb,
+                                           const size_t size,
+                                           int *const errno_tmp) {
+  // Provided by legacy msvcrt.
+  (void)errno_tmp;
+
+  return __asan_calloc(nmemb, size);
+}
+
+STATIC_MALLOC_INTERFACE void *_calloc_dbg(const size_t nmemb, const size_t size,
+                                          int, const char *, int) {
+  return __asan_calloc(nmemb, size);
+}
+
+// realloc
+STATIC_MALLOC_INTERFACE void *realloc(void *const ptr, const size_t size) {
+  return __asan_realloc(ptr, size);
+}
+
+STATIC_MALLOC_INTERFACE void *_realloc_base(void *const ptr,
+                                            const size_t size) {
+  return __asan_realloc(ptr, size);
+}
+
+STATIC_MALLOC_INTERFACE void *_realloc_dbg(void *const ptr, const size_t size,
+                                           int, const char *, int) {
+  return __asan_realloc(ptr, size);
+}
+
+// recalloc
+STATIC_MALLOC_INTERFACE void *_recalloc(void *const ptr, const size_t nmemb,
+                                        const size_t size) {
+  return __asan_recalloc(ptr, nmemb, size);
+}
+
+STATIC_MALLOC_INTERFACE void *_recalloc_base(void *const ptr,
+                                             const size_t nmemb,
+                                             const size_t size) {
+  return __asan_recalloc(ptr, nmemb, size);
+}
+
+STATIC_MALLOC_INTERFACE void *_recalloc_dbg(void *const ptr, const size_t nmemb,
+                                            const size_t size, int,
+                                            const char *, int) {
+  return __asan_recalloc(ptr, nmemb, size);
+}
+
+// expand
+STATIC_MALLOC_INTERFACE void *_expand(void *, size_t) {
+  // _expand is used in realloc-like functions to resize the buffer if possible.
+  // We don't want memory to stand still while resizing buffers, so return 0.
+  return nullptr;
+}
+
+STATIC_MALLOC_INTERFACE void *_expand_dbg(void *, size_t, int, const char *,
+                                          int) {
+  return nullptr;
+}
+
+// We need to provide symbols for all the debug CRT functions if we decide to
+// provide any. Most of these functions make no sense under ASan and so we
+// make them no-ops.
+long _CrtSetBreakAlloc(long const) { return ~0; }
+
+void _CrtSetDbgBlockType(void *const, int const) { return; }
+
+typedef int(__cdecl *CRT_ALLOC_HOOK)(int, void *, size_t, int, long,
+                                     const unsigned char *, int);
+
+CRT_ALLOC_HOOK _CrtGetAllocHook() { return nullptr; }
+
+CRT_ALLOC_HOOK _CrtSetAllocHook(CRT_ALLOC_HOOK const hook) { return hook; }
+
+int _CrtCheckMemory() { return 1; }
+
+int _CrtSetDbgFlag(int const new_bits) { return new_bits; }
+
+typedef void (*CrtDoForAllClientObjectsCallback)(void *, void *);
+
+void _CrtDoForAllClientObjects(CrtDoForAllClientObjectsCallback const,
+                               void *const) {
+  return;
+}
+
+int _CrtIsValidPointer(void const *const p, unsigned int const, int const) {
+  return p != nullptr;
+}
+
+int _CrtIsValidHeapPointer(void const *const block) {
+  if (!block) {
+    return 0;
+  }
+
+  return __sanitizer_get_ownership(block);
+}
+
+int _CrtIsMemoryBlock(void const *const, unsigned const, long *const,
+                      char **const, int *const) {
+  return 0;
+}
+
+int _CrtReportBlockType(void const *const) { return -1; }
+
+typedef void(__cdecl *CRT_DUMP_CLIENT)(void *, size_t);
+
+CRT_DUMP_CLIENT _CrtGetDumpClient() { return nullptr; }
+
+CRT_DUMP_CLIENT _CrtSetDumpClient(CRT_DUMP_CLIENT new_client) {
+  return new_client;
+}
+
+void _CrtMemCheckpoint(void *const) { return; }
+
+int _CrtMemDifference(void *const, void const *const, void const *const) {
+  return 0;
+}
+
+void _CrtMemDumpAllObjectsSince(void const *const) { return; }
+
+int _CrtDumpMemoryLeaks() { return 0; }
+
+void _CrtMemDumpStatistics(void const *const) { return; }
+
+int _crtDbgFlag{0};
+long _crtBreakAlloc{-1};
+CRT_DUMP_CLIENT _pfnDumpClient{nullptr};
+
+int *__p__crtDbgFlag() { return &_crtDbgFlag; }
+
+long *__p__crtBreakAlloc() { return &_crtBreakAlloc; }
+
+// TODO: These were added upstream but conflict with definitions in ucrtbased.
+// int _CrtDbgReport(int, const char *, int, const char *, const char *, ...) {
+//   ShowStatsAndAbort();
+// }
+//
+// int _CrtDbgReportW(int reportType, const wchar_t *, int, const wchar_t *,
+//                    const wchar_t *, ...) {
+//   ShowStatsAndAbort();
+// }
+//
+// int _CrtSetReportMode(int, int) { return 0; }
+
+}  // extern "C"
+#endif  // SANITIZER_STATIC_RUNTIME_THUNK
diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h
index 47ccf8444d31..91fe60db6329 100644
--- a/libsanitizer/asan/asan_mapping.h
+++ b/libsanitizer/asan/asan_mapping.h
@@ -72,7 +72,10 @@ 
 // || `[0x2000000000, 0x23ffffffff]` || LowShadow  ||
 // || `[0x0000000000, 0x1fffffffff]` || LowMem     ||
 //
-// Default Linux/RISCV64 Sv39 mapping:
+// Default Linux/RISCV64 Sv39 mapping with SHADOW_OFFSET == 0xd55550000;
+// (the exact location of SHADOW_OFFSET may vary depending the dynamic probing
+//  by FindDynamicShadowStart).
+//
 // || `[0x1555550000, 0x3fffffffff]` || HighMem    ||
 // || `[0x0fffffa000, 0x1555555fff]` || HighShadow ||
 // || `[0x0effffa000, 0x0fffff9fff]` || ShadowGap  ||
@@ -186,11 +189,11 @@ 
 #  elif SANITIZER_FREEBSD && defined(__aarch64__)
 #    define ASAN_SHADOW_OFFSET_CONST 0x0000800000000000
 #  elif SANITIZER_RISCV64
-#    define ASAN_SHADOW_OFFSET_CONST 0x0000000d55550000
+#    define ASAN_SHADOW_OFFSET_DYNAMIC
 #  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_new_delete.cpp b/libsanitizer/asan/asan_new_delete.cpp
index 17280129c758..b5b1ced8ac5e 100644
--- a/libsanitizer/asan/asan_new_delete.cpp
+++ b/libsanitizer/asan/asan_new_delete.cpp
@@ -48,15 +48,6 @@  COMMENT_EXPORT("??_V@YAXPAX@Z")                   // operator delete[]
 
 using namespace __asan;
 
-// FreeBSD prior v9.2 have wrong definition of 'size_t'.
-// http://svnweb.freebsd.org/base?view=revision&revision=232261
-#if SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
-#include <sys/param.h>
-#if __FreeBSD_version <= 902001  // v9.2
-#define size_t unsigned
-#endif  // __FreeBSD_version
-#endif  // SANITIZER_FREEBSD && SANITIZER_WORDSIZE == 32
-
 // This code has issues on OSX.
 // See https://github.com/google/sanitizers/issues/131.
 
diff --git a/libsanitizer/asan/asan_poisoning.cpp b/libsanitizer/asan/asan_poisoning.cpp
index 746ad61813c6..762670632f4e 100644
--- a/libsanitizer/asan/asan_poisoning.cpp
+++ b/libsanitizer/asan/asan_poisoning.cpp
@@ -16,6 +16,7 @@ 
 #include "asan_report.h"
 #include "asan_stack.h"
 #include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_interface_internal.h"
 #include "sanitizer_common/sanitizer_libc.h"
@@ -410,7 +411,7 @@  void __sanitizer_annotate_contiguous_container(const void *beg_p,
                                                const void *new_mid_p) {
   if (!flags()->detect_container_overflow)
     return;
-  VPrintf(2, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p,
+  VPrintf(3, "contiguous_container: %p %p %p %p\n", beg_p, end_p, old_mid_p,
           new_mid_p);
   uptr storage_beg = reinterpret_cast<uptr>(beg_p);
   uptr storage_end = reinterpret_cast<uptr>(end_p);
@@ -479,7 +480,7 @@  void __sanitizer_annotate_double_ended_contiguous_container(
   if (!flags()->detect_container_overflow)
     return;
 
-  VPrintf(2, "contiguous_container: %p %p %p %p %p %p\n", storage_beg_p,
+  VPrintf(3, "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);
 
@@ -576,6 +577,185 @@  void __sanitizer_annotate_double_ended_contiguous_container(
   }
 }
 
+// Marks the specified number of bytes in a granule as accessible or
+// poisones the whole granule with kAsanContiguousContainerOOBMagic value.
+static void SetContainerGranule(uptr ptr, u8 n) {
+  constexpr uptr granularity = ASAN_SHADOW_GRANULARITY;
+  u8 s = (n == granularity) ? 0 : (n ? n : kAsanContiguousContainerOOBMagic);
+  *(u8 *)MemToShadow(ptr) = s;
+}
+
+// Performs a byte-by-byte copy of ASan annotations (shadow memory values).
+// Result may be different due to ASan limitations, but result cannot lead
+// to false positives (more memory than requested may get unpoisoned).
+static void SlowCopyContainerAnnotations(uptr src_beg, uptr src_end,
+                                         uptr dst_beg, uptr dst_end) {
+  constexpr uptr granularity = ASAN_SHADOW_GRANULARITY;
+  uptr dst_end_down = RoundDownTo(dst_end, granularity);
+  uptr src_ptr = src_beg;
+  uptr dst_ptr = dst_beg;
+
+  while (dst_ptr < dst_end) {
+    uptr granule_beg = RoundDownTo(dst_ptr, granularity);
+    uptr granule_end = granule_beg + granularity;
+    uptr unpoisoned_bytes = 0;
+
+    uptr end = Min(granule_end, dst_end);
+    for (; dst_ptr != end; ++dst_ptr, ++src_ptr)
+      if (!AddressIsPoisoned(src_ptr))
+        unpoisoned_bytes = dst_ptr - granule_beg + 1;
+
+    if (dst_ptr == dst_end && dst_end != dst_end_down &&
+        !AddressIsPoisoned(dst_end))
+      continue;
+
+    if (unpoisoned_bytes != 0 || granule_beg >= dst_beg)
+      SetContainerGranule(granule_beg, unpoisoned_bytes);
+    else if (!AddressIsPoisoned(dst_beg))
+      SetContainerGranule(granule_beg, dst_beg - granule_beg);
+  }
+}
+
+// Performs a byte-by-byte copy of ASan annotations (shadow memory values),
+// going through bytes in reversed order, but not reversing annotations.
+// Result may be different due to ASan limitations, but result cannot lead
+// to false positives (more memory than requested may get unpoisoned).
+static void SlowReversedCopyContainerAnnotations(uptr src_beg, uptr src_end,
+                                                 uptr dst_beg, uptr dst_end) {
+  constexpr uptr granularity = ASAN_SHADOW_GRANULARITY;
+  uptr dst_end_down = RoundDownTo(dst_end, granularity);
+  uptr src_ptr = src_end;
+  uptr dst_ptr = dst_end;
+
+  while (dst_ptr > dst_beg) {
+    uptr granule_beg = RoundDownTo(dst_ptr - 1, granularity);
+    uptr unpoisoned_bytes = 0;
+
+    uptr end = Max(granule_beg, dst_beg);
+    for (; dst_ptr != end; --dst_ptr, --src_ptr)
+      if (unpoisoned_bytes == 0 && !AddressIsPoisoned(src_ptr - 1))
+        unpoisoned_bytes = dst_ptr - granule_beg;
+
+    if (dst_ptr >= dst_end_down && !AddressIsPoisoned(dst_end))
+      continue;
+
+    if (granule_beg == dst_ptr || unpoisoned_bytes != 0)
+      SetContainerGranule(granule_beg, unpoisoned_bytes);
+    else if (!AddressIsPoisoned(dst_beg))
+      SetContainerGranule(granule_beg, dst_beg - granule_beg);
+  }
+}
+
+// A helper function for __sanitizer_copy_contiguous_container_annotations,
+// has assumption about begin and end of the container.
+// Should not be used stand alone.
+static void CopyContainerFirstGranuleAnnotation(uptr src_beg, uptr dst_beg) {
+  constexpr uptr granularity = ASAN_SHADOW_GRANULARITY;
+  // First granule
+  uptr src_beg_down = RoundDownTo(src_beg, granularity);
+  uptr dst_beg_down = RoundDownTo(dst_beg, granularity);
+  if (dst_beg_down == dst_beg)
+    return;
+  if (!AddressIsPoisoned(src_beg))
+    *(u8 *)MemToShadow(dst_beg_down) = *(u8 *)MemToShadow(src_beg_down);
+  else if (!AddressIsPoisoned(dst_beg))
+    SetContainerGranule(dst_beg_down, dst_beg - dst_beg_down);
+}
+
+// A helper function for __sanitizer_copy_contiguous_container_annotations,
+// has assumption about begin and end of the container.
+// Should not be used stand alone.
+static void CopyContainerLastGranuleAnnotation(uptr src_end, uptr dst_end) {
+  constexpr uptr granularity = ASAN_SHADOW_GRANULARITY;
+  // Last granule
+  uptr src_end_down = RoundDownTo(src_end, granularity);
+  uptr dst_end_down = RoundDownTo(dst_end, granularity);
+  if (dst_end_down == dst_end || !AddressIsPoisoned(dst_end))
+    return;
+  if (AddressIsPoisoned(src_end))
+    *(u8 *)MemToShadow(dst_end_down) = *(u8 *)MemToShadow(src_end_down);
+  else
+    SetContainerGranule(dst_end_down, src_end - src_end_down);
+}
+
+// This function copies ASan memory annotations (poisoned/unpoisoned states)
+// from one buffer to another.
+// It's main purpose is to help with relocating trivially relocatable objects,
+// which memory may be poisoned, without calling copy constructor.
+// However, it does not move memory content itself, only annotations.
+// If the buffers aren't aligned (the distance between buffers isn't
+// granule-aligned)
+//     // src_beg % granularity != dst_beg % granularity
+// the function handles this by going byte by byte, slowing down performance.
+// The old buffer annotations are not removed. If necessary,
+// user can unpoison old buffer with __asan_unpoison_memory_region.
+void __sanitizer_copy_contiguous_container_annotations(const void *src_beg_p,
+                                                       const void *src_end_p,
+                                                       const void *dst_beg_p,
+                                                       const void *dst_end_p) {
+  if (!flags()->detect_container_overflow)
+    return;
+
+  VPrintf(3, "contiguous_container_src: %p %p\n", src_beg_p, src_end_p);
+  VPrintf(3, "contiguous_container_dst: %p %p\n", dst_beg_p, dst_end_p);
+
+  uptr src_beg = reinterpret_cast<uptr>(src_beg_p);
+  uptr src_end = reinterpret_cast<uptr>(src_end_p);
+  uptr dst_beg = reinterpret_cast<uptr>(dst_beg_p);
+  uptr dst_end = reinterpret_cast<uptr>(dst_end_p);
+
+  constexpr uptr granularity = ASAN_SHADOW_GRANULARITY;
+
+  if (src_beg > src_end || (dst_end - dst_beg) != (src_end - src_beg)) {
+    GET_STACK_TRACE_FATAL_HERE;
+    ReportBadParamsToCopyContiguousContainerAnnotations(
+        src_beg, src_end, dst_beg, dst_end, &stack);
+  }
+
+  if (src_beg == src_end || src_beg == dst_beg)
+    return;
+  // Due to support for overlapping buffers, we may have to copy elements
+  // in reversed order, when destination buffer starts in the middle of
+  // the source buffer (or shares first granule with it).
+  //
+  // When buffers are not granule-aligned (or distance between them,
+  // to be specific), annotatios have to be copied byte by byte.
+  //
+  // The only remaining edge cases involve edge granules,
+  // when the container starts or ends within a granule.
+  uptr src_beg_up = RoundUpTo(src_beg, granularity);
+  uptr src_end_up = RoundUpTo(src_end, granularity);
+  bool copy_in_reversed_order = src_beg < dst_beg && dst_beg <= src_end_up;
+  if (src_beg % granularity != dst_beg % granularity ||
+      RoundDownTo(dst_end - 1, granularity) <= dst_beg) {
+    if (copy_in_reversed_order)
+      SlowReversedCopyContainerAnnotations(src_beg, src_end, dst_beg, dst_end);
+    else
+      SlowCopyContainerAnnotations(src_beg, src_end, dst_beg, dst_end);
+    return;
+  }
+
+  // As buffers are granule-aligned, we can just copy annotations of granules
+  // from the middle.
+  uptr dst_beg_up = RoundUpTo(dst_beg, granularity);
+  uptr dst_end_down = RoundDownTo(dst_end, granularity);
+  if (copy_in_reversed_order)
+    CopyContainerLastGranuleAnnotation(src_end, dst_end);
+  else
+    CopyContainerFirstGranuleAnnotation(src_beg, dst_beg);
+
+  if (dst_beg_up < dst_end_down) {
+    internal_memmove((u8 *)MemToShadow(dst_beg_up),
+                     (u8 *)MemToShadow(src_beg_up),
+                     (dst_end_down - dst_beg_up) / granularity);
+  }
+
+  if (copy_in_reversed_order)
+    CopyContainerFirstGranuleAnnotation(src_beg, dst_beg);
+  else
+    CopyContainerLastGranuleAnnotation(src_end, dst_end);
+}
+
 static const void *FindBadAddress(uptr begin, uptr end, bool poisoned) {
   CHECK_LE(begin, end);
   constexpr uptr kMaxRangeToCheck = 32;
diff --git a/libsanitizer/asan/asan_posix.cpp b/libsanitizer/asan/asan_posix.cpp
index e1f66641617c..39685696a0d0 100644
--- a/libsanitizer/asan/asan_posix.cpp
+++ b/libsanitizer/asan/asan_posix.cpp
@@ -59,10 +59,10 @@  bool PlatformUnpoisonStacks() {
 
   // Since we're on the signal alternate stack, we cannot find the DEFAULT
   // stack bottom using a local variable.
-  uptr default_bottom, tls_addr, tls_size, stack_size;
-  GetThreadStackAndTls(/*main=*/false, &default_bottom, &stack_size, &tls_addr,
-                       &tls_size);
-  UnpoisonStack(default_bottom, default_bottom + stack_size, "default");
+  uptr stack_begin, stack_end, tls_begin, tls_end;
+  GetThreadStackAndTls(/*main=*/false, &stack_begin, &stack_end, &tls_begin,
+                       &tls_end);
+  UnpoisonStack(stack_begin, stack_end, "default");
   return true;
 }
 
@@ -146,7 +146,44 @@  void PlatformTSDDtor(void *tsd) {
 #    endif
   AsanThread::TSDDtor(tsd);
 }
-#endif
+#  endif
+
+static void BeforeFork() {
+  VReport(2, "BeforeFork tid: %llu\n", GetTid());
+  if (CAN_SANITIZE_LEAKS) {
+    __lsan::LockGlobal();
+  }
+  // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the
+  // stuff we need.
+  __lsan::LockThreads();
+  __lsan::LockAllocator();
+  StackDepotLockBeforeFork();
+}
+
+static void AfterFork(bool fork_child) {
+  StackDepotUnlockAfterFork(fork_child);
+  // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock
+  // the stuff we need.
+  __lsan::UnlockAllocator();
+  __lsan::UnlockThreads();
+  if (CAN_SANITIZE_LEAKS) {
+    __lsan::UnlockGlobal();
+  }
+  VReport(2, "AfterFork tid: %llu\n", GetTid());
+}
+
+void InstallAtForkHandler() {
+#  if SANITIZER_SOLARIS || SANITIZER_NETBSD || SANITIZER_APPLE || \
+      (SANITIZER_LINUX && SANITIZER_SPARC)
+  // While other Linux targets use clone in internal_fork which doesn't
+  // trigger pthread_atfork handlers, Linux/sparc64 uses __fork, causing a
+  // hang.
+  return;  // FIXME: Implement FutexWait.
+#  endif
+  pthread_atfork(
+      &BeforeFork, []() { AfterFork(/* fork_child= */ false); },
+      []() { AfterFork(/* fork_child= */ true); });
+}
 
 void InstallAtExitCheckLeaks() {
   if (CAN_SANITIZE_LEAKS) {
diff --git a/libsanitizer/asan/asan_preinit.cpp b/libsanitizer/asan/asan_preinit.cpp
index b07556ec96f8..23169383bb74 100644
--- a/libsanitizer/asan/asan_preinit.cpp
+++ b/libsanitizer/asan/asan_preinit.cpp
@@ -15,10 +15,8 @@ 
 using namespace __asan;
 
 #if SANITIZER_CAN_USE_PREINIT_ARRAY
-  // The symbol is called __local_asan_preinit, because it's not intended to be
-  // exported.
-  // This code linked into the main executable when -fsanitize=address is in
-  // the link flags. It can only use exported interface functions.
-  __attribute__((section(".preinit_array"), used))
-  void (*__local_asan_preinit)(void) = __asan_init;
+// This section is linked into the main executable when -fsanitize=address is
+// specified to perform initialization at a very early stage.
+__attribute__((section(".preinit_array"), used)) static auto preinit =
+    __asan_init;
 #endif
diff --git a/libsanitizer/asan/asan_premap_shadow.cpp b/libsanitizer/asan/asan_premap_shadow.cpp
index bed2f62a2251..6e08b8f96650 100644
--- a/libsanitizer/asan/asan_premap_shadow.cpp
+++ b/libsanitizer/asan/asan_premap_shadow.cpp
@@ -33,7 +33,8 @@  uptr PremapShadowSize() {
 // PremapShadowSize() bytes on the right of it are mapped r/o.
 uptr PremapShadow() {
   return MapDynamicShadow(PremapShadowSize(), /*mmap_alignment_scale*/ 3,
-                          /*min_shadow_base_alignment*/ 0, kHighMemEnd);
+                          /*min_shadow_base_alignment*/ 0, kHighMemEnd,
+                          GetMmapGranularity());
 }
 
 bool PremapShadowFailed() {
diff --git a/libsanitizer/asan/asan_report.cpp b/libsanitizer/asan/asan_report.cpp
index 7603e8131154..45aa607dcda0 100644
--- a/libsanitizer/asan/asan_report.cpp
+++ b/libsanitizer/asan/asan_report.cpp
@@ -24,6 +24,7 @@ 
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_interface_internal.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_report_decorator.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 #include "sanitizer_common/sanitizer_symbolizer.h"
@@ -32,8 +33,11 @@  namespace __asan {
 
 // -------------------- User-specified callbacks ----------------- {{{1
 static void (*error_report_callback)(const char*);
-static char *error_message_buffer = nullptr;
-static uptr error_message_buffer_pos = 0;
+using ErrorMessageBuffer = InternalMmapVectorNoCtor<char, true>;
+alignas(
+    alignof(ErrorMessageBuffer)) static char error_message_buffer_placeholder
+    [sizeof(ErrorMessageBuffer)];
+static ErrorMessageBuffer *error_message_buffer = nullptr;
 static Mutex error_message_buf_mutex;
 static const unsigned kAsanBuggyPcPoolSize = 25;
 static __sanitizer::atomic_uintptr_t AsanBuggyPcPool[kAsanBuggyPcPoolSize];
@@ -42,17 +46,14 @@  void AppendToErrorMessageBuffer(const char *buffer) {
   Lock l(&error_message_buf_mutex);
   if (!error_message_buffer) {
     error_message_buffer =
-      (char*)MmapOrDieQuietly(kErrorMessageBufferSize, __func__);
-    error_message_buffer_pos = 0;
+        new (error_message_buffer_placeholder) ErrorMessageBuffer();
+    error_message_buffer->Initialize(kErrorMessageBufferSize);
   }
-  uptr length = internal_strlen(buffer);
-  RAW_CHECK(kErrorMessageBufferSize >= error_message_buffer_pos);
-  uptr remaining = kErrorMessageBufferSize - error_message_buffer_pos;
-  internal_strncpy(error_message_buffer + error_message_buffer_pos,
-                   buffer, remaining);
-  error_message_buffer[kErrorMessageBufferSize - 1] = '\0';
-  // FIXME: reallocate the buffer instead of truncating the message.
-  error_message_buffer_pos += Min(remaining, length);
+  uptr error_message_buffer_len = error_message_buffer->size();
+  uptr buffer_len = internal_strlen(buffer);
+  error_message_buffer->resize(error_message_buffer_len + buffer_len);
+  internal_memcpy(error_message_buffer->data() + error_message_buffer_len,
+                  buffer, buffer_len);
 }
 
 // ---------------------- Helper functions ----------------------- {{{1
@@ -158,14 +159,14 @@  class ScopedInErrorReport {
 
     // Copy the message buffer so that we could start logging without holding a
     // lock that gets acquired during printing.
-    InternalMmapVector<char> buffer_copy(kErrorMessageBufferSize);
+    InternalScopedString buffer_copy;
     {
       Lock l(&error_message_buf_mutex);
-      internal_memcpy(buffer_copy.data(),
-                      error_message_buffer, kErrorMessageBufferSize);
+      error_message_buffer->push_back('\0');
+      buffer_copy.Append(error_message_buffer->data());
       // Clear error_message_buffer so that if we find other errors
       // we don't re-log this error.
-      error_message_buffer_pos = 0;
+      error_message_buffer->clear();
     }
 
     LogFullErrorReport(buffer_copy.data());
@@ -366,6 +367,16 @@  void ReportBadParamsToAnnotateDoubleEndedContiguousContainer(
   in_report.ReportError(error);
 }
 
+void ReportBadParamsToCopyContiguousContainerAnnotations(
+    uptr old_storage_beg, uptr old_storage_end, uptr new_storage_beg,
+    uptr new_storage_end, BufferedStackTrace *stack) {
+  ScopedInErrorReport in_report;
+  ErrorBadParamsToCopyContiguousContainerAnnotations error(
+      GetCurrentTidOrInvalid(), stack, old_storage_beg, old_storage_end,
+      new_storage_beg, new_storage_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 3540b3b4b1bf..3143d83abe39 100644
--- a/libsanitizer/asan/asan_report.h
+++ b/libsanitizer/asan/asan_report.h
@@ -88,6 +88,9 @@  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 ReportBadParamsToCopyContiguousContainerAnnotations(
+    uptr old_storage_beg, uptr old_storage_end, uptr new_storage_beg,
+    uptr new_storage_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_rtl.cpp b/libsanitizer/asan/asan_rtl.cpp
index d1e7856973b4..19c6c210b564 100644
--- a/libsanitizer/asan/asan_rtl.cpp
+++ b/libsanitizer/asan/asan_rtl.cpp
@@ -71,16 +71,16 @@  static void CheckUnwind() {
 }
 
 // -------------------------- Globals --------------------- {{{1
-static int asan_inited = 0;
-static int asan_init_is_running = 0;
+static StaticSpinMutex asan_inited_mutex;
+static atomic_uint8_t asan_inited = {0};
 
-void SetAsanInited(u32 val) { asan_inited = val; }
-
-void SetAsanInitIsRunning(u32 val) { asan_init_is_running = val; }
-
-bool AsanInited() { return asan_inited == 1; }
+static void SetAsanInited() {
+  atomic_store(&asan_inited, 1, memory_order_release);
+}
 
-bool AsanInitIsRunning() { return asan_init_is_running == 1; }
+bool AsanInited() {
+  return atomic_load(&asan_inited, memory_order_acquire) == 1;
+}
 
 bool replace_intrin_cached;
 
@@ -382,7 +382,7 @@  void PrintAddressSpaceLayout() {
 
   Printf("SHADOW_SCALE: %d\n", (int)ASAN_SHADOW_SCALE);
   Printf("SHADOW_GRANULARITY: %d\n", (int)ASAN_SHADOW_GRANULARITY);
-  Printf("SHADOW_OFFSET: 0x%zx\n", (uptr)ASAN_SHADOW_OFFSET);
+  Printf("SHADOW_OFFSET: %p\n", (void *)ASAN_SHADOW_OFFSET);
   CHECK(ASAN_SHADOW_SCALE >= 3 && ASAN_SHADOW_SCALE <= 7);
   if (kMidMemBeg)
     CHECK(kMidShadowBeg > kLowShadowEnd &&
@@ -390,12 +390,10 @@  void PrintAddressSpaceLayout() {
           kHighShadowBeg > kMidMemEnd);
 }
 
-static void AsanInitInternal() {
+static bool AsanInitInternal() {
   if (LIKELY(AsanInited()))
-    return;
+    return true;
   SanitizerToolName = "AddressSanitizer";
-  CHECK(!AsanInitIsRunning() && "ASan init calls itself!");
-  SetAsanInitIsRunning(1);
 
   CacheBinaryName();
 
@@ -408,11 +406,12 @@  static void AsanInitInternal() {
   // Stop performing init at this point if we are being loaded via
   // dlopen() and the platform supports it.
   if (SANITIZER_SUPPORTS_INIT_FOR_DLOPEN && UNLIKELY(HandleDlopenInit())) {
-    SetAsanInitIsRunning(0);
     VReport(1, "AddressSanitizer init is being performed for dlopen().\n");
-    return;
+    return false;
   }
 
+  // Make sure we are not statically linked.
+  __interception::DoesNotSupportStaticLinking();
   AsanCheckIncompatibleRT();
   AsanCheckDynamicRTPrereqs();
   AvoidCVE_2016_2143();
@@ -424,9 +423,6 @@  static void AsanInitInternal() {
 
   InitializeHighMemEnd();
 
-  // Make sure we are not statically linked.
-  AsanDoesNotSupportStaticLinkage();
-
   // Install tool-specific callbacks in sanitizer_common.
   AddDieCallback(AsanDie);
   SetCheckUnwindCallback(CheckUnwind);
@@ -470,8 +466,7 @@  static void AsanInitInternal() {
   // On Linux AsanThread::ThreadStart() calls malloc() that's why asan_inited
   // should be set to 1 prior to initializing the threads.
   replace_intrin_cached = flags()->replace_intrin;
-  SetAsanInited(1);
-  SetAsanInitIsRunning(0);
+  SetAsanInited();
 
   if (flags()->atexit)
     Atexit(asan_atexit);
@@ -483,9 +478,6 @@  static void AsanInitInternal() {
   if (flags()->start_deactivated)
     AsanDeactivate();
 
-  // interceptors
-  InitTlsSize();
-
   // Create main thread.
   AsanThread *main_thread = CreateMainThread();
   CHECK_EQ(0, main_thread->tid());
@@ -497,6 +489,8 @@  static void AsanInitInternal() {
     InstallAtExitCheckLeaks();
   }
 
+  InstallAtForkHandler();
+
 #if CAN_SANITIZE_UB
   __ubsan::InitAsPlugin();
 #endif
@@ -515,14 +509,29 @@  static void AsanInitInternal() {
   VReport(1, "AddressSanitizer Init done\n");
 
   WaitForDebugger(flags()->sleep_after_init, "after init");
+
+  return true;
 }
 
 // Initialize as requested from some part of ASan runtime library (interceptors,
 // allocator, etc).
 void AsanInitFromRtl() {
+  if (LIKELY(AsanInited()))
+    return;
+  SpinMutexLock lock(&asan_inited_mutex);
   AsanInitInternal();
 }
 
+bool TryAsanInitFromRtl() {
+  if (LIKELY(AsanInited()))
+    return true;
+  if (!asan_inited_mutex.TryLock())
+    return false;
+  bool result = AsanInitInternal();
+  asan_inited_mutex.Unlock();
+  return result;
+}
+
 #if ASAN_DYNAMIC
 // Initialize runtime in case it's LD_PRELOAD-ed into unsanitized executable
 // (and thus normal initializers from .preinit_array or modules haven't run).
@@ -568,10 +577,8 @@  static void UnpoisonDefaultStack() {
   } else {
     CHECK(!SANITIZER_FUCHSIA);
     // If we haven't seen this thread, try asking the OS for stack bounds.
-    uptr tls_addr, tls_size, stack_size;
-    GetThreadStackAndTls(/*main=*/false, &bottom, &stack_size, &tls_addr,
-                         &tls_size);
-    top = bottom + stack_size;
+    uptr tls_begin, tls_end;
+    GetThreadStackAndTls(/*main=*/false, &bottom, &top, &tls_begin, &tls_end);
   }
 
   UnpoisonStack(bottom, top, "default");
@@ -593,7 +600,7 @@  static void UnpoisonFakeStack() {
 using namespace __asan;
 
 void NOINLINE __asan_handle_no_return() {
-  if (AsanInitIsRunning())
+  if (UNLIKELY(!AsanInited()))
     return;
 
   if (!PlatformUnpoisonStacks())
@@ -623,7 +630,7 @@  void NOINLINE __asan_set_death_callback(void (*callback)(void)) {
 // We use this call as a trigger to wake up ASan from deactivated state.
 void __asan_init() {
   AsanActivate();
-  AsanInitInternal();
+  AsanInitFromRtl();
 }
 
 void __asan_version_mismatch_check() {
diff --git a/libsanitizer/asan/asan_rtl_x86_64.S b/libsanitizer/asan/asan_rtl_x86_64.S
index 0b7363018f42..9c5289856d8a 100644
--- a/libsanitizer/asan/asan_rtl_x86_64.S
+++ b/libsanitizer/asan/asan_rtl_x86_64.S
@@ -27,7 +27,12 @@  FNAME(reg, op, s, i): ;\
 #define ASAN_MEMORY_ACCESS_INITIAL_CHECK_ADD(reg, op, s) \
         mov    %##reg,%r10 ;\
         shr    $0x3,%r10 ;\
+        .if ASAN_SHADOW_OFFSET_CONST < 0x80000000   ;\
         movsbl ASAN_SHADOW_OFFSET_CONST(%r10),%r10d ;\
+        .else                                       ;\
+        movabsq $ASAN_SHADOW_OFFSET_CONST,%r11      ;\
+        movsbl (%r10,%r11),%r10d                    ;\
+        .endif                                      ;\
         test   %r10d,%r10d ;\
         jne    CLABEL(reg, op, s, add) ;\
 RLABEL(reg, op, s, add): ;\
@@ -84,7 +89,12 @@  ENDF
 #define ASAN_MEMORY_ACCESS_CHECK_ADD(reg, op, s, c) \
         mov    %##reg,%r10 ;\
         shr    $0x3,%r10 ;\
+        .if ASAN_SHADOW_OFFSET_CONST < 0x80000000  ;\
         ##c    $0x0,ASAN_SHADOW_OFFSET_CONST(%r10) ;\
+        .else                                      ;\
+        movabsq $ASAN_SHADOW_OFFSET_CONST,%r11     ;\
+        ##c    $0x0,(%r10,%r11)                    ;\
+        .endif                                     ;\
         jne    FLABEL(reg, op, s, add) ;\
         retq  ;\
 
diff --git a/libsanitizer/asan/asan_suppressions.cpp b/libsanitizer/asan/asan_suppressions.cpp
index 8cb2c3e3b9b6..94289d14d7e7 100644
--- a/libsanitizer/asan/asan_suppressions.cpp
+++ b/libsanitizer/asan/asan_suppressions.cpp
@@ -20,7 +20,7 @@ 
 
 namespace __asan {
 
-ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
+alignas(64) static char suppression_placeholder[sizeof(SuppressionContext)];
 static SuppressionContext *suppression_ctx = nullptr;
 static const char kInterceptorName[] = "interceptor_name";
 static const char kInterceptorViaFunction[] = "interceptor_via_fun";
@@ -39,8 +39,7 @@  void InitializeSuppressions() {
   suppression_ctx = new (suppression_placeholder)
       SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
   suppression_ctx->ParseFromFile(flags()->suppressions);
-  if (&__asan_default_suppressions)
-    suppression_ctx->Parse(__asan_default_suppressions());
+  suppression_ctx->Parse(__asan_default_suppressions());
 }
 
 bool IsInterceptorSuppressed(const char *interceptor_name) {
@@ -81,9 +80,10 @@  bool IsStackTraceSuppressed(const StackTrace *stack) {
     }
 
     if (suppression_ctx->HasSuppressionType(kInterceptorViaFunction)) {
-      SymbolizedStack *frames = symbolizer->SymbolizePC(addr);
+      SymbolizedStackHolder symbolized_stack(symbolizer->SymbolizePC(addr));
+      const SymbolizedStack *frames = symbolized_stack.get();
       CHECK(frames);
-      for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
+      for (const SymbolizedStack *cur = frames; cur; cur = cur->next) {
         const char *function_name = cur->info.function;
         if (!function_name) {
           continue;
@@ -91,11 +91,9 @@  bool IsStackTraceSuppressed(const StackTrace *stack) {
         // Match "interceptor_via_fun" suppressions.
         if (suppression_ctx->Match(function_name, kInterceptorViaFunction,
                                    &s)) {
-          frames->ClearAll();
           return true;
         }
       }
-      frames->ClearAll();
     }
   }
   return false;
diff --git a/libsanitizer/asan/asan_thread.cpp b/libsanitizer/asan/asan_thread.cpp
index 8798968947e8..37fb6f2b07f2 100644
--- a/libsanitizer/asan/asan_thread.cpp
+++ b/libsanitizer/asan/asan_thread.cpp
@@ -21,6 +21,7 @@ 
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
+#include "sanitizer_common/sanitizer_thread_history.h"
 #include "sanitizer_common/sanitizer_tls_get_addr.h"
 
 namespace __asan {
@@ -28,10 +29,7 @@  namespace __asan {
 // AsanThreadContext implementation.
 
 void AsanThreadContext::OnCreated(void *arg) {
-  CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs *>(arg);
-  if (args->stack)
-    stack_id = StackDepotPut(*args->stack);
-  thread = args->thread;
+  thread = static_cast<AsanThread *>(arg);
   thread->set_context(this);
 }
 
@@ -44,10 +42,15 @@  static ThreadRegistry *asan_thread_registry;
 static ThreadArgRetval *thread_data;
 
 static Mutex mu_for_thread_context;
+// TODO(leonardchan@): It should be possible to make LowLevelAllocator
+// threadsafe and consolidate this one into the GlobalLoweLevelAllocator.
+// We should be able to do something similar to what's in
+// sanitizer_stack_store.cpp.
+static LowLevelAllocator allocator_for_thread_context;
 
 static ThreadContextBase *GetAsanThreadContext(u32 tid) {
   Lock lock(&mu_for_thread_context);
-  return new (GetGlobalLowLevelAllocator()) AsanThreadContext(tid);
+  return new (allocator_for_thread_context) AsanThreadContext(tid);
 }
 
 static void InitThreads() {
@@ -62,10 +65,10 @@  static void InitThreads() {
   // thread before all TSD destructors will be called for it.
 
   // MIPS requires aligned address
-  static ALIGNED(alignof(
-      ThreadRegistry)) char thread_registry_placeholder[sizeof(ThreadRegistry)];
-  static ALIGNED(alignof(
-      ThreadArgRetval)) char thread_data_placeholder[sizeof(ThreadArgRetval)];
+  alignas(alignof(ThreadRegistry)) static char
+      thread_registry_placeholder[sizeof(ThreadRegistry)];
+  alignas(alignof(ThreadArgRetval)) static char
+      thread_data_placeholder[sizeof(ThreadArgRetval)];
 
   asan_thread_registry =
       new (thread_registry_placeholder) ThreadRegistry(GetAsanThreadContext);
@@ -101,8 +104,8 @@  AsanThread *AsanThread::Create(const void *start_data, uptr data_size,
     CHECK_LE(data_size, availible_size);
     internal_memcpy(thread->start_data_, start_data, data_size);
   }
-  AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
-  asanThreadRegistry().CreateThread(0, detached, parent_tid, &args);
+  asanThreadRegistry().CreateThread(0, detached, parent_tid,
+                                    stack ? StackDepotPut(*stack) : 0, thread);
 
   return thread;
 }
@@ -301,13 +304,10 @@  AsanThread *CreateMainThread() {
 // OS-specific implementations that need more information passed through.
 void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
   DCHECK_EQ(options, nullptr);
-  uptr tls_size = 0;
-  uptr stack_size = 0;
-  GetThreadStackAndTls(tid() == kMainTid, &stack_bottom_, &stack_size,
-                       &tls_begin_, &tls_size);
-  stack_top_ = RoundDownTo(stack_bottom_ + stack_size, ASAN_SHADOW_GRANULARITY);
+  GetThreadStackAndTls(tid() == kMainTid, &stack_bottom_, &stack_top_,
+                       &tls_begin_, &tls_end_);
+  stack_top_ = RoundDownTo(stack_top_, ASAN_SHADOW_GRANULARITY);
   stack_bottom_ = RoundDownTo(stack_bottom_, ASAN_SHADOW_GRANULARITY);
-  tls_end_ = tls_begin_ + tls_size;
   dtls_ = DTLS_Get();
 
   if (stack_top_ != stack_bottom_) {
@@ -556,6 +556,12 @@  void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) {
       threads);
 }
 
+void PrintThreads() {
+  InternalScopedString out;
+  PrintThreadHistory(__asan::asanThreadRegistry(), out);
+  Report("%s\n", out.data());
+}
+
 }  // namespace __lsan
 
 // ---------------------- Interface ---------------- {{{1
diff --git a/libsanitizer/asan/asan_thread.h b/libsanitizer/asan/asan_thread.h
index 62f1b5337fe4..ad9e03d68fe9 100644
--- a/libsanitizer/asan/asan_thread.h
+++ b/libsanitizer/asan/asan_thread.h
@@ -36,21 +36,16 @@  class AsanThread;
 class AsanThreadContext final : public ThreadContextBase {
  public:
   explicit AsanThreadContext(int tid)
-      : ThreadContextBase(tid), announced(false),
-        destructor_iterations(GetPthreadDestructorIterations()), stack_id(0),
+      : ThreadContextBase(tid),
+        announced(false),
+        destructor_iterations(GetPthreadDestructorIterations()),
         thread(nullptr) {}
   bool announced;
   u8 destructor_iterations;
-  u32 stack_id;
   AsanThread *thread;
 
   void OnCreated(void *arg) override;
   void OnFinished() override;
-
-  struct CreateThreadContextArgs {
-    AsanThread *thread;
-    StackTrace *stack;
-  };
 };
 
 // AsanThreadContext objects are never freed, so we need many of them.
diff --git a/libsanitizer/asan/asan_win.cpp b/libsanitizer/asan/asan_win.cpp
index d5a30f471e2b..09a13b11cff1 100644
--- a/libsanitizer/asan/asan_win.cpp
+++ b/libsanitizer/asan/asan_win.cpp
@@ -203,6 +203,8 @@  void InitializePlatformInterceptors() {
 
 void InstallAtExitCheckLeaks() {}
 
+void InstallAtForkHandler() {}
+
 void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
   UNIMPLEMENTED();
 }
@@ -264,16 +266,10 @@  void PlatformTSDDtor(void *tsd) { AsanThread::TSDDtor(tsd); }
 // }}}
 
 // ---------------------- Various stuff ---------------- {{{
-void *AsanDoesNotSupportStaticLinkage() {
-#if defined(_DEBUG)
-#error Please build the runtime with a non-debug CRT: /MD or /MT
-#endif
-  return 0;
-}
-
 uptr FindDynamicShadowStart() {
   return MapDynamicShadow(MemToShadowSize(kHighMemEnd), ASAN_SHADOW_SCALE,
-                          /*min_shadow_base_alignment*/ 0, kHighMemEnd);
+                          /*min_shadow_base_alignment*/ 0, kHighMemEnd,
+                          GetMmapGranularity());
 }
 
 void AsanCheckDynamicRTPrereqs() {}
diff --git a/libsanitizer/asan/asan_win_common_runtime_thunk.cpp b/libsanitizer/asan/asan_win_common_runtime_thunk.cpp
new file mode 100644
index 000000000000..056e49336d32
--- /dev/null
+++ b/libsanitizer/asan/asan_win_common_runtime_thunk.cpp
@@ -0,0 +1,112 @@ 
+//===-- asan_win_common_runtime_thunk.cpp --------------------------- -----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This file defines things that need to be present in the application modules
+// to interact with the ASan DLL runtime correctly and can't be implemented
+// using the default "import library" generated when linking the DLL.
+//
+// This includes:
+//  - Cloning shadow memory dynamic address from ASAN DLL
+//  - Creating weak aliases to default implementation imported from asan dll
+//  - Forwarding the detect_stack_use_after_return runtime option
+//  - installing a custom SEH handler
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) || \
+    defined(SANITIZER_STATIC_RUNTIME_THUNK)
+#  define SANITIZER_IMPORT_INTERFACE 1
+#  define WIN32_LEAN_AND_MEAN
+#  include "asan_win_common_runtime_thunk.h"
+
+#  include <windows.h>
+
+#  include "sanitizer_common/sanitizer_win_defs.h"
+#  include "sanitizer_common/sanitizer_win_thunk_interception.h"
+
+// Define weak alias for all weak functions imported from asan dll.
+#  define INTERFACE_FUNCTION(Name)
+#  define INTERFACE_WEAK_FUNCTION(Name) REGISTER_WEAK_FUNCTION(Name)
+#  include "asan_interface.inc"
+
+////////////////////////////////////////////////////////////////////////////////
+// Define a copy of __asan_option_detect_stack_use_after_return that should be
+// used when linking an MD runtime with a set of object files on Windows.
+//
+// The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return',
+// so normally we would just dllimport it.  Unfortunately, the dllimport
+// attribute adds __imp_ prefix to the symbol name of a variable.
+// Since in general we don't know if a given TU is going to be used
+// with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows
+// just to work around this issue, let's clone the variable that is constant
+// after initialization anyways.
+
+extern "C" {
+__declspec(dllimport) int __asan_should_detect_stack_use_after_return();
+int __asan_option_detect_stack_use_after_return;
+
+__declspec(dllimport) void *__asan_get_shadow_memory_dynamic_address();
+void *__asan_shadow_memory_dynamic_address;
+
+static void __asan_initialize_cloned_variables() {
+  __asan_option_detect_stack_use_after_return =
+      __asan_should_detect_stack_use_after_return();
+  __asan_shadow_memory_dynamic_address =
+      __asan_get_shadow_memory_dynamic_address();
+}
+}
+
+static int asan_thunk_init() {
+  __asan_initialize_cloned_variables();
+
+#  ifdef SANITIZER_STATIC_RUNTIME_THUNK
+  __asan_initialize_static_thunk();
+#  endif
+
+  return 0;
+}
+
+static void WINAPI asan_thread_init(void *mod, unsigned long reason,
+                                    void *reserved) {
+  if (reason == DLL_PROCESS_ATTACH) {
+    asan_thunk_init();
+  }
+}
+
+// Our cloned variables must be initialized before C/C++ constructors.  If TLS
+// is used, our .CRT$XLAB initializer will run first. If not, our .CRT$XIB
+// initializer is needed as a backup.
+extern "C" __declspec(allocate(".CRT$XIB")) int (*__asan_thunk_init)() =
+    asan_thunk_init;
+WIN_FORCE_LINK(__asan_thunk_init)
+
+extern "C" __declspec(allocate(".CRT$XLAB")) void(WINAPI *__asan_tls_init)(
+    void *, unsigned long, void *) = asan_thread_init;
+WIN_FORCE_LINK(__asan_tls_init)
+
+////////////////////////////////////////////////////////////////////////////////
+// ASan SEH handling.
+// We need to set the ASan-specific SEH handler at the end of CRT initialization
+// of each module (see also asan_win.cpp).
+extern "C" {
+__declspec(dllimport) int __asan_set_seh_filter();
+static int SetSEHFilter() { return __asan_set_seh_filter(); }
+
+// Unfortunately, putting a pointer to __asan_set_seh_filter into
+// __asan_intercept_seh gets optimized out, so we have to use an extra function.
+extern "C" __declspec(allocate(".CRT$XCAB")) int (*__asan_seh_interceptor)() =
+    SetSEHFilter;
+WIN_FORCE_LINK(__asan_seh_interceptor)
+}
+
+WIN_FORCE_LINK(__asan_dso_reg_hook)
+
+#endif  // defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) ||
+        // defined(SANITIZER_STATIC_RUNTIME_THUNK)
diff --git a/libsanitizer/asan/asan_win_common_runtime_thunk.h b/libsanitizer/asan/asan_win_common_runtime_thunk.h
new file mode 100644
index 000000000000..159cc152474e
--- /dev/null
+++ b/libsanitizer/asan/asan_win_common_runtime_thunk.h
@@ -0,0 +1,38 @@ 
+//===-- asan_win_common_runtime_thunk.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 file is a part of AddressSanitizer, an address sanity checker.
+//
+// This file defines things that need to be present in the application modules
+// to interact with the ASan DLL runtime correctly and can't be implemented
+// using the default "import library" generated when linking the DLL.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(SANITIZER_STATIC_RUNTIME_THUNK) || \
+    defined(SANITIZER_DYNAMIC_RUNTIME_THUNK)
+#  include "sanitizer_common/sanitizer_win_defs.h"
+
+#  pragma section(".CRT$XIB", long, \
+                  read)  // C initializer (during C init before dyninit)
+#  pragma section(".CRT$XID", long, \
+                  read)  // First C initializer after CRT initializers
+#  pragma section(".CRT$XCAB", long, \
+                  read)  // First C++ initializer after startup initializers
+
+#  pragma section(".CRT$XTW", long, read)  // First ASAN globals terminator
+#  pragma section(".CRT$XTY", long, read)  // Last ASAN globals terminator
+
+#  pragma section(".CRT$XLAB", long, read)  // First TLS initializer
+
+#  ifdef SANITIZER_STATIC_RUNTIME_THUNK
+extern "C" void __asan_initialize_static_thunk();
+#  endif
+
+#endif  // defined(SANITIZER_STATIC_RUNTIME_THUNK) ||
+        // defined(SANITIZER_DYNAMIC_RUNTIME_THUNK)
\ No newline at end of file
diff --git a/libsanitizer/asan/asan_win_dll_thunk.cpp b/libsanitizer/asan/asan_win_dll_thunk.cpp
deleted file mode 100644
index 0fa636bec0d0..000000000000
--- a/libsanitizer/asan/asan_win_dll_thunk.cpp
+++ /dev/null
@@ -1,165 +0,0 @@ 
-//===-- asan_win_dll_thunk.cpp --------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file is a part of AddressSanitizer, an address sanity checker.
-//
-// This file defines a family of thunks that should be statically linked into
-// the DLLs that have ASan instrumentation in order to delegate the calls to the
-// shared runtime that lives in the main binary.
-// See https://github.com/google/sanitizers/issues/209 for the details.
-//===----------------------------------------------------------------------===//
-
-#ifdef SANITIZER_DLL_THUNK
-#include "asan_init_version.h"
-#include "interception/interception.h"
-#include "sanitizer_common/sanitizer_win_defs.h"
-#include "sanitizer_common/sanitizer_win_dll_thunk.h"
-#include "sanitizer_common/sanitizer_platform_interceptors.h"
-
-// ASan own interface functions.
-#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name)
-#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
-#include "asan_interface.inc"
-
-// Memory allocation functions.
-INTERCEPT_WRAP_V_W(free)
-INTERCEPT_WRAP_V_W(_free_base)
-INTERCEPT_WRAP_V_WW(_free_dbg)
-
-INTERCEPT_WRAP_W_W(malloc)
-INTERCEPT_WRAP_W_W(_malloc_base)
-INTERCEPT_WRAP_W_WWWW(_malloc_dbg)
-
-INTERCEPT_WRAP_W_WW(calloc)
-INTERCEPT_WRAP_W_WW(_calloc_base)
-INTERCEPT_WRAP_W_WWWWW(_calloc_dbg)
-INTERCEPT_WRAP_W_WWW(_calloc_impl)
-
-INTERCEPT_WRAP_W_WW(realloc)
-INTERCEPT_WRAP_W_WW(_realloc_base)
-INTERCEPT_WRAP_W_WWW(_realloc_dbg)
-INTERCEPT_WRAP_W_WWW(_recalloc)
-INTERCEPT_WRAP_W_WWW(_recalloc_base)
-
-INTERCEPT_WRAP_W_W(_msize)
-INTERCEPT_WRAP_W_W(_msize_base)
-INTERCEPT_WRAP_W_W(_expand)
-INTERCEPT_WRAP_W_W(_expand_dbg)
-
-// TODO(timurrrr): Might want to add support for _aligned_* allocation
-// functions to detect a bit more bugs.  Those functions seem to wrap malloc().
-
-// TODO(timurrrr): Do we need to add _Crt* stuff here? (see asan_malloc_win.cpp)
-
-#  if defined(_MSC_VER) && !defined(__clang__)
-// Disable warnings such as: 'void memchr(void)': incorrect number of arguments
-// for intrinsic function, expected '3' arguments.
-#    pragma warning(push)
-#    pragma warning(disable : 4392)
-#  endif
-
-INTERCEPT_LIBRARY_FUNCTION(atoi);
-INTERCEPT_LIBRARY_FUNCTION(atol);
-INTERCEPT_LIBRARY_FUNCTION(atoll);
-INTERCEPT_LIBRARY_FUNCTION(frexp);
-INTERCEPT_LIBRARY_FUNCTION(longjmp);
-#if SANITIZER_INTERCEPT_MEMCHR
-INTERCEPT_LIBRARY_FUNCTION(memchr);
-#endif
-INTERCEPT_LIBRARY_FUNCTION(memcmp);
-INTERCEPT_LIBRARY_FUNCTION(memcpy);
-INTERCEPT_LIBRARY_FUNCTION(memmove);
-INTERCEPT_LIBRARY_FUNCTION(memset);
-INTERCEPT_LIBRARY_FUNCTION(strcat);
-INTERCEPT_LIBRARY_FUNCTION(strchr);
-INTERCEPT_LIBRARY_FUNCTION(strcmp);
-INTERCEPT_LIBRARY_FUNCTION(strcpy);
-INTERCEPT_LIBRARY_FUNCTION(strcspn);
-INTERCEPT_LIBRARY_FUNCTION(strdup);
-INTERCEPT_LIBRARY_FUNCTION(strlen);
-INTERCEPT_LIBRARY_FUNCTION(strncat);
-INTERCEPT_LIBRARY_FUNCTION(strncmp);
-INTERCEPT_LIBRARY_FUNCTION(strncpy);
-INTERCEPT_LIBRARY_FUNCTION(strnlen);
-INTERCEPT_LIBRARY_FUNCTION(strpbrk);
-INTERCEPT_LIBRARY_FUNCTION(strrchr);
-INTERCEPT_LIBRARY_FUNCTION(strspn);
-INTERCEPT_LIBRARY_FUNCTION(strstr);
-INTERCEPT_LIBRARY_FUNCTION(strtok);
-INTERCEPT_LIBRARY_FUNCTION(strtol);
-INTERCEPT_LIBRARY_FUNCTION(strtoll);
-INTERCEPT_LIBRARY_FUNCTION(wcslen);
-INTERCEPT_LIBRARY_FUNCTION(wcsnlen);
-
-#  if defined(_MSC_VER) && !defined(__clang__)
-#    pragma warning(pop)
-#  endif
-
-#ifdef _WIN64
-INTERCEPT_LIBRARY_FUNCTION(__C_specific_handler);
-#else
-INTERCEPT_LIBRARY_FUNCTION(_except_handler3);
-// _except_handler4 checks -GS cookie which is different for each module, so we
-// can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4).
-INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
-  __asan_handle_no_return();
-  return REAL(_except_handler4)(a, b, c, d);
-}
-#endif
-
-// Windows specific functions not included in asan_interface.inc.
-INTERCEPT_WRAP_W_V(__asan_should_detect_stack_use_after_return)
-INTERCEPT_WRAP_W_V(__asan_get_shadow_memory_dynamic_address)
-INTERCEPT_WRAP_W_W(__asan_unhandled_exception_filter)
-
-using namespace __sanitizer;
-
-extern "C" {
-int __asan_option_detect_stack_use_after_return;
-uptr __asan_shadow_memory_dynamic_address;
-} // extern "C"
-
-static int asan_dll_thunk_init() {
-  typedef void (*fntype)();
-  static fntype fn = 0;
-  // asan_dll_thunk_init is expected to be called by only one thread.
-  if (fn) return 0;
-
-  // Ensure all interception was executed.
-  __dll_thunk_init();
-
-  fn = (fntype) dllThunkGetRealAddrOrDie("__asan_init");
-  fn();
-  __asan_option_detect_stack_use_after_return =
-      (__asan_should_detect_stack_use_after_return() != 0);
-  __asan_shadow_memory_dynamic_address =
-      (uptr)__asan_get_shadow_memory_dynamic_address();
-
-#ifndef _WIN64
-  INTERCEPT_FUNCTION(_except_handler4);
-#endif
-  // In DLLs, the callbacks are expected to return 0,
-  // otherwise CRT initialization fails.
-  return 0;
-}
-
-#pragma section(".CRT$XIB", long, read)
-__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = asan_dll_thunk_init;
-
-static void WINAPI asan_thread_init(void *mod, unsigned long reason,
-                                    void *reserved) {
-  if (reason == /*DLL_PROCESS_ATTACH=*/1) asan_dll_thunk_init();
-}
-
-#pragma section(".CRT$XLAB", long, read)
-__declspec(allocate(".CRT$XLAB")) void (WINAPI *__asan_tls_init)(void *,
-    unsigned long, void *) = asan_thread_init;
-
-WIN_FORCE_LINK(__asan_dso_reg_hook)
-
-#endif // SANITIZER_DLL_THUNK
diff --git a/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cpp b/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cpp
index f0b5ec9eef7f..421fe651b7d9 100644
--- a/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cpp
+++ b/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cpp
@@ -8,76 +8,17 @@ 
 //
 // This file is a part of AddressSanitizer, an address sanity checker.
 //
-// This file defines things that need to be present in the application modules
-// to interact with the ASan DLL runtime correctly and can't be implemented
-// using the default "import library" generated when linking the DLL RTL.
-//
-// This includes:
-//  - creating weak aliases to default implementation imported from asan dll.
-//  - forwarding the detect_stack_use_after_return runtime option
-//  - working around deficiencies of the MD runtime
-//  - installing a custom SEH handler
+// This file defines things that need to be present for application modules
+// that are dynamic linked with the C Runtime.
 //
 //===----------------------------------------------------------------------===//
 
 #ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK
-#define SANITIZER_IMPORT_INTERFACE 1
-#include "sanitizer_common/sanitizer_win_defs.h"
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-// Define weak alias for all weak functions imported from asan dll.
-#define INTERFACE_FUNCTION(Name)
-#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name)
-#include "asan_interface.inc"
-
-// First, declare CRT sections we'll be using in this file
-#pragma section(".CRT$XIB", long, read)
-#pragma section(".CRT$XID", long, read)
-#pragma section(".CRT$XCAB", long, read)
-#pragma section(".CRT$XTW", long, read)
-#pragma section(".CRT$XTY", long, read)
-#pragma section(".CRT$XLAB", long, read)
-
-////////////////////////////////////////////////////////////////////////////////
-// Define a copy of __asan_option_detect_stack_use_after_return that should be
-// used when linking an MD runtime with a set of object files on Windows.
-//
-// The ASan MD runtime dllexports '__asan_option_detect_stack_use_after_return',
-// so normally we would just dllimport it.  Unfortunately, the dllimport
-// attribute adds __imp_ prefix to the symbol name of a variable.
-// Since in general we don't know if a given TU is going to be used
-// with a MT or MD runtime and we don't want to use ugly __imp_ names on Windows
-// just to work around this issue, let's clone the variable that is constant
-// after initialization anyways.
-extern "C" {
-__declspec(dllimport) int __asan_should_detect_stack_use_after_return();
-int __asan_option_detect_stack_use_after_return;
-
-__declspec(dllimport) void* __asan_get_shadow_memory_dynamic_address();
-void* __asan_shadow_memory_dynamic_address;
-}
-
-static int InitializeClonedVariables() {
-  __asan_option_detect_stack_use_after_return =
-    __asan_should_detect_stack_use_after_return();
-  __asan_shadow_memory_dynamic_address =
-    __asan_get_shadow_memory_dynamic_address();
-  return 0;
-}
-
-static void NTAPI asan_thread_init(void *mod, unsigned long reason,
-    void *reserved) {
-  if (reason == DLL_PROCESS_ATTACH) InitializeClonedVariables();
-}
+#  define WIN32_LEAN_AND_MEAN
+#  include <windows.h>
 
-// Our cloned variables must be initialized before C/C++ constructors.  If TLS
-// is used, our .CRT$XLAB initializer will run first. If not, our .CRT$XIB
-// initializer is needed as a backup.
-__declspec(allocate(".CRT$XIB")) int (*__asan_initialize_cloned_variables)() =
-    InitializeClonedVariables;
-__declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(void *,
-    unsigned long, void *) = asan_thread_init;
+#  include "asan_win_common_runtime_thunk.h"
+#  include "sanitizer_common/sanitizer_win_defs.h"
 
 ////////////////////////////////////////////////////////////////////////////////
 // For some reason, the MD CRT doesn't call the C/C++ terminators during on DLL
@@ -88,43 +29,26 @@  __declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(void *,
 // using atexit() that calls a small subset of C terminators
 // where LLVM global_dtors is placed.  Fingers crossed, no other C terminators
 // are there.
-extern "C" int __cdecl atexit(void (__cdecl *f)(void));
+extern "C" int __cdecl atexit(void(__cdecl *f)(void));
 extern "C" void __cdecl _initterm(void *a, void *b);
 
 namespace {
-__declspec(allocate(".CRT$XTW")) void* before_global_dtors = 0;
-__declspec(allocate(".CRT$XTY")) void* after_global_dtors = 0;
+__declspec(allocate(".CRT$XTW")) void *before_global_dtors = 0;
+__declspec(allocate(".CRT$XTY")) void *after_global_dtors = 0;
 
 void UnregisterGlobals() {
   _initterm(&before_global_dtors, &after_global_dtors);
 }
 
-int ScheduleUnregisterGlobals() {
-  return atexit(UnregisterGlobals);
-}
+int ScheduleUnregisterGlobals() { return atexit(UnregisterGlobals); }
 }  // namespace
 
 // We need to call 'atexit(UnregisterGlobals);' as early as possible, but after
 // atexit() is initialized (.CRT$XIC).  As this is executed before C++
 // initializers (think ctors for globals), UnregisterGlobals gets executed after
 // dtors for C++ globals.
-__declspec(allocate(".CRT$XID"))
-int (*__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals;
-
-////////////////////////////////////////////////////////////////////////////////
-// ASan SEH handling.
-// We need to set the ASan-specific SEH handler at the end of CRT initialization
-// of each module (see also asan_win.cpp).
-extern "C" {
-__declspec(dllimport) int __asan_set_seh_filter();
-static int SetSEHFilter() { return __asan_set_seh_filter(); }
-
-// Unfortunately, putting a pointer to __asan_set_seh_filter into
-// __asan_intercept_seh gets optimized out, so we have to use an extra function.
-__declspec(allocate(".CRT$XCAB")) int (*__asan_seh_interceptor)() =
-    SetSEHFilter;
-}
-
-WIN_FORCE_LINK(__asan_dso_reg_hook)
+extern "C" __declspec(allocate(".CRT$XID")) int (
+    *__asan_schedule_unregister_globals)() = ScheduleUnregisterGlobals;
+WIN_FORCE_LINK(__asan_schedule_unregister_globals)
 
-#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK
+#endif  // SANITIZER_DYNAMIC_RUNTIME_THUNK
diff --git a/libsanitizer/asan/asan_win_static_runtime_thunk.cpp b/libsanitizer/asan/asan_win_static_runtime_thunk.cpp
new file mode 100644
index 000000000000..4a69b6657403
--- /dev/null
+++ b/libsanitizer/asan/asan_win_static_runtime_thunk.cpp
@@ -0,0 +1,113 @@ 
+//===-- asan_win_static_runtime_thunk.cpp ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// This file defines a family of thunks that should be statically linked into
+// modules that are statically linked with the C Runtime in order to delegate
+// the calls to the ASAN runtime DLL.
+// See https://github.com/google/sanitizers/issues/209 for the details.
+//===----------------------------------------------------------------------===//
+
+#ifdef SANITIZER_STATIC_RUNTIME_THUNK
+#  include "asan_init_version.h"
+#  include "asan_interface_internal.h"
+#  include "asan_win_common_runtime_thunk.h"
+#  include "sanitizer_common/sanitizer_platform_interceptors.h"
+#  include "sanitizer_common/sanitizer_win_defs.h"
+#  include "sanitizer_common/sanitizer_win_thunk_interception.h"
+
+#  if defined(_MSC_VER) && !defined(__clang__)
+// Disable warnings such as: 'void memchr(void)': incorrect number of arguments
+// for intrinsic function, expected '3' arguments.
+#    pragma warning(push)
+#    pragma warning(disable : 4392)
+#  endif
+
+#  define INTERCEPT_LIBRARY_FUNCTION_ASAN(X) \
+    INTERCEPT_LIBRARY_FUNCTION(X, "__asan_wrap_" #X)
+
+INTERCEPT_LIBRARY_FUNCTION_ASAN(atoi);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(atol);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(atoll);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(frexp);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(longjmp);
+#  if SANITIZER_INTERCEPT_MEMCHR
+INTERCEPT_LIBRARY_FUNCTION_ASAN(memchr);
+#  endif
+INTERCEPT_LIBRARY_FUNCTION_ASAN(memcmp);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(memcpy);
+#  ifndef _WIN64
+// memmove and memcpy share an implementation on amd64
+INTERCEPT_LIBRARY_FUNCTION_ASAN(memmove);
+#  endif
+INTERCEPT_LIBRARY_FUNCTION_ASAN(memset);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(strcat);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(strchr);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(strcmp);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(strcpy);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(strcspn);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(_strdup);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(strlen);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(strncat);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(strncmp);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(strncpy);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(strnlen);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(strpbrk);
+// INTERCEPT_LIBRARY_FUNCTION_ASAN(strrchr);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(strspn);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(strstr);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(strtok);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(wcslen);
+INTERCEPT_LIBRARY_FUNCTION_ASAN(wcsnlen);
+
+// Note: Don't intercept strtol(l). They are supposed to set errno for out-of-
+// range values, but since the ASan runtime is linked against the dynamic CRT,
+// its errno is different from the one in the current module.
+
+#  if defined(_MSC_VER) && !defined(__clang__)
+#    pragma warning(pop)
+#  endif
+
+#  ifdef _WIN64
+INTERCEPT_LIBRARY_FUNCTION_ASAN(__C_specific_handler);
+#  else
+extern "C" void abort();
+INTERCEPT_LIBRARY_FUNCTION_ASAN(_except_handler3);
+// _except_handler4 checks -GS cookie which is different for each module, so we
+// can't use INTERCEPT_LIBRARY_FUNCTION_ASAN(_except_handler4), need to apply
+// manually
+extern "C" int _except_handler4(void *, void *, void *, void *);
+static int (*real_except_handler4)(void *, void *, void *,
+                                   void *) = &_except_handler4;
+static int intercept_except_handler4(void *a, void *b, void *c, void *d) {
+  __asan_handle_no_return();
+  return real_except_handler4(a, b, c, d);
+}
+#  endif
+
+// Windows specific functions not included in asan_interface.inc.
+// INTERCEPT_WRAP_W_V(__asan_should_detect_stack_use_after_return)
+// INTERCEPT_WRAP_W_V(__asan_get_shadow_memory_dynamic_address)
+// INTERCEPT_WRAP_W_W(__asan_unhandled_exception_filter)
+
+extern "C" void __asan_initialize_static_thunk() {
+#  ifndef _WIN64
+  if (real_except_handler4 == &_except_handler4) {
+    // Single threaded, no need for synchronization.
+    if (!__sanitizer_override_function_by_addr(
+            reinterpret_cast<__sanitizer::uptr>(&intercept_except_handler4),
+            reinterpret_cast<__sanitizer::uptr>(&_except_handler4),
+            reinterpret_cast<__sanitizer::uptr*>(&real_except_handler4))) {
+      abort();
+    }
+  }
+#  endif
+}
+
+#endif  // SANITIZER_DLL_THUNK
diff --git a/libsanitizer/asan/asan_win_weak_interception.cpp b/libsanitizer/asan/asan_win_weak_interception.cpp
deleted file mode 100644
index 62534e12e2a6..000000000000
--- a/libsanitizer/asan/asan_win_weak_interception.cpp
+++ /dev/null
@@ -1,22 +0,0 @@ 
-//===-- asan_win_weak_interception.cpp ------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// This module should be included in Address Sanitizer when it is implemented as
-// a shared library on Windows (dll), in order to delegate the calls of weak
-// functions to the implementation in the main executable when a strong
-// definition is provided.
-//===----------------------------------------------------------------------===//
-#ifdef SANITIZER_DYNAMIC
-#include "sanitizer_common/sanitizer_win_weak_interception.h"
-#include "asan_interface_internal.h"
-// Check if strong definitions for weak functions are present in the main
-// executable. If that is the case, override dll functions to point to strong
-// implementations.
-#define INTERFACE_FUNCTION(Name)
-#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
-#include "asan_interface.inc"
-#endif // SANITIZER_DYNAMIC
diff --git a/libsanitizer/builtins/assembly.h b/libsanitizer/builtins/assembly.h
index 169d49683f50..8c42fc773483 100644
--- a/libsanitizer/builtins/assembly.h
+++ b/libsanitizer/builtins/assembly.h
@@ -260,9 +260,10 @@ 
   .globl name SEPARATOR                                                        \
   SYMBOL_IS_FUNC(name) SEPARATOR                                               \
   DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) SEPARATOR                          \
-  CFI_START SEPARATOR                                                          \
   DECLARE_FUNC_ENCODING                                                        \
-  name: SEPARATOR BTI_C
+  name:                                                                        \
+  SEPARATOR CFI_START                                                          \
+  SEPARATOR BTI_C
 
 #define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target)                         \
   .globl SYMBOL_NAME(name) SEPARATOR                                           \
diff --git a/libsanitizer/hwasan/hwasan.cpp b/libsanitizer/hwasan/hwasan.cpp
index 2f6cb10caf1b..24384d8b4d2c 100644
--- a/libsanitizer/hwasan/hwasan.cpp
+++ b/libsanitizer/hwasan/hwasan.cpp
@@ -357,8 +357,6 @@  __attribute__((constructor(0))) void __hwasan_init() {
   hwasan_init_is_running = 1;
   SanitizerToolName = "HWAddressSanitizer";
 
-  InitTlsSize();
-
   CacheBinaryName();
   InitializeFlags();
 
@@ -367,6 +365,8 @@  __attribute__((constructor(0))) void __hwasan_init() {
 
   __sanitizer_set_report_path(common_flags()->log_path);
 
+  InitializePlatformEarly();
+
   AndroidTestTlsSlot();
 
   DisableCoreDumperIfNecessary();
@@ -678,6 +678,8 @@  uptr __hwasan_tag_pointer(uptr p, u8 tag) {
   return AddTagToPointer(p, tag);
 }
 
+u8 __hwasan_get_tag_from_pointer(uptr p) { return GetTagFromPointer(p); }
+
 void __hwasan_handle_longjmp(const void *sp_dst) {
   uptr dst = (uptr)sp_dst;
   // HWASan does not support tagged SP.
@@ -690,7 +692,7 @@  void __hwasan_handle_longjmp(const void *sp_dst) {
         "WARNING: HWASan is ignoring requested __hwasan_handle_longjmp: "
         "stack top: %p; target %p; distance: %p (%zd)\n"
         "False positive error reports may follow\n",
-        (void *)sp, (void *)dst, dst - sp);
+        (void *)sp, (void *)dst, dst - sp, dst - sp);
     return;
   }
   TagMemory(sp, dst - sp, 0);
diff --git a/libsanitizer/hwasan/hwasan.h b/libsanitizer/hwasan/hwasan.h
index 37ef48222851..1ae463f845c8 100644
--- a/libsanitizer/hwasan/hwasan.h
+++ b/libsanitizer/hwasan/hwasan.h
@@ -104,9 +104,9 @@  static inline void *UntagPtr(const void *tagged_ptr) {
 }
 
 static inline uptr AddTagToPointer(uptr p, tag_t tag) {
-  return InTaggableRegion(p)
-             ? ((p & ~kAddressTagMask) | ((uptr)tag << kAddressTagShift))
-             : p;
+  return InTaggableRegion(p) ? ((p & ~kAddressTagMask) |
+                                ((uptr)(tag & kTagMask) << kAddressTagShift))
+                             : p;
 }
 
 namespace __hwasan {
@@ -139,14 +139,14 @@  void hwasan_free(void *ptr, StackTrace *stack);
 void InstallAtExitHandler();
 
 #define GET_MALLOC_STACK_TRACE                                            \
-  BufferedStackTrace stack;                                               \
+  UNINITIALIZED BufferedStackTrace stack;                                 \
   if (hwasan_inited)                                                      \
     stack.Unwind(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(),         \
                  nullptr, common_flags()->fast_unwind_on_malloc,          \
                  common_flags()->malloc_context_size)
 
 #define GET_FATAL_STACK_TRACE_PC_BP(pc, bp)              \
-  BufferedStackTrace stack;                              \
+  UNINITIALIZED BufferedStackTrace stack;                \
   if (hwasan_inited)                                     \
     stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal)
 
diff --git a/libsanitizer/hwasan/hwasan_allocation_functions.cpp b/libsanitizer/hwasan/hwasan_allocation_functions.cpp
index 75d91ed09ce1..25ca0a3b0b68 100644
--- a/libsanitizer/hwasan/hwasan_allocation_functions.cpp
+++ b/libsanitizer/hwasan/hwasan_allocation_functions.cpp
@@ -17,7 +17,6 @@ 
 #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"
 
 using namespace __hwasan;
 
@@ -62,10 +61,7 @@  void *__sanitizer_aligned_alloc(uptr alignment, uptr size) {
 SANITIZER_INTERFACE_ATTRIBUTE
 void *__sanitizer___libc_memalign(uptr alignment, uptr size) {
   GET_MALLOC_STACK_TRACE;
-  void *ptr = hwasan_memalign(alignment, size, &stack);
-  if (ptr)
-    DTLS_on_libc_memalign(ptr, size);
-  return ptr;
+  return hwasan_memalign(alignment, size, &stack);
 }
 
 SANITIZER_INTERFACE_ATTRIBUTE
@@ -184,7 +180,7 @@  INTERCEPTOR_ALIAS(void *, malloc, SIZE_T size);
 INTERCEPTOR_ALIAS(void *, memalign, SIZE_T alignment, SIZE_T size);
 INTERCEPTOR_ALIAS(void *, pvalloc, SIZE_T size);
 INTERCEPTOR_ALIAS(void, cfree, void *ptr);
-INTERCEPTOR_ALIAS(__sanitizer_struct_mallinfo, mallinfo);
+INTERCEPTOR_ALIAS(__sanitizer_struct_mallinfo, mallinfo,);
 INTERCEPTOR_ALIAS(int, mallopt, int cmd, int value);
 INTERCEPTOR_ALIAS(void, malloc_stats, void);
 #  endif
diff --git a/libsanitizer/hwasan/hwasan_allocator.cpp b/libsanitizer/hwasan/hwasan_allocator.cpp
index d21ba024a20e..75dbb336e344 100644
--- a/libsanitizer/hwasan/hwasan_allocator.cpp
+++ b/libsanitizer/hwasan/hwasan_allocator.cpp
@@ -44,7 +44,7 @@  enum {
 
 
 // Initialized in HwasanAllocatorInit, an never changed.
-static ALIGNED(16) u8 tail_magic[kShadowAlignment - 1];
+alignas(16) static u8 tail_magic[kShadowAlignment - 1];
 static uptr max_malloc_size;
 
 bool HwasanChunkView::IsAllocated() const {
@@ -289,6 +289,9 @@  static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
   CHECK(tagged_ptr);
   void *untagged_ptr = UntagPtr(tagged_ptr);
 
+  if (RunFreeHooks(tagged_ptr))
+    return;
+
   if (CheckInvalidFree(stack, untagged_ptr, tagged_ptr))
     return;
 
@@ -302,8 +305,6 @@  static void HwasanDeallocate(StackTrace *stack, void *tagged_ptr) {
     return;
   }
 
-  RunFreeHooks(tagged_ptr);
-
   uptr orig_size = meta->GetRequestedSize();
   u32 free_context_id = StackDepotPut(*stack);
   u32 alloc_context_id = meta->GetAllocStackId();
diff --git a/libsanitizer/hwasan/hwasan_checks.h b/libsanitizer/hwasan/hwasan_checks.h
index 0911af30dcb8..735d21a5db77 100644
--- a/libsanitizer/hwasan/hwasan_checks.h
+++ b/libsanitizer/hwasan/hwasan_checks.h
@@ -140,7 +140,6 @@  __attribute__((always_inline, nodebug)) static inline uptr ShortTagSize(
 
 __attribute__((always_inline, nodebug)) static inline bool
 PossiblyShortTagMatches(tag_t mem_tag, uptr ptr, uptr sz) {
-  DCHECK(IsAligned(ptr, kShadowAlignment));
   tag_t ptr_tag = GetTagFromPointer(ptr);
   if (ptr_tag == mem_tag)
     return true;
diff --git a/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp b/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
index 7642ba6c0bf0..48bc3b631ac0 100644
--- a/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
+++ b/libsanitizer/hwasan/hwasan_dynamic_shadow.cpp
@@ -36,15 +36,20 @@  decltype(__hwasan_shadow)* __hwasan_premap_shadow();
 
 namespace __hwasan {
 
+// We cannot call anything in libc here (see comment above), so we need to
+// assume the biggest allowed page size.
+// Android max page size is defined as 16k here:
+// https://android.googlesource.com/platform/bionic/+/main/libc/platform/bionic/page.h#41
+static constexpr uptr kMaxGranularity = 16384;
+
 // Conservative upper limit.
 static uptr PremapShadowSize() {
-  return RoundUpTo(GetMaxVirtualAddress() >> kShadowScale,
-                   GetMmapGranularity());
+  return RoundUpTo(GetMaxVirtualAddress() >> kShadowScale, kMaxGranularity);
 }
 
 static uptr PremapShadow() {
   return MapDynamicShadow(PremapShadowSize(), kShadowScale,
-                          kShadowBaseAlignment, kHighMemEnd);
+                          kShadowBaseAlignment, kHighMemEnd, kMaxGranularity);
 }
 
 static bool IsPremapShadowAvailable() {
@@ -56,7 +61,7 @@  static bool IsPremapShadowAvailable() {
 }
 
 static uptr FindPremappedShadowStart(uptr shadow_size_bytes) {
-  const uptr granularity = GetMmapGranularity();
+  const uptr granularity = kMaxGranularity;
   const uptr shadow_start = reinterpret_cast<uptr>(&__hwasan_shadow);
   const uptr premap_shadow_size = PremapShadowSize();
   const uptr shadow_size = RoundUpTo(shadow_size_bytes, granularity);
@@ -109,7 +114,7 @@  uptr FindDynamicShadowStart(uptr shadow_size_bytes) {
   if (IsPremapShadowAvailable())
     return FindPremappedShadowStart(shadow_size_bytes);
   return MapDynamicShadow(shadow_size_bytes, kShadowScale, kShadowBaseAlignment,
-                          kHighMemEnd);
+                          kHighMemEnd, kMaxGranularity);
 }
 
 }  // namespace __hwasan
@@ -135,7 +140,7 @@  uptr FindDynamicShadowStart(uptr shadow_size_bytes) {
                                     RingBufferSize());
 #  endif
   return MapDynamicShadow(shadow_size_bytes, kShadowScale, kShadowBaseAlignment,
-                          kHighMemEnd);
+                          kHighMemEnd, GetMmapGranularity());
 }
 
 }  // namespace __hwasan
diff --git a/libsanitizer/hwasan/hwasan_flags.inc b/libsanitizer/hwasan/hwasan_flags.inc
index 978fa46b705c..058a0457b9e7 100644
--- a/libsanitizer/hwasan/hwasan_flags.inc
+++ b/libsanitizer/hwasan/hwasan_flags.inc
@@ -84,3 +84,10 @@  HWASAN_FLAG(bool, malloc_bisect_dump, false,
 // are untagged before the call.
 HWASAN_FLAG(bool, fail_without_syscall_abi, true,
             "Exit if fail to request relaxed syscall ABI.")
+
+HWASAN_FLAG(
+    uptr, fixed_shadow_base, -1,
+    "If not -1, HWASan will attempt to allocate the shadow at this address, "
+    "instead of choosing one dynamically."
+    "Tip: this can be combined with the compiler option, "
+    "-hwasan-mapping-offset, to optimize the instrumentation.")
diff --git a/libsanitizer/hwasan/hwasan_interceptors.cpp b/libsanitizer/hwasan/hwasan_interceptors.cpp
index 96df4dd0c24d..c10b5c158548 100644
--- a/libsanitizer/hwasan/hwasan_interceptors.cpp
+++ b/libsanitizer/hwasan/hwasan_interceptors.cpp
@@ -334,10 +334,10 @@  INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,
 }
 #    endif
 
-DEFINE_REAL_PTHREAD_FUNCTIONS
+DEFINE_INTERNAL_PTHREAD_FUNCTIONS
 
-DEFINE_REAL(int, vfork)
-DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork)
+DEFINE_REAL(int, vfork,)
+DECLARE_EXTERN_INTERCEPTOR_AND_WRAPPER(int, vfork,)
 
 // Get and/or change the set of blocked signals.
 extern "C" int sigprocmask(int __how, const __hw_sigset_t *__restrict __set,
@@ -520,6 +520,7 @@  void InitializeInterceptors() {
   CHECK_EQ(inited, 0);
 
 #  if HWASAN_WITH_INTERCEPTORS
+  __interception::DoesNotSupportStaticLinking();
   InitializeCommonInterceptors();
 
   (void)(read_iovec);
diff --git a/libsanitizer/hwasan/hwasan_interface_internal.h b/libsanitizer/hwasan/hwasan_interface_internal.h
index e7804cc49033..8f2f77dad917 100644
--- a/libsanitizer/hwasan/hwasan_interface_internal.h
+++ b/libsanitizer/hwasan/hwasan_interface_internal.h
@@ -160,6 +160,9 @@  void __hwasan_tag_memory(uptr p, u8 tag, uptr sz);
 SANITIZER_INTERFACE_ATTRIBUTE
 uptr __hwasan_tag_pointer(uptr p, u8 tag);
 
+SANITIZER_INTERFACE_ATTRIBUTE
+u8 __hwasan_get_tag_from_pointer(uptr p);
+
 SANITIZER_INTERFACE_ATTRIBUTE
 void __hwasan_tag_mismatch(uptr addr, u8 ts);
 
diff --git a/libsanitizer/hwasan/hwasan_linux.cpp b/libsanitizer/hwasan/hwasan_linux.cpp
index 6f5e9432974e..68651d3d39d0 100644
--- a/libsanitizer/hwasan/hwasan_linux.cpp
+++ b/libsanitizer/hwasan/hwasan_linux.cpp
@@ -106,8 +106,22 @@  static uptr GetHighMemEnd() {
 }
 
 static void InitializeShadowBaseAddress(uptr shadow_size_bytes) {
-  __hwasan_shadow_memory_dynamic_address =
-      FindDynamicShadowStart(shadow_size_bytes);
+  // FIXME: Android should init flags before shadow.
+  if (!SANITIZER_ANDROID && flags()->fixed_shadow_base != (uptr)-1) {
+    __hwasan_shadow_memory_dynamic_address = flags()->fixed_shadow_base;
+    uptr beg = __hwasan_shadow_memory_dynamic_address;
+    uptr end = beg + shadow_size_bytes;
+    if (!MemoryRangeIsAvailable(beg, end)) {
+      Report(
+          "FATAL: HWAddressSanitizer: Shadow range %p-%p is not available.\n",
+          (void *)beg, (void *)end);
+      DumpProcessMap();
+      CHECK(MemoryRangeIsAvailable(beg, end));
+    }
+  } else {
+    __hwasan_shadow_memory_dynamic_address =
+        FindDynamicShadowStart(shadow_size_bytes);
+  }
 }
 
 static void MaybeDieIfNoTaggingAbi(const char *message) {
@@ -246,9 +260,6 @@  bool InitShadow() {
   CHECK_GT(kLowShadowEnd, kLowShadowStart);
   CHECK_GT(kLowShadowStart, kLowMemEnd);
 
-  if (Verbosity())
-    PrintAddressSpaceLayout();
-
   // Reserve shadow memory.
   ReserveShadowMemoryRange(kLowShadowStart, kLowShadowEnd, "low shadow");
   ReserveShadowMemoryRange(kHighShadowStart, kHighShadowEnd, "high shadow");
@@ -262,6 +273,9 @@  bool InitShadow() {
   if (kHighShadowEnd + 1 < kHighMemStart)
     ProtectGap(kHighShadowEnd + 1, kHighMemStart - kHighShadowEnd - 1);
 
+  if (Verbosity())
+    PrintAddressSpaceLayout();
+
   return true;
 }
 
@@ -294,25 +308,6 @@  void InstallAtExitHandler() { atexit(HwasanAtExit); }
 
 // ---------------------- TSD ---------------- {{{1
 
-extern "C" void __hwasan_thread_enter() {
-  hwasanThreadList().CreateCurrentThread()->EnsureRandomStateInited();
-}
-
-extern "C" void __hwasan_thread_exit() {
-  Thread *t = GetCurrentThread();
-  // Make sure that signal handler can not see a stale current thread pointer.
-  atomic_signal_fence(memory_order_seq_cst);
-  if (t) {
-    // Block async signals on the thread as the handler can be instrumented.
-    // After this point instrumented code can't access essential data from TLS
-    // and will crash.
-    // Bionic already calls __hwasan_thread_exit with blocked signals.
-    if (SANITIZER_GLIBC)
-      BlockSignals();
-    hwasanThreadList().ReleaseThread(t);
-  }
-}
-
 #  if HWASAN_WITH_INTERCEPTORS
 static pthread_key_t tsd_key;
 static bool tsd_key_inited = false;
@@ -504,12 +499,8 @@  void HwasanOnDeadlySignal(int signo, void *info, void *context) {
 }
 
 void Thread::InitStackAndTls(const InitState *) {
-  uptr tls_size;
-  uptr stack_size;
-  GetThreadStackAndTls(IsMainThread(), &stack_bottom_, &stack_size, &tls_begin_,
-                       &tls_size);
-  stack_top_ = stack_bottom_ + stack_size;
-  tls_end_ = tls_begin_ + tls_size;
+  GetThreadStackAndTls(IsMainThread(), &stack_bottom_, &stack_top_, &tls_begin_,
+                       &tls_end_);
 }
 
 uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) {
@@ -536,16 +527,34 @@  uptr TagMemoryAligned(uptr p, uptr size, tag_t tag) {
   return AddTagToPointer(p, tag);
 }
 
+static void BeforeFork() {
+  VReport(2, "BeforeFork tid: %llu\n", GetTid());
+  if (CAN_SANITIZE_LEAKS) {
+    __lsan::LockGlobal();
+  }
+  // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and lock the
+  // stuff we need.
+  __lsan::LockThreads();
+  __lsan::LockAllocator();
+  StackDepotLockBeforeFork();
+}
+
+static void AfterFork(bool fork_child) {
+  StackDepotUnlockAfterFork(fork_child);
+  // `_lsan` functions defined regardless of `CAN_SANITIZE_LEAKS` and unlock
+  // the stuff we need.
+  __lsan::UnlockAllocator();
+  __lsan::UnlockThreads();
+  if (CAN_SANITIZE_LEAKS) {
+    __lsan::UnlockGlobal();
+  }
+  VReport(2, "AfterFork tid: %llu\n", GetTid());
+}
+
 void HwasanInstallAtForkHandler() {
-  auto before = []() {
-    HwasanAllocatorLock();
-    StackDepotLockAll();
-  };
-  auto after = []() {
-    StackDepotUnlockAll();
-    HwasanAllocatorUnlock();
-  };
-  pthread_atfork(before, after, after);
+  pthread_atfork(
+      &BeforeFork, []() { AfterFork(/* fork_child= */ false); },
+      []() { AfterFork(/* fork_child= */ true); });
 }
 
 void InstallAtExitCheckLeaks() {
@@ -561,4 +570,25 @@  void InstallAtExitCheckLeaks() {
 
 }  // namespace __hwasan
 
+using namespace __hwasan;
+
+extern "C" void __hwasan_thread_enter() {
+  hwasanThreadList().CreateCurrentThread()->EnsureRandomStateInited();
+}
+
+extern "C" void __hwasan_thread_exit() {
+  Thread *t = GetCurrentThread();
+  // Make sure that signal handler can not see a stale current thread pointer.
+  atomic_signal_fence(memory_order_seq_cst);
+  if (t) {
+    // Block async signals on the thread as the handler can be instrumented.
+    // After this point instrumented code can't access essential data from TLS
+    // and will crash.
+    // Bionic already calls __hwasan_thread_exit with blocked signals.
+    if (SANITIZER_GLIBC)
+      BlockSignals();
+    hwasanThreadList().ReleaseThread(t);
+  }
+}
+
 #endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
diff --git a/libsanitizer/hwasan/hwasan_preinit.cpp b/libsanitizer/hwasan/hwasan_preinit.cpp
index 8c9c95f413be..8da47b5a2b78 100644
--- a/libsanitizer/hwasan/hwasan_preinit.cpp
+++ b/libsanitizer/hwasan/hwasan_preinit.cpp
@@ -14,10 +14,8 @@ 
 #include "sanitizer_common/sanitizer_internal_defs.h"
 
 #if SANITIZER_CAN_USE_PREINIT_ARRAY
-// The symbol is called __local_hwasan_preinit, because it's not intended to
-// be exported.
-// This code linked into the main executable when -fsanitize=hwaddress is in
-// the link flags. It can only use exported interface functions.
-__attribute__((section(".preinit_array"), used)) static void (
-    *__local_hwasan_preinit)(void) = __hwasan_init;
+// This section is linked into the main executable when -fsanitize=hwaddress is
+// specified to perform initialization at a very early stage.
+__attribute__((section(".preinit_array"), used)) static auto preinit =
+    __hwasan_init;
 #endif
diff --git a/libsanitizer/hwasan/hwasan_report.cpp b/libsanitizer/hwasan/hwasan_report.cpp
index 5e8aa315801b..bc66e6e805c9 100644
--- a/libsanitizer/hwasan/hwasan_report.cpp
+++ b/libsanitizer/hwasan/hwasan_report.cpp
@@ -27,6 +27,7 @@ 
 #include "sanitizer_common/sanitizer_flags.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_mutex.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_report_decorator.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 #include "sanitizer_common/sanitizer_stacktrace_printer.h"
@@ -40,7 +41,7 @@  class ScopedReport {
  public:
   explicit ScopedReport(bool fatal) : fatal(fatal) {
     Lock lock(&error_message_lock_);
-    error_message_ptr_ = fatal ? &error_message_ : nullptr;
+    error_message_ptr_ = &error_message_;
     ++hwasan_report_count;
   }
 
@@ -205,6 +206,7 @@  static void PrintStackAllocations(const StackAllocationsRingBuffer *sa,
                                   tag_t addr_tag, uptr untagged_addr) {
   uptr frames = Min((uptr)flags()->stack_history_size, sa->size());
   bool found_local = false;
+  InternalScopedString location;
   for (uptr i = 0; i < frames; i++) {
     const uptr *record_addr = &(*sa)[i];
     uptr record = *record_addr;
@@ -212,35 +214,104 @@  static void PrintStackAllocations(const StackAllocationsRingBuffer *sa,
       break;
     tag_t base_tag =
         reinterpret_cast<uptr>(record_addr) >> kRecordAddrBaseTagShift;
-    uptr fp = (record >> kRecordFPShift) << kRecordFPLShift;
+    const uptr fp = (record >> kRecordFPShift) << kRecordFPLShift;
+    CHECK_LT(fp, kRecordFPModulus);
     uptr pc_mask = (1ULL << kRecordFPShift) - 1;
     uptr pc = record & pc_mask;
     FrameInfo frame;
-    if (Symbolizer::GetOrInit()->SymbolizeFrame(pc, &frame)) {
-      for (LocalInfo &local : frame.locals) {
-        if (!local.has_frame_offset || !local.has_size || !local.has_tag_offset)
-          continue;
-        tag_t obj_tag = base_tag ^ local.tag_offset;
-        if (obj_tag != addr_tag)
-          continue;
-        // Calculate the offset from the object address to the faulting
-        // address. Because we only store bits 4-19 of FP (bits 0-3 are
-        // guaranteed to be zero), the calculation is performed mod 2^20 and may
-        // harmlessly underflow if the address mod 2^20 is below the object
-        // address.
-        uptr obj_offset =
-            (untagged_addr - fp - local.frame_offset) & (kRecordFPModulus - 1);
-        if (obj_offset >= local.size)
-          continue;
-        if (!found_local) {
-          Printf("Potentially referenced stack objects:\n");
-          found_local = true;
+    if (!Symbolizer::GetOrInit()->SymbolizeFrame(pc, &frame))
+      continue;
+    for (LocalInfo &local : frame.locals) {
+      if (!local.has_frame_offset || !local.has_size || !local.has_tag_offset)
+        continue;
+      if (!(local.name && internal_strlen(local.name)) &&
+          !(local.function_name && internal_strlen(local.function_name)) &&
+          !(local.decl_file && internal_strlen(local.decl_file)))
+        continue;
+      tag_t obj_tag = base_tag ^ local.tag_offset;
+      if (obj_tag != addr_tag)
+        continue;
+
+      // We only store bits 4-19 of FP (bits 0-3 are guaranteed to be zero).
+      // So we know only `FP % kRecordFPModulus`, and we can only calculate
+      // `local_beg % kRecordFPModulus`.
+      // Out of all possible `local_beg` we will only consider 2 candidates
+      // nearest to the `untagged_addr`.
+      uptr local_beg_mod = (fp + local.frame_offset) % kRecordFPModulus;
+      // Pick `local_beg` in the same 1 MiB block as `untagged_addr`.
+      uptr local_beg =
+          RoundDownTo(untagged_addr, kRecordFPModulus) + local_beg_mod;
+      // Pick the largest `local_beg <= untagged_addr`. It's either the current
+      // one or the one before.
+      if (local_beg > untagged_addr)
+        local_beg -= kRecordFPModulus;
+
+      uptr offset = -1ull;
+      const char *whence;
+      const char *cause = nullptr;
+      uptr best_beg;
+
+      // Try two 1 MiB blocks options and pick nearest one.
+      for (uptr i = 0; i < 2; ++i, local_beg += kRecordFPModulus) {
+        uptr local_end = local_beg + local.size;
+        if (local_beg > local_end)
+          continue;  // This is a wraparound.
+        if (local_beg <= untagged_addr && untagged_addr < local_end) {
+          offset = untagged_addr - local_beg;
+          whence = "inside";
+          cause = "use-after-scope";
+          best_beg = local_beg;
+          break;  // This is as close at it can be.
+        }
+
+        if (untagged_addr >= local_end) {
+          uptr new_offset = untagged_addr - local_end;
+          if (new_offset < offset) {
+            offset = new_offset;
+            whence = "after";
+            cause = "stack-buffer-overflow";
+            best_beg = local_beg;
+          }
+        } else {
+          uptr new_offset = local_beg - untagged_addr;
+          if (new_offset < offset) {
+            offset = new_offset;
+            whence = "before";
+            cause = "stack-buffer-overflow";
+            best_beg = local_beg;
+          }
         }
-        Printf("  %s in %s %s:%d\n", local.name, local.function_name,
-               local.decl_file, local.decl_line);
       }
-      frame.Clear();
+
+      // To fail the `untagged_addr` must be near nullptr, which is impossible
+      // with Linux user space memory layout.
+      if (!cause)
+        continue;
+
+      if (!found_local) {
+        Printf("\nPotentially referenced stack objects:\n");
+        found_local = true;
+      }
+
+      Decorator d;
+      Printf("%s", d.Error());
+      Printf("Cause: %s\n", cause);
+      Printf("%s", d.Default());
+      Printf("%s", d.Location());
+      StackTracePrinter::GetOrInit()->RenderSourceLocation(
+          &location, local.decl_file, local.decl_line, /* column= */ 0,
+          common_flags()->symbolize_vs_style,
+          common_flags()->strip_path_prefix);
+      Printf(
+          "%p is located %zd bytes %s a %zd-byte local variable %s "
+          "[%p,%p) "
+          "in %s %s\n",
+          untagged_addr, offset, whence, local.size, local.name, best_beg,
+          best_beg + local.size, local.function_name, location.data());
+      location.clear();
+      Printf("%s\n", d.Default());
     }
+    frame.Clear();
   }
 
   if (found_local)
@@ -257,14 +328,16 @@  static void PrintStackAllocations(const StackAllocationsRingBuffer *sa,
       break;
     uptr pc_mask = (1ULL << 48) - 1;
     uptr pc = record & pc_mask;
-    frame_desc.AppendF("  record_addr:0x%zx record:0x%zx",
-                       reinterpret_cast<uptr>(record_addr), record);
-    if (SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc)) {
+    frame_desc.AppendF("  record_addr:%p record:0x%zx",
+                       reinterpret_cast<const void *>(record_addr), record);
+    SymbolizedStackHolder symbolized_stack(
+        Symbolizer::GetOrInit()->SymbolizePC(pc));
+    const SymbolizedStack *frame = symbolized_stack.get();
+    if (frame) {
       StackTracePrinter::GetOrInit()->RenderFrame(
           &frame_desc, " %F %L", 0, frame->info.address, &frame->info,
           common_flags()->symbolize_vs_style,
           common_flags()->strip_path_prefix);
-      frame->ClearAll();
     }
     Printf("%s\n", frame_desc.data());
     frame_desc.clear();
@@ -353,7 +426,7 @@  static void PrintTagInfoAroundAddr(uptr addr, uptr num_rows,
       print_tag(s, row + i);
       s.Append(row + i == addr ? "]" : " ");
     }
-    s.AppendF("\n");
+    s.Append("\n");
   }
 }
 
@@ -363,7 +436,7 @@  static void PrintTagsAroundAddr(uptr addr, GetTag get_tag,
   InternalScopedString s;
   addr = MemToShadow(addr);
   s.AppendF(
-      "Memory tags around the buggy address (one tag corresponds to %zd "
+      "\nMemory tags around the buggy address (one tag corresponds to %zd "
       "bytes):\n",
       kShadowAlignment);
   PrintTagInfoAroundAddr(addr, kShadowLines, s,
@@ -383,10 +456,10 @@  static void PrintTagsAroundAddr(uptr addr, GetTag get_tag,
                              tag_t short_tag = get_short_tag(tag_addr);
                              s.AppendF("%02x", short_tag);
                            } else {
-                             s.AppendF("..");
+                             s.Append("..");
                            }
                          });
-  s.AppendF(
+  s.Append(
       "See "
       "https://clang.llvm.org/docs/"
       "HardwareAssistedAddressSanitizerDesign.html#short-granules for a "
@@ -745,8 +818,6 @@  void BaseReport::PrintAddressDescription() const {
   // Check stack first. If the address is on the stack of a live thread, we
   // know it cannot be a heap / global overflow.
   for (const auto &sa : allocations.stack) {
-    // TODO(fmayer): figure out how to distinguish use-after-return and
-    // stack-buffer-overflow.
     Printf("%s", d.Error());
     Printf("\nCause: stack tag-mismatch\n");
     Printf("%s", d.Location());
@@ -803,8 +874,10 @@  void BaseReport::PrintAddressDescription() const {
   }
 
   // Print the remaining threads, as an extra information, 1 line per thread.
-  if (flags()->print_live_threads_info)
+  if (flags()->print_live_threads_info) {
+    Printf("\n");
     hwasanThreadList().VisitAllLiveThreads([&](Thread *t) { t->Announce(); });
+  }
 
   if (!num_descriptions_printed)
     // We exhausted our possibilities. Bail out.
@@ -912,16 +985,16 @@  TailOverwrittenReport::~TailOverwrittenReport() {
 
   InternalScopedString s;
   u8 *tail = tail_copy;
-  s.AppendF("Tail contains: ");
-  for (uptr i = 0; i < kShadowAlignment - tail_size; i++) s.AppendF(".. ");
+  s.Append("Tail contains: ");
+  for (uptr i = 0; i < kShadowAlignment - tail_size; i++) s.Append(".. ");
   for (uptr i = 0; i < tail_size; i++) s.AppendF("%02x ", tail[i]);
-  s.AppendF("\n");
-  s.AppendF("Expected:      ");
-  for (uptr i = 0; i < kShadowAlignment - tail_size; i++) s.AppendF(".. ");
+  s.Append("\n");
+  s.Append("Expected:      ");
+  for (uptr i = 0; i < kShadowAlignment - tail_size; i++) s.Append(".. ");
   for (uptr i = 0; i < tail_size; i++) s.AppendF("%02x ", actual_expected[i]);
-  s.AppendF("\n");
-  s.AppendF("               ");
-  for (uptr i = 0; i < kShadowAlignment - tail_size; i++) s.AppendF("   ");
+  s.Append("\n");
+  s.Append("               ");
+  for (uptr i = 0; i < kShadowAlignment - tail_size; i++) s.Append("   ");
   for (uptr i = 0; i < tail_size; i++)
     s.AppendF("%s ", actual_expected[i] != tail[i] ? "^^" : "  ");
 
@@ -1020,7 +1093,7 @@  void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
 // See the frame breakdown defined in __hwasan_tag_mismatch (from
 // hwasan_tag_mismatch_{aarch64,riscv64}.S).
 void ReportRegisters(const uptr *frame, uptr pc) {
-  Printf("Registers where the failure occurred (pc %p):\n", pc);
+  Printf("\nRegisters where the failure occurred (pc %p):\n", pc);
 
   // We explicitly print a single line (4 registers/line) each iteration to
   // reduce the amount of logcat error messages printed. Each Printf() will
diff --git a/libsanitizer/hwasan/hwasan_thread.cpp b/libsanitizer/hwasan/hwasan_thread.cpp
index ce36547580e6..8b32e4e760e2 100644
--- a/libsanitizer/hwasan/hwasan_thread.cpp
+++ b/libsanitizer/hwasan/hwasan_thread.cpp
@@ -68,6 +68,7 @@  void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size,
     }
     Print("Creating  : ");
   }
+  ClearShadowForThreadStackAndTLS();
 }
 
 void Thread::InitStackRingBuffer(uptr stack_buffer_start,
@@ -217,6 +218,11 @@  void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs) {
   __hwasan::hwasanThreadArgRetval().GetAllPtrsLocked(ptrs);
 }
 
-void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) {}
+void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) {
+  // TODO: implement.
+}
+void PrintThreads() {
+  // TODO: implement.
+}
 
 }  // namespace __lsan
diff --git a/libsanitizer/hwasan/hwasan_thread_list.cpp b/libsanitizer/hwasan/hwasan_thread_list.cpp
index 7df4dd3d7851..794cfb7550d7 100644
--- a/libsanitizer/hwasan/hwasan_thread_list.cpp
+++ b/libsanitizer/hwasan/hwasan_thread_list.cpp
@@ -1,5 +1,6 @@ 
 #include "hwasan_thread_list.h"
 
+#include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_thread_arg_retval.h"
 
 namespace __hwasan {
@@ -13,15 +14,15 @@  ThreadArgRetval &hwasanThreadArgRetval() { return *thread_data; }
 void InitThreadList(uptr storage, uptr size) {
   CHECK_EQ(hwasan_thread_list, nullptr);
 
-  static ALIGNED(alignof(
-      HwasanThreadList)) char thread_list_placeholder[sizeof(HwasanThreadList)];
+  alignas(alignof(HwasanThreadList)) static char
+      thread_list_placeholder[sizeof(HwasanThreadList)];
   hwasan_thread_list =
       new (thread_list_placeholder) HwasanThreadList(storage, size);
 
   CHECK_EQ(thread_data, nullptr);
 
-  static ALIGNED(alignof(
-      ThreadArgRetval)) char thread_data_placeholder[sizeof(ThreadArgRetval)];
+  alignas(alignof(ThreadArgRetval)) static char
+      thread_data_placeholder[sizeof(ThreadArgRetval)];
   thread_data = new (thread_data_placeholder) ThreadArgRetval();
 }
 
diff --git a/libsanitizer/hwasan/hwasan_thread_list.h b/libsanitizer/hwasan/hwasan_thread_list.h
index 82f6c70a03f8..369a1c3d6f5f 100644
--- a/libsanitizer/hwasan/hwasan_thread_list.h
+++ b/libsanitizer/hwasan/hwasan_thread_list.h
@@ -18,7 +18,7 @@ 
 // * Start of the shadow memory region is aligned to 2**kShadowBaseAlignment.
 // * All stack ring buffers are located within (2**kShadowBaseAlignment)
 // sized region below and adjacent to the shadow region.
-// * Each ring buffer has a size of (2**N)*4096 where N is in [0, 8), and is
+// * Each ring buffer has a size of (2**N)*4096 where N is in [0, 7), and is
 // aligned to twice its size. The value of N can be different for each buffer.
 //
 // These constrains guarantee that, given an address A of any element of the
@@ -47,7 +47,6 @@ 
 #include "hwasan_allocator.h"
 #include "hwasan_flags.h"
 #include "hwasan_thread.h"
-#include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_thread_arg_retval.h"
 
 namespace __hwasan {
@@ -56,7 +55,10 @@  static uptr RingBufferSize() {
   uptr desired_bytes = flags()->stack_history_size * sizeof(uptr);
   // FIXME: increase the limit to 8 once this bug is fixed:
   // https://bugs.llvm.org/show_bug.cgi?id=39030
-  for (int shift = 1; shift < 7; ++shift) {
+  // Note that we *cannot* do that on Android, as the runtime will indefinitely
+  // have to support code that is compiled with ashr, which only works with
+  // shifts up to 6.
+  for (int shift = 0; shift < 7; ++shift) {
     uptr size = 4096 * (1ULL << shift);
     if (size >= desired_bytes)
       return size;
diff --git a/libsanitizer/include/sanitizer/allocator_interface.h b/libsanitizer/include/sanitizer/allocator_interface.h
index a792e9f0136e..1696a92681e3 100644
--- a/libsanitizer/include/sanitizer/allocator_interface.h
+++ b/libsanitizer/include/sanitizer/allocator_interface.h
@@ -62,13 +62,20 @@  size_t SANITIZER_CDECL __sanitizer_get_free_bytes(void);
 size_t SANITIZER_CDECL __sanitizer_get_unmapped_bytes(void);
 
 /* Malloc hooks that may be optionally provided by user.
-   __sanitizer_malloc_hook(ptr, size) is called immediately after
-     allocation of "size" bytes, which returned "ptr".
-   __sanitizer_free_hook(ptr) is called immediately before
-     deallocation of "ptr". */
+   - __sanitizer_malloc_hook(ptr, size) is called immediately after allocation
+     of "size" bytes, which returned "ptr".
+   - __sanitizer_free_hook(ptr) is called immediately before deallocation of
+     "ptr".
+   - __sanitizer_ignore_free_hook(ptr) is called immediately before deallocation
+     of "ptr", and if it returns a non-zero value, the deallocation of "ptr"
+     will not take place. This allows software to make free a no-op until it
+     calls free() again in the same pointer at a later time. Hint: read this as
+     "ignore the free" rather than "ignore the hook".
+*/
 void SANITIZER_CDECL __sanitizer_malloc_hook(const volatile void *ptr,
                                              size_t size);
 void SANITIZER_CDECL __sanitizer_free_hook(const volatile void *ptr);
+int SANITIZER_CDECL __sanitizer_ignore_free_hook(const volatile void *ptr);
 
 /* Installs a pair of hooks for malloc/free.
    Several (currently, 5) hook pairs may be installed, they are executed
diff --git a/libsanitizer/include/sanitizer/common_interface_defs.h b/libsanitizer/include/sanitizer/common_interface_defs.h
index 56d9e008fa06..57313f9bc80e 100644
--- a/libsanitizer/include/sanitizer/common_interface_defs.h
+++ b/libsanitizer/include/sanitizer/common_interface_defs.h
@@ -193,6 +193,43 @@  void SANITIZER_CDECL __sanitizer_annotate_double_ended_contiguous_container(
     const void *old_container_beg, const void *old_container_end,
     const void *new_container_beg, const void *new_container_end);
 
+/// Copies memory annotations from a source storage region to a destination
+/// storage region. After the operation, the destination region has the same
+/// memory annotations as the source region, as long as sanitizer limitations
+/// allow it (more bytes may be unpoisoned than in the source region, resulting
+/// in more false negatives, but never false positives). If the source and
+/// destination regions overlap, only the minimal required changes are made to
+/// preserve the correct annotations. Old storage bytes that are not in the new
+/// storage should have the same annotations, as long as sanitizer limitations
+/// allow it.
+///
+/// This function is primarily designed to be used when moving trivially
+/// relocatable objects that may have poisoned memory, making direct copying
+/// problematic under sanitizer. However, this function does not move memory
+/// content itself, only annotations.
+///
+/// A contiguous container is a container that keeps all of its elements in a
+/// contiguous region of memory. The container owns the region of memory
+/// <c>[src_begin, src_end)</c> and <c>[dst_begin, dst_end)</c>. The memory
+/// within these regions may be alternately poisoned and non-poisoned, with
+/// possibly smaller poisoned and unpoisoned regions.
+///
+/// If this function fully poisons a granule, it is marked as "container
+/// overflow".
+///
+/// Argument requirements: The destination container must have the same size as
+/// the source container, which is inferred from the beginning and end of the
+/// source region. Addresses may be granule-unaligned, but this may affect
+/// performance.
+///
+/// \param src_begin Begin of the source container region.
+/// \param src_end End of the source container region.
+/// \param dst_begin Begin of the destination container region.
+/// \param dst_end End of the destination container region.
+void SANITIZER_CDECL __sanitizer_copy_contiguous_container_annotations(
+    const void *src_begin, const void *src_end, const void *dst_begin,
+    const void *dst_end);
+
 /// Returns true if the contiguous container <c>[beg, end)</c> is properly
 /// poisoned.
 ///
@@ -293,7 +330,7 @@  void SANITIZER_CDECL __sanitizer_symbolize_global(void *data_ptr,
 #define __sanitizer_return_address()                                           \
   __builtin_extract_return_addr(__builtin_return_address(0))
 #else
-void *SANITIZER_CDECL _ReturnAddress(void);
+void *_ReturnAddress(void);
 #pragma intrinsic(_ReturnAddress)
 #define __sanitizer_return_address() _ReturnAddress()
 #endif
diff --git a/libsanitizer/include/sanitizer/hwasan_interface.h b/libsanitizer/include/sanitizer/hwasan_interface.h
index abe310c06669..407f488a24a6 100644
--- a/libsanitizer/include/sanitizer/hwasan_interface.h
+++ b/libsanitizer/include/sanitizer/hwasan_interface.h
@@ -44,6 +44,10 @@  void SANITIZER_CDECL __hwasan_tag_memory(const volatile void *p,
 void *SANITIZER_CDECL __hwasan_tag_pointer(const volatile void *p,
                                            unsigned char tag);
 
+/// Get tag from the pointer.
+unsigned char SANITIZER_CDECL
+__hwasan_get_tag_from_pointer(const volatile void *p);
+
 // Set memory tag from the current SP address to the given address to zero.
 // This is meant to annotate longjmp and other non-local jumps.
 // This function needs to know the (almost) exact destination frame address;
diff --git a/libsanitizer/include/sanitizer/linux_syscall_hooks.h b/libsanitizer/include/sanitizer/linux_syscall_hooks.h
index 3f3f1e78dfb8..5f262455cb94 100644
--- a/libsanitizer/include/sanitizer/linux_syscall_hooks.h
+++ b/libsanitizer/include/sanitizer/linux_syscall_hooks.h
@@ -1856,6 +1856,15 @@ 
   __sanitizer_syscall_pre_impl_sigaltstack((long)ss, (long)oss)
 #define __sanitizer_syscall_post_sigaltstack(res, ss, oss)                     \
   __sanitizer_syscall_post_impl_sigaltstack(res, (long)ss, (long)oss)
+#define __sanitizer_syscall_pre_futex(uaddr, futex_op, val, timeout, uaddr2,   \
+                                      val3)                                    \
+  __sanitizer_syscall_pre_impl_futex((long)uaddr, (long)futex_op, (long)val,   \
+                                     (long)timeout, (long)uaddr2, (long)val3)
+#define __sanitizer_syscall_post_futex(res, uaddr, futex_op, val, timeout,     \
+                                       uaddr2, val3)                           \
+  __sanitizer_syscall_post_impl_futex(res, (long)uaddr, (long)futex_op,        \
+                                      (long)val, (long)timeout, (long)uaddr2,  \
+                                      (long)val3)
 
 // And now a few syscalls we don't handle yet.
 #define __sanitizer_syscall_pre_afs_syscall(...)
@@ -1875,7 +1884,6 @@ 
 #define __sanitizer_syscall_pre_fchown32(...)
 #define __sanitizer_syscall_pre_ftime(...)
 #define __sanitizer_syscall_pre_ftruncate64(...)
-#define __sanitizer_syscall_pre_futex(...)
 #define __sanitizer_syscall_pre_getegid32(...)
 #define __sanitizer_syscall_pre_geteuid32(...)
 #define __sanitizer_syscall_pre_getgid32(...)
@@ -1954,7 +1962,6 @@ 
 #define __sanitizer_syscall_post_fchown32(res, ...)
 #define __sanitizer_syscall_post_ftime(res, ...)
 #define __sanitizer_syscall_post_ftruncate64(res, ...)
-#define __sanitizer_syscall_post_futex(res, ...)
 #define __sanitizer_syscall_post_getegid32(res, ...)
 #define __sanitizer_syscall_post_geteuid32(res, ...)
 #define __sanitizer_syscall_post_getgid32(res, ...)
@@ -3093,6 +3100,11 @@  void __sanitizer_syscall_post_impl_rt_sigaction(long res, long signum, long act,
                                                 long oldact, long sz);
 void __sanitizer_syscall_pre_impl_sigaltstack(long ss, long oss);
 void __sanitizer_syscall_post_impl_sigaltstack(long res, long ss, long oss);
+void __sanitizer_syscall_pre_impl_futex(long uaddr, long futex_op, long val,
+                                        long timeout, long uaddr2, long val3);
+void __sanitizer_syscall_post_impl_futex(long res, long uaddr, long futex_op,
+                                         long val, long timeout, long uaddr2,
+                                         long val3);
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/libsanitizer/include/sanitizer/memprof_interface.h b/libsanitizer/include/sanitizer/memprof_interface.h
index fe0a2fc5ef02..4660a7818c92 100644
--- a/libsanitizer/include/sanitizer/memprof_interface.h
+++ b/libsanitizer/include/sanitizer/memprof_interface.h
@@ -59,6 +59,12 @@  const char *SANITIZER_CDECL __memprof_default_options(void);
 /// \returns 0 on success.
 int SANITIZER_CDECL __memprof_profile_dump(void);
 
+/// Closes the existing file descriptor, if it is valid and not stdout or
+/// stderr, and resets the internal state such that the profile filename is
+/// reopened on the next profile dump attempt. This can be used to enable
+/// multiple rounds of profiling on the same binary.
+void SANITIZER_CDECL __memprof_profile_reset(void);
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/libsanitizer/include/sanitizer/nsan_interface.h b/libsanitizer/include/sanitizer/nsan_interface.h
new file mode 100644
index 000000000000..057ca0473bb3
--- /dev/null
+++ b/libsanitizer/include/sanitizer/nsan_interface.h
@@ -0,0 +1,75 @@ 
+//===-- sanitizer/nsan_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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Public interface for nsan.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_NSAN_INTERFACE_H
+#define SANITIZER_NSAN_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/// User-provided default option settings.
+///
+/// You can provide your own implementation of this function to return a string
+/// containing NSan runtime options (for example,
+/// <c>verbosity=1:halt_on_error=0</c>).
+///
+/// \returns Default options string.
+const char *__nsan_default_options(void);
+
+// Dumps nsan shadow data for a block of `size_bytes` bytes of application
+// memory at location `addr`.
+//
+// Each line contains application address, shadow types, then values.
+// Unknown types are shown as `__`, while known values are shown as
+// `f`, `d`, `l` for float, double, and long double respectively. Position is
+// shown as a single hex digit. The shadow value itself appears on the line that
+// contains the first byte of the value.
+// FIXME: Show both shadow and application value.
+//
+// Example: `__nsan_dump_shadow_mem(addr, 32, 8, 0)` might print:
+//
+//  0x0add7359:  __ f0 f1 f2 f3 __ __ __   (42.000)
+//  0x0add7361:  __ d1 d2 d3 d4 d5 d6 d7
+//  0x0add7369:  d8 f0 f1 f2 f3 __ __ f2   (-1.000) (12.5)
+//  0x0add7371:  f3 __ __ __ __ __ __ __
+//
+// This means that there is:
+//   - a shadow double for the float at address 0x0add7360, with value 42;
+//   - a shadow float128 for the double at address 0x0add7362, with value -1;
+//   - a shadow double for the float at address 0x0add736a, with value 12.5;
+// There was also a shadow double for the float at address 0x0add736e, but bytes
+// f0 and f1 were overwritten by one or several stores, so that the shadow value
+// is no longer valid.
+// The argument `reserved` can be any value. Its true value is provided by the
+// instrumentation.
+void __nsan_dump_shadow_mem(const char *addr, size_t size_bytes,
+                            size_t bytes_per_line, size_t reserved);
+
+// Explicitly dumps a value.
+// FIXME: vector versions ?
+void __nsan_dump_float(float value);
+void __nsan_dump_double(double value);
+void __nsan_dump_longdouble(long double value);
+
+// Explicitly checks a value.
+// FIXME: vector versions ?
+void __nsan_check_float(float value);
+void __nsan_check_double(double value);
+void __nsan_check_longdouble(long double value);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // SANITIZER_NSAN_INTERFACE_H
diff --git a/libsanitizer/include/sanitizer/rtsan_interface.h b/libsanitizer/include/sanitizer/rtsan_interface.h
new file mode 100644
index 000000000000..5d7ce5345712
--- /dev/null
+++ b/libsanitizer/include/sanitizer/rtsan_interface.h
@@ -0,0 +1,75 @@ 
+//===-- sanitizer/rtsan_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.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of RealtimeSanitizer.
+//
+// Public interface header.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_RTSAN_INTERFACE_H
+#define SANITIZER_RTSAN_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+// Disable all RTSan error reporting.
+// Must be paired with a call to `__rtsan_enable`
+void SANITIZER_CDECL __rtsan_disable(void);
+
+// Re-enable all RTSan error reporting.
+// Must follow a call to `__rtsan_disable`.
+void SANITIZER_CDECL __rtsan_enable(void);
+
+#ifdef __cplusplus
+} // extern "C"
+
+namespace __rtsan {
+#if defined(__has_feature) && __has_feature(realtime_sanitizer)
+
+class ScopedDisabler {
+public:
+  ScopedDisabler() { __rtsan_disable(); }
+  ~ScopedDisabler() { __rtsan_enable(); }
+
+#if __cplusplus >= 201103L
+  ScopedDisabler(const ScopedDisabler &) = delete;
+  ScopedDisabler &operator=(const ScopedDisabler &) = delete;
+  ScopedDisabler(ScopedDisabler &&) = delete;
+  ScopedDisabler &operator=(ScopedDisabler &&) = delete;
+#else
+private:
+  ScopedDisabler(const ScopedDisabler &);
+  ScopedDisabler &operator=(const ScopedDisabler &);
+#endif // __cplusplus >= 201103L
+};
+
+#else
+
+class ScopedDisabler {
+public:
+  ScopedDisabler() {}
+#if __cplusplus >= 201103L
+  ScopedDisabler(const ScopedDisabler &) = delete;
+  ScopedDisabler &operator=(const ScopedDisabler &) = delete;
+  ScopedDisabler(ScopedDisabler &&) = delete;
+  ScopedDisabler &operator=(ScopedDisabler &&) = delete;
+#else
+private:
+  ScopedDisabler(const ScopedDisabler &);
+  ScopedDisabler &operator=(const ScopedDisabler &);
+#endif // __cplusplus >= 201103L
+};
+
+#endif // defined(__has_feature) && __has_feature(realtime_sanitizer)
+} // namespace __rtsan
+#endif // __cplusplus
+
+#endif // SANITIZER_RTSAN_INTERFACE_H
diff --git a/libsanitizer/include/sanitizer/ubsan_interface.h b/libsanitizer/include/sanitizer/ubsan_interface.h
index 435eb1ae332c..30a7fd875043 100644
--- a/libsanitizer/include/sanitizer/ubsan_interface.h
+++ b/libsanitizer/include/sanitizer/ubsan_interface.h
@@ -13,6 +13,8 @@ 
 #ifndef SANITIZER_UBSAN_INTERFACE_H
 #define SANITIZER_UBSAN_INTERFACE_H
 
+#include <sanitizer/common_interface_defs.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/libsanitizer/interception/interception.h b/libsanitizer/interception/interception.h
index 73135b34bee2..0580d97edda6 100644
--- a/libsanitizer/interception/interception.h
+++ b/libsanitizer/interception/interception.h
@@ -25,8 +25,19 @@ 
 
 // These typedefs should be used only in the interceptor definitions to replace
 // the standard system types (e.g. SSIZE_T instead of ssize_t)
-typedef __sanitizer::uptr    SIZE_T;
-typedef __sanitizer::sptr    SSIZE_T;
+// On Windows the system headers (basetsd.h) provide a conflicting definition
+// of SIZE_T/SSIZE_T that do not match the real size_t/ssize_t for 32-bit
+// systems (using long instead of the expected int). Work around the typedef
+// redefinition by #defining SIZE_T instead of using a typedef.
+// TODO: We should be using __sanitizer::usize (and a new ssize) instead of
+// these new macros as long as we ensure they match the real system definitions.
+#if SANITIZER_WINDOWS
+// Ensure that (S)SIZE_T were already defined as we are about to override them.
+#  include <basetsd.h>
+#endif
+
+#define SIZE_T __sanitizer::usize
+#define SSIZE_T __sanitizer::sptr
 typedef __sanitizer::sptr    PTRDIFF_T;
 typedef __sanitizer::s64     INTMAX_T;
 typedef __sanitizer::u64     UINTMAX_T;
@@ -338,16 +349,20 @@  const interpose_substitution substitution_##func_name[]             \
 #endif
 
 // ISO C++ forbids casting between pointer-to-function and pointer-to-object,
-// so we use casting via an integral type __interception::uptr,
-// assuming that system is POSIX-compliant. Using other hacks seem
-// challenging, as we don't even pass function type to
-// INTERCEPT_FUNCTION macro, only its name.
+// so we use casts via uintptr_t (the local __sanitizer::uptr equivalent).
 namespace __interception {
-#if defined(_WIN64)
-typedef unsigned long long uptr;
+
+#if defined(__ELF__) && !SANITIZER_FUCHSIA
+// The use of interceptors makes many sanitizers unusable for static linking.
+// Define a function, if called, will cause a linker error (undefined _DYNAMIC).
+// However, -static-pie (which is not common) cannot be detected at link time.
+extern uptr kDynamic[] asm("_DYNAMIC");
+inline void DoesNotSupportStaticLinking() {
+  [[maybe_unused]] volatile auto x = &kDynamic;
+}
 #else
-typedef unsigned long uptr;
-#endif  // _WIN64
+inline void DoesNotSupportStaticLinking() {}
+#endif
 }  // namespace __interception
 
 #define INCLUDED_FROM_INTERCEPTION_LIB
diff --git a/libsanitizer/interception/interception_linux.h b/libsanitizer/interception/interception_linux.h
index 433a3d9bd7fa..2e01ff44578c 100644
--- a/libsanitizer/interception/interception_linux.h
+++ b/libsanitizer/interception/interception_linux.h
@@ -28,12 +28,14 @@  bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
                        uptr func, uptr trampoline);
 }  // namespace __interception
 
-#define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) \
-  ::__interception::InterceptFunction(            \
-      #func,                                      \
-      (::__interception::uptr *)&REAL(func),      \
-      (::__interception::uptr)&(func),            \
-      (::__interception::uptr)&TRAMPOLINE(func))
+// Cast func to type of REAL(func) before casting to uptr in case it is an
+// overloaded function, which is the case for some glibc functions when
+// _FORTIFY_SOURCE is used. This disambiguates which overload to use.
+#define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)            \
+  ::__interception::InterceptFunction(                       \
+      #func, (::__interception::uptr *)&REAL(func),          \
+      (::__interception::uptr)(decltype(REAL(func)))&(func), \
+      (::__interception::uptr) &TRAMPOLINE(func))
 
 // dlvsym is a GNU extension supported by some other platforms.
 #if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
@@ -41,7 +43,7 @@  bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
   ::__interception::InterceptFunction(                        \
       #func, symver,                                          \
       (::__interception::uptr *)&REAL(func),                  \
-      (::__interception::uptr)&(func),                        \
+      (::__interception::uptr)(decltype(REAL(func)))&(func),  \
       (::__interception::uptr)&TRAMPOLINE(func))
 #else
 #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
diff --git a/libsanitizer/interception/interception_type_test.cpp b/libsanitizer/interception/interception_type_test.cpp
index 7c3de82a1e86..41041ce6f95c 100644
--- a/libsanitizer/interception/interception_type_test.cpp
+++ b/libsanitizer/interception/interception_type_test.cpp
@@ -12,28 +12,35 @@ 
 //===----------------------------------------------------------------------===//
 
 #include "interception.h"
+#include "sanitizer_common/sanitizer_type_traits.h"
 
-#if SANITIZER_LINUX || SANITIZER_APPLE
-
-#include <sys/types.h>
+#if __has_include(<sys/types.h>)
+#  include <sys/types.h>
+#endif
 #include <stddef.h>
 #include <stdint.h>
 
-COMPILER_CHECK(sizeof(::SIZE_T) == sizeof(size_t));
-COMPILER_CHECK(sizeof(::SSIZE_T) == sizeof(ssize_t));
-COMPILER_CHECK(sizeof(::PTRDIFF_T) == sizeof(ptrdiff_t));
+COMPILER_CHECK((__sanitizer::is_same<__sanitizer::uptr, ::uintptr_t>::value));
+COMPILER_CHECK((__sanitizer::is_same<__sanitizer::sptr, ::intptr_t>::value));
+COMPILER_CHECK((__sanitizer::is_same<__sanitizer::usize, ::size_t>::value));
+COMPILER_CHECK((__sanitizer::is_same<::PTRDIFF_T, ::ptrdiff_t>::value));
+COMPILER_CHECK((__sanitizer::is_same<::SIZE_T, ::size_t>::value));
+#if !SANITIZER_WINDOWS
+// No ssize_t on Windows.
+COMPILER_CHECK((__sanitizer::is_same<::SSIZE_T, ::ssize_t>::value));
+#endif
+// TODO: These are not actually the same type on Linux (long vs long long)
 COMPILER_CHECK(sizeof(::INTMAX_T) == sizeof(intmax_t));
+COMPILER_CHECK(sizeof(::UINTMAX_T) == sizeof(uintmax_t));
 
-#  if SANITIZER_GLIBC || SANITIZER_ANDROID
+#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
 // rest (they depend on _FILE_OFFSET_BITS setting when building an application).
-# if SANITIZER_ANDROID || !defined _FILE_OFFSET_BITS || \
-  _FILE_OFFSET_BITS != 64
+#if !SANITIZER_WINDOWS && (SANITIZER_ANDROID || !defined _FILE_OFFSET_BITS || \
+                           _FILE_OFFSET_BITS != 64)
 COMPILER_CHECK(sizeof(::OFF_T) == sizeof(off_t));
-# endif
-
 #endif
diff --git a/libsanitizer/interception/interception_win.cpp b/libsanitizer/interception/interception_win.cpp
index 1b681ada37b1..077a536dd2a3 100644
--- a/libsanitizer/interception/interception_win.cpp
+++ b/libsanitizer/interception/interception_win.cpp
@@ -27,7 +27,7 @@ 
 //
 // 1) Detour
 //
-//    The Detour hooking technique is assuming the presence of an header with
+//    The Detour hooking technique is assuming the presence of a header with
 //    padding and an overridable 2-bytes nop instruction (mov edi, edi). The
 //    nop instruction can safely be replaced by a 2-bytes jump without any need
 //    to save the instruction. A jump to the target is encoded in the function
@@ -47,7 +47,7 @@ 
 //
 //        func:  jmp <label>     -->     func:  jmp <hook>
 //
-//    On an 64-bit architecture, a trampoline is inserted.
+//    On a 64-bit architecture, a trampoline is inserted.
 //
 //        func:  jmp <label>     -->     func:  jmp <tramp>
 //                                              [...]
@@ -60,7 +60,7 @@ 
 //
 // 3) HotPatch
 //
-//    The HotPatch hooking is assuming the presence of an header with padding
+//    The HotPatch hooking is assuming the presence of a header with padding
 //    and a first instruction with at least 2-bytes.
 //
 //    The reason to enforce the 2-bytes limitation is to provide the minimal
@@ -80,7 +80,7 @@ 
 //                                       real:  <instr>
 //                                              jmp <body>
 //
-//    On an 64-bit architecture:
+//    On a 64-bit architecture:
 //
 //        head:   6 x nop                head:  jmp QWORD [addr1]
 //        func:   <instr>        -->     func:  jmp short <head>
@@ -110,7 +110,7 @@ 
 //                                              <instr>
 //                                              jmp <body>
 //
-//    On an 64-bit architecture:
+//    On a 64-bit architecture:
 //
 //        func:   <instr>        -->     func:  jmp QWORD [addr1]
 //                <instr>
@@ -130,6 +130,7 @@ 
 #include "sanitizer_common/sanitizer_platform.h"
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
+#include <psapi.h>
 
 namespace __interception {
 
@@ -339,7 +340,7 @@  struct TrampolineMemoryRegion {
   uptr max_size;
 };
 
-UNUSED static const uptr kTrampolineScanLimitRange = 1 << 31;  // 2 gig
+UNUSED static const uptr kTrampolineScanLimitRange = 1ull << 31;  // 2 gig
 static const int kMaxTrampolineRegion = 1024;
 static TrampolineMemoryRegion TrampolineRegions[kMaxTrampolineRegion];
 
@@ -385,7 +386,30 @@  void TestOnlyReleaseTrampolineRegions() {
   }
 }
 
-static uptr AllocateMemoryForTrampoline(uptr image_address, size_t size) {
+static uptr AllocateMemoryForTrampoline(uptr func_address, size_t size) {
+  uptr image_address = func_address;
+
+#if SANITIZER_WINDOWS64
+  // Allocate memory after the module (DLL or EXE file), but within 2GB
+  // of the start of the module so that any address within the module can be
+  // referenced with PC-relative operands.
+  // This allows us to not just jump to the trampoline with a PC-relative
+  // offset, but to relocate any instructions that we copy to the trampoline
+  // which have references to the original module. If we can't find the base
+  // address of the module (e.g. if func_address is in mmap'ed memory), just
+  // use func_address as is.
+  HMODULE module;
+  if (::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                           GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+                           (LPCWSTR)func_address, &module)) {
+    MODULEINFO module_info;
+    if (::GetModuleInformation(::GetCurrentProcess(), module,
+                                &module_info, sizeof(module_info))) {
+      image_address = (uptr)module_info.lpBaseOfDll;
+    }
+  }
+#endif
+
   // Find a region within 2G with enough space to allocate |size| bytes.
   TrampolineMemoryRegion *region = nullptr;
   for (size_t bucket = 0; bucket < kMaxTrampolineRegion; ++bucket) {
@@ -431,7 +455,8 @@  static uptr AllocateMemoryForTrampoline(uptr image_address, size_t size) {
 // The following prologues cannot be patched because of the short jump
 // jumping to the patching region.
 
-#if SANITIZER_WINDOWS64
+// Short jump patterns  below are only for x86_64.
+#  if SANITIZER_WINDOWS_x64
 // ntdll!wcslen in Win11
 //   488bc1          mov     rax,rcx
 //   0fb710          movzx   edx,word ptr [rax]
@@ -462,7 +487,7 @@  static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
   return 4;
 #endif
 
-#if SANITIZER_WINDOWS64
+#  if SANITIZER_WINDOWS_x64
   if (memcmp((u8*)address, kPrologueWithShortJump1,
              sizeof(kPrologueWithShortJump1)) == 0 ||
       memcmp((u8*)address, kPrologueWithShortJump2,
@@ -478,6 +503,8 @@  static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
 
   switch (*(u8*)address) {
     case 0x90:  // 90 : nop
+    case 0xC3:  // C3 : ret   (for small/empty function interception
+    case 0xCC:  // CC : int 3  i.e. registering weak functions)
       return 1;
 
     case 0x50:  // push eax / rax
@@ -494,6 +521,11 @@  static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
     case 0x6A:  // 6A XX = push XX
       return 2;
 
+    // This instruction can be encoded with a 16-bit immediate but that is
+    // incredibly unlikely.
+    case 0x68:  // 68 XX XX XX XX : push imm32
+      return 5;
+
     case 0xb8:  // b8 XX XX XX XX : mov eax, XX XX XX XX
     case 0xB9:  // b9 XX XX XX XX : mov ecx, XX XX XX XX
       return 5;
@@ -501,7 +533,6 @@  static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
     // Cannot overwrite control-instruction. Return 0 to indicate failure.
     case 0xE9:  // E9 XX XX XX XX : jmp <label>
     case 0xE8:  // E8 XX XX XX XX : call <func>
-    case 0xC3:  // C3 : ret
     case 0xEB:  // EB XX : jmp XX (short jump)
     case 0x70:  // 7Y YY : jy XX (short conditional jump)
     case 0x71:
@@ -532,6 +563,9 @@  static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
     case 0xC033:  // 33 C0 : xor eax, eax
     case 0xC933:  // 33 C9 : xor ecx, ecx
     case 0xD233:  // 33 D2 : xor edx, edx
+    case 0xDB84:  // 84 DB : test bl,bl
+    case 0xC984:  // 84 C9 : test cl,cl
+    case 0xD284:  // 84 D2 : test dl,dl
       return 2;
 
     // Cannot overwrite control-instruction. Return 0 to indicate failure.
@@ -540,15 +574,38 @@  static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
   }
 
   switch (0x00FFFFFF & *(u32*)address) {
+    case 0xF8E483:  // 83 E4 F8 : and esp, 0xFFFFFFF8
+    case 0x64EC83:  // 83 EC 64 : sub esp, 64h
+      return 3;
     case 0x24A48D:  // 8D A4 24 XX XX XX XX : lea esp, [esp + XX XX XX XX]
       return 7;
   }
 
-#if SANITIZER_WINDOWS64
+  switch (0x000000FF & *(u32 *)address) {
+    case 0xc2:  // C2 XX XX : ret XX (needed for registering weak functions)
+      return 3;
+  }
+
+#  if SANITIZER_WINDOWS_x64
   switch (*(u8*)address) {
     case 0xA1:  // A1 XX XX XX XX XX XX XX XX :
                 //   movabs eax, dword ptr ds:[XXXXXXXX]
       return 9;
+    case 0xF2:
+      switch (*(u32 *)(address + 1)) {
+          case 0x2444110f:  //  f2 0f 11 44 24 XX       movsd  QWORD PTR
+                            //  [rsp + XX], xmm0
+          case 0x244c110f:  //  f2 0f 11 4c 24 XX       movsd  QWORD PTR
+                            //  [rsp + XX], xmm1
+          case 0x2454110f:  //  f2 0f 11 54 24 XX       movsd  QWORD PTR
+                            //  [rsp + XX], xmm2
+          case 0x245c110f:  //  f2 0f 11 5c 24 XX       movsd  QWORD PTR
+                            //  [rsp + XX], xmm3
+          case 0x2464110f:  //  f2 0f 11 64 24 XX       movsd  QWORD PTR
+                            //  [rsp + XX], xmm4
+            return 6;
+      }
+      break;
 
     case 0x83:
       const u8 next_byte = *(u8*)(address + 1);
@@ -577,51 +634,126 @@  static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
     case 0x018a:  // mov al, byte ptr [rcx]
       return 2;
 
+    case 0x058A:  // 8A 05 XX XX XX XX : mov al, byte ptr [XX XX XX XX]
+    case 0x7E80:  // 80 7E YY XX  cmp BYTE PTR [rsi+YY], XX
+    case 0x7D80:  // 80 7D YY XX  cmp BYTE PTR [rbp+YY], XX
+    case 0x7A80:  // 80 7A YY XX  cmp BYTE PTR [rdx+YY], XX
+    case 0x7880:  // 80 78 YY XX  cmp BYTE PTR [rax+YY], XX
+    case 0x7B80:  // 80 7B YY XX  cmp BYTE PTR [rbx+YY], XX
+    case 0x7980:  // 80 79 YY XX  cmp BYTE ptr [rcx+YY], XX
+      return 4;
+
     case 0x058B:  // 8B 05 XX XX XX XX : mov eax, dword ptr [XX XX XX XX]
       if (rel_offset)
         *rel_offset = 2;
       return 6;
+
+    case 0x7E81:  // 81 7E YY XX XX XX XX  cmp DWORD PTR [rsi+YY], XX XX XX XX
+    case 0x7D81:  // 81 7D YY XX XX XX XX  cmp DWORD PTR [rbp+YY], XX XX XX XX
+    case 0x7A81:  // 81 7A YY XX XX XX XX  cmp DWORD PTR [rdx+YY], XX XX XX XX
+    case 0x7881:  // 81 78 YY XX XX XX XX  cmp DWORD PTR [rax+YY], XX XX XX XX
+    case 0x7B81:  // 81 7B YY XX XX XX XX  cmp DWORD PTR [rbx+YY], XX XX XX XX
+    case 0x7981:  // 81 79 YY XX XX XX XX  cmp dword ptr [rcx+YY], XX XX XX XX
+      return 7;
   }
 
   switch (0x00FFFFFF & *(u32*)address) {
-    case 0xe58948:    // 48 8b c4 : mov rbp, rsp
-    case 0xc18b48:    // 48 8b c1 : mov rax, rcx
-    case 0xc48b48:    // 48 8b c4 : mov rax, rsp
-    case 0xd9f748:    // 48 f7 d9 : neg rcx
-    case 0xd12b48:    // 48 2b d1 : sub rdx, rcx
     case 0x07c1f6:    // f6 c1 07 : test cl, 0x7
-    case 0xc98548:    // 48 85 C9 : test rcx, rcx
-    case 0xd28548:    // 48 85 d2 : test rdx, rdx
+    case 0x10b70f:    // 0f b7 10 : movzx edx, WORD PTR [rax]
+    case 0xc00b4d:    // 4d 0b c0 : or r8, r8
+    case 0xc03345:    // 45 33 c0 : xor r8d, r8d
+    case 0xc08548:    // 48 85 c0 : test rax, rax
     case 0xc0854d:    // 4d 85 c0 : test r8, r8
+    case 0xc08b41:    // 41 8b c0 : mov eax, r8d
+    case 0xc0ff48:    // 48 ff c0 : inc rax
+    case 0xc0ff49:    // 49 ff c0 : inc r8
+    case 0xc18b41:    // 41 8b c1 : mov eax, r9d
+    case 0xc18b48:    // 48 8b c1 : mov rax, rcx
+    case 0xc18b4c:    // 4c 8b c1 : mov r8, rcx
+    case 0xc1ff48:    // 48 ff c1 : inc rcx
+    case 0xc1ff49:    // 49 ff c1 : inc r9
+    case 0xc28b41:    // 41 8b c2 : mov eax, r10d
     case 0xc2b60f:    // 0f b6 c2 : movzx eax, dl
-    case 0xc03345:    // 45 33 c0 : xor r8d, r8d
+    case 0xc2ff48:    // 48 ff c2 : inc rdx
+    case 0xc2ff49:    // 49 ff c2 : inc r10
+    case 0xc38b41:    // 41 8b c3 : mov eax, r11d
+    case 0xc3ff48:    // 48 ff c3 : inc rbx
+    case 0xc3ff49:    // 49 ff c3 : inc r11
+    case 0xc48b41:    // 41 8b c4 : mov eax, r12d
+    case 0xc48b48:    // 48 8b c4 : mov rax, rsp
+    case 0xc4ff49:    // 49 ff c4 : inc r12
+    case 0xc5ff49:    // 49 ff c5 : inc r13
+    case 0xc6ff48:    // 48 ff c6 : inc rsi
+    case 0xc6ff49:    // 49 ff c6 : inc r14
+    case 0xc7ff48:    // 48 ff c7 : inc rdi
+    case 0xc7ff49:    // 49 ff c7 : inc r15
     case 0xc93345:    // 45 33 c9 : xor r9d, r9d
-    case 0xdb3345:    // 45 33 DB : xor r11d, r11d
-    case 0xd98b4c:    // 4c 8b d9 : mov r11, rcx
-    case 0xd28b4c:    // 4c 8b d2 : mov r10, rdx
-    case 0xc98b4c:    // 4C 8B C9 : mov r9, rcx
-    case 0xc18b4c:    // 4C 8B C1 : mov r8, rcx
-    case 0xd2b60f:    // 0f b6 d2 : movzx edx, dl
+    case 0xc98548:    // 48 85 c9 : test rcx, rcx
+    case 0xc9854d:    // 4d 85 c9 : test r9, r9
+    case 0xc98b4c:    // 4c 8b c9 : mov r9, rcx
     case 0xca2b48:    // 48 2b ca : sub rcx, rdx
-    case 0x10b70f:    // 0f b7 10 : movzx edx, WORD PTR [rax]
-    case 0xc00b4d:    // 3d 0b c0 : or r8, r8
-    case 0xc08b41:    // 41 8b c0 : mov eax, r8d
+    case 0xca3b48:    // 48 3b ca : cmp rcx, rdx
+    case 0xd12b48:    // 48 2b d1 : sub rdx, rcx
     case 0xd18b48:    // 48 8b d1 : mov rdx, rcx
-    case 0xdc8b4c:    // 4c 8b dc : mov r11, rsp
     case 0xd18b4c:    // 4c 8b d1 : mov r10, rcx
-    case 0xE0E483:    // 83 E4 E0 : and esp, 0xFFFFFFE0
+    case 0xd28548:    // 48 85 d2 : test rdx, rdx
+    case 0xd2854d:    // 4d 85 d2 : test r10, r10
+    case 0xd28b4c:    // 4c 8b d2 : mov r10, rdx
+    case 0xd2b60f:    // 0f b6 d2 : movzx edx, dl
+    case 0xd98b4c:    // 4c 8b d9 : mov r11, rcx
+    case 0xd9f748:    // 48 f7 d9 : neg rcx
+    case 0xdb3345:    // 45 33 db : xor r11d, r11d
+    case 0xdb8548:    // 48 85 db : test rbx, rbx
+    case 0xdb854d:    // 4d 85 db : test r11, r11
+    case 0xdc8b4c:    // 4c 8b dc : mov r11, rsp
+    case 0xe0e483:    // 83 e4 e0 : and esp, 0xFFFFFFE0
+    case 0xe48548:    // 48 85 e4 : test rsp, rsp
+    case 0xe4854d:    // 4d 85 e4 : test r12, r12
+    case 0xe58948:    // 48 89 e5 : mov rbp, rsp
+    case 0xed8548:    // 48 85 ed : test rbp, rbp
+    case 0xed854d:    // 4d 85 ed : test r13, r13
+    case 0xf6854d:    // 4d 85 f6 : test r14, r14
+    case 0xff854d:    // 4d 85 ff : test r15, r15
       return 3;
 
+    case 0x245489:    // 89 54 24 XX : mov DWORD PTR[rsp + XX], edx
+    case 0x428d44:    // 44 8d 42 XX : lea r8d , [rdx + XX]
+    case 0x588948:    // 48 89 58 XX : mov QWORD PTR[rax + XX], rbx
     case 0xec8348:    // 48 83 ec XX : sub rsp, XX
     case 0xf88349:    // 49 83 f8 XX : cmp r8, XX
-    case 0x588948:    // 48 89 58 XX : mov QWORD PTR[rax + XX], rbx
       return 4;
 
+    case 0x246483:  // 83 64 24 XX YY :   and    DWORD PTR [rsp+XX], YY
+      return 5;
+
+    case 0x788166:  // 66 81 78 XX YY YY  cmp WORD PTR [rax+XX], YY YY
+    case 0x798166:  // 66 81 79 XX YY YY  cmp WORD PTR [rcx+XX], YY YY
+    case 0x7a8166:  // 66 81 7a XX YY YY  cmp WORD PTR [rdx+XX], YY YY
+    case 0x7b8166:  // 66 81 7b XX YY YY  cmp WORD PTR [rbx+XX], YY YY
+    case 0x7e8166:  // 66 81 7e XX YY YY  cmp WORD PTR [rsi+XX], YY YY
+    case 0x7f8166:  // 66 81 7f XX YY YY  cmp WORD PTR [rdi+XX], YY YY
+      return 6;
+
     case 0xec8148:    // 48 81 EC XX XX XX XX : sub rsp, XXXXXXXX
       return 7;
 
+    // clang-format off
+    case 0x788141:  // 41 81 78 XX YY YY YY YY : cmp DWORD PTR [r8+YY], XX XX XX XX
+    case 0x798141:  // 41 81 79 XX YY YY YY YY : cmp DWORD PTR [r9+YY], XX XX XX XX
+    case 0x7a8141:  // 41 81 7a XX YY YY YY YY : cmp DWORD PTR [r10+YY], XX XX XX XX
+    case 0x7b8141:  // 41 81 7b XX YY YY YY YY : cmp DWORD PTR [r11+YY], XX XX XX XX
+    case 0x7c8141:  // 41 81 7c XX YY YY YY YY : cmp DWORD PTR [r12+YY], XX XX XX XX
+    case 0x7d8141:  // 41 81 7d XX YY YY YY YY : cmp DWORD PTR [r13+YY], XX XX XX XX
+    case 0x7e8141:  // 41 81 7e XX YY YY YY YY : cmp DWORD PTR [r14+YY], XX XX XX XX
+    case 0x7f8141:  // 41 81 7f YY XX XX XX XX : cmp DWORD PTR [r15+YY], XX XX XX XX
+    case 0x247c81:  // 81 7c 24 YY XX XX XX XX : cmp DWORD PTR [rsp+YY], XX XX XX XX
+      return 8;
+      // clang-format on
+
     case 0x058b48:    // 48 8b 05 XX XX XX XX :
                       //   mov rax, QWORD PTR [rip + XXXXXXXX]
+    case 0x058d48:    // 48 8d 05 XX XX XX XX :
+                      //   lea rax, QWORD PTR [rip + XXXXXXXX]
     case 0x25ff48:    // 48 ff 25 XX XX XX XX :
                       //   rex.W jmp QWORD PTR [rip + XXXXXXXX]
     case 0x158D4C:    // 4c 8d 15 XX XX XX XX : lea r10, [rip + XX]
@@ -636,6 +768,8 @@  static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
   }
 
   switch (*(u32*)(address)) {
+    case 0x1ab60f44:  // 44 0f b6 1a : movzx r11d, BYTE PTR [rdx]
+      return 4;
     case 0x24448b48:  // 48 8b 44 24 XX : mov rax, QWORD ptr [rsp + XX]
     case 0x246c8948:  // 48 89 6C 24 XX : mov QWORD ptr [rsp + XX], rbp
     case 0x245c8948:  // 48 89 5c 24 XX : mov QWORD PTR [rsp + XX], rbx
@@ -645,8 +779,11 @@  static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
     case 0x24548948:  // 48 89 54 24 XX : mov QWORD PTR [rsp + XX], rdx
     case 0x244c894c:  // 4c 89 4c 24 XX : mov QWORD PTR [rsp + XX], r9
     case 0x2444894c:  // 4c 89 44 24 XX : mov QWORD PTR [rsp + XX], r8
+    case 0x244c8944:  // 44 89 4c 24 XX   mov DWORD PTR [rsp + XX], r9d
+    case 0x24448944:  // 44 89 44 24 XX   mov DWORD PTR [rsp + XX], r8d
+    case 0x246c8d48:  // 48 8d 6c 24 XX : lea rbp, [rsp + XX]
       return 5;
-    case 0x24648348:  // 48 83 64 24 XX : and QWORD PTR [rsp + XX], YY
+    case 0x24648348:  // 48 83 64 24 XX YY : and QWORD PTR [rsp + XX], YY
       return 6;
   }
 
@@ -660,6 +797,7 @@  static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
     case 0x458B:  // 8B 45 XX : mov eax, dword ptr [ebp + XX]
     case 0x5D8B:  // 8B 5D XX : mov ebx, dword ptr [ebp + XX]
     case 0x7D8B:  // 8B 7D XX : mov edi, dword ptr [ebp + XX]
+    case 0x758B:  // 8B 75 XX : mov esi, dword ptr [ebp + XX]
     case 0xEC83:  // 83 EC XX : sub esp, XX
     case 0x75FF:  // FF 75 XX : push dword ptr [ebp + XX]
       return 3;
@@ -943,19 +1081,26 @@  bool OverrideFunction(
 
 static void **InterestingDLLsAvailable() {
   static const char *InterestingDLLs[] = {
-      "kernel32.dll",
-      "msvcr100.dll",      // VS2010
-      "msvcr110.dll",      // VS2012
-      "msvcr120.dll",      // VS2013
-      "vcruntime140.dll",  // VS2015
-      "ucrtbase.dll",      // Universal CRT
-#if (defined(__MINGW32__) && defined(__i386__))
-      "libc++.dll",        // libc++
-      "libunwind.dll",     // libunwind
-#endif
-      // NTDLL should go last as it exports some functions that we should
-      // override in the CRT [presumably only used internally].
-      "ntdll.dll", NULL};
+    "kernel32.dll",
+    "msvcr100d.dll",      // VS2010
+    "msvcr110d.dll",      // VS2012
+    "msvcr120d.dll",      // VS2013
+    "vcruntime140d.dll",  // VS2015
+    "ucrtbased.dll",      // Universal CRT
+    "msvcr100.dll",       // VS2010
+    "msvcr110.dll",       // VS2012
+    "msvcr120.dll",       // VS2013
+    "vcruntime140.dll",   // VS2015
+    "ucrtbase.dll",       // Universal CRT
+#  if (defined(__MINGW32__) && defined(__i386__))
+    "libc++.dll",     // libc++
+    "libunwind.dll",  // libunwind
+#  endif
+    // NTDLL should go last as it exports some functions that we should
+    // override in the CRT [presumably only used internally].
+    "ntdll.dll",
+    NULL
+  };
   static void *result[ARRAY_SIZE(InterestingDLLs)] = { 0 };
   if (!result[0]) {
     for (size_t i = 0, j = 0; InterestingDLLs[i]; ++i) {
@@ -1126,4 +1271,4 @@  bool OverrideImportedFunction(const char *module_to_patch,
 
 }  // namespace __interception
 
-#endif  // SANITIZER_APPLE
+#endif  // SANITIZER_WINDOWS
diff --git a/libsanitizer/lsan/lsan.cpp b/libsanitizer/lsan/lsan.cpp
index 6b223603c6a7..798294b499e2 100644
--- a/libsanitizer/lsan/lsan.cpp
+++ b/libsanitizer/lsan/lsan.cpp
@@ -92,15 +92,16 @@  extern "C" void __lsan_init() {
   CacheBinaryName();
   AvoidCVE_2016_2143();
   InitializeFlags();
+  InitializePlatformEarly();
   InitCommonLsan();
   InitializeAllocator();
   ReplaceSystemMalloc();
-  InitTlsSize();
   InitializeInterceptors();
   InitializeThreads();
   InstallDeadlySignalHandlers(LsanOnDeadlySignal);
   InitializeMainThread();
   InstallAtExitCheckLeaks();
+  InstallAtForkHandler();
 
   InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
 
diff --git a/libsanitizer/lsan/lsan.h b/libsanitizer/lsan/lsan.h
index 757edec8e104..0074ad530878 100644
--- a/libsanitizer/lsan/lsan.h
+++ b/libsanitizer/lsan/lsan.h
@@ -40,6 +40,7 @@  void InitializeInterceptors();
 void ReplaceSystemMalloc();
 void LsanOnDeadlySignal(int signo, void *siginfo, void *context);
 void InstallAtExitCheckLeaks();
+void InstallAtForkHandler();
 
 #define ENSURE_LSAN_INITED        \
   do {                            \
diff --git a/libsanitizer/lsan/lsan_allocator.cpp b/libsanitizer/lsan/lsan_allocator.cpp
index 12d579a9385b..493bf5f9efc5 100644
--- a/libsanitizer/lsan/lsan_allocator.cpp
+++ b/libsanitizer/lsan/lsan_allocator.cpp
@@ -31,7 +31,7 @@  static const uptr kMaxAllowedMallocSize = 1ULL << 30;
 #elif defined(__mips64) || defined(__aarch64__)
 static const uptr kMaxAllowedMallocSize = 4ULL << 30;
 #else
-static const uptr kMaxAllowedMallocSize = 8ULL << 30;
+static const uptr kMaxAllowedMallocSize = 1ULL << 40;
 #endif
 
 static Allocator allocator;
diff --git a/libsanitizer/lsan/lsan_common.cpp b/libsanitizer/lsan/lsan_common.cpp
index 8b1af5b629fb..5c44c000ae57 100644
--- a/libsanitizer/lsan/lsan_common.cpp
+++ b/libsanitizer/lsan/lsan_common.cpp
@@ -42,6 +42,9 @@  namespace __lsan {
 // also to protect the global list of root regions.
 static Mutex global_mutex;
 
+void LockGlobal() SANITIZER_ACQUIRE(global_mutex) { global_mutex.Lock(); }
+void UnlockGlobal() SANITIZER_RELEASE(global_mutex) { global_mutex.Unlock(); }
+
 Flags lsan_flags;
 
 void DisableCounterUnderflow() {
@@ -105,7 +108,7 @@  class LeakSuppressionContext {
   void PrintMatchedSuppressions();
 };
 
-ALIGNED(64) static char suppression_placeholder[sizeof(LeakSuppressionContext)];
+alignas(64) static char suppression_placeholder[sizeof(LeakSuppressionContext)];
 static LeakSuppressionContext *suppression_ctx = nullptr;
 static const char kSuppressionLeak[] = "leak";
 static const char *kSuppressionTypes[] = {kSuppressionLeak};
@@ -152,14 +155,15 @@  Suppression *LeakSuppressionContext::GetSuppressionForAddr(uptr addr) {
     return s;
 
   // Suppress by file or function name.
-  SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(addr);
-  for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
+  SymbolizedStackHolder symbolized_stack(
+      Symbolizer::GetOrInit()->SymbolizePC(addr));
+  const SymbolizedStack *frames = symbolized_stack.get();
+  for (const SymbolizedStack *cur = frames; cur; cur = cur->next) {
     if (context.Match(cur->info.function, kSuppressionLeak, &s) ||
         context.Match(cur->info.file, kSuppressionLeak, &s)) {
       break;
     }
   }
-  frames->ClearAll();
   return s;
 }
 
@@ -284,23 +288,54 @@  static inline bool MaybeUserPointer(uptr p) {
 #  endif
 }
 
+namespace {
+struct DirectMemoryAccessor {
+  void Init(uptr begin, uptr end) {};
+  void *LoadPtr(uptr p) const { return *reinterpret_cast<void **>(p); }
+};
+
+struct CopyMemoryAccessor {
+  void Init(uptr begin, uptr end) {
+    this->begin = begin;
+    buffer.clear();
+    buffer.resize(end - begin);
+    MemCpyAccessible(buffer.data(), reinterpret_cast<void *>(begin),
+                     buffer.size());
+  };
+
+  void *LoadPtr(uptr p) const {
+    uptr offset = p - begin;
+    CHECK_LE(offset + sizeof(void *), reinterpret_cast<uptr>(buffer.size()));
+    return *reinterpret_cast<void **>(offset +
+                                      reinterpret_cast<uptr>(buffer.data()));
+  }
+
+ private:
+  uptr begin;
+  InternalMmapVector<char> buffer;
+};
+}  // namespace
+
 // Scans the memory range, looking for byte patterns that point into allocator
 // chunks. Marks those chunks with |tag| and adds them to |frontier|.
 // There are two usage modes for this function: finding reachable chunks
 // (|tag| = kReachable) and finding indirectly leaked chunks
 // (|tag| = kIndirectlyLeaked). In the second case, there's no flood fill,
 // so |frontier| = 0.
-void ScanRangeForPointers(uptr begin, uptr end, Frontier *frontier,
-                          const char *region_type, ChunkTag tag) {
+template <class Accessor>
+void ScanForPointers(uptr begin, uptr end, Frontier *frontier,
+                     const char *region_type, ChunkTag tag,
+                     Accessor &accessor) {
   CHECK(tag == kReachable || tag == kIndirectlyLeaked);
   const uptr alignment = flags()->pointer_alignment();
   LOG_POINTERS("Scanning %s range %p-%p.\n", region_type, (void *)begin,
                (void *)end);
+  accessor.Init(begin, end);
   uptr pp = begin;
   if (pp % alignment)
     pp = pp + alignment - pp % alignment;
   for (; pp + sizeof(void *) <= end; pp += alignment) {
-    void *p = *reinterpret_cast<void **>(pp);
+    void *p = accessor.LoadPtr(pp);
 #  if SANITIZER_APPLE
     p = TransformPointer(p);
 #  endif
@@ -335,6 +370,12 @@  void ScanRangeForPointers(uptr begin, uptr end, Frontier *frontier,
   }
 }
 
+void ScanRangeForPointers(uptr begin, uptr end, Frontier *frontier,
+                          const char *region_type, ChunkTag tag) {
+  DirectMemoryAccessor accessor;
+  ScanForPointers(begin, end, frontier, region_type, tag, accessor);
+}
+
 // Scans a global range for pointers
 void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier) {
   uptr allocator_begin = 0, allocator_end = 0;
@@ -352,14 +393,21 @@  void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier) {
   }
 }
 
-void ScanExtraStackRanges(const InternalMmapVector<Range> &ranges,
-                          Frontier *frontier) {
+template <class Accessor>
+void ScanRanges(const InternalMmapVector<Range> &ranges, Frontier *frontier,
+                const char *region_type, Accessor &accessor) {
   for (uptr i = 0; i < ranges.size(); i++) {
-    ScanRangeForPointers(ranges[i].begin, ranges[i].end, frontier, "FAKE STACK",
-                         kReachable);
+    ScanForPointers(ranges[i].begin, ranges[i].end, frontier, region_type,
+                    kReachable, accessor);
   }
 }
 
+void ScanExtraStackRanges(const InternalMmapVector<Range> &ranges,
+                          Frontier *frontier) {
+  DirectMemoryAccessor accessor;
+  ScanRanges(ranges, frontier, "FAKE STACK", accessor);
+}
+
 #  if SANITIZER_FUCHSIA
 
 // Fuchsia handles all threads together with its own callback.
@@ -395,26 +443,129 @@  static void ProcessThreadRegistry(Frontier *frontier) {
 }
 
 // Scans thread data (stacks and TLS) for heap pointers.
+template <class Accessor>
+static void ProcessThread(tid_t os_id, uptr sp,
+                          const InternalMmapVector<uptr> &registers,
+                          InternalMmapVector<Range> &extra_ranges,
+                          Frontier *frontier, Accessor &accessor) {
+  // `extra_ranges` is outside of the function and the loop to reused mapped
+  // memory.
+  CHECK(extra_ranges.empty());
+  LOG_THREADS("Processing thread %llu.\n", os_id);
+  uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end;
+  DTLS *dtls;
+  bool thread_found =
+      GetThreadRangesLocked(os_id, &stack_begin, &stack_end, &tls_begin,
+                            &tls_end, &cache_begin, &cache_end, &dtls);
+  if (!thread_found) {
+    // If a thread can't be found in the thread registry, it's probably in the
+    // process of destruction. Log this event and move on.
+    LOG_THREADS("Thread %llu not found in registry.\n", os_id);
+    return;
+  }
+
+  if (!sp)
+    sp = stack_begin;
+
+  if (flags()->use_registers) {
+    uptr registers_begin = reinterpret_cast<uptr>(registers.data());
+    uptr registers_end =
+        reinterpret_cast<uptr>(registers.data() + registers.size());
+    ScanForPointers(registers_begin, registers_end, frontier, "REGISTERS",
+                    kReachable, accessor);
+  }
+
+  if (flags()->use_stacks) {
+    LOG_THREADS("Stack at %p-%p (SP = %p).\n", (void *)stack_begin,
+                (void *)stack_end, (void *)sp);
+    if (sp < stack_begin || sp >= stack_end) {
+      // SP is outside the recorded stack range (e.g. the thread is running a
+      // signal handler on alternate stack, or swapcontext was used).
+      // Again, consider the entire stack range to be reachable.
+      LOG_THREADS("WARNING: stack pointer not in stack range.\n");
+      uptr page_size = GetPageSizeCached();
+      int skipped = 0;
+      while (stack_begin < stack_end &&
+             !IsAccessibleMemoryRange(stack_begin, 1)) {
+        skipped++;
+        stack_begin += page_size;
+      }
+      LOG_THREADS("Skipped %d guard page(s) to obtain stack %p-%p.\n", skipped,
+                  (void *)stack_begin, (void *)stack_end);
+    } else {
+      // Shrink the stack range to ignore out-of-scope values.
+      stack_begin = sp;
+    }
+    ScanForPointers(stack_begin, stack_end, frontier, "STACK", kReachable,
+                    accessor);
+    GetThreadExtraStackRangesLocked(os_id, &extra_ranges);
+    ScanRanges(extra_ranges, frontier, "FAKE STACK", accessor);
+  }
+
+  if (flags()->use_tls) {
+    if (tls_begin) {
+      LOG_THREADS("TLS at %p-%p.\n", (void *)tls_begin, (void *)tls_end);
+      // If the tls and cache ranges don't overlap, scan full tls range,
+      // otherwise, only scan the non-overlapping portions
+      if (cache_begin == cache_end || tls_end < cache_begin ||
+          tls_begin > cache_end) {
+        ScanForPointers(tls_begin, tls_end, frontier, "TLS", kReachable,
+                        accessor);
+      } else {
+        if (tls_begin < cache_begin)
+          ScanForPointers(tls_begin, cache_begin, frontier, "TLS", kReachable,
+                          accessor);
+        if (tls_end > cache_end)
+          ScanForPointers(cache_end, tls_end, frontier, "TLS", kReachable,
+                          accessor);
+      }
+    }
+#    if SANITIZER_ANDROID
+    extra_ranges.clear();
+    auto *cb = +[](void *dtls_begin, void *dtls_end, uptr /*dso_idd*/,
+                   void *arg) -> void {
+      reinterpret_cast<InternalMmapVector<Range> *>(arg)->push_back(
+          {reinterpret_cast<uptr>(dtls_begin),
+           reinterpret_cast<uptr>(dtls_end)});
+    };
+    ScanRanges(extra_ranges, frontier, "DTLS", accessor);
+    // FIXME: There might be a race-condition here (and in Bionic) if the
+    // thread is suspended in the middle of updating its DTLS. IOWs, we
+    // could scan already freed memory. (probably fine for now)
+    __libc_iterate_dynamic_tls(os_id, cb, frontier);
+#    else
+    if (dtls && !DTLSInDestruction(dtls)) {
+      ForEachDVT(dtls, [&](const DTLS::DTV &dtv, int id) {
+        uptr dtls_beg = dtv.beg;
+        uptr dtls_end = dtls_beg + dtv.size;
+        if (dtls_beg < dtls_end) {
+          LOG_THREADS("DTLS %d at %p-%p.\n", id, (void *)dtls_beg,
+                      (void *)dtls_end);
+          ScanForPointers(dtls_beg, dtls_end, frontier, "DTLS", kReachable,
+                          accessor);
+        }
+      });
+    } else {
+      // We are handling a thread with DTLS under destruction. Log about
+      // this and continue.
+      LOG_THREADS("Thread %llu has DTLS under destruction.\n", os_id);
+    }
+#    endif
+  }
+}
+
 static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
                            Frontier *frontier, tid_t caller_tid,
                            uptr caller_sp) {
+  InternalMmapVector<tid_t> done_threads;
   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);
-    uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end;
-    DTLS *dtls;
-    bool thread_found =
-        GetThreadRangesLocked(os_id, &stack_begin, &stack_end, &tls_begin,
-                              &tls_end, &cache_begin, &cache_end, &dtls);
-    if (!thread_found) {
-      // If a thread can't be found in the thread registry, it's probably in the
-      // process of destruction. Log this event and move on.
-      LOG_THREADS("Thread %llu not found in registry.\n", os_id);
-      continue;
-    }
-    uptr sp;
+    registers.clear();
+    extra_ranges.clear();
+
+    const tid_t os_id = suspended_threads.GetThreadID(i);
+    uptr sp = 0;
     PtraceRegistersStatus have_registers =
         suspended_threads.GetRegistersAndSP(i, &registers, &sp);
     if (have_registers != REGISTERS_AVAILABLE) {
@@ -423,96 +574,32 @@  static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
       // GetRegistersAndSP failed with ESRCH.
       if (have_registers == REGISTERS_UNAVAILABLE_FATAL)
         continue;
-      sp = stack_begin;
+      sp = 0;
     }
-    if (suspended_threads.GetThreadID(i) == caller_tid) {
+
+    if (os_id == caller_tid)
       sp = caller_sp;
-    }
 
-    if (flags()->use_registers && have_registers) {
-      uptr registers_begin = reinterpret_cast<uptr>(registers.data());
-      uptr registers_end =
-          reinterpret_cast<uptr>(registers.data() + registers.size());
-      ScanRangeForPointers(registers_begin, registers_end, frontier,
-                           "REGISTERS", kReachable);
-    }
+    DirectMemoryAccessor accessor;
+    ProcessThread(os_id, sp, registers, extra_ranges, frontier, accessor);
+    if (flags()->use_detached)
+      done_threads.push_back(os_id);
+  }
 
-    if (flags()->use_stacks) {
-      LOG_THREADS("Stack at %p-%p (SP = %p).\n", (void *)stack_begin,
-                  (void *)stack_end, (void *)sp);
-      if (sp < stack_begin || sp >= stack_end) {
-        // SP is outside the recorded stack range (e.g. the thread is running a
-        // signal handler on alternate stack, or swapcontext was used).
-        // Again, consider the entire stack range to be reachable.
-        LOG_THREADS("WARNING: stack pointer not in stack range.\n");
-        uptr page_size = GetPageSizeCached();
-        int skipped = 0;
-        while (stack_begin < stack_end &&
-               !IsAccessibleMemoryRange(stack_begin, 1)) {
-          skipped++;
-          stack_begin += page_size;
-        }
-        LOG_THREADS("Skipped %d guard page(s) to obtain stack %p-%p.\n",
-                    skipped, (void *)stack_begin, (void *)stack_end);
-      } else {
-        // Shrink the stack range to ignore out-of-scope values.
-        stack_begin = sp;
-      }
-      ScanRangeForPointers(stack_begin, stack_end, frontier, "STACK",
-                           kReachable);
+  if (flags()->use_detached) {
+    CopyMemoryAccessor accessor;
+    InternalMmapVector<tid_t> known_threads;
+    GetRunningThreadsLocked(&known_threads);
+    Sort(done_threads.data(), done_threads.size());
+    for (tid_t os_id : known_threads) {
+      registers.clear();
       extra_ranges.clear();
-      GetThreadExtraStackRangesLocked(os_id, &extra_ranges);
-      ScanExtraStackRanges(extra_ranges, frontier);
-    }
 
-    if (flags()->use_tls) {
-      if (tls_begin) {
-        LOG_THREADS("TLS at %p-%p.\n", (void *)tls_begin, (void *)tls_end);
-        // If the tls and cache ranges don't overlap, scan full tls range,
-        // otherwise, only scan the non-overlapping portions
-        if (cache_begin == cache_end || tls_end < cache_begin ||
-            tls_begin > cache_end) {
-          ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable);
-        } else {
-          if (tls_begin < cache_begin)
-            ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS",
-                                 kReachable);
-          if (tls_end > cache_end)
-            ScanRangeForPointers(cache_end, tls_end, frontier, "TLS",
-                                 kReachable);
-        }
-      }
-#    if SANITIZER_ANDROID
-      auto *cb = +[](void *dtls_begin, void *dtls_end, uptr /*dso_idd*/,
-                     void *arg) -> void {
-        ScanRangeForPointers(reinterpret_cast<uptr>(dtls_begin),
-                             reinterpret_cast<uptr>(dtls_end),
-                             reinterpret_cast<Frontier *>(arg), "DTLS",
-                             kReachable);
-      };
-
-      // FIXME: There might be a race-condition here (and in Bionic) if the
-      // thread is suspended in the middle of updating its DTLS. IOWs, we
-      // could scan already freed memory. (probably fine for now)
-      __libc_iterate_dynamic_tls(os_id, cb, frontier);
-#    else
-      if (dtls && !DTLSInDestruction(dtls)) {
-        ForEachDVT(dtls, [&](const DTLS::DTV &dtv, int id) {
-          uptr dtls_beg = dtv.beg;
-          uptr dtls_end = dtls_beg + dtv.size;
-          if (dtls_beg < dtls_end) {
-            LOG_THREADS("DTLS %d at %p-%p.\n", id, (void *)dtls_beg,
-                        (void *)dtls_end);
-            ScanRangeForPointers(dtls_beg, dtls_end, frontier, "DTLS",
-                                 kReachable);
-          }
-        });
-      } else {
-        // We are handling a thread with DTLS under destruction. Log about
-        // this and continue.
-        LOG_THREADS("Thread %llu has DTLS under destruction.\n", os_id);
+      uptr i = InternalLowerBound(done_threads, os_id);
+      if (i >= done_threads.size() || done_threads[i] != os_id) {
+        uptr sp = (os_id == caller_tid) ? caller_sp : 0;
+        ProcessThread(os_id, sp, registers, extra_ranges, frontier, accessor);
       }
-#    endif
     }
   }
 
@@ -694,11 +781,13 @@  void LeakSuppressionContext::PrintMatchedSuppressions() {
 
 // Fuchsia provides a libc interface that guarantees all threads are
 // covered, and SuspendedThreadList is never really used.
-static void ReportUnsuspendedThreads(const SuspendedThreadsList &) {}
+static bool ReportUnsuspendedThreads(const SuspendedThreadsList &) {
+  return true;
+}
 
 #  else  // !SANITIZER_FUCHSIA
 
-static void ReportUnsuspendedThreads(
+static bool ReportUnsuspendedThreads(
     const SuspendedThreadsList &suspended_threads) {
   InternalMmapVector<tid_t> threads(suspended_threads.ThreadCount());
   for (uptr i = 0; i < suspended_threads.ThreadCount(); ++i)
@@ -706,16 +795,20 @@  static void ReportUnsuspendedThreads(
 
   Sort(threads.data(), threads.size());
 
-  InternalMmapVector<tid_t> unsuspended;
-  GetRunningThreadsLocked(&unsuspended);
+  InternalMmapVector<tid_t> known_threads;
+  GetRunningThreadsLocked(&known_threads);
 
-  for (auto os_id : unsuspended) {
+  bool succeded = true;
+  for (auto os_id : known_threads) {
     uptr i = InternalLowerBound(threads, os_id);
-    if (i >= threads.size() || threads[i] != os_id)
+    if (i >= threads.size() || threads[i] != os_id) {
+      succeded = false;
       Report(
           "Running thread %zu was not suspended. False leaks are possible.\n",
           os_id);
+    }
   }
+  return succeded;
 }
 
 #  endif  // !SANITIZER_FUCHSIA
@@ -725,7 +818,18 @@  static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads,
   CheckForLeaksParam *param = reinterpret_cast<CheckForLeaksParam *>(arg);
   CHECK(param);
   CHECK(!param->success);
-  ReportUnsuspendedThreads(suspended_threads);
+  if (!ReportUnsuspendedThreads(suspended_threads)) {
+    switch (flags()->thread_suspend_fail) {
+      case 0:
+        param->success = true;
+        return;
+      case 1:
+        break;
+      case 2:
+        // Will crash on return.
+        return;
+    }
+  }
   ClassifyAllChunks(suspended_threads, &param->frontier, param->caller_tid,
                     param->caller_sp);
   ForEachChunk(CollectLeaksCb, &param->leaks);
@@ -750,19 +854,20 @@  static bool PrintResults(LeakReport &report) {
   }
   if (common_flags()->print_suppressions)
     GetSuppressionContext()->PrintMatchedSuppressions();
-  if (unsuppressed_count > 0) {
+  if (unsuppressed_count)
     report.PrintSummary();
-    return true;
-  }
-  return false;
+  if ((unsuppressed_count && common_flags()->verbosity >= 2) ||
+      flags()->log_threads)
+    PrintThreads();
+  return unsuppressed_count;
 }
 
-static bool CheckForLeaks() {
+static bool CheckForLeaksOnce() {
   if (&__lsan_is_turned_off && __lsan_is_turned_off()) {
-    VReport(1, "LeakSanitizer is disabled");
+    VReport(1, "LeakSanitizer is disabled\n");
     return false;
   }
-  VReport(1, "LeakSanitizer: checking for leaks");
+  VReport(1, "LeakSanitizer: checking for leaks\n");
   // 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.
@@ -809,6 +914,12 @@  static bool CheckForLeaks() {
   }
 }
 
+static bool CheckForLeaks() {
+  int leaking_tries = 0;
+  for (int i = 0; i < flags()->tries; ++i) leaking_tries += CheckForLeaksOnce();
+  return leaking_tries == flags()->tries;
+}
+
 static bool has_reported_leaks = false;
 bool HasReportedLeaks() { return has_reported_leaks; }
 
diff --git a/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h
index d3e768363e93..f990c7850497 100644
--- a/libsanitizer/lsan/lsan_common.h
+++ b/libsanitizer/lsan/lsan_common.h
@@ -111,6 +111,7 @@  void GetThreadExtraStackRangesLocked(tid_t os_id,
                                      InternalMmapVector<Range> *ranges);
 void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs);
 void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads);
+void PrintThreads();
 
 //// --------------------------------------------------------------------------
 //// Allocator prototypes.
@@ -120,6 +121,10 @@  void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads);
 void LockAllocator();
 void UnlockAllocator();
 
+// Lock/unlock global mutext.
+void LockGlobal();
+void UnlockGlobal();
+
 // 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
diff --git a/libsanitizer/lsan/lsan_common_linux.cpp b/libsanitizer/lsan/lsan_common_linux.cpp
index 692ad35169e1..7a0b2f038be0 100644
--- a/libsanitizer/lsan/lsan_common_linux.cpp
+++ b/libsanitizer/lsan/lsan_common_linux.cpp
@@ -28,7 +28,7 @@  namespace __lsan {
 
 static const char kLinkerName[] = "ld";
 
-static char linker_placeholder[sizeof(LoadedModule)] ALIGNED(64);
+alignas(64) static char linker_placeholder[sizeof(LoadedModule)];
 static LoadedModule *linker = nullptr;
 
 static bool IsLinker(const LoadedModule& module) {
diff --git a/libsanitizer/lsan/lsan_flags.inc b/libsanitizer/lsan/lsan_flags.inc
index 9350f4bcdc34..e0b4aa4a3299 100644
--- a/libsanitizer/lsan/lsan_flags.inc
+++ b/libsanitizer/lsan/lsan_flags.inc
@@ -41,6 +41,13 @@  LSAN_FLAG(bool, use_ld_allocations, true,
 LSAN_FLAG(bool, use_unaligned, false, "Consider unaligned pointers valid.")
 LSAN_FLAG(bool, use_poisoned, false,
           "Consider pointers found in poisoned memory to be valid.")
+LSAN_FLAG(bool, use_detached, false,
+          "Scan threads even if attaching to them failed.")
 LSAN_FLAG(bool, log_pointers, false, "Debug logging")
 LSAN_FLAG(bool, log_threads, false, "Debug logging")
+LSAN_FLAG(int, tries, 1, "Debug option to repeat leak checking multiple times")
 LSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
+LSAN_FLAG(int, thread_suspend_fail, 1,
+          "Behaviour if thread suspendion all thread (0 - "
+          "abandon leak checking, 1 - continue with leak checking (reported "
+          "leaks can be false), 2 - crash (for debugging LSAN)).")
\ No newline at end of file
diff --git a/libsanitizer/lsan/lsan_fuchsia.cpp b/libsanitizer/lsan/lsan_fuchsia.cpp
index 4edac9757a9c..ba59bc9b71e3 100644
--- a/libsanitizer/lsan/lsan_fuchsia.cpp
+++ b/libsanitizer/lsan/lsan_fuchsia.cpp
@@ -80,6 +80,7 @@  void GetAllThreadAllocatorCachesLocked(InternalMmapVector<uptr> *caches) {
 // On Fuchsia, leak detection is done by a special hook after atexit hooks.
 // So this doesn't install any atexit hook like on other platforms.
 void InstallAtExitCheckLeaks() {}
+void InstallAtForkHandler() {}
 
 // ASan defines this to check its `halt_on_error` flag.
 bool UseExitcodeOnLeak() { return true; }
diff --git a/libsanitizer/lsan/lsan_interceptors.cpp b/libsanitizer/lsan/lsan_interceptors.cpp
index 885f7ad5ddba..a8252cddacf2 100644
--- a/libsanitizer/lsan/lsan_interceptors.cpp
+++ b/libsanitizer/lsan/lsan_interceptors.cpp
@@ -26,7 +26,6 @@ 
 #if SANITIZER_POSIX
 #include "sanitizer_common/sanitizer_posix.h"
 #endif
-#include "sanitizer_common/sanitizer_tls_get_addr.h"
 #include "lsan.h"
 #include "lsan_allocator.h"
 #include "lsan_common.h"
@@ -77,6 +76,8 @@  INTERCEPTOR(void*, malloc, uptr size) {
 }
 
 INTERCEPTOR(void, free, void *p) {
+  if (UNLIKELY(!p))
+    return;
   if (DlsymAlloc::PointerIsMine(p))
     return DlsymAlloc::Free(p);
   ENSURE_LSAN_INITED;
@@ -133,9 +134,7 @@  INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
 INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {
   ENSURE_LSAN_INITED;
   GET_STACK_TRACE_MALLOC;
-  void *res = lsan_memalign(alignment, size, stack);
-  DTLS_on_libc_memalign(res, size);
-  return res;
+  return lsan_memalign(alignment, size, stack);
 }
 #define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN INTERCEPT_FUNCTION(__libc_memalign)
 #else
@@ -389,7 +388,7 @@  INTERCEPTOR(int, atexit, void (*f)()) {
 extern "C" {
 extern int _pthread_atfork(void (*prepare)(), void (*parent)(),
                            void (*child)());
-};
+}
 
 INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
             void (*child)()) {
@@ -525,7 +524,7 @@  INTERCEPTOR(int, pthread_timedjoin_np, void *thread, void **ret,
 #    define LSAN_MAYBE_INTERCEPT_TIMEDJOIN
 #  endif  // SANITIZER_INTERCEPT_TIMEDJOIN
 
-DEFINE_REAL_PTHREAD_FUNCTIONS
+DEFINE_INTERNAL_PTHREAD_FUNCTIONS
 
 INTERCEPTOR(void, _exit, int status) {
   if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode;
@@ -543,6 +542,7 @@  namespace __lsan {
 void InitializeInterceptors() {
   // Fuchsia doesn't use interceptors that require any setup.
 #if !SANITIZER_FUCHSIA
+  __interception::DoesNotSupportStaticLinking();
   InitializeSignalInterceptors();
 
   INTERCEPT_FUNCTION(malloc);
diff --git a/libsanitizer/lsan/lsan_posix.cpp b/libsanitizer/lsan/lsan_posix.cpp
index d99e1cc0105e..593000b9eef9 100644
--- a/libsanitizer/lsan/lsan_posix.cpp
+++ b/libsanitizer/lsan/lsan_posix.cpp
@@ -14,11 +14,13 @@ 
 #include "sanitizer_common/sanitizer_platform.h"
 
 #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"
+#  include <pthread.h>
+
+#  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"
 
 namespace __lsan {
 
@@ -48,12 +50,8 @@  void ThreadContext::OnStarted(void *arg) {
 
 void ThreadStart(u32 tid, tid_t os_id, ThreadType thread_type) {
   OnStartedArgs args;
-  uptr stack_size = 0;
-  uptr tls_size = 0;
-  GetThreadStackAndTls(tid == kMainTid, &args.stack_begin, &stack_size,
-                       &args.tls_begin, &tls_size);
-  args.stack_end = args.stack_begin + stack_size;
-  args.tls_end = args.tls_begin + tls_size;
+  GetThreadStackAndTls(tid == kMainTid, &args.stack_begin, &args.stack_end,
+                       &args.tls_begin, &args.tls_end);
   GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
   args.dtls = DTLS_Get();
   ThreadContextLsanBase::ThreadStart(tid, os_id, thread_type, &args);
@@ -98,6 +96,31 @@  void InstallAtExitCheckLeaks() {
     Atexit(DoLeakCheck);
 }
 
+static void BeforeFork() {
+  VReport(2, "BeforeFork tid: %llu\n", GetTid());
+  LockGlobal();
+  LockThreads();
+  LockAllocator();
+  StackDepotLockBeforeFork();
+}
+
+static void AfterFork(bool fork_child) {
+  StackDepotUnlockAfterFork(fork_child);
+  UnlockAllocator();
+  UnlockThreads();
+  UnlockGlobal();
+  VReport(2, "AfterFork tid: %llu\n", GetTid());
+}
+
+void InstallAtForkHandler() {
+#  if SANITIZER_SOLARIS || SANITIZER_NETBSD || SANITIZER_APPLE
+  return;  // FIXME: Implement FutexWait.
+#  endif
+  pthread_atfork(
+      &BeforeFork, []() { AfterFork(/* fork_child= */ false); },
+      []() { AfterFork(/* fork_child= */ true); });
+}
+
 }  // namespace __lsan
 
 #endif  // SANITIZER_POSIX
diff --git a/libsanitizer/lsan/lsan_preinit.cpp b/libsanitizer/lsan/lsan_preinit.cpp
index cd94e1e8718e..30e90f728649 100644
--- a/libsanitizer/lsan/lsan_preinit.cpp
+++ b/libsanitizer/lsan/lsan_preinit.cpp
@@ -14,8 +14,8 @@ 
 #include "lsan.h"
 
 #if SANITIZER_CAN_USE_PREINIT_ARRAY
-  // We force __lsan_init to be called before anyone else by placing it into
-  // .preinit_array section.
-  __attribute__((section(".preinit_array"), used))
-  void (*__local_lsan_preinit)(void) = __lsan_init;
+// This section is linked into the main executable when -fsanitize=leak is
+// specified to perform initialization at a very early stage.
+__attribute__((section(".preinit_array"), used)) static auto preinit =
+    __lsan_init;
 #endif
diff --git a/libsanitizer/lsan/lsan_thread.cpp b/libsanitizer/lsan/lsan_thread.cpp
index 8aa3111eecf7..b66ea61a2de4 100644
--- a/libsanitizer/lsan/lsan_thread.cpp
+++ b/libsanitizer/lsan/lsan_thread.cpp
@@ -18,6 +18,7 @@ 
 #include "lsan_common.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_thread_history.h"
 #include "sanitizer_common/sanitizer_thread_registry.h"
 #include "sanitizer_common/sanitizer_tls_get_addr.h"
 
@@ -35,12 +36,12 @@  static ThreadContextBase *CreateThreadContext(u32 tid) {
 }
 
 void InitializeThreads() {
-  static ALIGNED(alignof(
-      ThreadRegistry)) char thread_registry_placeholder[sizeof(ThreadRegistry)];
+  alignas(alignof(ThreadRegistry)) static char
+      thread_registry_placeholder[sizeof(ThreadRegistry)];
   thread_registry =
       new (thread_registry_placeholder) ThreadRegistry(CreateThreadContext);
 
-  static ALIGNED(alignof(ThreadArgRetval)) char
+  alignas(alignof(ThreadArgRetval)) static char
       thread_arg_retval_placeholder[sizeof(ThreadArgRetval)];
   thread_arg_retval = new (thread_arg_retval_placeholder) ThreadArgRetval();
 }
@@ -109,6 +110,12 @@  void GetRunningThreadsLocked(InternalMmapVector<tid_t> *threads) {
       threads);
 }
 
+void PrintThreads() {
+  InternalScopedString out;
+  PrintThreadHistory(*thread_registry, out);
+  Report("%s\n", out.data());
+}
+
 void GetAdditionalThreadContextPtrsLocked(InternalMmapVector<uptr> *ptrs) {
   GetThreadArgRetval().GetAllPtrsLocked(ptrs);
 }
diff --git a/libsanitizer/sanitizer_common/Makefile.am b/libsanitizer/sanitizer_common/Makefile.am
index 9ed6ef88775a..d3445d802027 100644
--- a/libsanitizer/sanitizer_common/Makefile.am
+++ b/libsanitizer/sanitizer_common/Makefile.am
@@ -47,7 +47,6 @@  sanitizer_common_files = \
 	sanitizer_netbsd.cpp \
 	sanitizer_platform_limits_freebsd.cpp \
 	sanitizer_platform_limits_linux.cpp \
-	sanitizer_platform_limits_openbsd.cpp \
 	sanitizer_platform_limits_posix.cpp \
 	sanitizer_platform_limits_solaris.cpp \
 	sanitizer_posix.cpp \
@@ -74,15 +73,18 @@  sanitizer_common_files = \
 	sanitizer_symbolizer.cpp \
 	sanitizer_symbolizer_libbacktrace.cpp \
 	sanitizer_symbolizer_libcdep.cpp \
+	sanitizer_symbolizer_markup.cpp \
 	sanitizer_symbolizer_posix_libcdep.cpp \
 	sanitizer_symbolizer_win.cpp \
 	sanitizer_termination.cpp \
 	sanitizer_thread_arg_retval.cpp \
+	sanitizer_thread_history.cpp \
 	sanitizer_thread_registry.cpp \
 	sanitizer_tls_get_addr.cpp \
 	sanitizer_unwind_linux_libcdep.cpp \
 	sanitizer_unwind_win.cpp \
-	sanitizer_win.cpp
+	sanitizer_win.cpp \
+	sanitizer_win_interception.cpp
 
 
 libsanitizer_common_la_SOURCES = $(sanitizer_common_files) 
diff --git a/libsanitizer/sanitizer_common/Makefile.in b/libsanitizer/sanitizer_common/Makefile.in
index 31fff8236fee..df7a25491296 100644
--- a/libsanitizer/sanitizer_common/Makefile.in
+++ b/libsanitizer/sanitizer_common/Makefile.in
@@ -133,7 +133,6 @@  am__objects_1 = sancov_flags.lo sanitizer_allocator.lo \
 	sanitizer_mac.lo sanitizer_mac_libcdep.lo sanitizer_mutex.lo \
 	sanitizer_netbsd.lo sanitizer_platform_limits_freebsd.lo \
 	sanitizer_platform_limits_linux.lo \
-	sanitizer_platform_limits_openbsd.lo \
 	sanitizer_platform_limits_posix.lo \
 	sanitizer_platform_limits_solaris.lo sanitizer_posix.lo \
 	sanitizer_posix_libcdep.lo sanitizer_printf.lo \
@@ -148,12 +147,13 @@  am__objects_1 = sancov_flags.lo sanitizer_allocator.lo \
 	sanitizer_stoptheworld_linux_libcdep.lo \
 	sanitizer_stoptheworld_mac.lo sanitizer_suppressions.lo \
 	sanitizer_symbolizer.lo sanitizer_symbolizer_libbacktrace.lo \
-	sanitizer_symbolizer_libcdep.lo \
+	sanitizer_symbolizer_libcdep.lo sanitizer_symbolizer_markup.lo \
 	sanitizer_symbolizer_posix_libcdep.lo \
 	sanitizer_symbolizer_win.lo sanitizer_termination.lo \
-	sanitizer_thread_arg_retval.lo sanitizer_thread_registry.lo \
-	sanitizer_tls_get_addr.lo sanitizer_unwind_linux_libcdep.lo \
-	sanitizer_unwind_win.lo sanitizer_win.lo
+	sanitizer_thread_arg_retval.lo sanitizer_thread_history.lo \
+	sanitizer_thread_registry.lo sanitizer_tls_get_addr.lo \
+	sanitizer_unwind_linux_libcdep.lo sanitizer_unwind_win.lo \
+	sanitizer_win.lo sanitizer_win_interception.lo
 am_libsanitizer_common_la_OBJECTS = $(am__objects_1)
 libsanitizer_common_la_OBJECTS = $(am_libsanitizer_common_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
@@ -409,7 +409,6 @@  sanitizer_common_files = \
 	sanitizer_netbsd.cpp \
 	sanitizer_platform_limits_freebsd.cpp \
 	sanitizer_platform_limits_linux.cpp \
-	sanitizer_platform_limits_openbsd.cpp \
 	sanitizer_platform_limits_posix.cpp \
 	sanitizer_platform_limits_solaris.cpp \
 	sanitizer_posix.cpp \
@@ -436,15 +435,18 @@  sanitizer_common_files = \
 	sanitizer_symbolizer.cpp \
 	sanitizer_symbolizer_libbacktrace.cpp \
 	sanitizer_symbolizer_libcdep.cpp \
+	sanitizer_symbolizer_markup.cpp \
 	sanitizer_symbolizer_posix_libcdep.cpp \
 	sanitizer_symbolizer_win.cpp \
 	sanitizer_termination.cpp \
 	sanitizer_thread_arg_retval.cpp \
+	sanitizer_thread_history.cpp \
 	sanitizer_thread_registry.cpp \
 	sanitizer_tls_get_addr.cpp \
 	sanitizer_unwind_linux_libcdep.cpp \
 	sanitizer_unwind_win.cpp \
-	sanitizer_win.cpp
+	sanitizer_win.cpp \
+	sanitizer_win_interception.cpp
 
 libsanitizer_common_la_SOURCES = $(sanitizer_common_files) 
 libsanitizer_common_la_LIBADD = $(SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS)
@@ -568,7 +570,6 @@  distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_netbsd.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_platform_limits_freebsd.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_platform_limits_linux.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_platform_limits_openbsd.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_platform_limits_posix.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_platform_limits_solaris.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_posix.Plo@am__quote@
@@ -594,16 +595,19 @@  distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_libbacktrace.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_libcdep.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_mac.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_markup.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_posix_libcdep.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_report.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_win.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_termination.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_thread_arg_retval.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_thread_history.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_thread_registry.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_tls_get_addr.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_unwind_linux_libcdep.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_unwind_win.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_win.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_win_interception.Plo@am__quote@
 
 .cpp.o:
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
diff --git a/libsanitizer/sanitizer_common/sancov_flags.cpp b/libsanitizer/sanitizer_common/sancov_flags.cpp
index ed46e88acdfc..43b4bcc76729 100644
--- a/libsanitizer/sanitizer_common/sancov_flags.cpp
+++ b/libsanitizer/sanitizer_common/sancov_flags.cpp
@@ -37,10 +37,6 @@  static void RegisterSancovFlags(FlagParser *parser, SancovFlags *f) {
 #undef SANCOV_FLAG
 }
 
-static const char *MaybeCallSancovDefaultOptions() {
-  return (&__sancov_default_options) ? __sancov_default_options() : "";
-}
-
 void InitializeSancovFlags() {
   SancovFlags *f = sancov_flags();
   f->SetDefaults();
@@ -48,7 +44,7 @@  void InitializeSancovFlags() {
   FlagParser parser;
   RegisterSancovFlags(&parser, f);
 
-  parser.ParseString(MaybeCallSancovDefaultOptions());
+  parser.ParseString(__sancov_default_options());
   parser.ParseStringFromEnv("SANCOV_OPTIONS");
 
   ReportUnrecognizedFlags();
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.cpp b/libsanitizer/sanitizer_common/sanitizer_allocator.cpp
index 0513ae36fbc7..9d899371c2dd 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator.cpp
@@ -25,7 +25,7 @@  namespace __sanitizer {
 const char *PrimaryAllocatorName = "SizeClassAllocator";
 const char *SecondaryAllocatorName = "LargeMmapAllocator";
 
-static ALIGNED(64) char internal_alloc_placeholder[sizeof(InternalAllocator)];
+alignas(64) static char internal_alloc_placeholder[sizeof(InternalAllocator)];
 static atomic_uint8_t internal_allocator_initialized;
 static StaticSpinMutex internal_alloc_init_mu;
 
@@ -59,7 +59,7 @@  static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache,
 
 static void *RawInternalRealloc(void *ptr, uptr size,
                                 InternalAllocatorCache *cache) {
-  uptr alignment = 8;
+  constexpr usize alignment = Max<usize>(8, sizeof(void *));
   if (cache == 0) {
     SpinMutexLock l(&internal_allocator_cache_mu);
     return internal_allocator()->Reallocate(&internal_allocator_cache, ptr,
@@ -137,7 +137,8 @@  void InternalAllocatorUnlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
 }
 
 // LowLevelAllocator
-constexpr uptr kLowLevelAllocatorDefaultAlignment = 8;
+constexpr usize kLowLevelAllocatorDefaultAlignment =
+    Max<usize>(8, sizeof(void *));
 constexpr uptr kMinNumPagesRounded = 16;
 constexpr uptr kMinRoundedSize = 65536;
 static uptr low_level_alloc_min_alignment = kLowLevelAllocatorDefaultAlignment;
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_dlsym.h b/libsanitizer/sanitizer_common/sanitizer_allocator_dlsym.h
index 92b1373ef84d..b360478a058a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_dlsym.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_dlsym.h
@@ -15,6 +15,8 @@ 
 #define SANITIZER_ALLOCATOR_DLSYM_H
 
 #include "sanitizer_allocator_internal.h"
+#include "sanitizer_common/sanitizer_allocator_checks.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
 
 namespace __sanitizer {
 
@@ -31,15 +33,15 @@  struct DlSymAllocator {
            UNLIKELY(internal_allocator()->FromPrimary(ptr));
   }
 
-  static void *Allocate(uptr size_in_bytes) {
-    void *ptr = InternalAlloc(size_in_bytes, nullptr, kWordSize);
+  static void *Allocate(uptr size_in_bytes, uptr align = kWordSize) {
+    void *ptr = InternalAlloc(size_in_bytes, nullptr, align);
     CHECK(internal_allocator()->FromPrimary(ptr));
     Details::OnAllocate(ptr,
                         internal_allocator()->GetActuallyAllocatedSize(ptr));
     return ptr;
   }
 
-  static void *Callocate(SIZE_T nmemb, SIZE_T size) {
+  static void *Callocate(usize nmemb, usize size) {
     void *ptr = InternalCalloc(nmemb, size);
     CHECK(internal_allocator()->FromPrimary(ptr));
     Details::OnAllocate(ptr,
@@ -70,6 +72,11 @@  struct DlSymAllocator {
     return new_ptr;
   }
 
+  static void *ReallocArray(void *ptr, uptr count, uptr size) {
+    CHECK(!CheckForCallocOverflow(count, size));
+    return Realloc(ptr, count * size);
+  }
+
   static void OnAllocate(const void *ptr, uptr size) {}
   static void OnFree(const void *ptr, uptr size) {}
 };
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h b/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h
index de2b271fb0ed..d1a33a40bae1 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h
@@ -40,6 +40,8 @@  SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
     void __sanitizer_malloc_hook(void *ptr, uptr size);
 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
     void __sanitizer_free_hook(void *ptr);
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE int
+__sanitizer_ignore_free_hook(void *ptr);
 
 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
 __sanitizer_purge_allocator();
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
index 52fe3fe3d15b..602b197c42ae 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
@@ -278,7 +278,7 @@  class SizeClassAllocator32 {
   static const uptr kRegionSize = 1 << kRegionSizeLog;
   static const uptr kNumPossibleRegions = kSpaceSize / kRegionSize;
 
-  struct ALIGNED(SANITIZER_CACHE_LINE_SIZE) SizeClassInfo {
+  struct alignas(SANITIZER_CACHE_LINE_SIZE) SizeClassInfo {
     StaticSpinMutex mutex;
     IntrusiveList<TransferBatch> free_list;
     u32 rand_state;
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
index d77bc05b7802..0b0bdb07041e 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
@@ -316,13 +316,13 @@  class SizeClassAllocator64 {
     Printf(
         "%s %02zd (%6zd): mapped: %6zdK allocs: %7zd frees: %7zd inuse: %6zd "
         "num_freed_chunks %7zd avail: %6zd rss: %6zdK releases: %6zd "
-        "last released: %6lldK region: 0x%zx\n",
+        "last released: %6lldK region: %p\n",
         region->exhausted ? "F" : " ", class_id, ClassIdToSize(class_id),
         region->mapped_user >> 10, region->stats.n_allocated,
         region->stats.n_freed, in_use, region->num_freed_chunks, avail_chunks,
         rss >> 10, region->rtoi.num_releases,
         region->rtoi.last_released_bytes >> 10,
-        SpaceBeg() + kRegionSize * class_id);
+        (void *)(SpaceBeg() + kRegionSize * class_id));
   }
 
   void PrintStats() {
@@ -639,13 +639,14 @@  class SizeClassAllocator64 {
   static_assert(kRegionSize >= SizeClassMap::kMaxSize,
                 "Region size exceed largest size");
   // kRegionSize must be <= 2^36, see CompactPtrT.
-  COMPILER_CHECK((kRegionSize) <= (1ULL << (SANITIZER_WORDSIZE / 2 + 4)));
+  COMPILER_CHECK((kRegionSize) <=
+                 (1ULL << (sizeof(CompactPtrT) * 8 + kCompactPtrScale)));
   // Call mmap for user memory with at least this size.
-  static const uptr kUserMapSize = 1 << 16;
+  static const uptr kUserMapSize = 1 << 18;
   // Call mmap for metadata memory with at least this size.
   static const uptr kMetaMapSize = 1 << 16;
   // Call mmap for free array memory with at least this size.
-  static const uptr kFreeArrayMapSize = 1 << 16;
+  static const uptr kFreeArrayMapSize = 1 << 18;
 
   atomic_sint32_t release_to_os_interval_ms_;
 
@@ -666,7 +667,7 @@  class SizeClassAllocator64 {
     u64 last_released_bytes;
   };
 
-  struct ALIGNED(SANITIZER_CACHE_LINE_SIZE) RegionInfo {
+  struct alignas(SANITIZER_CACHE_LINE_SIZE) RegionInfo {
     Mutex mutex;
     uptr num_freed_chunks;  // Number of elements in the freearray.
     uptr mapped_free_array;  // Bytes mapped for freearray.
diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic.h b/libsanitizer/sanitizer_common/sanitizer_atomic.h
index 46f06957228c..257c457351db 100644
--- a/libsanitizer/sanitizer_common/sanitizer_atomic.h
+++ b/libsanitizer/sanitizer_common/sanitizer_atomic.h
@@ -18,12 +18,24 @@ 
 namespace __sanitizer {
 
 enum memory_order {
+// If the __atomic atomic builtins are supported (Clang/GCC), use the
+// compiler provided macro values so that we can map the atomic operations
+// to __atomic_* directly.
+#ifdef __ATOMIC_SEQ_CST
+  memory_order_relaxed = __ATOMIC_RELAXED,
+  memory_order_consume = __ATOMIC_CONSUME,
+  memory_order_acquire = __ATOMIC_ACQUIRE,
+  memory_order_release = __ATOMIC_RELEASE,
+  memory_order_acq_rel = __ATOMIC_ACQ_REL,
+  memory_order_seq_cst = __ATOMIC_SEQ_CST
+#else
   memory_order_relaxed = 1 << 0,
   memory_order_consume = 1 << 1,
   memory_order_acquire = 1 << 2,
   memory_order_release = 1 << 3,
   memory_order_acq_rel = 1 << 4,
   memory_order_seq_cst = 1 << 5
+#endif
 };
 
 struct atomic_uint8_t {
@@ -49,7 +61,7 @@  struct atomic_uint32_t {
 struct atomic_uint64_t {
   typedef u64 Type;
   // On 32-bit platforms u64 is not necessary aligned on 8 bytes.
-  volatile ALIGNED(8) Type val_dont_use;
+  alignas(8) volatile Type val_dont_use;
 };
 
 struct atomic_uintptr_t {
diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_clang.h b/libsanitizer/sanitizer_common/sanitizer_atomic_clang.h
index 4318d64d16cf..1414092e38d7 100644
--- a/libsanitizer/sanitizer_common/sanitizer_atomic_clang.h
+++ b/libsanitizer/sanitizer_common/sanitizer_atomic_clang.h
@@ -14,60 +14,63 @@ 
 #ifndef SANITIZER_ATOMIC_CLANG_H
 #define SANITIZER_ATOMIC_CLANG_H
 
-#if defined(__i386__) || defined(__x86_64__)
-# include "sanitizer_atomic_clang_x86.h"
-#else
-# include "sanitizer_atomic_clang_other.h"
-#endif
-
 namespace __sanitizer {
 
-// We would like to just use compiler builtin atomic operations
-// for loads and stores, but they are mostly broken in clang:
-// - they lead to vastly inefficient code generation
-// (http://llvm.org/bugs/show_bug.cgi?id=17281)
-// - 64-bit atomic operations are not implemented on x86_32
-// (http://llvm.org/bugs/show_bug.cgi?id=15034)
-// - they are not implemented on ARM
-// error: undefined reference to '__atomic_load_4'
+// We use the compiler builtin atomic operations for loads and stores, which
+// generates correct code for all architectures, but may require libatomic
+// on platforms where e.g. 64-bit atomics are not supported natively.
 
 // See http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
 // for mappings of the memory model to different processors.
 
-inline void atomic_signal_fence(memory_order) {
+inline void atomic_signal_fence(memory_order mo) { __atomic_signal_fence(mo); }
+
+inline void atomic_thread_fence(memory_order mo) { __atomic_thread_fence(mo); }
+
+inline void proc_yield(int cnt) {
+  __asm__ __volatile__("" ::: "memory");
+#if defined(__i386__) || defined(__x86_64__)
+  for (int i = 0; i < cnt; i++) __asm__ __volatile__("pause");
   __asm__ __volatile__("" ::: "memory");
+#endif
 }
 
-inline void atomic_thread_fence(memory_order) {
-  __sync_synchronize();
+template <typename T>
+inline typename T::Type atomic_load(const volatile T *a, memory_order mo) {
+  DCHECK(mo == memory_order_relaxed || mo == memory_order_consume ||
+         mo == memory_order_acquire || mo == memory_order_seq_cst);
+  DCHECK(!((uptr)a % sizeof(*a)));
+  return __atomic_load_n(&a->val_dont_use, mo);
 }
 
-template<typename T>
-inline typename T::Type atomic_fetch_add(volatile T *a,
-    typename T::Type v, memory_order mo) {
-  (void)mo;
+template <typename T>
+inline void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
+  DCHECK(mo == memory_order_relaxed || mo == memory_order_release ||
+         mo == memory_order_seq_cst);
   DCHECK(!((uptr)a % sizeof(*a)));
-  return __sync_fetch_and_add(&a->val_dont_use, v);
+  __atomic_store_n(&a->val_dont_use, v, mo);
 }
 
-template<typename T>
-inline typename T::Type atomic_fetch_sub(volatile T *a,
-    typename T::Type v, memory_order mo) {
+template <typename T>
+inline typename T::Type atomic_fetch_add(volatile T *a, typename T::Type v,
+                                         memory_order mo) {
+  DCHECK(!((uptr)a % sizeof(*a)));
+  return __atomic_fetch_add(&a->val_dont_use, v, mo);
+}
+
+template <typename T>
+inline typename T::Type atomic_fetch_sub(volatile T *a, typename T::Type v,
+                                         memory_order mo) {
   (void)mo;
   DCHECK(!((uptr)a % sizeof(*a)));
-  return __sync_fetch_and_add(&a->val_dont_use, -v);
+  return __atomic_fetch_sub(&a->val_dont_use, v, mo);
 }
 
-template<typename T>
-inline typename T::Type atomic_exchange(volatile T *a,
-    typename T::Type v, memory_order mo) {
+template <typename T>
+inline typename T::Type atomic_exchange(volatile T *a, typename T::Type v,
+                                        memory_order mo) {
   DCHECK(!((uptr)a % sizeof(*a)));
-  if (mo & (memory_order_release | memory_order_acq_rel | memory_order_seq_cst))
-    __sync_synchronize();
-  v = __sync_lock_test_and_set(&a->val_dont_use, v);
-  if (mo == memory_order_seq_cst)
-    __sync_synchronize();
-  return v;
+  return __atomic_exchange_n(&a->val_dont_use, v, mo);
 }
 
 template <typename T>
@@ -82,9 +85,8 @@  inline bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp,
                                    __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
 }
 
-template<typename T>
-inline bool atomic_compare_exchange_weak(volatile T *a,
-                                         typename T::Type *cmp,
+template <typename T>
+inline bool atomic_compare_exchange_weak(volatile T *a, typename T::Type *cmp,
                                          typename T::Type xchg,
                                          memory_order mo) {
   return atomic_compare_exchange_strong(a, cmp, xchg, mo);
@@ -92,13 +94,6 @@  inline bool atomic_compare_exchange_weak(volatile T *a,
 
 }  // namespace __sanitizer
 
-// This include provides explicit template instantiations for atomic_uint64_t
-// on MIPS32, which does not directly support 8 byte atomics. It has to
-// proceed the template definitions above.
-#if defined(_MIPS_SIM) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
-#  include "sanitizer_atomic_clang_mips.h"
-#endif
-
 #undef ATOMIC_ORDER
 
 #endif  // SANITIZER_ATOMIC_CLANG_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
deleted file mode 100644
index f3d3052e5b7c..000000000000
--- a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_mips.h
+++ /dev/null
@@ -1,117 +0,0 @@ 
-//===-- sanitizer_atomic_clang_mips.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 file is a part of ThreadSanitizer/AddressSanitizer runtime.
-// Not intended for direct inclusion. Include sanitizer_atomic.h.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef SANITIZER_ATOMIC_CLANG_MIPS_H
-#define SANITIZER_ATOMIC_CLANG_MIPS_H
-
-namespace __sanitizer {
-
-// MIPS32 does not support atomics > 4 bytes. To address this lack of
-// functionality, the sanitizer library provides helper methods which use an
-// internal spin lock mechanism to emulate atomic operations when the size is
-// 8 bytes.
-static void __spin_lock(volatile int *lock) {
-  while (__sync_lock_test_and_set(lock, 1))
-    while (*lock) {
-    }
-}
-
-static void __spin_unlock(volatile int *lock) { __sync_lock_release(lock); }
-
-// Make sure the lock is on its own cache line to prevent false sharing.
-// Put it inside a struct that is aligned and padded to the typical MIPS
-// cacheline which is 32 bytes.
-static struct {
-  int lock;
-  char pad[32 - sizeof(int)];
-} __attribute__((aligned(32))) lock = {0, {0}};
-
-template <>
-inline atomic_uint64_t::Type atomic_fetch_add(volatile atomic_uint64_t *ptr,
-                                              atomic_uint64_t::Type val,
-                                              memory_order mo) {
-  DCHECK(mo &
-         (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
-  DCHECK(!((uptr)ptr % sizeof(*ptr)));
-
-  atomic_uint64_t::Type ret;
-
-  __spin_lock(&lock.lock);
-  ret = *(const_cast<atomic_uint64_t::Type volatile *>(&ptr->val_dont_use));
-  ptr->val_dont_use = ret + val;
-  __spin_unlock(&lock.lock);
-
-  return ret;
-}
-
-template <>
-inline atomic_uint64_t::Type atomic_fetch_sub(volatile atomic_uint64_t *ptr,
-                                              atomic_uint64_t::Type val,
-                                              memory_order mo) {
-  return atomic_fetch_add(ptr, -val, mo);
-}
-
-template <>
-inline bool atomic_compare_exchange_strong(volatile atomic_uint64_t *ptr,
-                                           atomic_uint64_t::Type *cmp,
-                                           atomic_uint64_t::Type xchg,
-                                           memory_order mo) {
-  DCHECK(mo &
-         (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
-  DCHECK(!((uptr)ptr % sizeof(*ptr)));
-
-  typedef atomic_uint64_t::Type Type;
-  Type cmpv = *cmp;
-  Type prev;
-  bool ret = false;
-
-  __spin_lock(&lock.lock);
-  prev = *(const_cast<Type volatile *>(&ptr->val_dont_use));
-  if (prev == cmpv) {
-    ret = true;
-    ptr->val_dont_use = xchg;
-  }
-  __spin_unlock(&lock.lock);
-
-  return ret;
-}
-
-template <>
-inline atomic_uint64_t::Type atomic_load(const volatile atomic_uint64_t *ptr,
-                                         memory_order mo) {
-  DCHECK(mo &
-         (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
-  DCHECK(!((uptr)ptr % sizeof(*ptr)));
-
-  atomic_uint64_t::Type zero = 0;
-  volatile atomic_uint64_t *Newptr =
-      const_cast<volatile atomic_uint64_t *>(ptr);
-  return atomic_fetch_add(Newptr, zero, mo);
-}
-
-template <>
-inline void atomic_store(volatile atomic_uint64_t *ptr, atomic_uint64_t::Type v,
-                         memory_order mo) {
-  DCHECK(mo &
-         (memory_order_relaxed | memory_order_release | memory_order_seq_cst));
-  DCHECK(!((uptr)ptr % sizeof(*ptr)));
-
-  __spin_lock(&lock.lock);
-  ptr->val_dont_use = v;
-  __spin_unlock(&lock.lock);
-}
-
-}  // namespace __sanitizer
-
-#endif  // SANITIZER_ATOMIC_CLANG_MIPS_H
-
diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_other.h b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_other.h
deleted file mode 100644
index 4a39889e534a..000000000000
--- a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_other.h
+++ /dev/null
@@ -1,85 +0,0 @@ 
-//===-- sanitizer_atomic_clang_other.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 file is a part of ThreadSanitizer/AddressSanitizer runtime.
-// Not intended for direct inclusion. Include sanitizer_atomic.h.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef SANITIZER_ATOMIC_CLANG_OTHER_H
-#define SANITIZER_ATOMIC_CLANG_OTHER_H
-
-namespace __sanitizer {
-
-
-inline void proc_yield(int cnt) {
-  __asm__ __volatile__("" ::: "memory");
-}
-
-template<typename T>
-inline typename T::Type atomic_load(
-    const volatile T *a, memory_order mo) {
-  DCHECK(mo & (memory_order_relaxed | memory_order_consume
-      | memory_order_acquire | memory_order_seq_cst));
-  DCHECK(!((uptr)a % sizeof(*a)));
-  typename T::Type v;
-
-  if (sizeof(*a) < 8 || sizeof(void*) == 8) {
-    // Assume that aligned loads are atomic.
-    if (mo == memory_order_relaxed) {
-      v = a->val_dont_use;
-    } else if (mo == memory_order_consume) {
-      // Assume that processor respects data dependencies
-      // (and that compiler won't break them).
-      __asm__ __volatile__("" ::: "memory");
-      v = a->val_dont_use;
-      __asm__ __volatile__("" ::: "memory");
-    } else if (mo == memory_order_acquire) {
-      __asm__ __volatile__("" ::: "memory");
-      v = a->val_dont_use;
-      __sync_synchronize();
-    } else {  // seq_cst
-      // E.g. on POWER we need a hw fence even before the store.
-      __sync_synchronize();
-      v = a->val_dont_use;
-      __sync_synchronize();
-    }
-  } else {
-    __atomic_load(const_cast<typename T::Type volatile *>(&a->val_dont_use), &v,
-                  __ATOMIC_SEQ_CST);
-  }
-  return v;
-}
-
-template<typename T>
-inline void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
-  DCHECK(mo & (memory_order_relaxed | memory_order_release
-      | memory_order_seq_cst));
-  DCHECK(!((uptr)a % sizeof(*a)));
-
-  if (sizeof(*a) < 8 || sizeof(void*) == 8) {
-    // Assume that aligned loads are atomic.
-    if (mo == memory_order_relaxed) {
-      a->val_dont_use = v;
-    } else if (mo == memory_order_release) {
-      __sync_synchronize();
-      a->val_dont_use = v;
-      __asm__ __volatile__("" ::: "memory");
-    } else {  // seq_cst
-      __sync_synchronize();
-      a->val_dont_use = v;
-      __sync_synchronize();
-    }
-  } else {
-    __atomic_store(&a->val_dont_use, &v, __ATOMIC_SEQ_CST);
-  }
-}
-
-}  // namespace __sanitizer
-
-#endif  // #ifndef SANITIZER_ATOMIC_CLANG_OTHER_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_x86.h b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_x86.h
deleted file mode 100644
index 51597b492741..000000000000
--- a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_x86.h
+++ /dev/null
@@ -1,113 +0,0 @@ 
-//===-- sanitizer_atomic_clang_x86.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 file is a part of ThreadSanitizer/AddressSanitizer runtime.
-// Not intended for direct inclusion. Include sanitizer_atomic.h.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef SANITIZER_ATOMIC_CLANG_X86_H
-#define SANITIZER_ATOMIC_CLANG_X86_H
-
-namespace __sanitizer {
-
-inline void proc_yield(int cnt) {
-  __asm__ __volatile__("" ::: "memory");
-  for (int i = 0; i < cnt; i++)
-    __asm__ __volatile__("pause");
-  __asm__ __volatile__("" ::: "memory");
-}
-
-template<typename T>
-inline typename T::Type atomic_load(
-    const volatile T *a, memory_order mo) {
-  DCHECK(mo & (memory_order_relaxed | memory_order_consume
-      | memory_order_acquire | memory_order_seq_cst));
-  DCHECK(!((uptr)a % sizeof(*a)));
-  typename T::Type v;
-
-  if (sizeof(*a) < 8 || sizeof(void*) == 8) {
-    // Assume that aligned loads are atomic.
-    if (mo == memory_order_relaxed) {
-      v = a->val_dont_use;
-    } else if (mo == memory_order_consume) {
-      // Assume that processor respects data dependencies
-      // (and that compiler won't break them).
-      __asm__ __volatile__("" ::: "memory");
-      v = a->val_dont_use;
-      __asm__ __volatile__("" ::: "memory");
-    } else if (mo == memory_order_acquire) {
-      __asm__ __volatile__("" ::: "memory");
-      v = a->val_dont_use;
-      // On x86 loads are implicitly acquire.
-      __asm__ __volatile__("" ::: "memory");
-    } else {  // seq_cst
-      // On x86 plain MOV is enough for seq_cst store.
-      __asm__ __volatile__("" ::: "memory");
-      v = a->val_dont_use;
-      __asm__ __volatile__("" ::: "memory");
-    }
-  } else {
-    // 64-bit load on 32-bit platform.
-    __asm__ __volatile__(
-        "movq %1, %%mm0;"  // Use mmx reg for 64-bit atomic moves
-        "movq %%mm0, %0;"  // (ptr could be read-only)
-        "emms;"            // Empty mmx state/Reset FP regs
-        : "=m" (v)
-        : "m" (a->val_dont_use)
-        : // mark the mmx registers as clobbered
-#ifdef __MMX__
-          "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
-#endif  // #ifdef __MMX__
-          "memory");
-  }
-  return v;
-}
-
-template<typename T>
-inline void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
-  DCHECK(mo & (memory_order_relaxed | memory_order_release
-      | memory_order_seq_cst));
-  DCHECK(!((uptr)a % sizeof(*a)));
-
-  if (sizeof(*a) < 8 || sizeof(void*) == 8) {
-    // Assume that aligned loads are atomic.
-    if (mo == memory_order_relaxed) {
-      a->val_dont_use = v;
-    } else if (mo == memory_order_release) {
-      // On x86 stores are implicitly release.
-      __asm__ __volatile__("" ::: "memory");
-      a->val_dont_use = v;
-      __asm__ __volatile__("" ::: "memory");
-    } else {  // seq_cst
-      // On x86 stores are implicitly release.
-      __asm__ __volatile__("" ::: "memory");
-      a->val_dont_use = v;
-      __sync_synchronize();
-    }
-  } else {
-    // 64-bit store on 32-bit platform.
-    __asm__ __volatile__(
-        "movq %1, %%mm0;"  // Use mmx reg for 64-bit atomic moves
-        "movq %%mm0, %0;"
-        "emms;"            // Empty mmx state/Reset FP regs
-        : "=m" (a->val_dont_use)
-        : "m" (v)
-        : // mark the mmx registers as clobbered
-#ifdef __MMX__
-          "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7",
-#endif  // #ifdef __MMX__
-          "memory");
-    if (mo == memory_order_seq_cst)
-      __sync_synchronize();
-  }
-}
-
-}  // namespace __sanitizer
-
-#endif  // #ifndef SANITIZER_ATOMIC_CLANG_X86_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h b/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h
index 31317adcdfc9..d80bfdbf6a08 100644
--- a/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h
+++ b/libsanitizer/sanitizer_common/sanitizer_atomic_msvc.h
@@ -70,8 +70,8 @@  inline void proc_yield(int cnt) {
 template<typename T>
 inline typename T::Type atomic_load(
     const volatile T *a, memory_order mo) {
-  DCHECK(mo & (memory_order_relaxed | memory_order_consume
-      | memory_order_acquire | memory_order_seq_cst));
+  DCHECK(mo == memory_order_relaxed || mo == memory_order_consume ||
+         mo == memory_order_acquire || mo == memory_order_seq_cst);
   DCHECK(!((uptr)a % sizeof(*a)));
   typename T::Type v;
   // FIXME(dvyukov): 64-bit load is not atomic on 32-bits.
@@ -87,8 +87,8 @@  inline typename T::Type atomic_load(
 
 template<typename T>
 inline void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
-  DCHECK(mo & (memory_order_relaxed | memory_order_release
-      | memory_order_seq_cst));
+  DCHECK(mo == memory_order_relaxed || mo == memory_order_release ||
+         mo == memory_order_seq_cst);
   DCHECK(!((uptr)a % sizeof(*a)));
   // FIXME(dvyukov): 64-bit store is not atomic on 32-bits.
   if (mo == memory_order_relaxed) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_bitvector.h b/libsanitizer/sanitizer_common/sanitizer_bitvector.h
index 07a59ab11c42..eef1e7e9d957 100644
--- a/libsanitizer/sanitizer_common/sanitizer_bitvector.h
+++ b/libsanitizer/sanitizer_common/sanitizer_bitvector.h
@@ -321,23 +321,23 @@  class TwoLevelBitVector {
   };
 
  private:
-  void check(uptr idx) const { CHECK_LE(idx, size()); }
+  void check(uptr idx) const { CHECK_LT(idx, size()); }
 
   uptr idx0(uptr idx) const {
     uptr res = idx / (BV::kSize * BV::kSize);
-    CHECK_LE(res, kLevel1Size);
+    CHECK_LT(res, kLevel1Size);
     return res;
   }
 
   uptr idx1(uptr idx) const {
     uptr res = (idx / BV::kSize) % BV::kSize;
-    CHECK_LE(res, BV::kSize);
+    CHECK_LT(res, BV::kSize);
     return res;
   }
 
   uptr idx2(uptr idx) const {
     uptr res = idx % BV::kSize;
-    CHECK_LE(res, BV::kSize);
+    CHECK_LT(res, BV::kSize);
     return res;
   }
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
index e0e2bd01069f..df2b2eb23df2 100644
--- a/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.cpp
@@ -139,9 +139,11 @@  u32 ChainedOriginDepot::Get(u32 id, u32 *other) {
   return desc.here_id;
 }
 
-void ChainedOriginDepot::LockAll() { depot.LockAll(); }
+void ChainedOriginDepot::LockBeforeFork() { depot.LockBeforeFork(); }
 
-void ChainedOriginDepot::UnlockAll() { depot.UnlockAll(); }
+void ChainedOriginDepot::UnlockAfterFork(bool fork_child) {
+  depot.UnlockAfterFork(fork_child);
+}
 
 void ChainedOriginDepot::TestOnlyUnmap() { depot.TestOnlyUnmap(); }
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
index f9f192b68571..f3da28129e6b 100644
--- a/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
+++ b/libsanitizer/sanitizer_common/sanitizer_chained_origin_depot.h
@@ -32,8 +32,8 @@  class ChainedOriginDepot {
   // Retrieves the stored StackDepot ID for the given origin ID.
   u32 Get(u32 id, u32 *other);
 
-  void LockAll();
-  void UnlockAll();
+  void LockBeforeFork();
+  void UnlockAfterFork(bool fork_child);
   void TestOnlyUnmap();
 
  private:
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cpp b/libsanitizer/sanitizer_common/sanitizer_common.cpp
index 5efdd864295b..6cd69a53093e 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_common.cpp
@@ -347,7 +347,13 @@  void RunMallocHooks(void *ptr, uptr size) {
   }
 }
 
-void RunFreeHooks(void *ptr) {
+// Returns '1' if the call to free() should be ignored (based on
+// __sanitizer_ignore_free_hook), or '0' otherwise.
+int RunFreeHooks(void *ptr) {
+  if (__sanitizer_ignore_free_hook(ptr)) {
+    return 1;
+  }
+
   __sanitizer_free_hook(ptr);
   for (int i = 0; i < kMaxMallocFreeHooks; i++) {
     auto hook = MFHooks[i].free_hook;
@@ -355,6 +361,8 @@  void RunFreeHooks(void *ptr) {
       break;
     hook(ptr);
   }
+
+  return 0;
 }
 
 static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr),
@@ -419,4 +427,9 @@  SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook, void *ptr) {
   (void)ptr;
 }
 
+SANITIZER_INTERFACE_WEAK_DEF(int, __sanitizer_ignore_free_hook, void *ptr) {
+  (void)ptr;
+  return 0;
+}
+
 } // extern "C"
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h
index 6b327a4aa16f..0b5e68c5fd79 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.h
+++ b/libsanitizer/sanitizer_common/sanitizer_common.h
@@ -32,6 +32,7 @@  struct AddressInfo;
 struct BufferedStackTrace;
 struct SignalContext;
 struct StackTrace;
+struct SymbolizedStack;
 
 // Constants.
 const uptr kWordSize = SANITIZER_WORDSIZE / 8;
@@ -59,14 +60,10 @@  inline int Verbosity() {
   return atomic_load(&current_verbosity, memory_order_relaxed);
 }
 
-#if SANITIZER_ANDROID
-inline uptr GetPageSize() {
-// Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array.
-  return 4096;
-}
-inline uptr GetPageSizeCached() {
-  return 4096;
-}
+#if SANITIZER_ANDROID && !defined(__aarch64__)
+// 32-bit Android only has 4k pages.
+inline uptr GetPageSize() { return 4096; }
+inline uptr GetPageSizeCached() { return 4096; }
 #else
 uptr GetPageSize();
 extern uptr PageSizeCached;
@@ -76,6 +73,7 @@  inline uptr GetPageSizeCached() {
   return PageSizeCached;
 }
 #endif
+
 uptr GetMmapGranularity();
 uptr GetMaxVirtualAddress();
 uptr GetMaxUserVirtualAddress();
@@ -85,15 +83,16 @@  int TgKill(pid_t pid, tid_t tid, int sig);
 uptr GetThreadSelf();
 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
                                 uptr *stack_bottom);
-void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
-                          uptr *tls_addr, uptr *tls_size);
+void GetThreadStackAndTls(bool main, uptr *stk_begin, uptr *stk_end,
+                          uptr *tls_begin, uptr *tls_end);
 
 // Memory management
 void *MmapOrDie(uptr size, const char *mem_type, bool raw_report = false);
+
 inline void *MmapOrDieQuietly(uptr size, const char *mem_type) {
   return MmapOrDie(size, mem_type, /*raw_report*/ true);
 }
-void UnmapOrDie(void *addr, uptr size);
+void UnmapOrDie(void *addr, uptr size, bool raw_report = false);
 // Behaves just like MmapOrDie, but tolerates out of memory condition, in that
 // case returns nullptr.
 void *MmapOrDieOnFatalError(uptr size, const char *mem_type);
@@ -138,7 +137,8 @@  void UnmapFromTo(uptr from, uptr to);
 // shadow_size_bytes bytes on the right, which on linux is mapped no access.
 // The high_mem_end may be updated if the original shadow size doesn't fit.
 uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
-                      uptr min_shadow_base_alignment, uptr &high_mem_end);
+                      uptr min_shadow_base_alignment, uptr &high_mem_end,
+                      uptr granularity);
 
 // Let S = max(shadow_size, num_aliases * alias_size, ring_buffer_size).
 // Reserves 2*S bytes of address space to the right of the returned address and
@@ -177,7 +177,7 @@  bool DontDumpShadowMemory(uptr addr, uptr length);
 // Check if the built VMA size matches the runtime one.
 void CheckVMASize();
 void RunMallocHooks(void *ptr, uptr size);
-void RunFreeHooks(void *ptr);
+int RunFreeHooks(void *ptr);
 
 class ReservedAddressRange {
  public:
@@ -239,13 +239,15 @@  void RemoveANSIEscapeSequencesFromString(char *buffer);
 void Printf(const char *format, ...) FORMAT(1, 2);
 void Report(const char *format, ...) FORMAT(1, 2);
 void SetPrintfAndReportCallback(void (*callback)(const char *));
-#define VReport(level, ...)                                              \
-  do {                                                                   \
-    if ((uptr)Verbosity() >= (level)) Report(__VA_ARGS__); \
+#define VReport(level, ...)                     \
+  do {                                          \
+    if (UNLIKELY((uptr)Verbosity() >= (level))) \
+      Report(__VA_ARGS__);                      \
   } while (0)
-#define VPrintf(level, ...)                                              \
-  do {                                                                   \
-    if ((uptr)Verbosity() >= (level)) Printf(__VA_ARGS__); \
+#define VPrintf(level, ...)                     \
+  do {                                          \
+    if (UNLIKELY((uptr)Verbosity() >= (level))) \
+      Printf(__VA_ARGS__);                      \
   } while (0)
 
 // Lock sanitizer error reporting and protects against nested errors.
@@ -266,7 +268,15 @@  class ScopedErrorReportLock {
 extern uptr stoptheworld_tracer_pid;
 extern uptr stoptheworld_tracer_ppid;
 
+// Returns true if the entire range can be read.
 bool IsAccessibleMemoryRange(uptr beg, uptr size);
+// Attempts to copy `n` bytes from memory range starting at `src` to `dest`.
+// Returns true if the entire range can be read. Returns `false` if any part of
+// the source range cannot be read, in which case the contents of `dest` are
+// undefined.
+bool TryMemCpy(void *dest, const void *src, uptr n);
+// Copies accessible memory, and zero fill inaccessible.
+void MemCpyAccessible(void *dest, const void *src, uptr n);
 
 // Error report formatting.
 const char *StripPathPrefix(const char *filepath,
@@ -393,6 +403,8 @@  void ReportErrorSummary(const char *error_type, const AddressInfo &info,
 // Same as above, but obtains AddressInfo by symbolizing top stack trace frame.
 void ReportErrorSummary(const char *error_type, const StackTrace *trace,
                         const char *alt_tool_name = nullptr);
+// Skips frames which we consider internal and not usefull to the users.
+const SymbolizedStack *SkipInternalFrames(const SymbolizedStack *frames);
 
 void ReportMmapWriteExec(int prot, int mflags);
 
@@ -507,7 +519,7 @@  inline int ToLower(int c) {
 // A low-level vector based on mmap. May incur a significant memory overhead for
 // small vectors.
 // WARNING: The current implementation supports only POD types.
-template<typename T>
+template <typename T, bool raw_report = false>
 class InternalMmapVectorNoCtor {
  public:
   using value_type = T;
@@ -517,7 +529,7 @@  class InternalMmapVectorNoCtor {
     data_ = 0;
     reserve(initial_capacity);
   }
-  void Destroy() { UnmapOrDie(data_, capacity_bytes_); }
+  void Destroy() { UnmapOrDie(data_, capacity_bytes_, raw_report); }
   T &operator[](uptr i) {
     CHECK_LT(i, size_);
     return data_[i];
@@ -593,9 +605,10 @@  class InternalMmapVectorNoCtor {
     CHECK_LE(size_, new_capacity);
     uptr new_capacity_bytes =
         RoundUpTo(new_capacity * sizeof(T), GetPageSizeCached());
-    T *new_data = (T *)MmapOrDie(new_capacity_bytes, "InternalMmapVector");
+    T *new_data =
+        (T *)MmapOrDie(new_capacity_bytes, "InternalMmapVector", raw_report);
     internal_memcpy(new_data, data_, size_ * sizeof(T));
-    UnmapOrDie(data_, capacity_bytes_);
+    UnmapOrDie(data_, capacity_bytes_, raw_report);
     data_ = new_data;
     capacity_bytes_ = new_capacity_bytes;
   }
@@ -1094,7 +1107,7 @@  inline u32 GetNumberOfCPUsCached() {
 
 }  // namespace __sanitizer
 
-inline void *operator new(__sanitizer::operator_new_size_type size,
+inline void *operator new(__sanitizer::usize size,
                           __sanitizer::LowLevelAllocator &alloc) {
   return alloc.Allocate(size);
 }
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
index 607ecae6808b..b8627f8557af 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
@@ -41,6 +41,7 @@ 
 #include "sanitizer_errno.h"
 #include "sanitizer_placement_new.h"
 #include "sanitizer_platform_interceptors.h"
+#include "sanitizer_platform_limits_posix.h"
 #include "sanitizer_symbolizer.h"
 #include "sanitizer_tls_get_addr.h"
 
@@ -127,6 +128,39 @@  extern const short *_toupper_tab_;
 extern const short *_tolower_tab_;
 #endif
 
+#if SANITIZER_LINUX && SANITIZER_SPARC32
+// On 32-bit Linux/sparc64, double and long double are identical and glibc
+// uses a __nldbl_ (no long double) prefix for various stdio functions.
+#  define __isoc23_fscanf __nldbl___isoc23_fscanf
+#  define __isoc23_scanf __nldbl___isoc23_scanf
+#  define __isoc23_sscanf __nldbl___isoc23_sscanf
+#  define __isoc23_vfscanf __nldbl___isoc23_vfscanf
+#  define __isoc23_vscanf __nldbl___isoc23_vscanf
+#  define __isoc23_vsscanf __nldbl___isoc23_vsscanf
+#  define __isoc99_fscanf __nldbl___isoc99_fscanf
+#  define __isoc99_scanf __nldbl___isoc99_scanf
+#  define __isoc99_sscanf __nldbl___isoc99_sscanf
+#  define __isoc99_vfscanf __nldbl___isoc99_vfscanf
+#  define __isoc99_vscanf __nldbl___isoc99_vscanf
+#  define __isoc99_vsscanf __nldbl___isoc99_vsscanf
+#  define asprintf __nldbl_asprintf
+#  define fprintf __nldbl_fprintf
+#  define fscanf __nldbl_fscanf
+#  define printf __nldbl_printf
+#  define scanf __nldbl_scanf
+#  define snprintf __nldbl_snprintf
+#  define sprintf __nldbl_sprintf
+#  define sscanf __nldbl_sscanf
+#  define vasprintf __nldbl_vasprintf
+#  define vfprintf __nldbl_vfprintf
+#  define vfscanf __nldbl_vfscanf
+#  define vprintf __nldbl_vprintf
+#  define vscanf __nldbl_vscanf
+#  define vsnprintf __nldbl_vsnprintf
+#  define vsprintf __nldbl_vsprintf
+#  define vsscanf __nldbl_vsscanf
+#endif
+
 #if SANITIZER_MUSL && \
   (defined(__i386__) || defined(__arm__) || SANITIZER_MIPS32 || SANITIZER_PPC32)
 // musl 1.2.0 on existing 32-bit architectures uses new symbol names for the
@@ -974,7 +1008,7 @@  INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
   // https://github.com/google/sanitizers/issues/321.
-  SSIZE_T res = REAL(read)(fd, ptr, count);
+  SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(read)(fd, ptr, count);
   if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
   if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
   return res;
@@ -1009,7 +1043,7 @@  INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
   // https://github.com/google/sanitizers/issues/321.
-  SSIZE_T res = REAL(pread)(fd, ptr, count, offset);
+  SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(pread)(fd, ptr, count, offset);
   if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
   if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
   return res;
@@ -1027,7 +1061,7 @@  INTERCEPTOR(SSIZE_T, pread64, int fd, void *ptr, SIZE_T count, OFF64_T offset) {
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
   // https://github.com/google/sanitizers/issues/321.
-  SSIZE_T res = REAL(pread64)(fd, ptr, count, offset);
+  SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(pread64)(fd, ptr, count, offset);
   if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res);
   if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
   return res;
@@ -1043,7 +1077,7 @@  INTERCEPTOR_WITH_SUFFIX(SSIZE_T, readv, int fd, __sanitizer_iovec *iov,
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, readv, fd, iov, iovcnt);
   COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
-  SSIZE_T res = REAL(readv)(fd, iov, iovcnt);
+  SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(readv)(fd, iov, iovcnt);
   if (res > 0) write_iovec(ctx, iov, iovcnt, res);
   if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
   return res;
@@ -1059,7 +1093,7 @@  INTERCEPTOR(SSIZE_T, preadv, int fd, __sanitizer_iovec *iov, int iovcnt,
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, preadv, fd, iov, iovcnt, offset);
   COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
-  SSIZE_T res = REAL(preadv)(fd, iov, iovcnt, offset);
+  SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(preadv)(fd, iov, iovcnt, offset);
   if (res > 0) write_iovec(ctx, iov, iovcnt, res);
   if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
   return res;
@@ -1075,7 +1109,8 @@  INTERCEPTOR(SSIZE_T, preadv64, int fd, __sanitizer_iovec *iov, int iovcnt,
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, preadv64, fd, iov, iovcnt, offset);
   COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
-  SSIZE_T res = REAL(preadv64)(fd, iov, iovcnt, offset);
+  SSIZE_T res =
+      COMMON_INTERCEPTOR_BLOCK_REAL(preadv64)(fd, iov, iovcnt, offset);
   if (res > 0) write_iovec(ctx, iov, iovcnt, res);
   if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
   return res;
@@ -1091,8 +1126,9 @@  INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) {
   COMMON_INTERCEPTOR_ENTER(ctx, write, fd, ptr, count);
   COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
   if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
-  SSIZE_T res = REAL(write)(fd, ptr, count);
-  // FIXME: this check should be _before_ the call to REAL(write), not after
+  SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(write)(fd, ptr, count);
+  // FIXME: this check should be _before_ the call to
+  // COMMON_INTERCEPTOR_BLOCK_REAL(write), not after
   if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
   return res;
 }
@@ -1121,7 +1157,7 @@  INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count, OFF_T offset) {
   COMMON_INTERCEPTOR_ENTER(ctx, pwrite, fd, ptr, count, offset);
   COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
   if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
-  SSIZE_T res = REAL(pwrite)(fd, ptr, count, offset);
+  SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(pwrite)(fd, ptr, count, offset);
   if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
   return res;
 }
@@ -1137,7 +1173,7 @@  INTERCEPTOR(SSIZE_T, pwrite64, int fd, void *ptr, OFF64_T count,
   COMMON_INTERCEPTOR_ENTER(ctx, pwrite64, fd, ptr, count, offset);
   COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
   if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
-  SSIZE_T res = REAL(pwrite64)(fd, ptr, count, offset);
+  SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(pwrite64)(fd, ptr, count, offset);
   if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, ptr, res);
   return res;
 }
@@ -1153,7 +1189,7 @@  INTERCEPTOR_WITH_SUFFIX(SSIZE_T, writev, int fd, __sanitizer_iovec *iov,
   COMMON_INTERCEPTOR_ENTER(ctx, writev, fd, iov, iovcnt);
   COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
   if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
-  SSIZE_T res = REAL(writev)(fd, iov, iovcnt);
+  SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(writev)(fd, iov, iovcnt);
   if (res > 0) read_iovec(ctx, iov, iovcnt, res);
   return res;
 }
@@ -1169,7 +1205,7 @@  INTERCEPTOR(SSIZE_T, pwritev, int fd, __sanitizer_iovec *iov, int iovcnt,
   COMMON_INTERCEPTOR_ENTER(ctx, pwritev, fd, iov, iovcnt, offset);
   COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
   if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
-  SSIZE_T res = REAL(pwritev)(fd, iov, iovcnt, offset);
+  SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(pwritev)(fd, iov, iovcnt, offset);
   if (res > 0) read_iovec(ctx, iov, iovcnt, res);
   return res;
 }
@@ -1185,7 +1221,8 @@  INTERCEPTOR(SSIZE_T, pwritev64, int fd, __sanitizer_iovec *iov, int iovcnt,
   COMMON_INTERCEPTOR_ENTER(ctx, pwritev64, fd, iov, iovcnt, offset);
   COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
   if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
-  SSIZE_T res = REAL(pwritev64)(fd, iov, iovcnt, offset);
+  SSIZE_T res =
+      COMMON_INTERCEPTOR_BLOCK_REAL(pwritev64)(fd, iov, iovcnt, offset);
   if (res > 0) read_iovec(ctx, iov, iovcnt, res);
   return res;
 }
@@ -1248,9 +1285,16 @@  INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3,
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, prctl, option, arg2, arg3, arg4, arg5);
   static const int PR_SET_NAME = 15;
+  static const int PR_GET_NAME = 16;
   static const int PR_SET_VMA = 0x53564d41;
   static const int PR_SCHED_CORE = 62;
   static const int PR_SCHED_CORE_GET = 0;
+  static const int PR_GET_PDEATHSIG = 2;
+
+#  if !SANITIZER_ANDROID
+  static const int PR_SET_SECCOMP = 22;
+  static const int SECCOMP_MODE_FILTER = 2;
+#  endif
   if (option == PR_SET_VMA && arg2 == 0UL) {
     char *name = (char *)arg5;
     COMMON_INTERCEPTOR_READ_RANGE(ctx, name, internal_strlen(name) + 1);
@@ -1261,8 +1305,19 @@  INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3,
     internal_strncpy(buff, (char *)arg2, 15);
     buff[15] = 0;
     COMMON_INTERCEPTOR_SET_THREAD_NAME(ctx, buff);
-  } else if (res != -1 && option == PR_SCHED_CORE && arg2 == PR_SCHED_CORE_GET) {
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (u64*)(arg5), sizeof(u64));
+  } else if (res == 0 && option == PR_GET_NAME) {
+    char *name = (char *)arg2;
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, internal_strlen(name) + 1);
+  } else if (res != -1 && option == PR_SCHED_CORE &&
+             arg2 == PR_SCHED_CORE_GET) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (u64 *)(arg5), sizeof(u64));
+  } else if (res != -1 && option == PR_GET_PDEATHSIG) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (u64 *)(arg2), sizeof(int));
+#  if !SANITIZER_ANDROID
+  } else if (res != -1 && option == PR_SET_SECCOMP &&
+             arg2 == SECCOMP_MODE_FILTER) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, (u64 *)(arg3), struct_sock_fprog_sz);
+#  endif
   }
   return res;
 }
@@ -2549,7 +2604,7 @@  INTERCEPTOR_WITH_SUFFIX(int, wait, int *status) {
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
   // https://github.com/google/sanitizers/issues/321.
-  int res = REAL(wait)(status);
+  int res = COMMON_INTERCEPTOR_BLOCK_REAL(wait)(status);
   if (res != -1 && status)
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
   return res;
@@ -2567,7 +2622,7 @@  INTERCEPTOR_WITH_SUFFIX(int, waitid, int idtype, int id, void *infop,
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
   // https://github.com/google/sanitizers/issues/321.
-  int res = REAL(waitid)(idtype, id, infop, options);
+  int res = COMMON_INTERCEPTOR_BLOCK_REAL(waitid)(idtype, id, infop, options);
   if (res != -1 && infop)
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, infop, siginfo_t_sz);
   return res;
@@ -2578,7 +2633,7 @@  INTERCEPTOR_WITH_SUFFIX(int, waitpid, int pid, int *status, int options) {
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
   // https://github.com/google/sanitizers/issues/321.
-  int res = REAL(waitpid)(pid, status, options);
+  int res = COMMON_INTERCEPTOR_BLOCK_REAL(waitpid)(pid, status, options);
   if (res != -1 && status)
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
   return res;
@@ -2589,7 +2644,7 @@  INTERCEPTOR(int, wait3, int *status, int options, void *rusage) {
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
   // https://github.com/google/sanitizers/issues/321.
-  int res = REAL(wait3)(status, options, rusage);
+  int res = COMMON_INTERCEPTOR_BLOCK_REAL(wait3)(status, options, rusage);
   if (res != -1) {
     if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
     if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
@@ -2603,7 +2658,8 @@  INTERCEPTOR(int, __wait4, int pid, int *status, int options, void *rusage) {
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
   // https://github.com/google/sanitizers/issues/321.
-  int res = REAL(__wait4)(pid, status, options, rusage);
+  int res =
+      COMMON_INTERCEPTOR_BLOCK_REAL(__wait4)(pid, status, options, rusage);
   if (res != -1) {
     if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
     if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
@@ -2618,7 +2674,7 @@  INTERCEPTOR(int, wait4, int pid, int *status, int options, void *rusage) {
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
   // https://github.com/google/sanitizers/issues/321.
-  int res = REAL(wait4)(pid, status, options, rusage);
+  int res = COMMON_INTERCEPTOR_BLOCK_REAL(wait4)(pid, status, options, rusage);
   if (res != -1) {
     if (status) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, status, sizeof(*status));
     if (rusage) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rusage, struct_rusage_sz);
@@ -2996,7 +3052,7 @@  INTERCEPTOR(int, accept, int fd, void *addr, unsigned *addrlen) {
     COMMON_INTERCEPTOR_READ_RANGE(ctx, addrlen, sizeof(*addrlen));
     addrlen0 = *addrlen;
   }
-  int fd2 = REAL(accept)(fd, addr, addrlen);
+  int fd2 = COMMON_INTERCEPTOR_BLOCK_REAL(accept)(fd, addr, addrlen);
   if (fd2 >= 0) {
     if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
     if (addr && addrlen)
@@ -3021,7 +3077,7 @@  INTERCEPTOR(int, accept4, int fd, void *addr, unsigned *addrlen, int f) {
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
   // https://github.com/google/sanitizers/issues/321.
-  int fd2 = REAL(accept4)(fd, addr, addrlen, f);
+  int fd2 = COMMON_INTERCEPTOR_BLOCK_REAL(accept4)(fd, addr, addrlen, f);
   if (fd2 >= 0) {
     if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
     if (addr && addrlen)
@@ -3045,7 +3101,7 @@  INTERCEPTOR(int, paccept, int fd, void *addr, unsigned *addrlen,
     addrlen0 = *addrlen;
   }
   if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set));
-  int fd2 = REAL(paccept)(fd, addr, addrlen, set, f);
+  int fd2 = COMMON_INTERCEPTOR_BLOCK_REAL(paccept)(fd, addr, addrlen, set, f);
   if (fd2 >= 0) {
     if (fd >= 0) COMMON_INTERCEPTOR_FD_SOCKET_ACCEPT(ctx, fd, fd2);
     if (addr && addrlen)
@@ -3126,7 +3182,7 @@  INTERCEPTOR(SSIZE_T, recvmsg, int fd, struct __sanitizer_msghdr *msg,
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
   // https://github.com/google/sanitizers/issues/321.
-  SSIZE_T res = REAL(recvmsg)(fd, msg, flags);
+  SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(recvmsg)(fd, msg, flags);
   if (res >= 0) {
     if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
     if (msg) {
@@ -3147,7 +3203,8 @@  INTERCEPTOR(int, recvmmsg, int fd, struct __sanitizer_mmsghdr *msgvec,
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, recvmmsg, fd, msgvec, vlen, flags, timeout);
   if (timeout) COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout, struct_timespec_sz);
-  int res = REAL(recvmmsg)(fd, msgvec, vlen, flags, timeout);
+  int res =
+      COMMON_INTERCEPTOR_BLOCK_REAL(recvmmsg)(fd, msgvec, vlen, flags, timeout);
   if (res >= 0) {
     if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
     for (int i = 0; i < res; ++i) {
@@ -3225,7 +3282,7 @@  INTERCEPTOR(SSIZE_T, sendmsg, int fd, struct __sanitizer_msghdr *msg,
     COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
     COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
   }
-  SSIZE_T res = REAL(sendmsg)(fd, msg, flags);
+  SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(sendmsg)(fd, msg, flags);
   if (common_flags()->intercept_send && res >= 0 && msg)
     read_msghdr(ctx, msg, res);
   return res;
@@ -3244,7 +3301,7 @@  INTERCEPTOR(int, sendmmsg, int fd, struct __sanitizer_mmsghdr *msgvec,
     COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
     COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
   }
-  int res = REAL(sendmmsg)(fd, msgvec, vlen, flags);
+  int res = COMMON_INTERCEPTOR_BLOCK_REAL(sendmmsg)(fd, msgvec, vlen, flags);
   if (res >= 0 && msgvec) {
     for (int i = 0; i < res; ++i) {
       COMMON_INTERCEPTOR_WRITE_RANGE(ctx, &msgvec[i].msg_len,
@@ -3267,7 +3324,7 @@  INTERCEPTOR(int, msgsnd, int msqid, const void *msgp, SIZE_T msgsz,
   COMMON_INTERCEPTOR_ENTER(ctx, msgsnd, msqid, msgp, msgsz, msgflg);
   if (msgp)
     COMMON_INTERCEPTOR_READ_RANGE(ctx, msgp, sizeof(long) + msgsz);
-  int res = REAL(msgsnd)(msqid, msgp, msgsz, msgflg);
+  int res = COMMON_INTERCEPTOR_BLOCK_REAL(msgsnd)(msqid, msgp, msgsz, msgflg);
   return res;
 }
 
@@ -3275,7 +3332,8 @@  INTERCEPTOR(SSIZE_T, msgrcv, int msqid, void *msgp, SIZE_T msgsz,
             long msgtyp, int msgflg) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, msgrcv, msqid, msgp, msgsz, msgtyp, msgflg);
-  SSIZE_T len = REAL(msgrcv)(msqid, msgp, msgsz, msgtyp, msgflg);
+  SSIZE_T len =
+      COMMON_INTERCEPTOR_BLOCK_REAL(msgrcv)(msqid, msgp, msgsz, msgtyp, msgflg);
   if (len != -1)
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, msgp, sizeof(long) + len);
   return len;
@@ -3416,23 +3474,27 @@  INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
   COMMON_INTERCEPTOR_ENTER(ctx, ptrace, request, pid, addr, data);
   __sanitizer_iovec local_iovec;
 
-  if (data) {
+  void *data_arg = ptrace_data_arg(request, addr, data);
+  if (data_arg) {
     if (request == ptrace_setregs) {
-      COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_regs_struct_sz);
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, data_arg, struct_user_regs_struct_sz);
     } else if (request == ptrace_setfpregs) {
-      COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpregs_struct_sz);
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, data_arg,
+                                    struct_user_fpregs_struct_sz);
     } else if (request == ptrace_setfpxregs) {
-      COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_fpxregs_struct_sz);
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, data_arg,
+                                    struct_user_fpxregs_struct_sz);
     } else if (request == ptrace_setvfpregs) {
-      COMMON_INTERCEPTOR_READ_RANGE(ctx, data, struct_user_vfpregs_struct_sz);
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, data_arg,
+                                    struct_user_vfpregs_struct_sz);
     } else if (request == ptrace_setsiginfo) {
-      COMMON_INTERCEPTOR_READ_RANGE(ctx, data, siginfo_t_sz);
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, data_arg, siginfo_t_sz);
 
-    // Some kernel might zero the iovec::iov_base in case of invalid
-    // write access.  In this case copy the invalid address for further
-    // inspection.
+      // Some kernel might zero the iovec::iov_base in case of invalid
+      // write access.  In this case copy the invalid address for further
+      // inspection.
     } else if (request == ptrace_setregset || request == ptrace_getregset) {
-      __sanitizer_iovec *iovec = (__sanitizer_iovec*)data;
+      __sanitizer_iovec *iovec = (__sanitizer_iovec *)data_arg;
       COMMON_INTERCEPTOR_READ_RANGE(ctx, iovec, sizeof(*iovec));
       local_iovec = *iovec;
       if (request == ptrace_setregset)
@@ -3445,23 +3507,26 @@  INTERCEPTOR(uptr, ptrace, int request, int pid, void *addr, void *data) {
   // https://github.com/google/sanitizers/issues/321.
   uptr res = REAL(ptrace)(request, pid, addr, data);
 
-  if (!res && data) {
+  if (!res && data_arg) {
     // Note that PEEK* requests assign different meaning to the return value.
     // This function does not handle them (nor does it need to).
     if (request == ptrace_getregs) {
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_regs_struct_sz);
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg, struct_user_regs_struct_sz);
     } else if (request == ptrace_getfpregs) {
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpregs_struct_sz);
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg,
+                                     struct_user_fpregs_struct_sz);
     } else if (request == ptrace_getfpxregs) {
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_fpxregs_struct_sz);
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg,
+                                     struct_user_fpxregs_struct_sz);
     } else if (request == ptrace_getvfpregs) {
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, struct_user_vfpregs_struct_sz);
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg,
+                                     struct_user_vfpregs_struct_sz);
     } else if (request == ptrace_getsiginfo) {
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, siginfo_t_sz);
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg, siginfo_t_sz);
     } else if (request == ptrace_geteventmsg) {
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(unsigned long));
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data_arg, sizeof(unsigned long));
     } else if (request == ptrace_getregset) {
-      __sanitizer_iovec *iovec = (__sanitizer_iovec*)data;
+      __sanitizer_iovec *iovec = (__sanitizer_iovec *)data_arg;
       COMMON_INTERCEPTOR_WRITE_RANGE(ctx, iovec, sizeof(*iovec));
       COMMON_INTERCEPTOR_WRITE_RANGE(ctx, local_iovec.iov_base,
                                      local_iovec.iov_len);
@@ -6119,7 +6184,7 @@  INTERCEPTOR(int, flopen, const char *path, int flags, ...) {
   if (path) {
     COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1);
   }
-  return REAL(flopen)(path, flags, mode);
+  return COMMON_INTERCEPTOR_BLOCK_REAL(flopen)(path, flags, mode);
 }
 
 INTERCEPTOR(int, flopenat, int dirfd, const char *path, int flags, ...) {
@@ -6132,7 +6197,7 @@  INTERCEPTOR(int, flopenat, int dirfd, const char *path, int flags, ...) {
   if (path) {
     COMMON_INTERCEPTOR_READ_RANGE(ctx, path, internal_strlen(path) + 1);
   }
-  return REAL(flopenat)(dirfd, path, flags, mode);
+  return COMMON_INTERCEPTOR_BLOCK_REAL(flopenat)(dirfd, path, flags, mode);
 }
 
 #define INIT_FLOPEN    \
@@ -6325,9 +6390,9 @@  INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
 
       const char *SelfFName = DladdrSelfFName();
       VPrintf(1, "dlopen interceptor: DladdrSelfFName: %p %s\n",
-              (void *)SelfFName, SelfFName);
+              (const void *)SelfFName, SelfFName);
 
-      if (internal_strcmp(SelfFName, filename) == 0) {
+      if (SelfFName && internal_strcmp(SelfFName, filename) == 0) {
         // It's possible they copied the string from dladdr, so
         // we do a string comparison rather than pointer comparison.
         VPrintf(1, "dlopen interceptor: replacing %s because it matches %s\n",
@@ -6717,7 +6782,7 @@  INTERCEPTOR(SSIZE_T, recv, int fd, void *buf, SIZE_T len, int flags) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, recv, fd, buf, len, flags);
   COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
-  SSIZE_T res = REAL(recv)(fd, buf, len, flags);
+  SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(recv)(fd, buf, len, flags);
   if (res > 0) {
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, Min((SIZE_T)res, len));
   }
@@ -6734,7 +6799,8 @@  INTERCEPTOR(SSIZE_T, recvfrom, int fd, void *buf, SIZE_T len, int flags,
   SIZE_T srcaddr_sz;
   if (srcaddr) srcaddr_sz = *addrlen;
   (void)srcaddr_sz;  // prevent "set but not used" warning
-  SSIZE_T res = REAL(recvfrom)(fd, buf, len, flags, srcaddr, addrlen);
+  SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(recvfrom)(fd, buf, len, flags,
+                                                        srcaddr, addrlen);
   if (res > 0)
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, Min((SIZE_T)res, len));
   if (res >= 0 && srcaddr)
@@ -6757,7 +6823,7 @@  INTERCEPTOR(SSIZE_T, send, int fd, void *buf, SIZE_T len, int flags) {
     COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
     COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
   }
-  SSIZE_T res = REAL(send)(fd, buf, len, flags);
+  SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(send)(fd, buf, len, flags);
   if (common_flags()->intercept_send && res > 0)
     COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, Min((SIZE_T)res, len));
   return res;
@@ -6772,7 +6838,8 @@  INTERCEPTOR(SSIZE_T, sendto, int fd, void *buf, SIZE_T len, int flags,
     COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
   }
   // Can't check dstaddr as it may have uninitialized padding at the end.
-  SSIZE_T res = REAL(sendto)(fd, buf, len, flags, dstaddr, addrlen);
+  SSIZE_T res = COMMON_INTERCEPTOR_BLOCK_REAL(sendto)(fd, buf, len, flags,
+                                                      dstaddr, addrlen);
   if (common_flags()->intercept_send && res > 0)
     COMMON_INTERCEPTOR_READ_RANGE(ctx, buf, Min((SIZE_T)res, len));
   return res;
@@ -6785,25 +6852,25 @@  INTERCEPTOR(SSIZE_T, sendto, int fd, void *buf, SIZE_T len, int flags,
 #endif
 
 #if SANITIZER_INTERCEPT_EVENTFD_READ_WRITE
-INTERCEPTOR(int, eventfd_read, int fd, u64 *value) {
+INTERCEPTOR(int, eventfd_read, int fd, __sanitizer_eventfd_t *value) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, eventfd_read, fd, value);
   COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
-  int res = REAL(eventfd_read)(fd, value);
+  int res = COMMON_INTERCEPTOR_BLOCK_REAL(eventfd_read)(fd, value);
   if (res == 0) {
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, sizeof(*value));
     if (fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
   }
   return res;
 }
-INTERCEPTOR(int, eventfd_write, int fd, u64 value) {
+INTERCEPTOR(int, eventfd_write, int fd, __sanitizer_eventfd_t value) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, eventfd_write, fd, value);
   if (fd >= 0) {
     COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
     COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
   }
-  int res = REAL(eventfd_write)(fd, value);
+  int res = COMMON_INTERCEPTOR_BLOCK_REAL(eventfd_write)(fd, value);
   return res;
 }
 #define INIT_EVENTFD_READ_WRITE            \
@@ -7426,7 +7493,8 @@  INTERCEPTOR(int, open_by_handle_at, int mount_fd, struct file_handle* handle,
   COMMON_INTERCEPTOR_READ_RANGE(
       ctx, &sanitizer_handle->f_handle, sanitizer_handle->handle_bytes);
 
-  return REAL(open_by_handle_at)(mount_fd, handle, flags);
+  return COMMON_INTERCEPTOR_BLOCK_REAL(open_by_handle_at)(mount_fd, handle,
+                                                          flags);
 }
 
 #define INIT_OPEN_BY_HANDLE_AT COMMON_INTERCEPT_FUNCTION(open_by_handle_at)
@@ -7641,9 +7709,9 @@  static void write_protoent(void *ctx, struct __sanitizer_protoent *p) {
   COMMON_INTERCEPTOR_WRITE_RANGE(ctx, p->p_aliases, pp_size * sizeof(char *));
 }
 
-INTERCEPTOR(struct __sanitizer_protoent *, getprotoent) {
+INTERCEPTOR(struct __sanitizer_protoent *, getprotoent,) {
   void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, getprotoent);
+  COMMON_INTERCEPTOR_ENTER(ctx, getprotoent,);
   struct __sanitizer_protoent *p = REAL(getprotoent)();
   if (p)
     write_protoent(ctx, p);
@@ -7730,9 +7798,9 @@  INTERCEPTOR(int, getprotobynumber_r, int num,
 #endif
 
 #if SANITIZER_INTERCEPT_NETENT
-INTERCEPTOR(struct __sanitizer_netent *, getnetent) {
+INTERCEPTOR(struct __sanitizer_netent *, getnetent,) {
   void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, getnetent);
+  COMMON_INTERCEPTOR_ENTER(ctx, getnetent,);
   struct __sanitizer_netent *n = REAL(getnetent)();
   if (n) {
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, n, sizeof(*n));
@@ -8809,83 +8877,6 @@  INTERCEPTOR(char *, RMD160Data, u8 *data, SIZE_T len, char *buf) {
 #define INIT_RMD160
 #endif
 
-#if SANITIZER_INTERCEPT_MD5
-INTERCEPTOR(void, MD5Init, void *context) {
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, MD5Init, context);
-  REAL(MD5Init)(context);
-  if (context)
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD5_CTX_sz);
-}
-
-INTERCEPTOR(void, MD5Update, void *context, const unsigned char *data,
-            unsigned int len) {
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, MD5Update, context, data, len);
-  if (data && len > 0)
-    COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
-  if (context)
-    COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD5_CTX_sz);
-  REAL(MD5Update)(context, data, len);
-  if (context)
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD5_CTX_sz);
-}
-
-INTERCEPTOR(void, MD5Final, unsigned char digest[16], void *context) {
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, MD5Final, digest, context);
-  if (context)
-    COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD5_CTX_sz);
-  REAL(MD5Final)(digest, context);
-  if (digest)
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(unsigned char) * 16);
-}
-
-INTERCEPTOR(char *, MD5End, void *context, char *buf) {
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, MD5End, context, buf);
-  if (context)
-    COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD5_CTX_sz);
-  char *ret = REAL(MD5End)(context, buf);
-  if (ret)
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD5_return_length);
-  return ret;
-}
-
-INTERCEPTOR(char *, MD5File, const char *filename, char *buf) {
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, MD5File, filename, buf);
-  if (filename)
-    COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, internal_strlen(filename) + 1);
-  char *ret = REAL(MD5File)(filename, buf);
-  if (ret)
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD5_return_length);
-  return ret;
-}
-
-INTERCEPTOR(char *, MD5Data, const unsigned char *data, unsigned int len,
-            char *buf) {
-  void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, MD5Data, data, len, buf);
-  if (data && len > 0)
-    COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
-  char *ret = REAL(MD5Data)(data, len, buf);
-  if (ret)
-    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD5_return_length);
-  return ret;
-}
-
-#define INIT_MD5                                                               \
-  COMMON_INTERCEPT_FUNCTION(MD5Init);                                          \
-  COMMON_INTERCEPT_FUNCTION(MD5Update);                                        \
-  COMMON_INTERCEPT_FUNCTION(MD5Final);                                         \
-  COMMON_INTERCEPT_FUNCTION(MD5End);                                           \
-  COMMON_INTERCEPT_FUNCTION(MD5File);                                          \
-  COMMON_INTERCEPT_FUNCTION(MD5Data)
-#else
-#define INIT_MD5
-#endif
-
 #if SANITIZER_INTERCEPT_FSEEK
 INTERCEPTOR(int, fseek, __sanitizer_FILE *stream, long int offset, int whence) {
   void *ctx;
@@ -9016,107 +9007,6 @@  INTERCEPTOR(char *, MD2Data, const unsigned char *data, unsigned int len,
 #define INIT_MD2
 #endif
 
-#if SANITIZER_INTERCEPT_SHA2
-#define SHA2_INTERCEPTORS(LEN, SHA2_STATE_T) \
-  INTERCEPTOR(void, SHA##LEN##_Init, void *context) { \
-    void *ctx; \
-    COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_Init, context); \
-    REAL(SHA##LEN##_Init)(context); \
-    if (context) \
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, SHA##LEN##_CTX_sz); \
-  } \
-  INTERCEPTOR(void, SHA##LEN##_Update, void *context, \
-              const u8 *data, SIZE_T len) { \
-    void *ctx; \
-    COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_Update, context, data, len); \
-    if (data && len > 0) \
-      COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); \
-    if (context) \
-      COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA##LEN##_CTX_sz); \
-    REAL(SHA##LEN##_Update)(context, data, len); \
-    if (context) \
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, SHA##LEN##_CTX_sz); \
-  } \
-  INTERCEPTOR(void, SHA##LEN##_Final, u8 digest[LEN/8], \
-  void *context) { \
-    void *ctx; \
-    CHECK_EQ(SHA##LEN##_digest_length, LEN/8); \
-    COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_Final, digest, context); \
-    if (context) \
-      COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA##LEN##_CTX_sz); \
-    REAL(SHA##LEN##_Final)(digest, context); \
-    if (digest) \
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, \
-                                     sizeof(digest[0]) * \
-  SHA##LEN##_digest_length); \
-  } \
-  INTERCEPTOR(char *, SHA##LEN##_End, void *context, char *buf) { \
-    void *ctx; \
-    COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_End, context, buf); \
-    if (context) \
-      COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA##LEN##_CTX_sz); \
-    char *ret = REAL(SHA##LEN##_End)(context, buf); \
-    if (ret) \
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA##LEN##_return_length); \
-    return ret; \
-  } \
-  INTERCEPTOR(char *, SHA##LEN##_File, const char *filename, char *buf) { \
-    void *ctx; \
-    COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_File, filename, buf); \
-    if (filename) \
-      COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, internal_strlen(filename) + 1);\
-    char *ret = REAL(SHA##LEN##_File)(filename, buf); \
-    if (ret) \
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA##LEN##_return_length); \
-    return ret; \
-  } \
-  INTERCEPTOR(char *, SHA##LEN##_FileChunk, const char *filename, char *buf, \
-              OFF_T offset, OFF_T length) { \
-    void *ctx; \
-    COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_FileChunk, filename, buf, offset, \
-  length); \
-    if (filename) \
-      COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, internal_strlen(filename) + 1);\
-    char *ret = REAL(SHA##LEN##_FileChunk)(filename, buf, offset, length); \
-    if (ret) \
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA##LEN##_return_length); \
-    return ret; \
-  } \
-  INTERCEPTOR(char *, SHA##LEN##_Data, u8 *data, SIZE_T len, char *buf) { \
-    void *ctx; \
-    COMMON_INTERCEPTOR_ENTER(ctx, SHA##LEN##_Data, data, len, buf); \
-    if (data && len > 0) \
-      COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len); \
-    char *ret = REAL(SHA##LEN##_Data)(data, len, buf); \
-    if (ret) \
-      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA##LEN##_return_length); \
-    return ret; \
-  }
-
-SHA2_INTERCEPTORS(224, u32)
-SHA2_INTERCEPTORS(256, u32)
-SHA2_INTERCEPTORS(384, u64)
-SHA2_INTERCEPTORS(512, u64)
-
-#define INIT_SHA2_INTECEPTORS(LEN) \
-  COMMON_INTERCEPT_FUNCTION(SHA##LEN##_Init); \
-  COMMON_INTERCEPT_FUNCTION(SHA##LEN##_Update); \
-  COMMON_INTERCEPT_FUNCTION(SHA##LEN##_Final); \
-  COMMON_INTERCEPT_FUNCTION(SHA##LEN##_End); \
-  COMMON_INTERCEPT_FUNCTION(SHA##LEN##_File); \
-  COMMON_INTERCEPT_FUNCTION(SHA##LEN##_FileChunk); \
-  COMMON_INTERCEPT_FUNCTION(SHA##LEN##_Data)
-
-#define INIT_SHA2 \
-  INIT_SHA2_INTECEPTORS(224); \
-  INIT_SHA2_INTECEPTORS(256); \
-  INIT_SHA2_INTECEPTORS(384); \
-  INIT_SHA2_INTECEPTORS(512)
-#undef SHA2_INTERCEPTORS
-#else
-#define INIT_SHA2
-#endif
-
 #if SANITIZER_INTERCEPT_VIS
 INTERCEPTOR(char *, vis, char *dst, int c, int flag, int nextc) {
   void *ctx;
@@ -9894,9 +9784,9 @@  INTERCEPTOR(char *, fdevname_r,  int fd, char *buf, SIZE_T len) {
 #endif
 
 #if SANITIZER_INTERCEPT_GETUSERSHELL
-INTERCEPTOR(char *, getusershell) {
+INTERCEPTOR(char *, getusershell,) {
   void *ctx;
-  COMMON_INTERCEPTOR_ENTER(ctx, getusershell);
+  COMMON_INTERCEPTOR_ENTER(ctx, getusershell,);
   char *res = REAL(getusershell)();
   if (res)
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, internal_strlen(res) + 1);
@@ -9965,7 +9855,13 @@  INTERCEPTOR(void, sl_free, void *sl, int freeall) {
 INTERCEPTOR(SSIZE_T, getrandom, void *buf, SIZE_T buflen, unsigned int flags) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, getrandom, buf, buflen, flags);
-  SSIZE_T n = REAL(getrandom)(buf, buflen, flags);
+  // If GRND_NONBLOCK is set in the flags, it is non blocking.
+  static const int grnd_nonblock = 1;
+  SSIZE_T n;
+  if ((flags & grnd_nonblock))
+    n = REAL(getrandom)(buf, buflen, flags);
+  else
+    n = COMMON_INTERCEPTOR_BLOCK_REAL(getrandom)(buf, buflen, flags);
   if (n > 0) {
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, n);
   }
@@ -10212,20 +10108,6 @@  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) {
@@ -10258,6 +10140,55 @@  INTERCEPTOR(int, cpuset_getaffinity, int level, int which, __int64_t id, SIZE_T
 #define INIT_CPUSET_GETAFFINITY
 #endif
 
+#if SANITIZER_INTERCEPT_PREADV2
+INTERCEPTOR(SSIZE_T, preadv2, int fd, __sanitizer_iovec *iov, int iovcnt,
+            OFF_T offset, int flags) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, preadv2, fd, iov, iovcnt, offset, flags);
+  COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+  SSIZE_T res = REAL(preadv2)(fd, iov, iovcnt, offset, flags);
+  if (res > 0) write_iovec(ctx, iov, iovcnt, res);
+  if (res >= 0 && fd >= 0) COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+  return res;
+}
+#define INIT_PREADV2 COMMON_INTERCEPT_FUNCTION(preadv2)
+#else
+#define INIT_PREADV2
+#endif
+
+#if SANITIZER_INTERCEPT_PWRITEV2
+INTERCEPTOR(SSIZE_T, pwritev2, int fd, __sanitizer_iovec *iov, int iovcnt,
+            OFF_T offset, int flags) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, pwritev2, fd, iov, iovcnt, offset, flags);
+  COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+  if (fd >= 0) COMMON_INTERCEPTOR_FD_RELEASE(ctx, fd);
+  SSIZE_T res = REAL(pwritev2)(fd, iov, iovcnt, offset, flags);
+  if (res > 0) read_iovec(ctx, iov, iovcnt, res);
+  return res;
+}
+#define INIT_PWRITEV2 COMMON_INTERCEPT_FUNCTION(pwritev2)
+#else
+#define INIT_PWRITEV2
+#endif
+
+#if SANITIZER_INTERCEPT_FREADLINK
+INTERCEPTOR(SSIZE_T, freadlink, int fd, char *buf, SIZE_T bufsiz) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, freadlink, fd, buf, bufsiz);
+  COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+  SSIZE_T res = REAL(freadlink)(fd, buf, bufsiz);
+  if (res > 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, res);
+  if (res >= 0 && fd > 0)
+    COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+  return res;
+}
+#  define INIT_FREADLINK COMMON_INTERCEPT_FUNCTION(freadlink)
+#else
+#  define INIT_FREADLINK
+#endif
+
 #include "sanitizer_common_interceptors_netbsd_compat.inc"
 
 namespace __sanitizer {
@@ -10550,10 +10481,8 @@  static void InitializeCommonInterceptors() {
   INIT_SHA1;
   INIT_MD4;
   INIT_RMD160;
-  INIT_MD5;
   INIT_FSEEK;
   INIT_MD2;
-  INIT_SHA2;
   INIT_VIS;
   INIT_CDB;
   INIT_GETFSENT;
@@ -10575,9 +10504,11 @@  static void InitializeCommonInterceptors() {
   INIT_PROCCTL
   INIT_UNAME;
   INIT___XUNAME;
-  INIT_HEXDUMP;
   INIT_ARGP_PARSE;
   INIT_CPUSET_GETAFFINITY;
+  INIT_PREADV2;
+  INIT_PWRITEV2;
+  INIT_FREADLINK;
 
   INIT___PRINTF_CHK;
 }
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
index 557207fe62ac..4ea75cdd67cb 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
@@ -10,6 +10,7 @@ 
 INTERFACE_FUNCTION(__sanitizer_acquire_crash_state)
 INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container)
 INTERFACE_FUNCTION(__sanitizer_annotate_double_ended_contiguous_container)
+INTERFACE_FUNCTION(__sanitizer_copy_contiguous_container_annotations)
 INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
 INTERFACE_FUNCTION(
     __sanitizer_double_ended_contiguous_container_find_bad_address)
@@ -22,6 +23,7 @@  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)
+INTERFACE_WEAK_FUNCTION(__sanitizer_get_dtls_size)
 // Sanitizer weak hooks
 INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_memcmp)
 INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_strcmp)
@@ -46,7 +48,14 @@  INTERFACE_FUNCTION(__sanitizer_purge_allocator)
 INTERFACE_FUNCTION(__sanitizer_print_memory_profile)
 INTERFACE_WEAK_FUNCTION(__sanitizer_free_hook)
 INTERFACE_WEAK_FUNCTION(__sanitizer_malloc_hook)
+INTERFACE_WEAK_FUNCTION(__sanitizer_ignore_free_hook)
 // Memintrinsic functions.
 INTERFACE_FUNCTION(__sanitizer_internal_memcpy)
 INTERFACE_FUNCTION(__sanitizer_internal_memmove)
 INTERFACE_FUNCTION(__sanitizer_internal_memset)
+
+#if SANITIZER_WINDOWS
+INTERFACE_FUNCTION(__sanitizer_override_function)
+INTERFACE_FUNCTION(__sanitizer_override_function_by_addr)
+INTERFACE_FUNCTION(__sanitizer_register_weak_function)
+#endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
index 7b74bb1a7e0f..f275e81ff041 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cpp
@@ -87,8 +87,8 @@  void MaybeStartBackgroudThread() {
   if (!common_flags()->hard_rss_limit_mb &&
       !common_flags()->soft_rss_limit_mb &&
       !common_flags()->heap_profile) return;
-  if (!&real_pthread_create) {
-    VPrintf(1, "%s: real_pthread_create undefined\n", SanitizerToolName);
+  if (!&internal_pthread_create) {
+    VPrintf(1, "%s: internal_pthread_create undefined\n", SanitizerToolName);
     return;  // Can't spawn the thread anyway.
   }
 
@@ -169,9 +169,9 @@  void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name,
                      : !MmapFixedNoReserve(beg, size, name)) {
     Report(
         "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
-        "Perhaps you're using ulimit -v\n",
+        "Perhaps you're using ulimit -v or ulimit -d\n",
         size);
-    Abort();
+    Die();
   }
   if (madvise_shadow && common_flags()->use_madv_dontdump)
     DontDumpShadowMemory(beg, size);
@@ -219,6 +219,32 @@  static void StopStackDepotBackgroundThread() {
 static void StopStackDepotBackgroundThread() {}
 #endif
 
+void MemCpyAccessible(void *dest, const void *src, uptr n) {
+  if (TryMemCpy(dest, src, n))
+    return;
+
+  const uptr page_size = GetPageSize();
+  uptr b = reinterpret_cast<uptr>(src);
+  uptr b_up = RoundUpTo(b, page_size);
+
+  uptr e = reinterpret_cast<uptr>(src) + n;
+  uptr e_down = RoundDownTo(e, page_size);
+
+  auto copy_or_zero = [dest, src](uptr beg, uptr end) {
+    const uptr udest = reinterpret_cast<uptr>(dest);
+    const uptr usrc = reinterpret_cast<uptr>(src);
+    void *d = reinterpret_cast<void *>(udest + (beg - usrc));
+    const uptr size = end - beg;
+    if (!TryMemCpy(d, reinterpret_cast<void *>(beg), size))
+      internal_memset(d, 0, size);
+  };
+
+  copy_or_zero(b, b_up);
+  for (uptr p = b_up; p < e_down; p += page_size)
+    copy_or_zero(p, p + page_size);
+  copy_or_zero(e_down, e);
+}
+
 }  // namespace __sanitizer
 
 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify,
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_nolibc.cpp b/libsanitizer/sanitizer_common/sanitizer_common_nolibc.cpp
index 67e77a877781..e49285f22dff 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_nolibc.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_common_nolibc.cpp
@@ -20,13 +20,14 @@  namespace __sanitizer {
 // The Windows implementations of these functions use the win32 API directly,
 // bypassing libc.
 #if !SANITIZER_WINDOWS
-#if SANITIZER_LINUX
+#  if SANITIZER_LINUX
 void LogMessageOnPrintf(const char *str) {}
-#endif
+void InitTlsSize() {}
+#  endif
 void WriteToSyslog(const char *buffer) {}
 void Abort() { internal__exit(1); }
 bool CreateDir(const char *pathname) { return false; }
-#endif // !SANITIZER_WINDOWS
+#endif  // !SANITIZER_WINDOWS
 
 #if !SANITIZER_WINDOWS && !SANITIZER_APPLE
 void ListOfModules::init() {}
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
index c10943b3e487..29fe4721ba40 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_syscalls.inc
@@ -38,12 +38,17 @@ 
 //          Called before fork syscall.
 //   COMMON_SYSCALL_POST_FORK(long res)
 //          Called after fork syscall.
+//   COMMON_SYSCALL_BLOCKING_START()
+//         Called before blocking syscall.
+//   COMMON_SYSCALL_BLOCKING_END()
+//         Called after blocking syscall.
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_platform.h"
 #if SANITIZER_LINUX
 
 #  include "sanitizer_libc.h"
+#  include "sanitizer_platform_limits_posix.h"
 
 #  define PRE_SYSCALL(name) \
     SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_syscall_pre_impl_##name
@@ -85,6 +90,16 @@ 
       {}
 #  endif
 
+#  ifndef COMMON_SYSCALL_BLOCKING_START
+#    define COMMON_SYSCALL_BLOCKING_START() \
+      {}
+#  endif
+
+#  ifndef COMMON_SYSCALL_BLOCKING_END
+#    define COMMON_SYSCALL_BLOCKING_END() \
+      {}
+#  endif
+
 // FIXME: do some kind of PRE_READ for all syscall arguments (int(s) and such).
 
 extern "C" {
@@ -2516,18 +2531,19 @@  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__) || \
-       defined(__loongarch__) || SANITIZER_RISCV64)
-  if (data) {
+       defined(__loongarch__) || SANITIZER_RISCV64 || defined(__sparc__))
+  long data_arg = ptrace_data_arg(request, addr, data);
+  if (data_arg) {
     if (request == ptrace_setregs) {
-      PRE_READ((void *)data, struct_user_regs_struct_sz);
+      PRE_READ((void *)data_arg, struct_user_regs_struct_sz);
     } else if (request == ptrace_setfpregs) {
-      PRE_READ((void *)data, struct_user_fpregs_struct_sz);
+      PRE_READ((void *)data_arg, struct_user_fpregs_struct_sz);
     } else if (request == ptrace_setfpxregs) {
-      PRE_READ((void *)data, struct_user_fpxregs_struct_sz);
+      PRE_READ((void *)data_arg, struct_user_fpxregs_struct_sz);
     } else if (request == ptrace_setsiginfo) {
-      PRE_READ((void *)data, siginfo_t_sz);
+      PRE_READ((void *)data_arg, siginfo_t_sz);
     } else if (request == ptrace_setregset) {
-      __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
+      __sanitizer_iovec *iov = (__sanitizer_iovec *)data_arg;
       PRE_READ(iov->iov_base, iov->iov_len);
     }
   }
@@ -2538,25 +2554,26 @@  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__) || \
-       defined(__loongarch__) || SANITIZER_RISCV64)
-  if (res >= 0 && data) {
+       defined(__loongarch__) || SANITIZER_RISCV64 || defined(__sparc__))
+  long data_arg = ptrace_data_arg(request, addr, data);
+  if (res >= 0 && data_arg) {
     // Note that this is different from the interceptor in
     // sanitizer_common_interceptors.inc.
     // PEEK* requests return resulting values through data pointer.
     if (request == ptrace_getregs) {
-      POST_WRITE((void *)data, struct_user_regs_struct_sz);
+      POST_WRITE((void *)data_arg, struct_user_regs_struct_sz);
     } else if (request == ptrace_getfpregs) {
-      POST_WRITE((void *)data, struct_user_fpregs_struct_sz);
+      POST_WRITE((void *)data_arg, struct_user_fpregs_struct_sz);
     } else if (request == ptrace_getfpxregs) {
-      POST_WRITE((void *)data, struct_user_fpxregs_struct_sz);
+      POST_WRITE((void *)data_arg, struct_user_fpxregs_struct_sz);
     } else if (request == ptrace_getsiginfo) {
-      POST_WRITE((void *)data, siginfo_t_sz);
+      POST_WRITE((void *)data_arg, siginfo_t_sz);
     } else if (request == ptrace_getregset) {
-      __sanitizer_iovec *iov = (__sanitizer_iovec *)data;
+      __sanitizer_iovec *iov = (__sanitizer_iovec *)data_arg;
       POST_WRITE(iov->iov_base, iov->iov_len);
     } else if (request == ptrace_peekdata || request == ptrace_peektext ||
                request == ptrace_peekuser) {
-      POST_WRITE((void *)data, sizeof(void *));
+      POST_WRITE((void *)data_arg, sizeof(void *));
     }
   }
 #  endif
@@ -2808,6 +2825,15 @@  PRE_SYSCALL(fchownat)
 POST_SYSCALL(fchownat)
 (long res, long dfd, const void *filename, long user, long group, long flag) {}
 
+PRE_SYSCALL(fchmodat2)(long dfd, const void *filename, long mode, long flag) {
+  if (filename)
+    PRE_READ(filename,
+             __sanitizer::internal_strlen((const char *)filename) + 1);
+}
+
+POST_SYSCALL(fchmodat2)
+(long res, long dfd, const void *filename, long mode, long flag) {}
+
 PRE_SYSCALL(openat)(long dfd, const void *filename, long flags, long mode) {
   if (filename)
     PRE_READ(filename,
@@ -3167,6 +3193,18 @@  POST_SYSCALL(sigaltstack)(long res, void *ss, void *oss) {
     }
   }
 }
+
+PRE_SYSCALL(futex)
+(void *uaddr, long futex_op, long val, void *timeout, void *uaddr2, long val3) {
+  COMMON_SYSCALL_BLOCKING_START();
+}
+
+POST_SYSCALL(futex)
+(long res, void *uaddr, long futex_op, long val, void *timeout, void *uaddr2,
+ long val3) {
+  COMMON_SYSCALL_BLOCKING_END();
+}
+
 }  // extern "C"
 
 #  undef PRE_SYSCALL
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp
index 35c325359148..73668a56218c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cpp
@@ -35,7 +35,7 @@ 
 #include "sanitizer_common.h"
 #include "sanitizer_interface_internal.h"
 #include "sanitizer_internal_defs.h"
-#include "sanitizer_symbolizer_fuchsia.h"
+#  include "sanitizer_symbolizer_markup_constants.h"
 
 using namespace __sanitizer;
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
index ce4326967180..506659a58c45 100644
--- a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cpp
@@ -75,7 +75,8 @@  static void SanitizerDumpCoverage(const uptr* unsorted_pcs, uptr len) {
     if (!pc) continue;
 
     if (!GetModuleAndOffsetForPc(pc, nullptr, 0, &pcs[i])) {
-      Printf("ERROR: unknown pc 0x%zx (may happen if dlclose is used)\n", pc);
+      Printf("ERROR: unknown pc %p (may happen if dlclose is used)\n",
+             (void*)pc);
       continue;
     }
     uptr module_base = pc - pcs[i];
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_win_dll_thunk.cpp b/libsanitizer/sanitizer_common/sanitizer_coverage_win_dll_thunk.cpp
deleted file mode 100644
index d0bf8a455643..000000000000
--- a/libsanitizer/sanitizer_common/sanitizer_coverage_win_dll_thunk.cpp
+++ /dev/null
@@ -1,20 +0,0 @@ 
-//===-- sanitizer_coverage_win_dll_thunk.cpp ------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a family of thunks that should be statically linked into
-// the DLLs that have instrumentation in order to delegate the calls to the
-// shared runtime that lives in the main binary.
-// See https://github.com/google/sanitizers/issues/209 for the details.
-//===----------------------------------------------------------------------===//
-#ifdef SANITIZER_DLL_THUNK
-#include "sanitizer_win_dll_thunk.h"
-// Sanitizer Coverage interface functions.
-#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name)
-#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
-#include "sanitizer_coverage_interface.inc"
-#endif // SANITIZER_DLL_THUNK
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cpp b/libsanitizer/sanitizer_common/sanitizer_coverage_win_runtime_thunk.cpp
similarity index 59%
rename from libsanitizer/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cpp
rename to libsanitizer/sanitizer_common/sanitizer_coverage_win_runtime_thunk.cpp
index 0bdf0c5aed41..281944643f21 100644
--- a/libsanitizer/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage_win_runtime_thunk.cpp
@@ -1,4 +1,4 @@ 
-//===-- sanitizer_coverage_win_dynamic_runtime_thunk.cpp ------------------===//
+//===-- sanitizer_coverage_win_runtime_thunk.cpp --------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -10,17 +10,20 @@ 
 // to interact with Sanitizer Coverage, when it is included in a dll.
 //
 //===----------------------------------------------------------------------===//
-#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK
-#define SANITIZER_IMPORT_INTERFACE 1
-#include "sanitizer_win_defs.h"
+#if defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) || \
+    defined(SANITIZER_STATIC_RUNTIME_THUNK)
+#  define SANITIZER_IMPORT_INTERFACE 1
+#  include "sanitizer_win_defs.h"
+#  include "sanitizer_win_thunk_interception.h"
 // Define weak alias for all weak functions imported from sanitizer coverage.
-#define INTERFACE_FUNCTION(Name)
-#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name)
-#include "sanitizer_coverage_interface.inc"
-#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK
+#  define INTERFACE_FUNCTION(Name)
+#  define INTERFACE_WEAK_FUNCTION(Name) REGISTER_WEAK_FUNCTION(Name)
+#  include "sanitizer_coverage_interface.inc"
+#endif  // defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) ||
+        // defined(SANITIZER_STATIC_RUNTIME_THUNK)
 
 namespace __sanitizer {
 // Add one, otherwise unused, external symbol to this object file so that the
 // Visual C++ linker includes it and reads the .drective section.
 void ForceWholeArchiveIncludeForSanCov() {}
-}
+}  // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_win_weak_interception.cpp b/libsanitizer/sanitizer_common/sanitizer_coverage_win_weak_interception.cpp
deleted file mode 100644
index 55263981705f..000000000000
--- a/libsanitizer/sanitizer_common/sanitizer_coverage_win_weak_interception.cpp
+++ /dev/null
@@ -1,23 +0,0 @@ 
-//===-- sanitizer_coverage_win_weak_interception.cpp ----------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// This module should be included in Sanitizer Coverage when it implemented as a
-// shared library on Windows (dll), in order to delegate the calls of weak
-// functions to the implementation in the main executable when a strong
-// definition is provided.
-//===----------------------------------------------------------------------===//
-#ifdef SANITIZER_DYNAMIC
-#include "sanitizer_win_weak_interception.h"
-#include "sanitizer_interface_internal.h"
-#include "sancov_flags.h"
-// Check if strong definitions for weak functions are present in the main
-// executable. If that is the case, override dll functions to point to strong
-// implementations.
-#define INTERFACE_FUNCTION(Name)
-#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
-#include "sanitizer_coverage_interface.inc"
-#endif // SANITIZER_DYNAMIC
diff --git a/libsanitizer/sanitizer_common/sanitizer_dense_map.h b/libsanitizer/sanitizer_common/sanitizer_dense_map.h
index 046d77dddc9c..c63788653de7 100644
--- a/libsanitizer/sanitizer_common/sanitizer_dense_map.h
+++ b/libsanitizer/sanitizer_common/sanitizer_dense_map.h
@@ -69,24 +69,14 @@  class DenseMapBase {
     setNumTombstones(0);
   }
 
+  /// Return true if the specified key is in the map, false otherwise.
+  bool contains(const KeyT &Key) const { return doFind(Key) != nullptr; }
+
   /// Return 1 if the specified key is in the map, 0 otherwise.
-  size_type count(const KeyT &Key) const {
-    const BucketT *TheBucket;
-    return LookupBucketFor(Key, TheBucket) ? 1 : 0;
-  }
+  size_type count(const KeyT &Key) const { return contains(Key) ? 1 : 0; }
 
-  value_type *find(const KeyT &Key) {
-    BucketT *TheBucket;
-    if (LookupBucketFor(Key, TheBucket))
-      return TheBucket;
-    return nullptr;
-  }
-  const value_type *find(const KeyT &Key) const {
-    const BucketT *TheBucket;
-    if (LookupBucketFor(Key, TheBucket))
-      return TheBucket;
-    return nullptr;
-  }
+  value_type *find(const KeyT &Key) { return doFind(Key); }
+  const value_type *find(const KeyT &Key) const { return doFind(Key); }
 
   /// Alternate version of find() which allows a different, and possibly
   /// less expensive, key type.
@@ -95,25 +85,18 @@  class DenseMapBase {
   /// type used.
   template <class LookupKeyT>
   value_type *find_as(const LookupKeyT &Key) {
-    BucketT *TheBucket;
-    if (LookupBucketFor(Key, TheBucket))
-      return TheBucket;
-    return nullptr;
+    return doFind(Key);
   }
   template <class LookupKeyT>
   const value_type *find_as(const LookupKeyT &Key) const {
-    const BucketT *TheBucket;
-    if (LookupBucketFor(Key, TheBucket))
-      return TheBucket;
-    return nullptr;
+    return doFind(Key);
   }
 
   /// lookup - Return the entry for the specified key, or a default
   /// constructed value if no such entry exists.
   ValueT lookup(const KeyT &Key) const {
-    const BucketT *TheBucket;
-    if (LookupBucketFor(Key, TheBucket))
-      return TheBucket->getSecond();
+    if (const BucketT *Bucket = doFind(Key))
+      return Bucket->getSecond();
     return ValueT();
   }
 
@@ -184,8 +167,8 @@  class DenseMapBase {
   }
 
   bool erase(const KeyT &Val) {
-    BucketT *TheBucket;
-    if (!LookupBucketFor(Val, TheBucket))
+    BucketT *TheBucket = doFind(Val);
+    if (!TheBucket)
       return false;  // not in map.
 
     TheBucket->getSecond().~ValueT();
@@ -449,6 +432,35 @@  class DenseMapBase {
     return TheBucket;
   }
 
+  template <typename LookupKeyT>
+  BucketT *doFind(const LookupKeyT &Val) {
+    BucketT *BucketsPtr = getBuckets();
+    const unsigned NumBuckets = getNumBuckets();
+    if (NumBuckets == 0)
+      return nullptr;
+
+    const KeyT EmptyKey = getEmptyKey();
+    unsigned BucketNo = getHashValue(Val) & (NumBuckets - 1);
+    unsigned ProbeAmt = 1;
+    while (true) {
+      BucketT *Bucket = BucketsPtr + BucketNo;
+      if (LIKELY(KeyInfoT::isEqual(Val, Bucket->getFirst())))
+        return Bucket;
+      if (LIKELY(KeyInfoT::isEqual(Bucket->getFirst(), EmptyKey)))
+        return nullptr;
+
+      // Otherwise, it's a hash collision or a tombstone, continue quadratic
+      // probing.
+      BucketNo += ProbeAmt++;
+      BucketNo &= NumBuckets - 1;
+    }
+  }
+
+  template <typename LookupKeyT>
+  const BucketT *doFind(const LookupKeyT &Val) const {
+    return const_cast<DenseMapBase *>(this)->doFind(Val);
+  }
+
   /// LookupBucketFor - Lookup the appropriate bucket for Val, returning it in
   /// FoundBucket.  If the bucket contains the key and a value, this returns
   /// true, otherwise it returns a bucket with an empty marker or tombstone and
diff --git a/libsanitizer/sanitizer_common/sanitizer_errno.cpp b/libsanitizer/sanitizer_common/sanitizer_errno.cpp
index cbadf4d924a7..a7cdf3256757 100644
--- a/libsanitizer/sanitizer_common/sanitizer_errno.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_errno.cpp
@@ -23,6 +23,7 @@  namespace __sanitizer {
 COMPILER_CHECK(errno_ENOMEM == ENOMEM);
 COMPILER_CHECK(errno_EBUSY == EBUSY);
 COMPILER_CHECK(errno_EINVAL == EINVAL);
+COMPILER_CHECK(errno_ERANGE == ERANGE);
 
 // EOWNERDEAD is not present in some older platforms.
 #if defined(EOWNERDEAD)
diff --git a/libsanitizer/sanitizer_common/sanitizer_errno_codes.h b/libsanitizer/sanitizer_common/sanitizer_errno_codes.h
index 3917b2817f2e..9e6e71ec80c1 100644
--- a/libsanitizer/sanitizer_common/sanitizer_errno_codes.h
+++ b/libsanitizer/sanitizer_common/sanitizer_errno_codes.h
@@ -24,6 +24,7 @@  namespace __sanitizer {
 #define errno_ENOMEM 12
 #define errno_EBUSY 16
 #define errno_EINVAL 22
+#define errno_ERANGE 34
 #define errno_ENAMETOOLONG 36
 #define errno_ENOSYS 38
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_file.cpp b/libsanitizer/sanitizer_common/sanitizer_file.cpp
index 7ef499ce07b1..96af270f9d8b 100644
--- a/libsanitizer/sanitizer_common/sanitizer_file.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_file.cpp
@@ -69,7 +69,7 @@  void ReportFile::ReopenIfNecessary() {
     WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
     WriteToFile(kStderrFd, full_path, internal_strlen(full_path));
     char errmsg[100];
-    internal_snprintf(errmsg, sizeof(errmsg), " (reason: %d)", err);
+    internal_snprintf(errmsg, sizeof(errmsg), " (reason: %d)\n", err);
     WriteToFile(kStderrFd, errmsg, internal_strlen(errmsg));
     Die();
   }
@@ -88,6 +88,8 @@  static void RecursiveCreateParentDirs(char *path) {
       const char *ErrorMsgPrefix = "ERROR: Can't create directory: ";
       WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
       WriteToFile(kStderrFd, path, internal_strlen(path));
+      const char *ErrorMsgSuffix = "\n";
+      WriteToFile(kStderrFd, ErrorMsgSuffix, internal_strlen(ErrorMsgSuffix));
       Die();
     }
     path[i] = save;
diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.inc b/libsanitizer/sanitizer_common/sanitizer_flags.inc
index 949bdbd148b6..c1e3530618c2 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flags.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_flags.inc
@@ -275,3 +275,10 @@  COMMON_FLAG(bool, test_only_emulate_no_memorymap, false,
 // program.
 COMMON_FLAG(bool, test_only_replace_dlopen_main_program, false,
             "TEST ONLY replace dlopen(<main program>,...) with dlopen(NULL)")
+
+COMMON_FLAG(bool, enable_symbolizer_markup, SANITIZER_FUCHSIA,
+            "Use sanitizer symbolizer markup, available on Linux "
+            "and always set true for Fuchsia.")
+
+COMMON_FLAG(bool, detect_invalid_join, true,
+            "If set, check invalid joins of threads.")
diff --git a/libsanitizer/sanitizer_common/sanitizer_flat_map.h b/libsanitizer/sanitizer_common/sanitizer_flat_map.h
index 8bb8304910c7..d246781fe1df 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flat_map.h
+++ b/libsanitizer/sanitizer_common/sanitizer_flat_map.h
@@ -109,6 +109,10 @@  class TwoLevelMap {
     return *AddressSpaceView::LoadWritable(&map2[idx % kSize2]);
   }
 
+  void Lock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { mu_.Lock(); }
+
+  void Unlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS { mu_.Unlock(); }
+
  private:
   constexpr uptr MmapSize() const {
     return RoundUpTo(kSize2 * sizeof(T), GetPageSizeCached());
diff --git a/libsanitizer/sanitizer_common/sanitizer_freebsd.h b/libsanitizer/sanitizer_common/sanitizer_freebsd.h
deleted file mode 100644
index 82b227eab6da..000000000000
--- a/libsanitizer/sanitizer_common/sanitizer_freebsd.h
+++ /dev/null
@@ -1,137 +0,0 @@ 
-//===-- sanitizer_freebsd.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 file is a part of Sanitizer runtime. It contains FreeBSD-specific
-// definitions.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef SANITIZER_FREEBSD_H
-#define SANITIZER_FREEBSD_H
-
-#include "sanitizer_internal_defs.h"
-
-// x86-64 FreeBSD 9.2 and older define 'ucontext_t' incorrectly in
-// 32-bit mode.
-#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
-#include <osreldate.h>
-#if __FreeBSD_version <= 902001  // v9.2
-#include <link.h>
-#include <sys/param.h>
-#include <ucontext.h>
-
-namespace __sanitizer {
-
-typedef unsigned long long __xuint64_t;
-
-typedef __int32_t __xregister_t;
-
-typedef struct __xmcontext {
-  __xregister_t mc_onstack;
-  __xregister_t mc_gs;
-  __xregister_t mc_fs;
-  __xregister_t mc_es;
-  __xregister_t mc_ds;
-  __xregister_t mc_edi;
-  __xregister_t mc_esi;
-  __xregister_t mc_ebp;
-  __xregister_t mc_isp;
-  __xregister_t mc_ebx;
-  __xregister_t mc_edx;
-  __xregister_t mc_ecx;
-  __xregister_t mc_eax;
-  __xregister_t mc_trapno;
-  __xregister_t mc_err;
-  __xregister_t mc_eip;
-  __xregister_t mc_cs;
-  __xregister_t mc_eflags;
-  __xregister_t mc_esp;
-  __xregister_t mc_ss;
-
-  int mc_len;
-  int mc_fpformat;
-  int mc_ownedfp;
-  __xregister_t mc_flags;
-
-  int mc_fpstate[128] __aligned(16);
-  __xregister_t mc_fsbase;
-  __xregister_t mc_gsbase;
-  __xregister_t mc_xfpustate;
-  __xregister_t mc_xfpustate_len;
-
-  int mc_spare2[4];
-} xmcontext_t;
-
-typedef struct __xucontext {
-  sigset_t uc_sigmask;
-  xmcontext_t uc_mcontext;
-
-  struct __ucontext *uc_link;
-  stack_t uc_stack;
-  int uc_flags;
-  int __spare__[4];
-} xucontext_t;
-
-struct xkinfo_vmentry {
-  int kve_structsize;
-  int kve_type;
-  __xuint64_t kve_start;
-  __xuint64_t kve_end;
-  __xuint64_t kve_offset;
-  __xuint64_t kve_vn_fileid;
-  __uint32_t kve_vn_fsid;
-  int kve_flags;
-  int kve_resident;
-  int kve_private_resident;
-  int kve_protection;
-  int kve_ref_count;
-  int kve_shadow_count;
-  int kve_vn_type;
-  __xuint64_t kve_vn_size;
-  __uint32_t kve_vn_rdev;
-  __uint16_t kve_vn_mode;
-  __uint16_t kve_status;
-  int _kve_ispare[12];
-  char kve_path[PATH_MAX];
-};
-
-typedef struct {
-  __uint32_t p_type;
-  __uint32_t p_offset;
-  __uint32_t p_vaddr;
-  __uint32_t p_paddr;
-  __uint32_t p_filesz;
-  __uint32_t p_memsz;
-  __uint32_t p_flags;
-  __uint32_t p_align;
-} XElf32_Phdr;
-
-struct xdl_phdr_info {
-  Elf_Addr dlpi_addr;
-  const char *dlpi_name;
-  const XElf32_Phdr *dlpi_phdr;
-  Elf_Half dlpi_phnum;
-  unsigned long long int dlpi_adds;
-  unsigned long long int dlpi_subs;
-  size_t dlpi_tls_modid;
-  void *dlpi_tls_data;
-};
-
-typedef int (*__xdl_iterate_hdr_callback)(struct xdl_phdr_info *, size_t,
-                                          void *);
-typedef int xdl_iterate_phdr_t(__xdl_iterate_hdr_callback, void *);
-
-#define xdl_iterate_phdr(callback, param) \
-  (((xdl_iterate_phdr_t *)dl_iterate_phdr)((callback), (param)))
-
-}  // namespace __sanitizer
-
-#endif  // __FreeBSD_version <= 902001
-#endif  // SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
-
-#endif  // SANITIZER_FREEBSD_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
index 0245164403c5..acbf3ebfc95c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cpp
@@ -94,7 +94,6 @@  void DisableCoreDumperIfNecessary() {}
 void InstallDeadlySignalHandlers(SignalHandlerType handler) {}
 void SetAlternateSignalStack() {}
 void UnsetAlternateSignalStack() {}
-void InitTlsSize() {}
 
 bool SignalContext::IsStackOverflow() const { return false; }
 void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); }
@@ -129,6 +128,60 @@  uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); }
 
 bool ErrorIsOOM(error_t err) { return err == ZX_ERR_NO_MEMORY; }
 
+// For any sanitizer internal that needs to map something which can be unmapped
+// later, first attempt to map to a pre-allocated VMAR. This helps reduce
+// fragmentation from many small anonymous mmap calls. A good value for this
+// VMAR size would be the total size of your typical sanitizer internal objects
+// allocated in an "average" process lifetime. Examples of this include:
+// FakeStack, LowLevelAllocator mappings, TwoLevelMap, InternalMmapVector,
+// StackStore, CreateAsanThread, etc.
+//
+// This is roughly equal to the total sum of sanitizer internal mappings for a
+// large test case.
+constexpr size_t kSanitizerHeapVmarSize = 13ULL << 20;
+static zx_handle_t gSanitizerHeapVmar = ZX_HANDLE_INVALID;
+
+static zx_status_t GetSanitizerHeapVmar(zx_handle_t *vmar) {
+  zx_status_t status = ZX_OK;
+  if (gSanitizerHeapVmar == ZX_HANDLE_INVALID) {
+    CHECK_EQ(kSanitizerHeapVmarSize % GetPageSizeCached(), 0);
+    uintptr_t base;
+    status = _zx_vmar_allocate(
+        _zx_vmar_root_self(),
+        ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0,
+        kSanitizerHeapVmarSize, &gSanitizerHeapVmar, &base);
+  }
+  *vmar = gSanitizerHeapVmar;
+  if (status == ZX_OK)
+    CHECK_NE(gSanitizerHeapVmar, ZX_HANDLE_INVALID);
+  return status;
+}
+
+static zx_status_t TryVmoMapSanitizerVmar(zx_vm_option_t options,
+                                          size_t vmar_offset, zx_handle_t vmo,
+                                          size_t size, uintptr_t *addr,
+                                          zx_handle_t *vmar_used = nullptr) {
+  zx_handle_t vmar;
+  zx_status_t status = GetSanitizerHeapVmar(&vmar);
+  if (status != ZX_OK)
+    return status;
+
+  status = _zx_vmar_map(gSanitizerHeapVmar, options, vmar_offset, vmo,
+                        /*vmo_offset=*/0, size, addr);
+  if (vmar_used)
+    *vmar_used = gSanitizerHeapVmar;
+  if (status == ZX_ERR_NO_RESOURCES || status == ZX_ERR_INVALID_ARGS) {
+    // This means there's no space in the heap VMAR, so fallback to the root
+    // VMAR.
+    status = _zx_vmar_map(_zx_vmar_root_self(), options, vmar_offset, vmo,
+                          /*vmo_offset=*/0, size, addr);
+    if (vmar_used)
+      *vmar_used = _zx_vmar_root_self();
+  }
+
+  return status;
+}
+
 static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type,
                                   bool raw_report, bool die_for_nomem) {
   size = RoundUpTo(size, GetPageSize());
@@ -144,11 +197,9 @@  static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type,
   _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type,
                           internal_strlen(mem_type));
 
-  // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that?
   uintptr_t addr;
-  status =
-      _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0,
-                   vmo, 0, size, &addr);
+  status = TryVmoMapSanitizerVmar(ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
+                                  /*vmar_offset=*/0, vmo, size, &addr);
   _zx_handle_close(vmo);
 
   if (status != ZX_OK) {
@@ -236,18 +287,22 @@  uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr map_size,
                           name ? name : name_, true);
 }
 
-void UnmapOrDieVmar(void *addr, uptr size, zx_handle_t target_vmar) {
+void UnmapOrDieVmar(void *addr, uptr size, zx_handle_t target_vmar,
+                    bool raw_report) {
   if (!addr || !size)
     return;
   size = RoundUpTo(size, GetPageSize());
 
   zx_status_t status =
       _zx_vmar_unmap(target_vmar, reinterpret_cast<uintptr_t>(addr), size);
-  if (status != ZX_OK) {
-    Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
-           SanitizerToolName, size, size, addr);
-    CHECK("unable to unmap" && 0);
+  if (status == ZX_ERR_INVALID_ARGS && target_vmar == gSanitizerHeapVmar) {
+    // If there wasn't any space in the heap vmar, the fallback was the root
+    // vmar.
+    status = _zx_vmar_unmap(_zx_vmar_root_self(),
+                            reinterpret_cast<uintptr_t>(addr), size);
   }
+  if (status != ZX_OK)
+    ReportMunmapFailureAndDie(addr, size, status, raw_report);
 
   DecreaseTotalMmap(size);
 }
@@ -269,7 +324,8 @@  void ReservedAddressRange::Unmap(uptr addr, uptr size) {
   }
   // Partial unmapping does not affect the fact that the initial range is still
   // reserved, and the resulting unmapped memory can't be reused.
-  UnmapOrDieVmar(reinterpret_cast<void *>(addr), size, vmar);
+  UnmapOrDieVmar(reinterpret_cast<void *>(addr), size, vmar,
+                 /*raw_report=*/false);
 }
 
 // This should never be called.
@@ -308,17 +364,16 @@  void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
   _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type,
                           internal_strlen(mem_type));
 
-  // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that?
-
   // Map a larger size to get a chunk of address space big enough that
   // it surely contains an aligned region of the requested size.  Then
   // overwrite the aligned middle portion with a mapping from the
   // beginning of the VMO, and unmap the excess before and after.
   size_t map_size = size + alignment;
   uintptr_t addr;
-  status =
-      _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0,
-                   vmo, 0, map_size, &addr);
+  zx_handle_t vmar_used;
+  status = TryVmoMapSanitizerVmar(ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
+                                  /*vmar_offset=*/0, vmo, map_size, &addr,
+                                  &vmar_used);
   if (status == ZX_OK) {
     uintptr_t map_addr = addr;
     uintptr_t map_end = map_addr + map_size;
@@ -326,12 +381,12 @@  void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
     uintptr_t end = addr + size;
     if (addr != map_addr) {
       zx_info_vmar_t info;
-      status = _zx_object_get_info(_zx_vmar_root_self(), ZX_INFO_VMAR, &info,
-                                   sizeof(info), NULL, NULL);
+      status = _zx_object_get_info(vmar_used, ZX_INFO_VMAR, &info, sizeof(info),
+                                   NULL, NULL);
       if (status == ZX_OK) {
         uintptr_t new_addr;
         status = _zx_vmar_map(
-            _zx_vmar_root_self(),
+            vmar_used,
             ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC_OVERWRITE,
             addr - info.base, vmo, 0, size, &new_addr);
         if (status == ZX_OK)
@@ -339,9 +394,9 @@  void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
       }
     }
     if (status == ZX_OK && addr != map_addr)
-      status = _zx_vmar_unmap(_zx_vmar_root_self(), map_addr, addr - map_addr);
+      status = _zx_vmar_unmap(vmar_used, map_addr, addr - map_addr);
     if (status == ZX_OK && end != map_end)
-      status = _zx_vmar_unmap(_zx_vmar_root_self(), end, map_end - end);
+      status = _zx_vmar_unmap(vmar_used, end, map_end - end);
   }
   _zx_handle_close(vmo);
 
@@ -356,8 +411,8 @@  void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
   return reinterpret_cast<void *>(addr);
 }
 
-void UnmapOrDie(void *addr, uptr size) {
-  UnmapOrDieVmar(addr, size, _zx_vmar_root_self());
+void UnmapOrDie(void *addr, uptr size, bool raw_report) {
+  UnmapOrDieVmar(addr, size, gSanitizerHeapVmar, raw_report);
 }
 
 void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
@@ -389,6 +444,11 @@  bool IsAccessibleMemoryRange(uptr beg, uptr size) {
   return status == ZX_OK;
 }
 
+bool TryMemCpy(void *dest, const void *src, uptr n) {
+  // TODO: implement.
+  return false;
+}
+
 // FIXME implement on this platform.
 void GetMemoryProfile(fill_profile_f cb, uptr *stats) {}
 
@@ -463,7 +523,6 @@  uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
 uptr MainThreadStackBase, MainThreadStackSize;
 
 bool GetRandom(void *buffer, uptr length, bool blocking) {
-  CHECK_LE(length, ZX_CPRNG_DRAW_MAX_LEN);
   _zx_cprng_draw(buffer, length);
   return true;
 }
diff --git a/libsanitizer/sanitizer_common/sanitizer_hash.h b/libsanitizer/sanitizer_common/sanitizer_hash.h
index f7cf9f234e6f..648fcfaa44e9 100644
--- a/libsanitizer/sanitizer_common/sanitizer_hash.h
+++ b/libsanitizer/sanitizer_common/sanitizer_hash.h
@@ -62,6 +62,6 @@  class MurMur2Hash64Builder {
     return x;
   }
 };
-}  //namespace __sanitizer
+}  // namespace __sanitizer
 
 #endif  // SANITIZER_HASH_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
index cd0d45e2f3fa..387a4d87d97b 100644
--- a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
+++ b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
@@ -49,6 +49,11 @@  __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args);
 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
 __sanitizer_report_error_summary(const char *error_summary);
 
+// Returns size of dynamically allocated block. This function can be overridden
+// by the client.
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE __sanitizer::uptr
+__sanitizer_get_dtls_size(const void *tls_begin);
+
 SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump();
 SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage(
     const __sanitizer::uptr *pcs, const __sanitizer::uptr len);
@@ -71,6 +76,11 @@  void __sanitizer_annotate_double_ended_contiguous_container(
     const void *old_container_beg, const void *old_container_end,
     const void *new_container_beg, const void *new_container_end);
 SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_copy_contiguous_container_annotations(const void *src_begin,
+                                                       const void *src_end,
+                                                       const void *dst_begin,
+                                                       const void *dst_end);
+SANITIZER_INTERFACE_ATTRIBUTE
 int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
                                             const void *end);
 SANITIZER_INTERFACE_ATTRIBUTE
diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
index 3809669dd48b..9208b12552ff 100644
--- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
+++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
@@ -35,13 +35,20 @@ 
 # define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllexport)
 #endif
 # define SANITIZER_WEAK_ATTRIBUTE
+#  define SANITIZER_WEAK_IMPORT
 #elif SANITIZER_GO
 # define SANITIZER_INTERFACE_ATTRIBUTE
 # define SANITIZER_WEAK_ATTRIBUTE
+#  define SANITIZER_WEAK_IMPORT
 #else
 # define SANITIZER_INTERFACE_ATTRIBUTE __attribute__((visibility("default")))
 # define SANITIZER_WEAK_ATTRIBUTE  __attribute__((weak))
-#endif
+#  if SANITIZER_APPLE
+#    define SANITIZER_WEAK_IMPORT extern "C" __attribute((weak_import))
+#  else
+#    define SANITIZER_WEAK_IMPORT extern "C" SANITIZER_WEAK_ATTRIBUTE
+#  endif  // SANITIZER_APPLE
+#endif    // SANITIZER_WINDOWS
 
 //--------------------------- WEAK FUNCTIONS ---------------------------------//
 // When working with weak functions, to simplify the code and make it more
@@ -131,19 +138,25 @@ 
 // in a portable way by the language itself.
 namespace __sanitizer {
 
-#if defined(_WIN64)
+#if defined(__UINTPTR_TYPE__)
+#  if defined(__arm__) && defined(__linux__)
+// Linux Arm headers redefine __UINTPTR_TYPE__ and disagree with clang/gcc.
+typedef unsigned int uptr;
+typedef int sptr;
+#  else
+typedef __UINTPTR_TYPE__ uptr;
+typedef __INTPTR_TYPE__ sptr;
+#  endif
+#elif defined(_WIN64)
 // 64-bit Windows uses LLP64 data model.
 typedef unsigned long long uptr;
 typedef signed long long sptr;
-#else
-#  if (SANITIZER_WORDSIZE == 64) || SANITIZER_APPLE || SANITIZER_WINDOWS
-typedef unsigned long uptr;
-typedef signed long sptr;
-#  else
+#elif defined(_WIN32)
 typedef unsigned int uptr;
 typedef signed int sptr;
-#  endif
-#endif  // defined(_WIN64)
+#else
+#  error Unsupported compiler, missing __UINTPTR_TYPE__
+#endif  // defined(__UINTPTR_TYPE__)
 #if defined(__x86_64__)
 // Since x32 uses ILP32 data model in 64-bit hardware mode, we must use
 // 64-bit pointer to unwind stack frame.
@@ -184,15 +197,10 @@  typedef uptr OFF_T;
 #endif
 typedef u64  OFF64_T;
 
-#if (SANITIZER_WORDSIZE == 64) || SANITIZER_APPLE
-typedef uptr operator_new_size_type;
+#ifdef __SIZE_TYPE__
+typedef __SIZE_TYPE__ usize;
 #else
-# if defined(__s390__) && !defined(__s390x__)
-// Special case: 31-bit s390 has unsigned long as size_t.
-typedef unsigned long operator_new_size_type;
-# else
-typedef u32 operator_new_size_type;
-# endif
+typedef uptr usize;
 #endif
 
 typedef u64 tid_t;
@@ -455,6 +463,9 @@  using namespace __sanitizer;
 namespace __msan {
 using namespace __sanitizer;
 }
+namespace __nsan {
+using namespace __sanitizer;
+}
 namespace __hwasan {
 using namespace __sanitizer;
 }
diff --git a/libsanitizer/sanitizer_common/sanitizer_libignore.cpp b/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
index b7fc9444cc66..271c92e330b6 100644
--- a/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_libignore.cpp
@@ -32,7 +32,7 @@  void LibIgnore::AddIgnoredLibrary(const char *name_templ) {
   lib->templ = internal_strdup(name_templ);
   lib->name = nullptr;
   lib->real_name = nullptr;
-  lib->loaded = false;
+  lib->range_id = kInvalidCodeRangeId;
 }
 
 void LibIgnore::OnLibraryLoaded(const char *name) {
@@ -43,7 +43,7 @@  void LibIgnore::OnLibraryLoaded(const char *name) {
       buf[0]) {
     for (uptr i = 0; i < count_; i++) {
       Lib *lib = &libs_[i];
-      if (!lib->loaded && (!lib->real_name) &&
+      if (!lib->loaded() && (!lib->real_name) &&
           TemplateMatch(lib->templ, name))
         lib->real_name = internal_strdup(buf.data());
     }
@@ -70,28 +70,31 @@  void LibIgnore::OnLibraryLoaded(const char *name) {
           Die();
         }
         loaded = true;
-        if (lib->loaded)
+        if (lib->loaded())
           continue;
         VReport(1,
                 "Matched called_from_lib suppression '%s' against library"
                 " '%s'\n",
                 lib->templ, mod.full_name());
-        lib->loaded = true;
         lib->name = internal_strdup(mod.full_name());
         const uptr idx =
             atomic_load(&ignored_ranges_count_, memory_order_relaxed);
         CHECK_LT(idx, ARRAY_SIZE(ignored_code_ranges_));
-        ignored_code_ranges_[idx].begin = range.beg;
-        ignored_code_ranges_[idx].end = range.end;
+        ignored_code_ranges_[idx].OnLoad(range.beg, range.end);
+        // Record the index of the ignored range.
+        lib->range_id = idx;
         atomic_store(&ignored_ranges_count_, idx + 1, memory_order_release);
         break;
       }
     }
-    if (lib->loaded && !loaded) {
-      Report("%s: library '%s' that was matched against called_from_lib"
-             " suppression '%s' is unloaded\n",
-             SanitizerToolName, lib->name, lib->templ);
-      Die();
+    if (lib->loaded() && !loaded) {
+      VReport(1,
+              "%s: library '%s' that was matched against called_from_lib"
+              " suppression '%s' is unloaded\n",
+              SanitizerToolName, lib->name, lib->templ);
+      // The library is unloaded so mark the ignored code range as unloaded.
+      ignored_code_ranges_[lib->range_id].OnUnload();
+      lib->range_id = kInvalidCodeRangeId;
     }
   }
 
@@ -105,13 +108,12 @@  void LibIgnore::OnLibraryLoaded(const char *name) {
           continue;
         if (IsPcInstrumented(range.beg) && IsPcInstrumented(range.end - 1))
           continue;
-        VReport(1, "Adding instrumented range 0x%zx-0x%zx from library '%s'\n",
-                range.beg, range.end, mod.full_name());
+        VReport(1, "Adding instrumented range %p-%p from library '%s'\n",
+                (void *)range.beg, (void *)range.end, mod.full_name());
         const uptr idx =
             atomic_load(&instrumented_ranges_count_, memory_order_relaxed);
         CHECK_LT(idx, ARRAY_SIZE(instrumented_code_ranges_));
-        instrumented_code_ranges_[idx].begin = range.beg;
-        instrumented_code_ranges_[idx].end = range.end;
+        instrumented_code_ranges_[idx].OnLoad(range.beg, range.end);
         atomic_store(&instrumented_ranges_count_, idx + 1,
                      memory_order_release);
       }
diff --git a/libsanitizer/sanitizer_common/sanitizer_libignore.h b/libsanitizer/sanitizer_common/sanitizer_libignore.h
index 18e4d83ed77f..0e26ff44c81c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_libignore.h
+++ b/libsanitizer/sanitizer_common/sanitizer_libignore.h
@@ -49,25 +49,36 @@  class LibIgnore {
   bool IsPcInstrumented(uptr pc) const;
 
  private:
+  static const uptr kMaxIgnoredRanges = 128;
+  static const uptr kMaxInstrumentedRanges = 1024;
+  static const uptr kMaxLibs = 1024;
+  static const uptr kInvalidCodeRangeId = -1;
+
   struct Lib {
     char *templ;
     char *name;
     char *real_name;  // target of symlink
-    bool loaded;
+    uptr range_id;
+    bool loaded() const { return range_id != kInvalidCodeRangeId; };
   };
 
   struct LibCodeRange {
-    uptr begin;
-    uptr end;
-  };
+    bool IsInRange(uptr pc) const {
+      return (pc >= begin && pc < atomic_load(&end, memory_order_acquire));
+    }
 
-  inline bool IsInRange(uptr pc, const LibCodeRange &range) const {
-    return (pc >= range.begin && pc < range.end);
-  }
+    void OnLoad(uptr b, uptr e) {
+      begin = b;
+      atomic_store(&end, e, memory_order_release);
+    }
 
-  static const uptr kMaxIgnoredRanges = 128;
-  static const uptr kMaxInstrumentedRanges = 1024;
-  static const uptr kMaxLibs = 1024;
+    void OnUnload() { atomic_store(&end, 0, memory_order_release); }
+
+   private:
+    uptr begin;
+    // A value of 0 means the associated module was unloaded.
+    atomic_uintptr_t end;
+  };
 
   // Hot part:
   atomic_uintptr_t ignored_ranges_count_;
@@ -90,7 +101,7 @@  class LibIgnore {
 inline bool LibIgnore::IsIgnored(uptr pc, bool *pc_in_ignored_lib) const {
   const uptr n = atomic_load(&ignored_ranges_count_, memory_order_acquire);
   for (uptr i = 0; i < n; i++) {
-    if (IsInRange(pc, ignored_code_ranges_[i])) {
+    if (ignored_code_ranges_[i].IsInRange(pc)) {
       *pc_in_ignored_lib = true;
       return true;
     }
@@ -104,7 +115,7 @@  inline bool LibIgnore::IsIgnored(uptr pc, bool *pc_in_ignored_lib) const {
 inline bool LibIgnore::IsPcInstrumented(uptr pc) const {
   const uptr n = atomic_load(&instrumented_ranges_count_, memory_order_acquire);
   for (uptr i = 0; i < n; i++) {
-    if (IsInRange(pc, instrumented_code_ranges_[i]))
+    if (instrumented_code_ranges_[i].IsInRange(pc))
       return true;
   }
   return false;
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
index d2b3b63f3a7a..8b1850f85010 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.cpp
@@ -16,101 +16,107 @@ 
 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
     SANITIZER_SOLARIS
 
-#include "sanitizer_common.h"
-#include "sanitizer_flags.h"
-#include "sanitizer_getauxval.h"
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_libc.h"
-#include "sanitizer_linux.h"
-#include "sanitizer_mutex.h"
-#include "sanitizer_placement_new.h"
-#include "sanitizer_procmaps.h"
-
-#if SANITIZER_LINUX && !SANITIZER_GO
-#include <asm/param.h>
-#endif
+#  include "sanitizer_common.h"
+#  include "sanitizer_flags.h"
+#  include "sanitizer_getauxval.h"
+#  include "sanitizer_internal_defs.h"
+#  include "sanitizer_libc.h"
+#  include "sanitizer_linux.h"
+#  include "sanitizer_mutex.h"
+#  include "sanitizer_placement_new.h"
+#  include "sanitizer_procmaps.h"
+
+#  if SANITIZER_LINUX && !SANITIZER_GO
+#    include <asm/param.h>
+#  endif
 
 // For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat'
 // format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To
 // access stat from asm/stat.h, without conflicting with definition in
-// sys/stat.h, we use this trick.
-#if SANITIZER_MIPS64
-#include <asm/unistd.h>
-#include <sys/types.h>
-#define stat kernel_stat
-#if SANITIZER_GO
-#undef st_atime
-#undef st_mtime
-#undef st_ctime
-#define st_atime st_atim
-#define st_mtime st_mtim
-#define st_ctime st_ctim
-#endif
-#include <asm/stat.h>
-#undef stat
-#endif
+// sys/stat.h, we use this trick.  sparc64 is similar, using
+// syscall(__NR_stat64) and struct kernel_stat64.
+#  if SANITIZER_LINUX && (SANITIZER_MIPS64 || SANITIZER_SPARC64)
+#    include <asm/unistd.h>
+#    include <sys/types.h>
+#    define stat kernel_stat
+#    if SANITIZER_SPARC64
+#      define stat64 kernel_stat64
+#    endif
+#    if SANITIZER_GO
+#      undef st_atime
+#      undef st_mtime
+#      undef st_ctime
+#      define st_atime st_atim
+#      define st_mtime st_mtim
+#      define st_ctime st_ctim
+#    endif
+#    include <asm/stat.h>
+#    undef stat
+#    undef stat64
+#  endif
 
-#include <dlfcn.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <link.h>
-#include <pthread.h>
-#include <sched.h>
-#include <signal.h>
-#include <sys/mman.h>
-#include <sys/param.h>
-#if !SANITIZER_SOLARIS
-#include <sys/ptrace.h>
-#endif
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <sys/syscall.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <ucontext.h>
-#include <unistd.h>
-
-#if SANITIZER_LINUX
-#include <sys/utsname.h>
-#endif
+#  include <dlfcn.h>
+#  include <errno.h>
+#  include <fcntl.h>
+#  include <link.h>
+#  include <pthread.h>
+#  include <sched.h>
+#  include <signal.h>
+#  include <sys/mman.h>
+#  if !SANITIZER_SOLARIS
+#    include <sys/ptrace.h>
+#  endif
+#  include <sys/resource.h>
+#  include <sys/stat.h>
+#  include <sys/syscall.h>
+#  include <sys/time.h>
+#  include <sys/types.h>
+#  include <ucontext.h>
+#  include <unistd.h>
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
-#include <sys/personality.h>
-#endif
+#  if SANITIZER_LINUX
+#    include <sys/utsname.h>
+#  endif
 
-#if SANITIZER_LINUX && defined(__loongarch__)
-#  include <sys/sysmacros.h>
-#endif
+#  if SANITIZER_LINUX && !SANITIZER_ANDROID
+#    include <sys/personality.h>
+#  endif
+
+#  if SANITIZER_LINUX && defined(__loongarch__)
+#    include <sys/sysmacros.h>
+#  endif
 
-#if SANITIZER_FREEBSD
-#include <sys/exec.h>
-#include <sys/procctl.h>
-#include <sys/sysctl.h>
-#include <machine/atomic.h>
+#  if SANITIZER_FREEBSD
+#    include <machine/atomic.h>
+#    include <sys/exec.h>
+#    include <sys/procctl.h>
+#    include <sys/sysctl.h>
 extern "C" {
 // <sys/umtx.h> must be included after <errno.h> and <sys/types.h> on
 // FreeBSD 9.2 and 10.0.
-#include <sys/umtx.h>
+#    include <sys/umtx.h>
 }
-#include <sys/thr.h>
-#endif  // SANITIZER_FREEBSD
+#    include <sys/thr.h>
+#  endif  // SANITIZER_FREEBSD
 
-#if SANITIZER_NETBSD
-#include <limits.h>  // For NAME_MAX
-#include <sys/sysctl.h>
-#include <sys/exec.h>
+#  if SANITIZER_NETBSD
+#    include <limits.h>  // For NAME_MAX
+#    include <sys/exec.h>
+#    include <sys/sysctl.h>
 extern struct ps_strings *__ps_strings;
-#endif  // SANITIZER_NETBSD
-
-#if SANITIZER_SOLARIS
-#include <stdlib.h>
-#include <thread.h>
-#define environ _environ
-#endif
+#  endif  // SANITIZER_NETBSD
+
+#  if SANITIZER_SOLARIS
+#    include <stddef.h>
+#    include <stdlib.h>
+#    include <sys/frame.h>
+#    include <thread.h>
+#    define environ _environ
+#  endif
 
 extern char **environ;
 
-#if SANITIZER_LINUX
+#  if SANITIZER_LINUX
 // <linux/time.h>
 struct kernel_timeval {
   long tv_sec;
@@ -123,36 +129,34 @@  const int FUTEX_WAKE = 1;
 const int FUTEX_PRIVATE_FLAG = 128;
 const int FUTEX_WAIT_PRIVATE = FUTEX_WAIT | FUTEX_PRIVATE_FLAG;
 const int FUTEX_WAKE_PRIVATE = FUTEX_WAKE | FUTEX_PRIVATE_FLAG;
-#endif  // SANITIZER_LINUX
+#  endif  // SANITIZER_LINUX
 
 // Are we using 32-bit or 64-bit Linux syscalls?
 // x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
 // but it still needs to use 64-bit syscalls.
-#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \
-                        SANITIZER_WORDSIZE == 64 ||                      \
-                        (defined(__mips__) && _MIPS_SIM == _ABIN32))
-# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1
-#else
-# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
-#endif
+#  if SANITIZER_LINUX && (defined(__x86_64__) || defined(__powerpc64__) || \
+                          SANITIZER_WORDSIZE == 64 ||                      \
+                          (defined(__mips__) && _MIPS_SIM == _ABIN32))
+#    define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1
+#  else
+#    define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
+#  endif
 
-// Note : FreeBSD had implemented both
-// Linux apis, available from
-// future 12.x version most likely
-#if SANITIZER_LINUX && defined(__NR_getrandom)
-# if !defined(GRND_NONBLOCK)
-#  define GRND_NONBLOCK 1
-# endif
-# define SANITIZER_USE_GETRANDOM 1
-#else
-# define SANITIZER_USE_GETRANDOM 0
-#endif  // SANITIZER_LINUX && defined(__NR_getrandom)
-
-#if SANITIZER_FREEBSD && __FreeBSD_version >= 1200000
-#  define SANITIZER_USE_GETENTROPY 1
-#else
-#  define SANITIZER_USE_GETENTROPY 0
-#endif
+// Note : FreeBSD implemented both Linux and OpenBSD apis.
+#  if SANITIZER_LINUX && defined(__NR_getrandom)
+#    if !defined(GRND_NONBLOCK)
+#      define GRND_NONBLOCK 1
+#    endif
+#    define SANITIZER_USE_GETRANDOM 1
+#  else
+#    define SANITIZER_USE_GETRANDOM 0
+#  endif  // SANITIZER_LINUX && defined(__NR_getrandom)
+
+#  if SANITIZER_FREEBSD
+#    define SANITIZER_USE_GETENTROPY 1
+extern "C" void *__sys_mmap(void *addr, size_t len, int prot, int flags, int fd,
+                            off_t offset);
+#  endif
 
 namespace __sanitizer {
 
@@ -160,6 +164,7 @@  void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) {
   CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, set, oldset));
 }
 
+// Block asynchronous signals
 void BlockSignals(__sanitizer_sigset_t *oldset) {
   __sanitizer_sigset_t set;
   internal_sigfillset(&set);
@@ -174,7 +179,17 @@  void BlockSignals(__sanitizer_sigset_t *oldset) {
   // If this signal is blocked, such calls cannot be handled and the process may
   // hang.
   internal_sigdelset(&set, 31);
+
+  // Don't block synchronous signals
+  internal_sigdelset(&set, SIGSEGV);
+  internal_sigdelset(&set, SIGBUS);
+  internal_sigdelset(&set, SIGILL);
+  internal_sigdelset(&set, SIGTRAP);
+  internal_sigdelset(&set, SIGABRT);
+  internal_sigdelset(&set, SIGFPE);
+  internal_sigdelset(&set, SIGPIPE);
 #  endif
+
   SetSigProcMask(&set, oldset);
 }
 
@@ -203,33 +218,35 @@  ScopedBlockSignals::~ScopedBlockSignals() { SetSigProcMask(&saved_, nullptr); }
 #  endif
 
 // --------------- sanitizer_libc.h
-#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
-#if !SANITIZER_S390
+#  if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
+#    if !SANITIZER_S390
 uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
                    u64 offset) {
-#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
+#      if SANITIZER_FREEBSD
+  return (uptr)__sys_mmap(addr, length, prot, flags, fd, offset);
+#      elif SANITIZER_LINUX_USES_64BIT_SYSCALLS
   return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd,
                           offset);
-#else
+#      else
   // mmap2 specifies file offset in 4096-byte units.
   CHECK(IsAligned(offset, 4096));
   return internal_syscall(SYSCALL(mmap2), addr, length, prot, flags, fd,
-                          offset / 4096);
-#endif
+                          (OFF_T)(offset / 4096));
+#      endif
 }
-#endif // !SANITIZER_S390
+#    endif  // !SANITIZER_S390
 
 uptr internal_munmap(void *addr, uptr length) {
   return internal_syscall(SYSCALL(munmap), (uptr)addr, length);
 }
 
-#if SANITIZER_LINUX
+#    if SANITIZER_LINUX
 uptr internal_mremap(void *old_address, uptr old_size, uptr new_size, int flags,
                      void *new_address) {
   return internal_syscall(SYSCALL(mremap), (uptr)old_address, old_size,
                           new_size, flags, (uptr)new_address);
 }
-#endif
+#    endif
 
 int internal_mprotect(void *addr, uptr length, int prot) {
   return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot);
@@ -239,25 +256,28 @@  int internal_madvise(uptr addr, uptr length, int advice) {
   return internal_syscall(SYSCALL(madvise), addr, length, advice);
 }
 
-uptr internal_close(fd_t fd) {
-  return internal_syscall(SYSCALL(close), fd);
+#    if SANITIZER_FREEBSD
+uptr internal_close_range(fd_t lowfd, fd_t highfd, int flags) {
+  return internal_syscall(SYSCALL(close_range), lowfd, highfd, flags);
 }
+#    endif
+uptr internal_close(fd_t fd) { return internal_syscall(SYSCALL(close), fd); }
 
 uptr internal_open(const char *filename, int flags) {
 #    if SANITIZER_LINUX
   return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags);
-#else
+#    else
   return internal_syscall(SYSCALL(open), (uptr)filename, flags);
-#endif
+#    endif
 }
 
 uptr internal_open(const char *filename, int flags, u32 mode) {
 #    if SANITIZER_LINUX
   return internal_syscall(SYSCALL(openat), AT_FDCWD, (uptr)filename, flags,
                           mode);
-#else
+#    else
   return internal_syscall(SYSCALL(open), (uptr)filename, flags, mode);
-#endif
+#    endif
 }
 
 uptr internal_read(fd_t fd, void *buf, uptr count) {
@@ -276,12 +296,12 @@  uptr internal_write(fd_t fd, const void *buf, uptr count) {
 
 uptr internal_ftruncate(fd_t fd, uptr size) {
   sptr res;
-  HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd,
-               (OFF_T)size));
+  HANDLE_EINTR(res,
+               (sptr)internal_syscall(SYSCALL(ftruncate), fd, (OFF_T)size));
   return res;
 }
 
-#if (!SANITIZER_LINUX_USES_64BIT_SYSCALLS || SANITIZER_SPARC) && SANITIZER_LINUX
+#    if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX
 static void stat64_to_stat(struct stat64 *in, struct stat *out) {
   internal_memset(out, 0, sizeof(*out));
   out->st_dev = in->st_dev;
@@ -298,9 +318,9 @@  static void stat64_to_stat(struct stat64 *in, struct stat *out) {
   out->st_mtime = in->st_mtime;
   out->st_ctime = in->st_ctime;
 }
-#endif
+#    endif
 
-#if SANITIZER_LINUX && defined(__loongarch__)
+#    if SANITIZER_LINUX && defined(__loongarch__)
 static void statx_to_stat(struct statx *in, struct stat *out) {
   internal_memset(out, 0, sizeof(*out));
   out->st_dev = makedev(in->stx_dev_major, in->stx_dev_minor);
@@ -320,27 +340,32 @@  static void statx_to_stat(struct statx *in, struct stat *out) {
   out->st_ctime = in->stx_ctime.tv_sec;
   out->st_ctim.tv_nsec = in->stx_ctime.tv_nsec;
 }
-#endif
+#    endif
 
-#if SANITIZER_MIPS64
+#    if SANITIZER_MIPS64 || SANITIZER_SPARC64
+#      if SANITIZER_MIPS64
+typedef struct kernel_stat kstat_t;
+#      else
+typedef struct kernel_stat64 kstat_t;
+#      endif
 // Undefine compatibility macros from <sys/stat.h>
 // so that they would not clash with the kernel_stat
 // st_[a|m|c]time fields
-#if !SANITIZER_GO
-#undef st_atime
-#undef st_mtime
-#undef st_ctime
-#endif
-#if defined(SANITIZER_ANDROID)
+#      if !SANITIZER_GO
+#        undef st_atime
+#        undef st_mtime
+#        undef st_ctime
+#      endif
+#      if defined(SANITIZER_ANDROID)
 // Bionic sys/stat.h defines additional macros
 // for compatibility with the old NDKs and
 // they clash with the kernel_stat structure
 // st_[a|m|c]time_nsec fields.
-#undef st_atime_nsec
-#undef st_mtime_nsec
-#undef st_ctime_nsec
-#endif
-static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) {
+#        undef st_atime_nsec
+#        undef st_mtime_nsec
+#        undef st_ctime_nsec
+#      endif
+static void kernel_stat_to_stat(kstat_t *in, struct stat *out) {
   internal_memset(out, 0, sizeof(*out));
   out->st_dev = in->st_dev;
   out->st_ino = in->st_ino;
@@ -352,96 +377,113 @@  static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) {
   out->st_size = in->st_size;
   out->st_blksize = in->st_blksize;
   out->st_blocks = in->st_blocks;
-#if defined(__USE_MISC)     || \
-    defined(__USE_XOPEN2K8) || \
-    defined(SANITIZER_ANDROID)
+#      if defined(__USE_MISC) || defined(__USE_XOPEN2K8) || \
+          defined(SANITIZER_ANDROID)
   out->st_atim.tv_sec = in->st_atime;
   out->st_atim.tv_nsec = in->st_atime_nsec;
   out->st_mtim.tv_sec = in->st_mtime;
   out->st_mtim.tv_nsec = in->st_mtime_nsec;
   out->st_ctim.tv_sec = in->st_ctime;
   out->st_ctim.tv_nsec = in->st_ctime_nsec;
-#else
+#      else
   out->st_atime = in->st_atime;
   out->st_atimensec = in->st_atime_nsec;
   out->st_mtime = in->st_mtime;
   out->st_mtimensec = in->st_mtime_nsec;
   out->st_ctime = in->st_ctime;
   out->st_atimensec = in->st_ctime_nsec;
-#endif
+#      endif
 }
-#endif
+#    endif
 
 uptr internal_stat(const char *path, void *buf) {
-#  if SANITIZER_FREEBSD
+#    if SANITIZER_FREEBSD
   return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0);
-#  elif SANITIZER_LINUX
-#    if defined(__loongarch__)
+#    elif SANITIZER_LINUX
+#      if defined(__loongarch__)
   struct statx bufx;
   int res = internal_syscall(SYSCALL(statx), AT_FDCWD, (uptr)path,
                              AT_NO_AUTOMOUNT, STATX_BASIC_STATS, (uptr)&bufx);
   statx_to_stat(&bufx, (struct stat *)buf);
   return res;
-#    elif (SANITIZER_WORDSIZE == 64 || SANITIZER_X32 ||    \
-           (defined(__mips__) && _MIPS_SIM == _ABIN32)) && \
-        !SANITIZER_SPARC
+#      elif (SANITIZER_WORDSIZE == 64 || SANITIZER_X32 ||    \
+             (defined(__mips__) && _MIPS_SIM == _ABIN32)) && \
+          !SANITIZER_SPARC
   return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf,
                           0);
-#    else
+#      elif SANITIZER_SPARC64
+  kstat_t buf64;
+  int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
+                             (uptr)&buf64, 0);
+  kernel_stat_to_stat(&buf64, (struct stat *)buf);
+  return res;
+#      else
   struct stat64 buf64;
   int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
                              (uptr)&buf64, 0);
   stat64_to_stat(&buf64, (struct stat *)buf);
   return res;
-#    endif
-#  else
+#      endif
+#    else
   struct stat64 buf64;
   int res = internal_syscall(SYSCALL(stat64), path, &buf64);
   stat64_to_stat(&buf64, (struct stat *)buf);
   return res;
-#  endif
+#    endif
 }
 
 uptr internal_lstat(const char *path, void *buf) {
-#  if SANITIZER_FREEBSD
+#    if SANITIZER_FREEBSD
   return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path, (uptr)buf,
                           AT_SYMLINK_NOFOLLOW);
-#  elif SANITIZER_LINUX
-#    if defined(__loongarch__)
+#    elif SANITIZER_LINUX
+#      if defined(__loongarch__)
   struct statx bufx;
   int res = internal_syscall(SYSCALL(statx), AT_FDCWD, (uptr)path,
                              AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT,
                              STATX_BASIC_STATS, (uptr)&bufx);
   statx_to_stat(&bufx, (struct stat *)buf);
   return res;
-#    elif (defined(_LP64) || SANITIZER_X32 ||              \
-           (defined(__mips__) && _MIPS_SIM == _ABIN32)) && \
-        !SANITIZER_SPARC
+#      elif (defined(_LP64) || SANITIZER_X32 ||              \
+             (defined(__mips__) && _MIPS_SIM == _ABIN32)) && \
+          !SANITIZER_SPARC
   return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf,
                           AT_SYMLINK_NOFOLLOW);
-#    else
+#      elif SANITIZER_SPARC64
+  kstat_t buf64;
+  int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
+                             (uptr)&buf64, AT_SYMLINK_NOFOLLOW);
+  kernel_stat_to_stat(&buf64, (struct stat *)buf);
+  return res;
+#      else
   struct stat64 buf64;
   int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path,
                              (uptr)&buf64, AT_SYMLINK_NOFOLLOW);
   stat64_to_stat(&buf64, (struct stat *)buf);
   return res;
-#    endif
-#  else
+#      endif
+#    else
   struct stat64 buf64;
   int res = internal_syscall(SYSCALL(lstat64), path, &buf64);
   stat64_to_stat(&buf64, (struct stat *)buf);
   return res;
-#  endif
+#    endif
 }
 
 uptr internal_fstat(fd_t fd, void *buf) {
-#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
-#if SANITIZER_MIPS64
+#    if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
+#      if SANITIZER_MIPS64
   // For mips64, fstat syscall fills buffer in the format of kernel_stat
-  struct kernel_stat kbuf;
+  kstat_t kbuf;
   int res = internal_syscall(SYSCALL(fstat), fd, &kbuf);
   kernel_stat_to_stat(&kbuf, (struct stat *)buf);
   return res;
+#      elif SANITIZER_LINUX && SANITIZER_SPARC64
+  // For sparc64, fstat64 syscall fills buffer in the format of kernel_stat64
+  kstat_t kbuf;
+  int res = internal_syscall(SYSCALL(fstat64), fd, &kbuf);
+  kernel_stat_to_stat(&kbuf, (struct stat *)buf);
+  return res;
 #      elif SANITIZER_LINUX && defined(__loongarch__)
   struct statx bufx;
   int res = internal_syscall(SYSCALL(statx), fd, "", AT_EMPTY_PATH,
@@ -451,12 +493,12 @@  uptr internal_fstat(fd_t fd, void *buf) {
 #      else
   return internal_syscall(SYSCALL(fstat), fd, (uptr)buf);
 #      endif
-#else
+#    else
   struct stat64 buf64;
   int res = internal_syscall(SYSCALL(fstat64), fd, &buf64);
   stat64_to_stat(&buf64, (struct stat *)buf);
   return res;
-#endif
+#    endif
 }
 
 uptr internal_filesize(fd_t fd) {
@@ -466,50 +508,46 @@  uptr internal_filesize(fd_t fd) {
   return (uptr)st.st_size;
 }
 
-uptr internal_dup(int oldfd) {
-  return internal_syscall(SYSCALL(dup), oldfd);
-}
+uptr internal_dup(int oldfd) { return internal_syscall(SYSCALL(dup), oldfd); }
 
 uptr internal_dup2(int oldfd, int newfd) {
 #    if SANITIZER_LINUX
   return internal_syscall(SYSCALL(dup3), oldfd, newfd, 0);
-#else
+#    else
   return internal_syscall(SYSCALL(dup2), oldfd, newfd);
-#endif
+#    endif
 }
 
 uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
 #    if SANITIZER_LINUX
   return internal_syscall(SYSCALL(readlinkat), AT_FDCWD, (uptr)path, (uptr)buf,
                           bufsize);
-#else
+#    else
   return internal_syscall(SYSCALL(readlink), (uptr)path, (uptr)buf, bufsize);
-#endif
+#    endif
 }
 
 uptr internal_unlink(const char *path) {
 #    if SANITIZER_LINUX
   return internal_syscall(SYSCALL(unlinkat), AT_FDCWD, (uptr)path, 0);
-#else
+#    else
   return internal_syscall(SYSCALL(unlink), (uptr)path);
-#endif
+#    endif
 }
 
 uptr internal_rename(const char *oldpath, const char *newpath) {
-#  if (defined(__riscv) || defined(__loongarch__)) && defined(__linux__)
+#    if (defined(__riscv) || defined(__loongarch__)) && defined(__linux__)
   return internal_syscall(SYSCALL(renameat2), AT_FDCWD, (uptr)oldpath, AT_FDCWD,
                           (uptr)newpath, 0);
-#  elif SANITIZER_LINUX
+#    elif SANITIZER_LINUX
   return internal_syscall(SYSCALL(renameat), AT_FDCWD, (uptr)oldpath, AT_FDCWD,
                           (uptr)newpath);
-#  else
+#    else
   return internal_syscall(SYSCALL(rename), (uptr)oldpath, (uptr)newpath);
-#  endif
+#    endif
 }
 
-uptr internal_sched_yield() {
-  return internal_syscall(SYSCALL(sched_yield));
-}
+uptr internal_sched_yield() { return internal_syscall(SYSCALL(sched_yield)); }
 
 void internal_usleep(u64 useconds) {
   struct timespec ts;
@@ -523,18 +561,18 @@  uptr internal_execve(const char *filename, char *const argv[],
   return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv,
                           (uptr)envp);
 }
-#endif  // !SANITIZER_SOLARIS && !SANITIZER_NETBSD
+#  endif  // !SANITIZER_SOLARIS && !SANITIZER_NETBSD
 
-#if !SANITIZER_NETBSD
+#  if !SANITIZER_NETBSD
 void internal__exit(int exitcode) {
-#if SANITIZER_FREEBSD || SANITIZER_SOLARIS
+#    if SANITIZER_FREEBSD || SANITIZER_SOLARIS
   internal_syscall(SYSCALL(exit), exitcode);
-#else
+#    else
   internal_syscall(SYSCALL(exit_group), exitcode);
-#endif
+#    endif
   Die();  // Unreachable.
 }
-#endif  // !SANITIZER_NETBSD
+#  endif  // !SANITIZER_NETBSD
 
 // ----------------- sanitizer_common.h
 bool FileExists(const char *filename) {
@@ -556,30 +594,32 @@  bool DirExists(const char *path) {
 
 #  if !SANITIZER_NETBSD
 tid_t GetTid() {
-#if SANITIZER_FREEBSD
+#    if SANITIZER_FREEBSD
   long Tid;
   thr_self(&Tid);
   return Tid;
-#elif SANITIZER_SOLARIS
+#    elif SANITIZER_SOLARIS
   return thr_self();
-#else
+#    else
   return internal_syscall(SYSCALL(gettid));
-#endif
+#    endif
 }
 
 int TgKill(pid_t pid, tid_t tid, int sig) {
-#if SANITIZER_LINUX
+#    if SANITIZER_LINUX
   return internal_syscall(SYSCALL(tgkill), pid, tid, sig);
-#elif SANITIZER_FREEBSD
+#    elif SANITIZER_FREEBSD
   return internal_syscall(SYSCALL(thr_kill2), pid, tid, sig);
-#elif SANITIZER_SOLARIS
+#    elif SANITIZER_SOLARIS
   (void)pid;
-  return thr_kill(tid, sig);
-#endif
+  errno = thr_kill(tid, sig);
+  // TgKill is expected to return -1 on error, not an errno.
+  return errno != 0 ? -1 : 0;
+#    endif
 }
-#endif
+#  endif
 
-#if SANITIZER_GLIBC
+#  if SANITIZER_GLIBC
 u64 NanoTime() {
   kernel_timeval tv;
   internal_memset(&tv, 0, sizeof(tv));
@@ -590,19 +630,19 @@  u64 NanoTime() {
 uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) {
   return internal_syscall(SYSCALL(clock_gettime), clk_id, tp);
 }
-#elif !SANITIZER_SOLARIS && !SANITIZER_NETBSD
+#  elif !SANITIZER_SOLARIS && !SANITIZER_NETBSD
 u64 NanoTime() {
   struct timespec ts;
   clock_gettime(CLOCK_REALTIME, &ts);
   return (u64)ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
 }
-#endif
+#  endif
 
 // Like getenv, but reads env directly from /proc (on Linux) or parses the
 // 'environ' array (on some others) and does not use libc. This function
 // should be called first inside __asan_init.
 const char *GetEnv(const char *name) {
-#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS
+#  if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS
   if (::environ != 0) {
     uptr NameLen = internal_strlen(name);
     for (char **Env = ::environ; *Env != 0; Env++) {
@@ -611,7 +651,7 @@  const char *GetEnv(const char *name) {
     }
   }
   return 0;  // Not found.
-#elif SANITIZER_LINUX
+#  elif SANITIZER_LINUX
   static char *environ;
   static uptr len;
   static bool inited;
@@ -621,13 +661,13 @@  const char *GetEnv(const char *name) {
     if (!ReadFileToBuffer("/proc/self/environ", &environ, &environ_size, &len))
       environ = nullptr;
   }
-  if (!environ || len == 0) return nullptr;
+  if (!environ || len == 0)
+    return nullptr;
   uptr namelen = internal_strlen(name);
   const char *p = environ;
   while (*p != '\0') {  // will happen at the \0\0 that terminates the buffer
     // proc file has the format NAME=value\0NAME=value\0NAME=value\0...
-    const char* endp =
-        (char*)internal_memchr(p, '\0', len - (p - environ));
+    const char *endp = (char *)internal_memchr(p, '\0', len - (p - environ));
     if (!endp)  // this entry isn't NUL terminated
       return nullptr;
     else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=')  // Match.
@@ -635,18 +675,18 @@  const char *GetEnv(const char *name) {
     p = endp + 1;
   }
   return nullptr;  // Not found.
-#else
-#error "Unsupported platform"
-#endif
+#  else
+#    error "Unsupported platform"
+#  endif
 }
 
-#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_GO
+#  if !SANITIZER_FREEBSD && !SANITIZER_NETBSD && !SANITIZER_GO
 extern "C" {
 SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end;
 }
-#endif
+#  endif
 
-#if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
+#  if !SANITIZER_FREEBSD && !SANITIZER_NETBSD
 static void ReadNullSepFileToArray(const char *path, char ***arr,
                                    int arr_size) {
   char *buff;
@@ -659,20 +699,21 @@  static void ReadNullSepFileToArray(const char *path, char ***arr,
   }
   (*arr)[0] = buff;
   int count, i;
-  for (count = 1, i = 1; ; i++) {
+  for (count = 1, i = 1;; i++) {
     if (buff[i] == 0) {
-      if (buff[i+1] == 0) break;
-      (*arr)[count] = &buff[i+1];
+      if (buff[i + 1] == 0)
+        break;
+      (*arr)[count] = &buff[i + 1];
       CHECK_LE(count, arr_size - 1);  // FIXME: make this more flexible.
       count++;
     }
   }
   (*arr)[count] = nullptr;
 }
-#endif
+#  endif
 
 static void GetArgsAndEnv(char ***argv, char ***envp) {
-#if SANITIZER_FREEBSD
+#  if SANITIZER_FREEBSD
   // On FreeBSD, retrieving the argument and environment arrays is done via the
   // kern.ps_strings sysctl, which returns a pointer to a structure containing
   // this information. See also <sys/exec.h>.
@@ -684,30 +725,35 @@  static void GetArgsAndEnv(char ***argv, char ***envp) {
   }
   *argv = pss->ps_argvstr;
   *envp = pss->ps_envstr;
-#elif SANITIZER_NETBSD
+#  elif SANITIZER_NETBSD
   *argv = __ps_strings->ps_argvstr;
   *envp = __ps_strings->ps_envstr;
-#else // SANITIZER_FREEBSD
-#if !SANITIZER_GO
+#  else  // SANITIZER_FREEBSD
+#    if !SANITIZER_GO
   if (&__libc_stack_end) {
-    uptr* stack_end = (uptr*)__libc_stack_end;
+    uptr *stack_end = (uptr *)__libc_stack_end;
+    // Linux/sparc64 needs an adjustment, cf. glibc
+    // sysdeps/sparc/sparc{32,64}/dl-machine.h (DL_STACK_END).
+#      if SANITIZER_LINUX && defined(__sparc__)
+    stack_end = &stack_end[16];
+#      endif
     // Normally argc can be obtained from *stack_end, however, on ARM glibc's
     // _start clobbers it:
     // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/arm/start.S;hb=refs/heads/release/2.31/master#l75
     // Do not special-case ARM and infer argc from argv everywhere.
     int argc = 0;
     while (stack_end[argc + 1]) argc++;
-    *argv = (char**)(stack_end + 1);
-    *envp = (char**)(stack_end + argc + 2);
+    *argv = (char **)(stack_end + 1);
+    *envp = (char **)(stack_end + argc + 2);
   } else {
-#endif // !SANITIZER_GO
+#    endif  // !SANITIZER_GO
     static const int kMaxArgv = 2000, kMaxEnvp = 2000;
     ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv);
     ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp);
-#if !SANITIZER_GO
+#    if !SANITIZER_GO
   }
-#endif // !SANITIZER_GO
-#endif // SANITIZER_FREEBSD
+#    endif  // !SANITIZER_GO
+#  endif    // SANITIZER_FREEBSD
 }
 
 char **GetArgv() {
@@ -722,12 +768,12 @@  char **GetEnviron() {
   return envp;
 }
 
-#if !SANITIZER_SOLARIS
+#  if !SANITIZER_SOLARIS
 void FutexWait(atomic_uint32_t *p, u32 cmp) {
 #    if SANITIZER_FREEBSD
   _umtx_op(p, UMTX_OP_WAIT_UINT, cmp, 0, 0);
 #    elif SANITIZER_NETBSD
-  sched_yield();   /* No userspace futex-like synchronization */
+  sched_yield(); /* No userspace futex-like synchronization */
 #    else
   internal_syscall(SYSCALL(futex), (uptr)p, FUTEX_WAIT_PRIVATE, cmp, 0, 0, 0);
 #    endif
@@ -737,7 +783,7 @@  void FutexWake(atomic_uint32_t *p, u32 count) {
 #    if SANITIZER_FREEBSD
   _umtx_op(p, UMTX_OP_WAKE, count, 0, 0);
 #    elif SANITIZER_NETBSD
-                   /* No userspace futex-like synchronization */
+  /* No userspace futex-like synchronization */
 #    else
   internal_syscall(SYSCALL(futex), (uptr)p, FUTEX_WAKE_PRIVATE, count, 0, 0, 0);
 #    endif
@@ -749,26 +795,26 @@  void FutexWake(atomic_uint32_t *p, u32 count) {
 // The actual size of this structure is specified by d_reclen.
 // Note that getdents64 uses a different structure format. We only provide the
 // 32-bit syscall here.
-#if SANITIZER_NETBSD
+#  if SANITIZER_NETBSD
 // Not used
-#else
+#  else
 struct linux_dirent {
 #    if SANITIZER_X32 || SANITIZER_LINUX
   u64 d_ino;
   u64 d_off;
 #    else
-  unsigned long      d_ino;
-  unsigned long      d_off;
+  unsigned long d_ino;
+  unsigned long d_off;
 #    endif
-  unsigned short     d_reclen;
+  unsigned short d_reclen;
 #    if SANITIZER_LINUX
-  unsigned char      d_type;
+  unsigned char d_type;
 #    endif
-  char               d_name[256];
+  char d_name[256];
 };
-#endif
+#  endif
 
-#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
+#  if !SANITIZER_SOLARIS && !SANITIZER_NETBSD
 // Syscall wrappers.
 uptr internal_ptrace(int request, int pid, void *addr, void *data) {
   return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr,
@@ -780,24 +826,20 @@  uptr internal_waitpid(int pid, int *status, int options) {
                           0 /* rusage */);
 }
 
-uptr internal_getpid() {
-  return internal_syscall(SYSCALL(getpid));
-}
+uptr internal_getpid() { return internal_syscall(SYSCALL(getpid)); }
 
-uptr internal_getppid() {
-  return internal_syscall(SYSCALL(getppid));
-}
+uptr internal_getppid() { return internal_syscall(SYSCALL(getppid)); }
 
 int internal_dlinfo(void *handle, int request, void *p) {
-#if SANITIZER_FREEBSD
+#    if SANITIZER_FREEBSD
   return dlinfo(handle, request, p);
-#else
+#    else
   UNIMPLEMENTED();
-#endif
+#    endif
 }
 
 uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
-#if SANITIZER_FREEBSD
+#    if SANITIZER_FREEBSD
   return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL);
 #    elif SANITIZER_LINUX
   return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count);
@@ -810,7 +852,7 @@  uptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
   return internal_syscall(SYSCALL(lseek), fd, offset, whence);
 }
 
-#if SANITIZER_LINUX
+#    if SANITIZER_LINUX
 uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
   return internal_syscall(SYSCALL(prctl), option, arg2, arg3, arg4, arg5);
 }
@@ -827,10 +869,16 @@  uptr internal_sigaltstack(const void *ss, void *oss) {
   return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss);
 }
 
+extern "C" pid_t __fork(void);
+
 int internal_fork() {
 #    if SANITIZER_LINUX
 #      if SANITIZER_S390
   return internal_syscall(SYSCALL(clone), 0, SIGCHLD);
+#      elif SANITIZER_SPARC
+  // The clone syscall interface on SPARC differs massively from the rest,
+  // so fall back to __fork.
+  return __fork();
 #      else
   return internal_syscall(SYSCALL(clone), SIGCHLD, 0);
 #      endif
@@ -839,7 +887,7 @@  int internal_fork() {
 #    endif
 }
 
-#if SANITIZER_FREEBSD
+#    if SANITIZER_FREEBSD
 int internal_sysctl(const int *name, unsigned int namelen, void *oldp,
                     uptr *oldlenp, const void *newp, uptr newlen) {
   return internal_syscall(SYSCALL(__sysctl), name, namelen, oldp,
@@ -854,11 +902,11 @@  int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,
   // followed by sysctl(). To avoid calling the intercepted version and
   // asserting if this happens during startup, call the real sysctlnametomib()
   // followed by internal_sysctl() if the syscall is not available.
-#ifdef SYS___sysctlbyname
+#      ifdef SYS___sysctlbyname
   return internal_syscall(SYSCALL(__sysctlbyname), sname,
                           internal_strlen(sname), oldp, (size_t *)oldlenp, newp,
                           (size_t)newlen);
-#else
+#      else
   static decltype(sysctlnametomib) *real_sysctlnametomib = nullptr;
   if (!real_sysctlnametomib)
     real_sysctlnametomib =
@@ -870,12 +918,12 @@  int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,
   if (real_sysctlnametomib(sname, oid, &len) == -1)
     return (-1);
   return internal_sysctl(oid, len, oldp, oldlenp, newp, newlen);
-#endif
+#      endif
 }
-#endif
+#    endif
 
-#if SANITIZER_LINUX
-#define SA_RESTORER 0x04000000
+#    if SANITIZER_LINUX
+#      define SA_RESTORER 0x04000000
 // Doesn't set sa_restorer if the caller did not set it, so use with caution
 //(see below).
 int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
@@ -899,15 +947,15 @@  int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
     // rt_sigaction, so we need to do the same (we'll need to reimplement the
     // restorers; for x86_64 the restorer address can be obtained from
     // oldact->sa_restorer upon a call to sigaction(xxx, NULL, oldact).
-#if !SANITIZER_ANDROID || !SANITIZER_MIPS32
+#      if !SANITIZER_ANDROID || !SANITIZER_MIPS32
     k_act.sa_restorer = u_act->sa_restorer;
-#endif
+#      endif
   }
 
   uptr result = internal_syscall(SYSCALL(rt_sigaction), (uptr)signum,
-      (uptr)(u_act ? &k_act : nullptr),
-      (uptr)(u_oldact ? &k_oldact : nullptr),
-      (uptr)sizeof(__sanitizer_kernel_sigset_t));
+                                 (uptr)(u_act ? &k_act : nullptr),
+                                 (uptr)(u_oldact ? &k_oldact : nullptr),
+                                 (uptr)sizeof(__sanitizer_kernel_sigset_t));
 
   if ((result == 0) && u_oldact) {
     u_oldact->handler = k_oldact.handler;
@@ -915,24 +963,24 @@  int internal_sigaction_norestorer(int signum, const void *act, void *oldact) {
     internal_memcpy(&u_oldact->sa_mask, &k_oldact.sa_mask,
                     sizeof(__sanitizer_kernel_sigset_t));
     u_oldact->sa_flags = k_oldact.sa_flags;
-#if !SANITIZER_ANDROID || !SANITIZER_MIPS32
+#      if !SANITIZER_ANDROID || !SANITIZER_MIPS32
     u_oldact->sa_restorer = k_oldact.sa_restorer;
-#endif
+#      endif
   }
   return result;
 }
-#endif  // SANITIZER_LINUX
+#    endif  // SANITIZER_LINUX
 
 uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
                           __sanitizer_sigset_t *oldset) {
-#if SANITIZER_FREEBSD
+#    if SANITIZER_FREEBSD
   return internal_syscall(SYSCALL(sigprocmask), how, set, oldset);
-#else
+#    else
   __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
   __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset;
   return internal_syscall(SYSCALL(rt_sigprocmask), (uptr)how, (uptr)k_set,
                           (uptr)k_oldset, sizeof(__sanitizer_kernel_sigset_t));
-#endif
+#    endif
 }
 
 void internal_sigfillset(__sanitizer_sigset_t *set) {
@@ -943,7 +991,7 @@  void internal_sigemptyset(__sanitizer_sigset_t *set) {
   internal_memset(set, 0, sizeof(*set));
 }
 
-#if SANITIZER_LINUX
+#    if SANITIZER_LINUX
 void internal_sigdelset(__sanitizer_sigset_t *set, int signum) {
   signum -= 1;
   CHECK_GE(signum, 0);
@@ -963,7 +1011,7 @@  bool internal_sigismember(__sanitizer_sigset_t *set, int signum) {
   const uptr bit = signum % (sizeof(k_set->sig[0]) * 8);
   return k_set->sig[idx] & ((uptr)1 << bit);
 }
-#elif SANITIZER_FREEBSD
+#    elif SANITIZER_FREEBSD
 uptr internal_procctl(int type, int id, int cmd, void *data) {
   return internal_syscall(SYSCALL(procctl), type, id, cmd, data);
 }
@@ -977,39 +1025,34 @@  bool internal_sigismember(__sanitizer_sigset_t *set, int signum) {
   sigset_t *rset = reinterpret_cast<sigset_t *>(set);
   return sigismember(rset, signum);
 }
-#endif
-#endif // !SANITIZER_SOLARIS
+#    endif
+#  endif  // !SANITIZER_SOLARIS
 
-#if !SANITIZER_NETBSD
+#  if !SANITIZER_NETBSD
 // ThreadLister implementation.
-ThreadLister::ThreadLister(pid_t pid) : pid_(pid), buffer_(4096) {
-  char task_directory_path[80];
-  internal_snprintf(task_directory_path, sizeof(task_directory_path),
-                    "/proc/%d/task/", pid);
-  descriptor_ = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY);
-  if (internal_iserror(descriptor_)) {
-    Report("Can't open /proc/%d/task for reading.\n", pid);
-  }
+ThreadLister::ThreadLister(pid_t pid) : buffer_(4096) {
+  task_path_.AppendF("/proc/%d/task", pid);
 }
 
 ThreadLister::Result ThreadLister::ListThreads(
     InternalMmapVector<tid_t> *threads) {
-  if (internal_iserror(descriptor_))
+  int descriptor = internal_open(task_path_.data(), O_RDONLY | O_DIRECTORY);
+  if (internal_iserror(descriptor)) {
+    Report("Can't open %s for reading.\n", task_path_.data());
     return Error;
-  internal_lseek(descriptor_, 0, SEEK_SET);
+  }
+  auto cleanup = at_scope_exit([&] { internal_close(descriptor); });
   threads->clear();
 
   Result result = Ok;
   for (bool first_read = true;; first_read = false) {
-    // Resize to max capacity if it was downsized by IsAlive.
-    buffer_.resize(buffer_.capacity());
     CHECK_GE(buffer_.size(), 4096);
     uptr read = internal_getdents(
-        descriptor_, (struct linux_dirent *)buffer_.data(), buffer_.size());
+        descriptor, (struct linux_dirent *)buffer_.data(), buffer_.size());
     if (!read)
       return result;
     if (internal_iserror(read)) {
-      Report("Can't read directory entries from /proc/%d/task.\n", pid_);
+      Report("Can't read directory entries from %s.\n", task_path_.data());
       return Error;
     }
 
@@ -1047,45 +1090,53 @@  ThreadLister::Result ThreadLister::ListThreads(
   }
 }
 
-bool ThreadLister::IsAlive(int tid) {
+const char *ThreadLister::LoadStatus(tid_t tid) {
+  status_path_.clear();
+  status_path_.AppendF("%s/%llu/status", task_path_.data(), tid);
+  auto cleanup = at_scope_exit([&] {
+    // Resize back to capacity if it is downsized by `ReadFileToVector`.
+    buffer_.resize(buffer_.capacity());
+  });
+  if (!ReadFileToVector(status_path_.data(), &buffer_) || buffer_.empty())
+    return nullptr;
+  buffer_.push_back('\0');
+  return buffer_.data();
+}
+
+bool ThreadLister::IsAlive(tid_t tid) {
   // /proc/%d/task/%d/status uses same call to detect alive threads as
   // proc_task_readdir. See task_state implementation in Linux.
-  char path[80];
-  internal_snprintf(path, sizeof(path), "/proc/%d/task/%d/status", pid_, tid);
-  if (!ReadFileToVector(path, &buffer_) || buffer_.empty())
-    return false;
-  buffer_.push_back(0);
   static const char kPrefix[] = "\nPPid:";
-  const char *field = internal_strstr(buffer_.data(), kPrefix);
+  const char *status = LoadStatus(tid);
+  if (!status)
+    return false;
+  const char *field = internal_strstr(status, kPrefix);
   if (!field)
     return false;
   field += internal_strlen(kPrefix);
   return (int)internal_atoll(field) != 0;
 }
 
-ThreadLister::~ThreadLister() {
-  if (!internal_iserror(descriptor_))
-    internal_close(descriptor_);
-}
-#endif
+#  endif
 
-#if SANITIZER_WORDSIZE == 32
+#  if SANITIZER_WORDSIZE == 32
 // Take care of unusable kernel area in top gigabyte.
 static uptr GetKernelAreaSize() {
-#if SANITIZER_LINUX && !SANITIZER_X32
+#    if SANITIZER_LINUX && !SANITIZER_X32
   const uptr gbyte = 1UL << 30;
 
   // Firstly check if there are writable segments
   // mapped to top gigabyte (e.g. stack).
-  MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+  MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
   if (proc_maps.Error())
     return 0;
   MemoryMappedSegment segment;
   while (proc_maps.Next(&segment)) {
-    if ((segment.end >= 3 * gbyte) && segment.IsWritable()) return 0;
+    if ((segment.end >= 3 * gbyte) && segment.IsWritable())
+      return 0;
   }
 
-#if !SANITIZER_ANDROID
+#      if !SANITIZER_ANDROID
   // Even if nothing is mapped, top Gb may still be accessible
   // if we are running on 64-bit kernel.
   // Uname may report misleading results if personality type
@@ -1095,21 +1146,22 @@  static uptr GetKernelAreaSize() {
   if (!(pers & PER_MASK) && internal_uname(&uname_info) == 0 &&
       internal_strstr(uname_info.machine, "64"))
     return 0;
-#endif  // SANITIZER_ANDROID
+#      endif  // SANITIZER_ANDROID
 
   // Top gigabyte is reserved for kernel.
   return gbyte;
-#else
+#    else
   return 0;
-#endif  // SANITIZER_LINUX && !SANITIZER_X32
+#    endif  // SANITIZER_LINUX && !SANITIZER_X32
 }
-#endif  // SANITIZER_WORDSIZE == 32
+#  endif  // SANITIZER_WORDSIZE == 32
 
 uptr GetMaxVirtualAddress() {
-#if SANITIZER_NETBSD && defined(__x86_64__)
+#  if SANITIZER_NETBSD && defined(__x86_64__)
   return 0x7f7ffffff000ULL;  // (0x00007f8000000000 - PAGE_SIZE)
-#elif SANITIZER_WORDSIZE == 64
-# if defined(__powerpc64__) || defined(__aarch64__) || defined(__loongarch__)
+#  elif SANITIZER_WORDSIZE == 64
+#    if defined(__powerpc64__) || defined(__aarch64__) || \
+        defined(__loongarch__) || SANITIZER_RISCV64
   // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
   // We somehow need to figure out which one we are using now and choose
   // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
@@ -1118,97 +1170,97 @@  uptr GetMaxVirtualAddress() {
   // This should (does) work for both PowerPC64 Endian modes.
   // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit.
   // loongarch64 also has multiple address space layouts: default is 47-bit.
+  // RISC-V 64 also has multiple address space layouts: 39, 48 and 57-bit.
   return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
-#elif SANITIZER_RISCV64
-  return (1ULL << 38) - 1;
-# elif SANITIZER_MIPS64
+#    elif SANITIZER_MIPS64
   return (1ULL << 40) - 1;  // 0x000000ffffffffffUL;
-# elif defined(__s390x__)
+#    elif defined(__s390x__)
   return (1ULL << 53) - 1;  // 0x001fffffffffffffUL;
-#elif defined(__sparc__)
+#    elif defined(__sparc__)
   return ~(uptr)0;
-# else
+#    else
   return (1ULL << 47) - 1;  // 0x00007fffffffffffUL;
-# endif
-#else  // SANITIZER_WORDSIZE == 32
-# if defined(__s390__)
+#    endif
+#  else  // SANITIZER_WORDSIZE == 32
+#    if defined(__s390__)
   return (1ULL << 31) - 1;  // 0x7fffffff;
-# else
+#    else
   return (1ULL << 32) - 1;  // 0xffffffff;
-# endif
-#endif  // SANITIZER_WORDSIZE
+#    endif
+#  endif  // SANITIZER_WORDSIZE
 }
 
 uptr GetMaxUserVirtualAddress() {
   uptr addr = GetMaxVirtualAddress();
-#if SANITIZER_WORDSIZE == 32 && !defined(__s390__)
+#  if SANITIZER_WORDSIZE == 32 && !defined(__s390__)
   if (!common_flags()->full_address_space)
     addr -= GetKernelAreaSize();
   CHECK_LT(reinterpret_cast<uptr>(&addr), addr);
-#endif
+#  endif
   return addr;
 }
 
-#if !SANITIZER_ANDROID
+#  if !SANITIZER_ANDROID || defined(__aarch64__)
 uptr GetPageSize() {
-#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) && \
-    defined(EXEC_PAGESIZE)
+#    if SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__)) && \
+        defined(EXEC_PAGESIZE)
   return EXEC_PAGESIZE;
-#elif SANITIZER_FREEBSD || SANITIZER_NETBSD
-// Use sysctl as sysconf can trigger interceptors internally.
+#    elif SANITIZER_FREEBSD || SANITIZER_NETBSD
+  // Use sysctl as sysconf can trigger interceptors internally.
   int pz = 0;
   uptr pzl = sizeof(pz);
   int mib[2] = {CTL_HW, HW_PAGESIZE};
   int rv = internal_sysctl(mib, 2, &pz, &pzl, nullptr, 0);
   CHECK_EQ(rv, 0);
   return (uptr)pz;
-#elif SANITIZER_USE_GETAUXVAL
+#    elif SANITIZER_USE_GETAUXVAL
   return getauxval(AT_PAGESZ);
-#else
+#    else
   return sysconf(_SC_PAGESIZE);  // EXEC_PAGESIZE may not be trustworthy.
-#endif
+#    endif
 }
-#endif // !SANITIZER_ANDROID
+#  endif
 
-uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
-#if SANITIZER_SOLARIS
+uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) {
+#  if SANITIZER_SOLARIS
   const char *default_module_name = getexecname();
   CHECK_NE(default_module_name, NULL);
   return internal_snprintf(buf, buf_len, "%s", default_module_name);
-#else
-#if SANITIZER_FREEBSD || SANITIZER_NETBSD
-#if SANITIZER_FREEBSD
+#  else
+#    if SANITIZER_FREEBSD || SANITIZER_NETBSD
+#      if SANITIZER_FREEBSD
   const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
-#else
+#      else
   const int Mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME};
-#endif
+#      endif
   const char *default_module_name = "kern.proc.pathname";
   uptr Size = buf_len;
   bool IsErr =
       (internal_sysctl(Mib, ARRAY_SIZE(Mib), buf, &Size, NULL, 0) != 0);
   int readlink_error = IsErr ? errno : 0;
   uptr module_name_len = Size;
-#else
+#    else
   const char *default_module_name = "/proc/self/exe";
-  uptr module_name_len = internal_readlink(
-      default_module_name, buf, buf_len);
+  uptr module_name_len = internal_readlink(default_module_name, buf, buf_len);
   int readlink_error;
   bool IsErr = internal_iserror(module_name_len, &readlink_error);
-#endif  // SANITIZER_SOLARIS
+#    endif
   if (IsErr) {
     // We can't read binary name for some reason, assume it's unknown.
-    Report("WARNING: reading executable name failed with errno %d, "
-           "some stack frames may not be symbolized\n", readlink_error);
-    module_name_len = internal_snprintf(buf, buf_len, "%s",
-                                        default_module_name);
+    Report(
+        "WARNING: reading executable name failed with errno %d, "
+        "some stack frames may not be symbolized\n",
+        readlink_error);
+    module_name_len =
+        internal_snprintf(buf, buf_len, "%s", default_module_name);
     CHECK_LT(module_name_len, buf_len);
   }
   return module_name_len;
-#endif
+#  endif
 }
 
 uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
-#if SANITIZER_LINUX
+#  if SANITIZER_LINUX
   char *tmpbuf;
   uptr tmpsize;
   uptr tmplen;
@@ -1218,7 +1270,7 @@  uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
     UnmapOrDie(tmpbuf, tmpsize);
     return internal_strlen(buf);
   }
-#endif
+#  endif
   return ReadBinaryName(buf, buf_len);
 }
 
@@ -1228,20 +1280,22 @@  bool LibraryNameIs(const char *full_name, const char *base_name) {
   // Strip path.
   while (*name != '\0') name++;
   while (name > full_name && *name != '/') name--;
-  if (*name == '/') name++;
+  if (*name == '/')
+    name++;
   uptr base_name_length = internal_strlen(base_name);
-  if (internal_strncmp(name, base_name, base_name_length)) return false;
+  if (internal_strncmp(name, base_name, base_name_length))
+    return false;
   return (name[base_name_length] == '-' || name[base_name_length] == '.');
 }
 
-#if !SANITIZER_ANDROID
+#  if !SANITIZER_ANDROID
 // Call cb for each region mapped by map.
 void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
   CHECK_NE(map, nullptr);
-#if !SANITIZER_FREEBSD
+#    if !SANITIZER_FREEBSD
   typedef ElfW(Phdr) Elf_Phdr;
   typedef ElfW(Ehdr) Elf_Ehdr;
-#endif // !SANITIZER_FREEBSD
+#    endif  // !SANITIZER_FREEBSD
   char *base = (char *)map->l_addr;
   Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
   char *phdrs = base + ehdr->e_phoff;
@@ -1273,10 +1327,10 @@  void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
     }
   }
 }
-#endif
+#  endif
 
-#if SANITIZER_LINUX
-#if defined(__x86_64__)
+#  if SANITIZER_LINUX
+#    if defined(__x86_64__)
 // We cannot use glibc's clone wrapper, because it messes with the child
 // task's TLS. It writes the PID and TID of the child task to its thread
 // descriptor, but in our case the child task shares the thread descriptor with
@@ -1295,50 +1349,46 @@  uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
   register void *r8 __asm__("r8") = newtls;
   register int *r10 __asm__("r10") = child_tidptr;
   __asm__ __volatile__(
-                       /* %rax = syscall(%rax = SYSCALL(clone),
-                        *                %rdi = flags,
-                        *                %rsi = child_stack,
-                        *                %rdx = parent_tidptr,
-                        *                %r8  = new_tls,
-                        *                %r10 = child_tidptr)
-                        */
-                       "syscall\n"
-
-                       /* if (%rax != 0)
-                        *   return;
-                        */
-                       "testq  %%rax,%%rax\n"
-                       "jnz    1f\n"
-
-                       /* In the child. Terminate unwind chain. */
-                       // XXX: We should also terminate the CFI unwind chain
-                       // here. Unfortunately clang 3.2 doesn't support the
-                       // necessary CFI directives, so we skip that part.
-                       "xorq   %%rbp,%%rbp\n"
-
-                       /* Call "fn(arg)". */
-                       "popq   %%rax\n"
-                       "popq   %%rdi\n"
-                       "call   *%%rax\n"
-
-                       /* Call _exit(%rax). */
-                       "movq   %%rax,%%rdi\n"
-                       "movq   %2,%%rax\n"
-                       "syscall\n"
-
-                       /* Return to parent. */
-                     "1:\n"
-                       : "=a" (res)
-                       : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)),
-                         "S"(child_stack),
-                         "D"(flags),
-                         "d"(parent_tidptr),
-                         "r"(r8),
-                         "r"(r10)
-                       : "memory", "r11", "rcx");
+      /* %rax = syscall(%rax = SYSCALL(clone),
+       *                %rdi = flags,
+       *                %rsi = child_stack,
+       *                %rdx = parent_tidptr,
+       *                %r8  = new_tls,
+       *                %r10 = child_tidptr)
+       */
+      "syscall\n"
+
+      /* if (%rax != 0)
+       *   return;
+       */
+      "testq  %%rax,%%rax\n"
+      "jnz    1f\n"
+
+      /* In the child. Terminate unwind chain. */
+      // XXX: We should also terminate the CFI unwind chain
+      // here. Unfortunately clang 3.2 doesn't support the
+      // necessary CFI directives, so we skip that part.
+      "xorq   %%rbp,%%rbp\n"
+
+      /* Call "fn(arg)". */
+      "popq   %%rax\n"
+      "popq   %%rdi\n"
+      "call   *%%rax\n"
+
+      /* Call _exit(%rax). */
+      "movq   %%rax,%%rdi\n"
+      "movq   %2,%%rax\n"
+      "syscall\n"
+
+      /* Return to parent. */
+      "1:\n"
+      : "=a"(res)
+      : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)), "S"(child_stack), "D"(flags),
+        "d"(parent_tidptr), "r"(r8), "r"(r10)
+      : "memory", "r11", "rcx");
   return res;
 }
-#elif defined(__mips__)
+#    elif defined(__mips__)
 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
                     int *parent_tidptr, void *newtls, int *child_tidptr) {
   long long res;
@@ -1353,68 +1403,63 @@  uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
   // We don't have proper CFI directives here because it requires alot of code
   // for very marginal benefits.
   __asm__ __volatile__(
-                       /* $v0 = syscall($v0 = __NR_clone,
-                        * $a0 = flags,
-                        * $a1 = child_stack,
-                        * $a2 = parent_tidptr,
-                        * $a3 = new_tls,
-                        * $a4 = child_tidptr)
-                        */
-                       ".cprestore 16;\n"
-                       "move $4,%1;\n"
-                       "move $5,%2;\n"
-                       "move $6,%3;\n"
-                       "move $7,%4;\n"
-                       /* Store the fifth argument on stack
-                        * if we are using 32-bit abi.
-                        */
-#if SANITIZER_WORDSIZE == 32
-                       "lw %5,16($29);\n"
-#else
-                       "move $8,%5;\n"
-#endif
-                       "li $2,%6;\n"
-                       "syscall;\n"
-
-                       /* if ($v0 != 0)
-                        * return;
-                        */
-                       "bnez $2,1f;\n"
-
-                       /* Call "fn(arg)". */
-#if SANITIZER_WORDSIZE == 32
-#ifdef __BIG_ENDIAN__
-                       "lw $25,4($29);\n"
-                       "lw $4,12($29);\n"
-#else
-                       "lw $25,0($29);\n"
-                       "lw $4,8($29);\n"
-#endif
-#else
-                       "ld $25,0($29);\n"
-                       "ld $4,8($29);\n"
-#endif
-                       "jal $25;\n"
-
-                       /* Call _exit($v0). */
-                       "move $4,$2;\n"
-                       "li $2,%7;\n"
-                       "syscall;\n"
-
-                       /* Return to parent. */
-                     "1:\n"
-                       : "=r" (res)
-                       : "r"(flags),
-                         "r"(child_stack),
-                         "r"(parent_tidptr),
-                         "r"(a3),
-                         "r"(a4),
-                         "i"(__NR_clone),
-                         "i"(__NR_exit)
-                       : "memory", "$29" );
+      /* $v0 = syscall($v0 = __NR_clone,
+       * $a0 = flags,
+       * $a1 = child_stack,
+       * $a2 = parent_tidptr,
+       * $a3 = new_tls,
+       * $a4 = child_tidptr)
+       */
+      ".cprestore 16;\n"
+      "move $4,%1;\n"
+      "move $5,%2;\n"
+      "move $6,%3;\n"
+      "move $7,%4;\n"
+  /* Store the fifth argument on stack
+   * if we are using 32-bit abi.
+   */
+#      if SANITIZER_WORDSIZE == 32
+      "lw %5,16($29);\n"
+#      else
+      "move $8,%5;\n"
+#      endif
+      "li $2,%6;\n"
+      "syscall;\n"
+
+      /* if ($v0 != 0)
+       * return;
+       */
+      "bnez $2,1f;\n"
+
+  /* Call "fn(arg)". */
+#      if SANITIZER_WORDSIZE == 32
+#        ifdef __BIG_ENDIAN__
+      "lw $25,4($29);\n"
+      "lw $4,12($29);\n"
+#        else
+      "lw $25,0($29);\n"
+      "lw $4,8($29);\n"
+#        endif
+#      else
+      "ld $25,0($29);\n"
+      "ld $4,8($29);\n"
+#      endif
+      "jal $25;\n"
+
+      /* Call _exit($v0). */
+      "move $4,$2;\n"
+      "li $2,%7;\n"
+      "syscall;\n"
+
+      /* Return to parent. */
+      "1:\n"
+      : "=r"(res)
+      : "r"(flags), "r"(child_stack), "r"(parent_tidptr), "r"(a3), "r"(a4),
+        "i"(__NR_clone), "i"(__NR_exit)
+      : "memory", "$29");
   return res;
 }
-#elif SANITIZER_RISCV64
+#    elif SANITIZER_RISCV64
 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)
@@ -1455,7 +1500,7 @@  uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
       : "memory");
   return res;
 }
-#elif defined(__aarch64__)
+#    elif defined(__aarch64__)
 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
                     int *parent_tidptr, void *newtls, int *child_tidptr) {
   register long long res __asm__("x0");
@@ -1466,47 +1511,45 @@  uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
   ((unsigned long long *)child_stack)[0] = (uptr)fn;
   ((unsigned long long *)child_stack)[1] = (uptr)arg;
 
-  register int (*__fn)(void *)  __asm__("x0") = fn;
+  register int (*__fn)(void *) __asm__("x0") = fn;
   register void *__stack __asm__("x1") = child_stack;
-  register int   __flags __asm__("x2") = flags;
-  register void *__arg   __asm__("x3") = arg;
-  register int  *__ptid  __asm__("x4") = parent_tidptr;
-  register void *__tls   __asm__("x5") = newtls;
-  register int  *__ctid  __asm__("x6") = child_tidptr;
+  register int __flags __asm__("x2") = flags;
+  register void *__arg __asm__("x3") = arg;
+  register int *__ptid __asm__("x4") = parent_tidptr;
+  register void *__tls __asm__("x5") = newtls;
+  register int *__ctid __asm__("x6") = child_tidptr;
 
   __asm__ __volatile__(
-                       "mov x0,x2\n" /* flags  */
-                       "mov x2,x4\n" /* ptid  */
-                       "mov x3,x5\n" /* tls  */
-                       "mov x4,x6\n" /* ctid  */
-                       "mov x8,%9\n" /* clone  */
-
-                       "svc 0x0\n"
-
-                       /* if (%r0 != 0)
-                        *   return %r0;
-                        */
-                       "cmp x0, #0\n"
-                       "bne 1f\n"
-
-                       /* In the child, now. Call "fn(arg)". */
-                       "ldp x1, x0, [sp], #16\n"
-                       "blr x1\n"
-
-                       /* Call _exit(%r0).  */
-                       "mov x8, %10\n"
-                       "svc 0x0\n"
-                     "1:\n"
-
-                       : "=r" (res)
-                       : "i"(-EINVAL),
-                         "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg),
-                         "r"(__ptid), "r"(__tls), "r"(__ctid),
-                         "i"(__NR_clone), "i"(__NR_exit)
-                       : "x30", "memory");
+      "mov x0,x2\n" /* flags  */
+      "mov x2,x4\n" /* ptid  */
+      "mov x3,x5\n" /* tls  */
+      "mov x4,x6\n" /* ctid  */
+      "mov x8,%9\n" /* clone  */
+
+      "svc 0x0\n"
+
+      /* if (%r0 != 0)
+       *   return %r0;
+       */
+      "cmp x0, #0\n"
+      "bne 1f\n"
+
+      /* In the child, now. Call "fn(arg)". */
+      "ldp x1, x0, [sp], #16\n"
+      "blr x1\n"
+
+      /* Call _exit(%r0).  */
+      "mov x8, %10\n"
+      "svc 0x0\n"
+      "1:\n"
+
+      : "=r"(res)
+      : "i"(-EINVAL), "r"(__fn), "r"(__stack), "r"(__flags), "r"(__arg),
+        "r"(__ptid), "r"(__tls), "r"(__ctid), "i"(__NR_clone), "i"(__NR_exit)
+      : "x30", "memory");
   return res;
 }
-#elif SANITIZER_LOONGARCH64
+#    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)
@@ -1544,119 +1587,110 @@  uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
       : "=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");
+      : "memory", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
+        "$t8");
   return res;
 }
-#elif defined(__powerpc64__)
+#    elif defined(__powerpc64__)
 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
-                   int *parent_tidptr, void *newtls, int *child_tidptr) {
+                    int *parent_tidptr, void *newtls, int *child_tidptr) {
   long long res;
 // Stack frame structure.
-#if SANITIZER_PPC64V1
-//   Back chain == 0        (SP + 112)
-// Frame (112 bytes):
-//   Parameter save area    (SP + 48), 8 doublewords
-//   TOC save area          (SP + 40)
-//   Link editor doubleword (SP + 32)
-//   Compiler doubleword    (SP + 24)
-//   LR save area           (SP + 16)
-//   CR save area           (SP + 8)
-//   Back chain             (SP + 0)
-# define FRAME_SIZE 112
-# define FRAME_TOC_SAVE_OFFSET 40
-#elif SANITIZER_PPC64V2
-//   Back chain == 0        (SP + 32)
-// Frame (32 bytes):
-//   TOC save area          (SP + 24)
-//   LR save area           (SP + 16)
-//   CR save area           (SP + 8)
-//   Back chain             (SP + 0)
-# define FRAME_SIZE 32
-# define FRAME_TOC_SAVE_OFFSET 24
-#else
-# error "Unsupported PPC64 ABI"
-#endif
+#      if SANITIZER_PPC64V1
+  //   Back chain == 0        (SP + 112)
+  // Frame (112 bytes):
+  //   Parameter save area    (SP + 48), 8 doublewords
+  //   TOC save area          (SP + 40)
+  //   Link editor doubleword (SP + 32)
+  //   Compiler doubleword    (SP + 24)
+  //   LR save area           (SP + 16)
+  //   CR save area           (SP + 8)
+  //   Back chain             (SP + 0)
+#        define FRAME_SIZE 112
+#        define FRAME_TOC_SAVE_OFFSET 40
+#      elif SANITIZER_PPC64V2
+  //   Back chain == 0        (SP + 32)
+  // Frame (32 bytes):
+  //   TOC save area          (SP + 24)
+  //   LR save area           (SP + 16)
+  //   CR save area           (SP + 8)
+  //   Back chain             (SP + 0)
+#        define FRAME_SIZE 32
+#        define FRAME_TOC_SAVE_OFFSET 24
+#      else
+#        error "Unsupported PPC64 ABI"
+#      endif
   if (!fn || !child_stack)
     return -EINVAL;
   CHECK_EQ(0, (uptr)child_stack % 16);
 
   register int (*__fn)(void *) __asm__("r3") = fn;
-  register void *__cstack      __asm__("r4") = child_stack;
-  register int __flags         __asm__("r5") = flags;
-  register void *__arg         __asm__("r6") = arg;
-  register int *__ptidptr      __asm__("r7") = parent_tidptr;
-  register void *__newtls      __asm__("r8") = newtls;
-  register int *__ctidptr      __asm__("r9") = child_tidptr;
-
- __asm__ __volatile__(
-           /* fn and arg are saved across the syscall */
-           "mr 28, %5\n\t"
-           "mr 27, %8\n\t"
-
-           /* syscall
-             r0 == __NR_clone
-             r3 == flags
-             r4 == child_stack
-             r5 == parent_tidptr
-             r6 == newtls
-             r7 == child_tidptr */
-           "mr 3, %7\n\t"
-           "mr 5, %9\n\t"
-           "mr 6, %10\n\t"
-           "mr 7, %11\n\t"
-           "li 0, %3\n\t"
-           "sc\n\t"
-
-           /* Test if syscall was successful */
-           "cmpdi  cr1, 3, 0\n\t"
-           "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t"
-           "bne-   cr1, 1f\n\t"
-
-           /* Set up stack frame */
-           "li    29, 0\n\t"
-           "stdu  29, -8(1)\n\t"
-           "stdu  1, -%12(1)\n\t"
-           /* Do the function call */
-           "std   2, %13(1)\n\t"
-#if SANITIZER_PPC64V1
-           "ld    0, 0(28)\n\t"
-           "ld    2, 8(28)\n\t"
-           "mtctr 0\n\t"
-#elif SANITIZER_PPC64V2
-           "mr    12, 28\n\t"
-           "mtctr 12\n\t"
-#else
-# error "Unsupported PPC64 ABI"
-#endif
-           "mr    3, 27\n\t"
-           "bctrl\n\t"
-           "ld    2, %13(1)\n\t"
-
-           /* Call _exit(r3) */
-           "li 0, %4\n\t"
-           "sc\n\t"
-
-           /* Return to parent */
-           "1:\n\t"
-           "mr %0, 3\n\t"
-             : "=r" (res)
-             : "0" (-1),
-               "i" (EINVAL),
-               "i" (__NR_clone),
-               "i" (__NR_exit),
-               "r" (__fn),
-               "r" (__cstack),
-               "r" (__flags),
-               "r" (__arg),
-               "r" (__ptidptr),
-               "r" (__newtls),
-               "r" (__ctidptr),
-               "i" (FRAME_SIZE),
-               "i" (FRAME_TOC_SAVE_OFFSET)
-             : "cr0", "cr1", "memory", "ctr", "r0", "r27", "r28", "r29");
+  register void *__cstack __asm__("r4") = child_stack;
+  register int __flags __asm__("r5") = flags;
+  register void *__arg __asm__("r6") = arg;
+  register int *__ptidptr __asm__("r7") = parent_tidptr;
+  register void *__newtls __asm__("r8") = newtls;
+  register int *__ctidptr __asm__("r9") = child_tidptr;
+
+  __asm__ __volatile__(
+      /* fn and arg are saved across the syscall */
+      "mr 28, %5\n\t"
+      "mr 27, %8\n\t"
+
+      /* syscall
+        r0 == __NR_clone
+        r3 == flags
+        r4 == child_stack
+        r5 == parent_tidptr
+        r6 == newtls
+        r7 == child_tidptr */
+      "mr 3, %7\n\t"
+      "mr 5, %9\n\t"
+      "mr 6, %10\n\t"
+      "mr 7, %11\n\t"
+      "li 0, %3\n\t"
+      "sc\n\t"
+
+      /* Test if syscall was successful */
+      "cmpdi  cr1, 3, 0\n\t"
+      "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t"
+      "bne-   cr1, 1f\n\t"
+
+      /* Set up stack frame */
+      "li    29, 0\n\t"
+      "stdu  29, -8(1)\n\t"
+      "stdu  1, -%12(1)\n\t"
+      /* Do the function call */
+      "std   2, %13(1)\n\t"
+#      if SANITIZER_PPC64V1
+      "ld    0, 0(28)\n\t"
+      "ld    2, 8(28)\n\t"
+      "mtctr 0\n\t"
+#      elif SANITIZER_PPC64V2
+      "mr    12, 28\n\t"
+      "mtctr 12\n\t"
+#      else
+#        error "Unsupported PPC64 ABI"
+#      endif
+      "mr    3, 27\n\t"
+      "bctrl\n\t"
+      "ld    2, %13(1)\n\t"
+
+      /* Call _exit(r3) */
+      "li 0, %4\n\t"
+      "sc\n\t"
+
+      /* Return to parent */
+      "1:\n\t"
+      "mr %0, 3\n\t"
+      : "=r"(res)
+      : "0"(-1), "i"(EINVAL), "i"(__NR_clone), "i"(__NR_exit), "r"(__fn),
+        "r"(__cstack), "r"(__flags), "r"(__arg), "r"(__ptidptr), "r"(__newtls),
+        "r"(__ctidptr), "i"(FRAME_SIZE), "i"(FRAME_TOC_SAVE_OFFSET)
+      : "cr0", "cr1", "memory", "ctr", "r0", "r27", "r28", "r29");
   return res;
 }
-#elif defined(__i386__)
+#    elif defined(__i386__)
 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
                     int *parent_tidptr, void *newtls, int *child_tidptr) {
   int res;
@@ -1669,59 +1703,56 @@  uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
   ((unsigned int *)child_stack)[2] = (uptr)fn;
   ((unsigned int *)child_stack)[3] = (uptr)arg;
   __asm__ __volatile__(
-                       /* %eax = syscall(%eax = SYSCALL(clone),
-                        *                %ebx = flags,
-                        *                %ecx = child_stack,
-                        *                %edx = parent_tidptr,
-                        *                %esi  = new_tls,
-                        *                %edi = child_tidptr)
-                        */
-
-                        /* Obtain flags */
-                        "movl    (%%ecx), %%ebx\n"
-                        /* Do the system call */
-                        "pushl   %%ebx\n"
-                        "pushl   %%esi\n"
-                        "pushl   %%edi\n"
-                        /* Remember the flag value.  */
-                        "movl    %%ebx, (%%ecx)\n"
-                        "int     $0x80\n"
-                        "popl    %%edi\n"
-                        "popl    %%esi\n"
-                        "popl    %%ebx\n"
-
-                        /* if (%eax != 0)
-                         *   return;
-                         */
-
-                        "test    %%eax,%%eax\n"
-                        "jnz    1f\n"
-
-                        /* terminate the stack frame */
-                        "xorl   %%ebp,%%ebp\n"
-                        /* Call FN. */
-                        "call    *%%ebx\n"
-#ifdef PIC
-                        "call    here\n"
-                        "here:\n"
-                        "popl    %%ebx\n"
-                        "addl    $_GLOBAL_OFFSET_TABLE_+[.-here], %%ebx\n"
-#endif
-                        /* Call exit */
-                        "movl    %%eax, %%ebx\n"
-                        "movl    %2, %%eax\n"
-                        "int     $0x80\n"
-                        "1:\n"
-                       : "=a" (res)
-                       : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)),
-                         "c"(child_stack),
-                         "d"(parent_tidptr),
-                         "S"(newtls),
-                         "D"(child_tidptr)
-                       : "memory");
+      /* %eax = syscall(%eax = SYSCALL(clone),
+       *                %ebx = flags,
+       *                %ecx = child_stack,
+       *                %edx = parent_tidptr,
+       *                %esi  = new_tls,
+       *                %edi = child_tidptr)
+       */
+
+      /* Obtain flags */
+      "movl    (%%ecx), %%ebx\n"
+      /* Do the system call */
+      "pushl   %%ebx\n"
+      "pushl   %%esi\n"
+      "pushl   %%edi\n"
+      /* Remember the flag value.  */
+      "movl    %%ebx, (%%ecx)\n"
+      "int     $0x80\n"
+      "popl    %%edi\n"
+      "popl    %%esi\n"
+      "popl    %%ebx\n"
+
+      /* if (%eax != 0)
+       *   return;
+       */
+
+      "test    %%eax,%%eax\n"
+      "jnz    1f\n"
+
+      /* terminate the stack frame */
+      "xorl   %%ebp,%%ebp\n"
+      /* Call FN. */
+      "call    *%%ebx\n"
+#      ifdef PIC
+      "call    here\n"
+      "here:\n"
+      "popl    %%ebx\n"
+      "addl    $_GLOBAL_OFFSET_TABLE_+[.-here], %%ebx\n"
+#      endif
+      /* Call exit */
+      "movl    %%eax, %%ebx\n"
+      "movl    %2, %%eax\n"
+      "int     $0x80\n"
+      "1:\n"
+      : "=a"(res)
+      : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)), "c"(child_stack),
+        "d"(parent_tidptr), "S"(newtls), "D"(child_tidptr)
+      : "memory");
   return res;
 }
-#elif defined(__arm__)
+#    elif defined(__arm__)
 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
                     int *parent_tidptr, void *newtls, int *child_tidptr) {
   unsigned int res;
@@ -1737,70 +1768,68 @@  uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
   register int *r4 __asm__("r4") = child_tidptr;
   register int r7 __asm__("r7") = __NR_clone;
 
-#if __ARM_ARCH > 4 || defined (__ARM_ARCH_4T__)
-# define ARCH_HAS_BX
-#endif
-#if __ARM_ARCH > 4
-# define ARCH_HAS_BLX
-#endif
+#      if __ARM_ARCH > 4 || defined(__ARM_ARCH_4T__)
+#        define ARCH_HAS_BX
+#      endif
+#      if __ARM_ARCH > 4
+#        define ARCH_HAS_BLX
+#      endif
 
-#ifdef ARCH_HAS_BX
-# ifdef ARCH_HAS_BLX
-#  define BLX(R) "blx "  #R "\n"
-# else
-#  define BLX(R) "mov lr, pc; bx " #R "\n"
-# endif
-#else
-# define BLX(R)  "mov lr, pc; mov pc," #R "\n"
-#endif
+#      ifdef ARCH_HAS_BX
+#        ifdef ARCH_HAS_BLX
+#          define BLX(R) "blx " #R "\n"
+#        else
+#          define BLX(R) "mov lr, pc; bx " #R "\n"
+#        endif
+#      else
+#        define BLX(R) "mov lr, pc; mov pc," #R "\n"
+#      endif
 
   __asm__ __volatile__(
-                       /* %r0 = syscall(%r7 = SYSCALL(clone),
-                        *               %r0 = flags,
-                        *               %r1 = child_stack,
-                        *               %r2 = parent_tidptr,
-                        *               %r3  = new_tls,
-                        *               %r4 = child_tidptr)
-                        */
-
-                       /* Do the system call */
-                       "swi 0x0\n"
-
-                       /* if (%r0 != 0)
-                        *   return %r0;
-                        */
-                       "cmp r0, #0\n"
-                       "bne 1f\n"
-
-                       /* In the child, now. Call "fn(arg)". */
-                       "ldr r0, [sp, #4]\n"
-                       "ldr ip, [sp], #8\n"
-                       BLX(ip)
-                       /* Call _exit(%r0). */
-                       "mov r7, %7\n"
-                       "swi 0x0\n"
-                       "1:\n"
-                       "mov %0, r0\n"
-                       : "=r"(res)
-                       : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7),
-                         "i"(__NR_exit)
-                       : "memory");
+      /* %r0 = syscall(%r7 = SYSCALL(clone),
+       *               %r0 = flags,
+       *               %r1 = child_stack,
+       *               %r2 = parent_tidptr,
+       *               %r3  = new_tls,
+       *               %r4 = child_tidptr)
+       */
+
+      /* Do the system call */
+      "swi 0x0\n"
+
+      /* if (%r0 != 0)
+       *   return %r0;
+       */
+      "cmp r0, #0\n"
+      "bne 1f\n"
+
+      /* In the child, now. Call "fn(arg)". */
+      "ldr r0, [sp, #4]\n"
+      "ldr ip, [sp], #8\n" BLX(ip)
+      /* Call _exit(%r0). */
+      "mov r7, %7\n"
+      "swi 0x0\n"
+      "1:\n"
+      "mov %0, r0\n"
+      : "=r"(res)
+      : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7), "i"(__NR_exit)
+      : "memory");
   return res;
 }
-#endif
-#endif  // SANITIZER_LINUX
+#    endif
+#  endif  // SANITIZER_LINUX
 
-#if SANITIZER_LINUX
+#  if SANITIZER_LINUX
 int internal_uname(struct utsname *buf) {
   return internal_syscall(SYSCALL(uname), buf);
 }
-#endif
+#  endif
 
-#if SANITIZER_ANDROID
-#if __ANDROID_API__ < 21
+#  if SANITIZER_ANDROID
+#    if __ANDROID_API__ < 21
 extern "C" __attribute__((weak)) int dl_iterate_phdr(
     int (*)(struct dl_phdr_info *, size_t, void *), void *);
-#endif
+#    endif
 
 static int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size,
                                    void *data) {
@@ -1817,40 +1846,41 @@  static int dl_iterate_phdr_test_cb(struct dl_phdr_info *info, size_t size,
 static atomic_uint32_t android_api_level;
 
 static AndroidApiLevel AndroidDetectApiLevelStatic() {
-#if __ANDROID_API__ <= 19
+#    if __ANDROID_API__ <= 19
   return ANDROID_KITKAT;
-#elif __ANDROID_API__ <= 22
+#    elif __ANDROID_API__ <= 22
   return ANDROID_LOLLIPOP_MR1;
-#else
+#    else
   return ANDROID_POST_LOLLIPOP;
-#endif
+#    endif
 }
 
 static AndroidApiLevel AndroidDetectApiLevel() {
   if (!&dl_iterate_phdr)
-    return ANDROID_KITKAT; // K or lower
+    return ANDROID_KITKAT;  // K or lower
   bool base_name_seen = false;
   dl_iterate_phdr(dl_iterate_phdr_test_cb, &base_name_seen);
   if (base_name_seen)
-    return ANDROID_LOLLIPOP_MR1; // L MR1
+    return ANDROID_LOLLIPOP_MR1;  // L MR1
   return ANDROID_POST_LOLLIPOP;   // post-L
   // Plain L (API level 21) is completely broken wrt ASan and not very
   // interesting to detect.
 }
 
-extern "C" __attribute__((weak)) void* _DYNAMIC;
+extern "C" __attribute__((weak)) void *_DYNAMIC;
 
 AndroidApiLevel AndroidGetApiLevel() {
   AndroidApiLevel level =
       (AndroidApiLevel)atomic_load(&android_api_level, memory_order_relaxed);
-  if (level) return level;
+  if (level)
+    return level;
   level = &_DYNAMIC == nullptr ? AndroidDetectApiLevelStatic()
                                : AndroidDetectApiLevel();
   atomic_store(&android_api_level, level, memory_order_relaxed);
   return level;
 }
 
-#endif
+#  endif
 
 static HandleSignalMode GetHandleSignalModeImpl(int signum) {
   switch (signum) {
@@ -1877,28 +1907,28 @@  HandleSignalMode GetHandleSignalMode(int signum) {
   return result;
 }
 
-#if !SANITIZER_GO
+#  if !SANITIZER_GO
 void *internal_start_thread(void *(*func)(void *arg), void *arg) {
-  if (&real_pthread_create == 0)
+  if (&internal_pthread_create == 0)
     return nullptr;
   // Start the thread with signals blocked, otherwise it can steal user signals.
   ScopedBlockSignals block(nullptr);
   void *th;
-  real_pthread_create(&th, nullptr, func, arg);
+  internal_pthread_create(&th, nullptr, func, arg);
   return th;
 }
 
 void internal_join_thread(void *th) {
-  if (&real_pthread_join)
-    real_pthread_join(th, nullptr);
+  if (&internal_pthread_join)
+    internal_pthread_join(th, nullptr);
 }
-#else
+#  else
 void *internal_start_thread(void *(*func)(void *), void *arg) { return 0; }
 
 void internal_join_thread(void *th) {}
-#endif
+#  endif
 
-#if SANITIZER_LINUX && defined(__aarch64__)
+#  if SANITIZER_LINUX && defined(__aarch64__)
 // Android headers in the older NDK releases miss this definition.
 struct __sanitizer_esr_context {
   struct _aarch64_ctx head;
@@ -1910,7 +1940,8 @@  static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) {
   u8 *aux = reinterpret_cast<u8 *>(ucontext->uc_mcontext.__reserved);
   while (true) {
     _aarch64_ctx *ctx = (_aarch64_ctx *)aux;
-    if (ctx->size == 0) break;
+    if (ctx->size == 0)
+      break;
     if (ctx->magic == kEsrMagic) {
       *esr = ((__sanitizer_esr_context *)ctx)->esr;
       return true;
@@ -1919,31 +1950,29 @@  static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) {
   }
   return false;
 }
-#elif SANITIZER_FREEBSD && defined(__aarch64__)
+#  elif SANITIZER_FREEBSD && defined(__aarch64__)
 // FreeBSD doesn't provide ESR in the ucontext.
-static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) {
-  return false;
-}
-#endif
+static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) { return false; }
+#  endif
 
 using Context = ucontext_t;
 
 SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
   Context *ucontext = (Context *)context;
-#if defined(__x86_64__) || defined(__i386__)
+#  if defined(__x86_64__) || defined(__i386__)
   static const uptr PF_WRITE = 1U << 1;
-#if SANITIZER_FREEBSD
+#    if SANITIZER_FREEBSD
   uptr err = ucontext->uc_mcontext.mc_err;
-#elif SANITIZER_NETBSD
+#    elif SANITIZER_NETBSD
   uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR];
-#elif SANITIZER_SOLARIS && defined(__i386__)
+#    elif SANITIZER_SOLARIS && defined(__i386__)
   const int Err = 13;
   uptr err = ucontext->uc_mcontext.gregs[Err];
-#else
+#    else
   uptr err = ucontext->uc_mcontext.gregs[REG_ERR];
-#endif // SANITIZER_FREEBSD
+#    endif  // SANITIZER_FREEBSD
   return err & PF_WRITE ? Write : Read;
-#elif defined(__mips__)
+#  elif defined(__mips__)
   uint32_t *exception_source;
   uint32_t faulty_instruction;
   uint32_t op_code;
@@ -1959,12 +1988,12 @@  SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
     case 0x29:  // sh
     case 0x2b:  // sw
     case 0x3f:  // sd
-#if __mips_isa_rev < 6
+#    if __mips_isa_rev < 6
     case 0x2c:  // sdl
     case 0x2d:  // sdr
     case 0x2a:  // swl
     case 0x2e:  // swr
-#endif
+#    endif
       return SignalContext::Write;
 
     case 0x20:  // lb
@@ -1974,14 +2003,14 @@  SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
     case 0x23:  // lw
     case 0x27:  // lwu
     case 0x37:  // ld
-#if __mips_isa_rev < 6
+#    if __mips_isa_rev < 6
     case 0x1a:  // ldl
     case 0x1b:  // ldr
     case 0x22:  // lwl
     case 0x26:  // lwr
-#endif
+#    endif
       return SignalContext::Read;
-#if __mips_isa_rev == 6
+#    if __mips_isa_rev == 6
     case 0x3b:  // pcrel
       op_code = (faulty_instruction >> 19) & 0x3;
       switch (op_code) {
@@ -1989,50 +2018,63 @@  SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
         case 0x2:  // lwupc
           return SignalContext::Read;
       }
-#endif
+#    endif
   }
   return SignalContext::Unknown;
-#elif defined(__arm__)
+#  elif defined(__arm__)
   static const uptr FSR_WRITE = 1U << 11;
   uptr fsr = ucontext->uc_mcontext.error_code;
   return fsr & FSR_WRITE ? Write : Read;
-#elif defined(__aarch64__)
+#  elif defined(__aarch64__)
   static const u64 ESR_ELx_WNR = 1U << 6;
   u64 esr;
-  if (!Aarch64GetESR(ucontext, &esr)) return Unknown;
+  if (!Aarch64GetESR(ucontext, &esr))
+    return Unknown;
   return esr & ESR_ELx_WNR ? Write : Read;
-#elif defined(__loongarch__)
+#  elif defined(__loongarch__)
+  // In the musl environment, the Linux kernel uapi sigcontext.h is not
+  // included in signal.h. To avoid missing the SC_ADDRERR_{RD,WR} macros,
+  // copy them here. The LoongArch Linux kernel uapi is already stable,
+  // so there's no need to worry about the value changing.
+#    ifndef SC_ADDRERR_RD
+  // Address error was due to memory load
+#      define SC_ADDRERR_RD (1 << 30)
+#    endif
+#    ifndef SC_ADDRERR_WR
+  // Address error was due to memory store
+#      define SC_ADDRERR_WR (1 << 31)
+#    endif
   u32 flags = ucontext->uc_mcontext.__flags;
   if (flags & SC_ADDRERR_RD)
     return SignalContext::Read;
   if (flags & SC_ADDRERR_WR)
     return SignalContext::Write;
   return SignalContext::Unknown;
-#elif defined(__sparc__)
+#  elif defined(__sparc__)
   // Decode the instruction to determine the access type.
   // From OpenSolaris $SRC/uts/sun4/os/trap.c (get_accesstype).
-#if SANITIZER_SOLARIS
+#    if SANITIZER_SOLARIS
   uptr pc = ucontext->uc_mcontext.gregs[REG_PC];
-#else
+#    else
   // Historical BSDism here.
   struct sigcontext *scontext = (struct sigcontext *)context;
-#if defined(__arch64__)
+#      if defined(__arch64__)
   uptr pc = scontext->sigc_regs.tpc;
-#else
+#      else
   uptr pc = scontext->si_regs.pc;
-#endif
-#endif
+#      endif
+#    endif
   u32 instr = *(u32 *)pc;
-  return (instr >> 21) & 1 ? Write: Read;
-#elif defined(__riscv)
-#if SANITIZER_FREEBSD
+  return (instr >> 21) & 1 ? Write : Read;
+#  elif defined(__riscv)
+#    if SANITIZER_FREEBSD
   unsigned long pc = ucontext->uc_mcontext.mc_gpregs.gp_sepc;
-#else
+#    else
   unsigned long pc = ucontext->uc_mcontext.__gregs[REG_PC];
-#endif
+#    endif
   unsigned faulty_instruction = *(uint16_t *)pc;
 
-#if defined(__riscv_compressed)
+#    if defined(__riscv_compressed)
   if ((faulty_instruction & 0x3) != 0x3) {  // it's a compressed instruction
     // set op_bits to the instruction bits [1, 0, 15, 14, 13]
     unsigned op_bits =
@@ -2040,38 +2082,38 @@  SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
     unsigned rd = faulty_instruction & 0xF80;  // bits 7-11, inclusive
     switch (op_bits) {
       case 0b10'010:  // c.lwsp (rd != x0)
-#if __riscv_xlen == 64
+#      if __riscv_xlen == 64
       case 0b10'011:  // c.ldsp (rd != x0)
-#endif
+#      endif
         return rd ? SignalContext::Read : SignalContext::Unknown;
       case 0b00'010:  // c.lw
-#if __riscv_flen >= 32 && __riscv_xlen == 32
+#      if __riscv_flen >= 32 && __riscv_xlen == 32
       case 0b10'011:  // c.flwsp
-#endif
-#if __riscv_flen >= 32 || __riscv_xlen == 64
+#      endif
+#      if __riscv_flen >= 32 || __riscv_xlen == 64
       case 0b00'011:  // c.flw / c.ld
-#endif
-#if __riscv_flen == 64
+#      endif
+#      if __riscv_flen == 64
       case 0b00'001:  // c.fld
       case 0b10'001:  // c.fldsp
-#endif
+#      endif
         return SignalContext::Read;
       case 0b00'110:  // c.sw
       case 0b10'110:  // c.swsp
-#if __riscv_flen >= 32 || __riscv_xlen == 64
+#      if __riscv_flen >= 32 || __riscv_xlen == 64
       case 0b00'111:  // c.fsw / c.sd
       case 0b10'111:  // c.fswsp / c.sdsp
-#endif
-#if __riscv_flen == 64
+#      endif
+#      if __riscv_flen == 64
       case 0b00'101:  // c.fsd
       case 0b10'101:  // c.fsdsp
-#endif
+#      endif
         return SignalContext::Write;
       default:
         return SignalContext::Unknown;
     }
   }
-#endif
+#    endif
 
   unsigned opcode = faulty_instruction & 0x7f;         // lower 7 bits
   unsigned funct3 = (faulty_instruction >> 12) & 0x7;  // bits 12-14, inclusive
@@ -2081,9 +2123,9 @@  SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
         case 0b000:  // lb
         case 0b001:  // lh
         case 0b010:  // lw
-#if __riscv_xlen == 64
+#    if __riscv_xlen == 64
         case 0b011:  // ld
-#endif
+#    endif
         case 0b100:  // lbu
         case 0b101:  // lhu
           return SignalContext::Read;
@@ -2095,20 +2137,20 @@  SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
         case 0b000:  // sb
         case 0b001:  // sh
         case 0b010:  // sw
-#if __riscv_xlen == 64
+#    if __riscv_xlen == 64
         case 0b011:  // sd
-#endif
+#    endif
           return SignalContext::Write;
         default:
           return SignalContext::Unknown;
       }
-#if __riscv_flen >= 32
+#    if __riscv_flen >= 32
     case 0b0000111:  // floating-point loads
       switch (funct3) {
         case 0b010:  // flw
-#if __riscv_flen == 64
+#      if __riscv_flen == 64
         case 0b011:  // fld
-#endif
+#      endif
           return SignalContext::Read;
         default:
           return SignalContext::Unknown;
@@ -2116,21 +2158,21 @@  SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
     case 0b0100111:  // floating-point stores
       switch (funct3) {
         case 0b010:  // fsw
-#if __riscv_flen == 64
+#      if __riscv_flen == 64
         case 0b011:  // fsd
-#endif
+#      endif
           return SignalContext::Write;
         default:
           return SignalContext::Unknown;
       }
-#endif
+#    endif
     default:
       return SignalContext::Unknown;
   }
-#else
+#  else
   (void)ucontext;
   return Unknown;  // FIXME: Implement.
-#endif
+#  endif
 }
 
 bool SignalContext::IsTrueFaultingAddress() const {
@@ -2139,129 +2181,497 @@  bool SignalContext::IsTrueFaultingAddress() const {
   return si->si_signo == SIGSEGV && si->si_code != 128;
 }
 
+UNUSED
+static const char *RegNumToRegName(int reg) {
+  switch (reg) {
+#  if SANITIZER_LINUX && SANITIZER_GLIBC || SANITIZER_NETBSD
+#    if defined(__x86_64__)
+#      if SANITIZER_NETBSD
+#        define REG_RAX _REG_RAX
+#        define REG_RBX _REG_RBX
+#        define REG_RCX _REG_RCX
+#        define REG_RDX _REG_RDX
+#        define REG_RDI _REG_RDI
+#        define REG_RSI _REG_RSI
+#        define REG_RBP _REG_RBP
+#        define REG_RSP _REG_RSP
+#        define REG_R8 _REG_R8
+#        define REG_R9 _REG_R9
+#        define REG_R10 _REG_R10
+#        define REG_R11 _REG_R11
+#        define REG_R12 _REG_R12
+#        define REG_R13 _REG_R13
+#        define REG_R14 _REG_R14
+#        define REG_R15 _REG_R15
+#      endif
+    case REG_RAX:
+      return "rax";
+    case REG_RBX:
+      return "rbx";
+    case REG_RCX:
+      return "rcx";
+    case REG_RDX:
+      return "rdx";
+    case REG_RDI:
+      return "rdi";
+    case REG_RSI:
+      return "rsi";
+    case REG_RBP:
+      return "rbp";
+    case REG_RSP:
+      return "rsp";
+    case REG_R8:
+      return "r8";
+    case REG_R9:
+      return "r9";
+    case REG_R10:
+      return "r10";
+    case REG_R11:
+      return "r11";
+    case REG_R12:
+      return "r12";
+    case REG_R13:
+      return "r13";
+    case REG_R14:
+      return "r14";
+    case REG_R15:
+      return "r15";
+#    elif defined(__i386__)
+#      if SANITIZER_NETBSD
+#        define REG_EAX _REG_EAX
+#        define REG_EBX _REG_EBX
+#        define REG_ECX _REG_ECX
+#        define REG_EDX _REG_EDX
+#        define REG_EDI _REG_EDI
+#        define REG_ESI _REG_ESI
+#        define REG_EBP _REG_EBP
+#        define REG_ESP _REG_ESP
+#      endif
+    case REG_EAX:
+      return "eax";
+    case REG_EBX:
+      return "ebx";
+    case REG_ECX:
+      return "ecx";
+    case REG_EDX:
+      return "edx";
+    case REG_EDI:
+      return "edi";
+    case REG_ESI:
+      return "esi";
+    case REG_EBP:
+      return "ebp";
+    case REG_ESP:
+      return "esp";
+#    elif defined(__arm__)
+#      ifdef MAKE_CASE
+#        undef MAKE_CASE
+#      endif
+#      define REG_STR(reg) #reg
+#      define MAKE_CASE(N) \
+        case REG_R##N:     \
+          return REG_STR(r##N)
+    MAKE_CASE(0);
+    MAKE_CASE(1);
+    MAKE_CASE(2);
+    MAKE_CASE(3);
+    MAKE_CASE(4);
+    MAKE_CASE(5);
+    MAKE_CASE(6);
+    MAKE_CASE(7);
+    MAKE_CASE(8);
+    MAKE_CASE(9);
+    MAKE_CASE(10);
+    MAKE_CASE(11);
+    MAKE_CASE(12);
+    case REG_R13:
+      return "sp";
+    case REG_R14:
+      return "lr";
+    case REG_R15:
+      return "pc";
+#    elif defined(__aarch64__)
+#      define REG_STR(reg) #reg
+#      define MAKE_CASE(N) \
+        case N:            \
+          return REG_STR(x##N)
+    MAKE_CASE(0);
+    MAKE_CASE(1);
+    MAKE_CASE(2);
+    MAKE_CASE(3);
+    MAKE_CASE(4);
+    MAKE_CASE(5);
+    MAKE_CASE(6);
+    MAKE_CASE(7);
+    MAKE_CASE(8);
+    MAKE_CASE(9);
+    MAKE_CASE(10);
+    MAKE_CASE(11);
+    MAKE_CASE(12);
+    MAKE_CASE(13);
+    MAKE_CASE(14);
+    MAKE_CASE(15);
+    MAKE_CASE(16);
+    MAKE_CASE(17);
+    MAKE_CASE(18);
+    MAKE_CASE(19);
+    MAKE_CASE(20);
+    MAKE_CASE(21);
+    MAKE_CASE(22);
+    MAKE_CASE(23);
+    MAKE_CASE(24);
+    MAKE_CASE(25);
+    MAKE_CASE(26);
+    MAKE_CASE(27);
+    MAKE_CASE(28);
+    case 29:
+      return "fp";
+    case 30:
+      return "lr";
+    case 31:
+      return "sp";
+#    endif
+#  endif  // SANITIZER_LINUX && SANITIZER_GLIBC
+    default:
+      return NULL;
+  }
+  return NULL;
+}
+
+#  if ((SANITIZER_LINUX && SANITIZER_GLIBC) || SANITIZER_NETBSD) && \
+      (defined(__arm__) || defined(__aarch64__))
+static uptr GetArmRegister(ucontext_t *ctx, int RegNum) {
+  switch (RegNum) {
+#    if defined(__arm__) && !SANITIZER_NETBSD
+#      ifdef MAKE_CASE
+#        undef MAKE_CASE
+#      endif
+#      define MAKE_CASE(N) \
+        case REG_R##N:     \
+          return ctx->uc_mcontext.arm_r##N
+    MAKE_CASE(0);
+    MAKE_CASE(1);
+    MAKE_CASE(2);
+    MAKE_CASE(3);
+    MAKE_CASE(4);
+    MAKE_CASE(5);
+    MAKE_CASE(6);
+    MAKE_CASE(7);
+    MAKE_CASE(8);
+    MAKE_CASE(9);
+    MAKE_CASE(10);
+    case REG_R11:
+      return ctx->uc_mcontext.arm_fp;
+    case REG_R12:
+      return ctx->uc_mcontext.arm_ip;
+    case REG_R13:
+      return ctx->uc_mcontext.arm_sp;
+    case REG_R14:
+      return ctx->uc_mcontext.arm_lr;
+    case REG_R15:
+      return ctx->uc_mcontext.arm_pc;
+#    elif defined(__aarch64__)
+#      if SANITIZER_LINUX
+    case 0 ... 30:
+      return ctx->uc_mcontext.regs[RegNum];
+    case 31:
+      return ctx->uc_mcontext.sp;
+#      elif SANITIZER_NETBSD
+    case 0 ... 31:
+      return ctx->uc_mcontext.__gregs[RegNum];
+#      endif
+#    endif
+    default:
+      return 0;
+  }
+  return 0;
+}
+#  endif  // SANITIZER_LINUX && SANITIZER_GLIBC && (defined(__arm__) ||
+          // defined(__aarch64__))
+
+UNUSED
+static void DumpSingleReg(ucontext_t *ctx, int RegNum) {
+  const char *RegName = RegNumToRegName(RegNum);
+#  if SANITIZER_LINUX && SANITIZER_GLIBC || SANITIZER_NETBSD
+#    if defined(__x86_64__)
+  Printf("%s%s = 0x%016llx  ", internal_strlen(RegName) == 2 ? " " : "",
+         RegName,
+#      if SANITIZER_LINUX
+         ctx->uc_mcontext.gregs[RegNum]
+#      elif SANITIZER_NETBSD
+         ctx->uc_mcontext.__gregs[RegNum]
+#      endif
+  );
+#    elif defined(__i386__)
+  Printf("%s = 0x%08x  ", RegName,
+#      if SANITIZER_LINUX
+         ctx->uc_mcontext.gregs[RegNum]
+#      elif SANITIZER_NETBSD
+         ctx->uc_mcontext.__gregs[RegNum]
+#      endif
+  );
+#    elif defined(__arm__)
+  Printf("%s%s = 0x%08zx  ", internal_strlen(RegName) == 2 ? " " : "", RegName,
+         GetArmRegister(ctx, RegNum));
+#    elif defined(__aarch64__)
+  Printf("%s%s = 0x%016zx  ", internal_strlen(RegName) == 2 ? " " : "", RegName,
+         GetArmRegister(ctx, RegNum));
+#    else
+  (void)RegName;
+#    endif
+#  else
+  (void)RegName;
+#  endif
+}
+
 void SignalContext::DumpAllRegisters(void *context) {
-  // FIXME: Implement this.
+  ucontext_t *ucontext = (ucontext_t *)context;
+#  if SANITIZER_LINUX && SANITIZER_GLIBC || SANITIZER_NETBSD
+#    if defined(__x86_64__)
+  Report("Register values:\n");
+  DumpSingleReg(ucontext, REG_RAX);
+  DumpSingleReg(ucontext, REG_RBX);
+  DumpSingleReg(ucontext, REG_RCX);
+  DumpSingleReg(ucontext, REG_RDX);
+  Printf("\n");
+  DumpSingleReg(ucontext, REG_RDI);
+  DumpSingleReg(ucontext, REG_RSI);
+  DumpSingleReg(ucontext, REG_RBP);
+  DumpSingleReg(ucontext, REG_RSP);
+  Printf("\n");
+  DumpSingleReg(ucontext, REG_R8);
+  DumpSingleReg(ucontext, REG_R9);
+  DumpSingleReg(ucontext, REG_R10);
+  DumpSingleReg(ucontext, REG_R11);
+  Printf("\n");
+  DumpSingleReg(ucontext, REG_R12);
+  DumpSingleReg(ucontext, REG_R13);
+  DumpSingleReg(ucontext, REG_R14);
+  DumpSingleReg(ucontext, REG_R15);
+  Printf("\n");
+#    elif defined(__i386__)
+  // Duplication of this report print is caused by partial support
+  // of register values dumping. In case of unsupported yet architecture let's
+  // avoid printing 'Register values:' without actual values in the following
+  // output.
+  Report("Register values:\n");
+  DumpSingleReg(ucontext, REG_EAX);
+  DumpSingleReg(ucontext, REG_EBX);
+  DumpSingleReg(ucontext, REG_ECX);
+  DumpSingleReg(ucontext, REG_EDX);
+  Printf("\n");
+  DumpSingleReg(ucontext, REG_EDI);
+  DumpSingleReg(ucontext, REG_ESI);
+  DumpSingleReg(ucontext, REG_EBP);
+  DumpSingleReg(ucontext, REG_ESP);
+  Printf("\n");
+#    elif defined(__arm__) && !SANITIZER_NETBSD
+  Report("Register values:\n");
+  DumpSingleReg(ucontext, REG_R0);
+  DumpSingleReg(ucontext, REG_R1);
+  DumpSingleReg(ucontext, REG_R2);
+  DumpSingleReg(ucontext, REG_R3);
+  Printf("\n");
+  DumpSingleReg(ucontext, REG_R4);
+  DumpSingleReg(ucontext, REG_R5);
+  DumpSingleReg(ucontext, REG_R6);
+  DumpSingleReg(ucontext, REG_R7);
+  Printf("\n");
+  DumpSingleReg(ucontext, REG_R8);
+  DumpSingleReg(ucontext, REG_R9);
+  DumpSingleReg(ucontext, REG_R10);
+  DumpSingleReg(ucontext, REG_R11);
+  Printf("\n");
+  DumpSingleReg(ucontext, REG_R12);
+  DumpSingleReg(ucontext, REG_R13);
+  DumpSingleReg(ucontext, REG_R14);
+  DumpSingleReg(ucontext, REG_R15);
+  Printf("\n");
+#    elif defined(__aarch64__)
+  Report("Register values:\n");
+  for (int i = 0; i <= 31; ++i) {
+    DumpSingleReg(ucontext, i);
+    if (i % 4 == 3)
+      Printf("\n");
+  }
+#    else
+  (void)ucontext;
+#    endif
+#  elif SANITIZER_FREEBSD
+#    if defined(__x86_64__)
+  Report("Register values:\n");
+  Printf("rax = 0x%016lx  ", ucontext->uc_mcontext.mc_rax);
+  Printf("rbx = 0x%016lx  ", ucontext->uc_mcontext.mc_rbx);
+  Printf("rcx = 0x%016lx  ", ucontext->uc_mcontext.mc_rcx);
+  Printf("rdx = 0x%016lx  ", ucontext->uc_mcontext.mc_rdx);
+  Printf("\n");
+  Printf("rdi = 0x%016lx  ", ucontext->uc_mcontext.mc_rdi);
+  Printf("rsi = 0x%016lx  ", ucontext->uc_mcontext.mc_rsi);
+  Printf("rbp = 0x%016lx  ", ucontext->uc_mcontext.mc_rbp);
+  Printf("rsp = 0x%016lx  ", ucontext->uc_mcontext.mc_rsp);
+  Printf("\n");
+  Printf(" r8 = 0x%016lx  ", ucontext->uc_mcontext.mc_r8);
+  Printf(" r9 = 0x%016lx  ", ucontext->uc_mcontext.mc_r9);
+  Printf("r10 = 0x%016lx  ", ucontext->uc_mcontext.mc_r10);
+  Printf("r11 = 0x%016lx  ", ucontext->uc_mcontext.mc_r11);
+  Printf("\n");
+  Printf("r12 = 0x%016lx  ", ucontext->uc_mcontext.mc_r12);
+  Printf("r13 = 0x%016lx  ", ucontext->uc_mcontext.mc_r13);
+  Printf("r14 = 0x%016lx  ", ucontext->uc_mcontext.mc_r14);
+  Printf("r15 = 0x%016lx  ", ucontext->uc_mcontext.mc_r15);
+  Printf("\n");
+#    elif defined(__i386__)
+  Report("Register values:\n");
+  Printf("eax = 0x%08x  ", ucontext->uc_mcontext.mc_eax);
+  Printf("ebx = 0x%08x  ", ucontext->uc_mcontext.mc_ebx);
+  Printf("ecx = 0x%08x  ", ucontext->uc_mcontext.mc_ecx);
+  Printf("edx = 0x%08x  ", ucontext->uc_mcontext.mc_edx);
+  Printf("\n");
+  Printf("edi = 0x%08x  ", ucontext->uc_mcontext.mc_edi);
+  Printf("esi = 0x%08x  ", ucontext->uc_mcontext.mc_esi);
+  Printf("ebp = 0x%08x  ", ucontext->uc_mcontext.mc_ebp);
+  Printf("esp = 0x%08x  ", ucontext->uc_mcontext.mc_esp);
+  Printf("\n");
+#    else
+  (void)ucontext;
+#    endif
+#  else
+  (void)ucontext;
+#  endif
+  // FIXME: Implement this for other OSes and architectures.
 }
 
 static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
-#if SANITIZER_NETBSD
+#  if SANITIZER_NETBSD
   // This covers all NetBSD architectures
   ucontext_t *ucontext = (ucontext_t *)context;
   *pc = _UC_MACHINE_PC(ucontext);
   *bp = _UC_MACHINE_FP(ucontext);
   *sp = _UC_MACHINE_SP(ucontext);
-#elif defined(__arm__)
-  ucontext_t *ucontext = (ucontext_t*)context;
+#  elif defined(__arm__)
+  ucontext_t *ucontext = (ucontext_t *)context;
   *pc = ucontext->uc_mcontext.arm_pc;
   *bp = ucontext->uc_mcontext.arm_fp;
   *sp = ucontext->uc_mcontext.arm_sp;
-#elif defined(__aarch64__)
-# if SANITIZER_FREEBSD
-  ucontext_t *ucontext = (ucontext_t*)context;
+#  elif defined(__aarch64__)
+#    if SANITIZER_FREEBSD
+  ucontext_t *ucontext = (ucontext_t *)context;
   *pc = ucontext->uc_mcontext.mc_gpregs.gp_elr;
   *bp = ucontext->uc_mcontext.mc_gpregs.gp_x[29];
   *sp = ucontext->uc_mcontext.mc_gpregs.gp_sp;
-# else
-  ucontext_t *ucontext = (ucontext_t*)context;
+#    else
+  ucontext_t *ucontext = (ucontext_t *)context;
   *pc = ucontext->uc_mcontext.pc;
   *bp = ucontext->uc_mcontext.regs[29];
   *sp = ucontext->uc_mcontext.sp;
-# endif
-#elif defined(__hppa__)
-  ucontext_t *ucontext = (ucontext_t*)context;
+#    endif
+#  elif defined(__hppa__)
+  ucontext_t *ucontext = (ucontext_t *)context;
   *pc = ucontext->uc_mcontext.sc_iaoq[0];
   /* GCC uses %r3 whenever a frame pointer is needed.  */
   *bp = ucontext->uc_mcontext.sc_gr[3];
   *sp = ucontext->uc_mcontext.sc_gr[30];
-#elif defined(__x86_64__)
-# if SANITIZER_FREEBSD
-  ucontext_t *ucontext = (ucontext_t*)context;
+#  elif defined(__x86_64__)
+#    if SANITIZER_FREEBSD
+  ucontext_t *ucontext = (ucontext_t *)context;
   *pc = ucontext->uc_mcontext.mc_rip;
   *bp = ucontext->uc_mcontext.mc_rbp;
   *sp = ucontext->uc_mcontext.mc_rsp;
-# else
-  ucontext_t *ucontext = (ucontext_t*)context;
+#    else
+  ucontext_t *ucontext = (ucontext_t *)context;
   *pc = ucontext->uc_mcontext.gregs[REG_RIP];
   *bp = ucontext->uc_mcontext.gregs[REG_RBP];
   *sp = ucontext->uc_mcontext.gregs[REG_RSP];
-# endif
-#elif defined(__i386__)
-# if SANITIZER_FREEBSD
-  ucontext_t *ucontext = (ucontext_t*)context;
+#    endif
+#  elif defined(__i386__)
+#    if SANITIZER_FREEBSD
+  ucontext_t *ucontext = (ucontext_t *)context;
   *pc = ucontext->uc_mcontext.mc_eip;
   *bp = ucontext->uc_mcontext.mc_ebp;
   *sp = ucontext->uc_mcontext.mc_esp;
-# else
-  ucontext_t *ucontext = (ucontext_t*)context;
-# if SANITIZER_SOLARIS
+#    else
+  ucontext_t *ucontext = (ucontext_t *)context;
+#      if SANITIZER_SOLARIS
   /* Use the numeric values: the symbolic ones are undefined by llvm
      include/llvm/Support/Solaris.h.  */
-# ifndef REG_EIP
-#  define REG_EIP 14 // REG_PC
-# endif
-# ifndef REG_EBP
-#  define REG_EBP  6 // REG_FP
-# endif
-# ifndef REG_UESP
-#  define REG_UESP 17 // REG_SP
-# endif
-# endif
+#        ifndef REG_EIP
+#          define REG_EIP 14  // REG_PC
+#        endif
+#        ifndef REG_EBP
+#          define REG_EBP 6  // REG_FP
+#        endif
+#        ifndef REG_UESP
+#          define REG_UESP 17  // REG_SP
+#        endif
+#      endif
   *pc = ucontext->uc_mcontext.gregs[REG_EIP];
   *bp = ucontext->uc_mcontext.gregs[REG_EBP];
   *sp = ucontext->uc_mcontext.gregs[REG_UESP];
-# endif
-#elif defined(__powerpc__) || defined(__powerpc64__)
+#    endif
+#  elif defined(__powerpc__) || defined(__powerpc64__)
 #    if SANITIZER_FREEBSD
   ucontext_t *ucontext = (ucontext_t *)context;
   *pc = ucontext->uc_mcontext.mc_srr0;
   *sp = ucontext->uc_mcontext.mc_frame[1];
   *bp = ucontext->uc_mcontext.mc_frame[31];
 #    else
-  ucontext_t *ucontext = (ucontext_t*)context;
+  ucontext_t *ucontext = (ucontext_t *)context;
   *pc = ucontext->uc_mcontext.regs->nip;
   *sp = ucontext->uc_mcontext.regs->gpr[PT_R1];
   // The powerpc{,64}-linux ABIs do not specify r31 as the frame
   // pointer, but GCC always uses r31 when we need a frame pointer.
   *bp = ucontext->uc_mcontext.regs->gpr[PT_R31];
 #    endif
-#elif defined(__sparc__)
-#if defined(__arch64__) || defined(__sparcv9)
-#define STACK_BIAS 2047
-#else
-#define STACK_BIAS 0
-# endif
-# if SANITIZER_SOLARIS
+#  elif defined(__sparc__)
+#    if defined(__arch64__) || defined(__sparcv9)
+#      define STACK_BIAS 2047
+#    else
+#      define STACK_BIAS 0
+#    endif
+#    if SANITIZER_SOLARIS
   ucontext_t *ucontext = (ucontext_t *)context;
   *pc = ucontext->uc_mcontext.gregs[REG_PC];
-  *sp = ucontext->uc_mcontext.gregs[REG_O6] + STACK_BIAS;
-#else
+  *sp = ucontext->uc_mcontext.gregs[REG_SP] + STACK_BIAS;
+  // Avoid SEGV when dereferencing sp on stack overflow with non-faulting load.
+  // This requires a SPARC V9 CPU.  Cannot use #ASI_PNF here: only supported
+  // since clang-19.
+#      if defined(__sparcv9)
+  asm("ldxa [%[fp]] 0x82, %[bp]"
+#      else
+  asm("lduwa [%[fp]] 0x82, %[bp]"
+#      endif
+      : [bp] "=r"(*bp)
+      : [fp] "r"(&((struct frame *)*sp)->fr_savfp));
+  if (*bp)
+    *bp += STACK_BIAS;
+#    else
   // Historical BSDism here.
   struct sigcontext *scontext = (struct sigcontext *)context;
-#if defined(__arch64__)
+#      if defined(__arch64__)
   *pc = scontext->sigc_regs.tpc;
   *sp = scontext->sigc_regs.u_regs[14] + STACK_BIAS;
-#else
+#      else
   *pc = scontext->si_regs.pc;
   *sp = scontext->si_regs.u_regs[14];
-#endif
-# endif
+#      endif
   *bp = (uptr)((uhwptr *)*sp)[14] + STACK_BIAS;
-#elif defined(__mips__)
-  ucontext_t *ucontext = (ucontext_t*)context;
+#    endif
+#  elif defined(__mips__)
+  ucontext_t *ucontext = (ucontext_t *)context;
   *pc = ucontext->uc_mcontext.pc;
   *bp = ucontext->uc_mcontext.gregs[30];
   *sp = ucontext->uc_mcontext.gregs[29];
-#elif defined(__s390__)
-  ucontext_t *ucontext = (ucontext_t*)context;
-# if defined(__s390x__)
+#  elif defined(__s390__)
+  ucontext_t *ucontext = (ucontext_t *)context;
+#    if defined(__s390x__)
   *pc = ucontext->uc_mcontext.psw.addr;
-# else
+#    else
   *pc = ucontext->uc_mcontext.psw.addr & 0x7fffffff;
-# endif
+#    endif
   *bp = ucontext->uc_mcontext.gregs[11];
   *sp = ucontext->uc_mcontext.gregs[15];
-#elif defined(__riscv)
-  ucontext_t *ucontext = (ucontext_t*)context;
+#  elif defined(__riscv)
+  ucontext_t *ucontext = (ucontext_t *)context;
 #    if SANITIZER_FREEBSD
   *pc = ucontext->uc_mcontext.mc_gpregs.gp_sepc;
   *bp = ucontext->uc_mcontext.mc_gpregs.gp_s[0];
@@ -2288,12 +2698,10 @@  static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
 
 void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); }
 
-void InitializePlatformEarly() {
-  // Do nothing.
-}
+void InitializePlatformEarly() { InitTlsSize(); }
 
 void CheckASLR() {
-#if SANITIZER_NETBSD
+#  if SANITIZER_NETBSD
   int mib[3];
   int paxflags;
   uptr len = sizeof(paxflags);
@@ -2308,12 +2716,13 @@  void CheckASLR() {
   }
 
   if (UNLIKELY(paxflags & CTL_PROC_PAXFLAGS_ASLR)) {
-    Printf("This sanitizer is not compatible with enabled ASLR.\n"
-           "To disable ASLR, please run \"paxctl +a %s\" and try again.\n",
-           GetArgv()[0]);
+    Printf(
+        "This sanitizer is not compatible with enabled ASLR.\n"
+        "To disable ASLR, please run \"paxctl +a %s\" and try again.\n",
+        GetArgv()[0]);
     Die();
   }
-#elif SANITIZER_FREEBSD
+#  elif SANITIZER_FREEBSD
   int aslr_status;
   int r = internal_procctl(P_PID, 0, PROC_ASLR_STATUS, &aslr_status);
   if (UNLIKELY(r == -1)) {
@@ -2323,9 +2732,13 @@  void CheckASLR() {
     return;
   }
   if ((aslr_status & PROC_ASLR_ACTIVE) != 0) {
-    Printf("This sanitizer is not compatible with enabled ASLR "
-           "and binaries compiled with PIE\n");
-    Die();
+    VReport(1,
+            "This sanitizer is not compatible with enabled ASLR "
+            "and binaries compiled with PIE\n"
+            "ASLR will be disabled and the program re-executed.\n");
+    int aslr_ctl = PROC_ASLR_FORCE_DISABLE;
+    CHECK_NE(internal_procctl(P_PID, 0, PROC_ASLR_CTL, &aslr_ctl), -1);
+    ReExec();
   }
 #  elif SANITIZER_PPC64V2
   // Disable ASLR for Linux PPC64LE.
@@ -2345,7 +2758,7 @@  void CheckASLR() {
 }
 
 void CheckMPROTECT() {
-#if SANITIZER_NETBSD
+#  if SANITIZER_NETBSD
   int mib[3];
   int paxflags;
   uptr len = sizeof(paxflags);
@@ -2363,13 +2776,13 @@  void CheckMPROTECT() {
     Printf("This sanitizer is not compatible with enabled MPROTECT\n");
     Die();
   }
-#else
+#  else
   // Do nothing
-#endif
+#  endif
 }
 
 void CheckNoDeepBind(const char *filename, int flag) {
-#ifdef RTLD_DEEPBIND
+#  ifdef RTLD_DEEPBIND
   if (flag & RTLD_DEEPBIND) {
     Report(
         "You are trying to dlopen a %s shared library with RTLD_DEEPBIND flag"
@@ -2380,7 +2793,7 @@  void CheckNoDeepBind(const char *filename, int flag) {
         filename, filename);
     Die();
   }
-#endif
+#  endif
 }
 
 uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
@@ -2393,16 +2806,16 @@  uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
 bool GetRandom(void *buffer, uptr length, bool blocking) {
   if (!buffer || !length || length > 256)
     return false;
-#if SANITIZER_USE_GETENTROPY
+#  if SANITIZER_USE_GETENTROPY
   uptr rnd = getentropy(buffer, length);
   int rverrno = 0;
   if (internal_iserror(rnd, &rverrno) && rverrno == EFAULT)
     return false;
   else if (rnd == 0)
     return true;
-#endif // SANITIZER_USE_GETENTROPY
+#  endif  // SANITIZER_USE_GETENTROPY
 
-#if SANITIZER_USE_GETRANDOM
+#  if SANITIZER_USE_GETRANDOM
   static atomic_uint8_t skip_getrandom_syscall;
   if (!atomic_load_relaxed(&skip_getrandom_syscall)) {
     // Up to 256 bytes, getrandom will not be interrupted.
@@ -2414,7 +2827,7 @@  bool GetRandom(void *buffer, uptr length, bool blocking) {
     else if (res == length)
       return true;
   }
-#endif // SANITIZER_USE_GETRANDOM
+#  endif  // SANITIZER_USE_GETRANDOM
   // Up to 256 bytes, a read off /dev/urandom will not be interrupted.
   // blocking is moot here, O_NONBLOCK has no effect when opening /dev/urandom.
   uptr fd = internal_open("/dev/urandom", O_RDONLY);
@@ -2427,6 +2840,6 @@  bool GetRandom(void *buffer, uptr length, bool blocking) {
   return true;
 }
 
-} // namespace __sanitizer
+}  // namespace __sanitizer
 
 #endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h b/libsanitizer/sanitizer_common/sanitizer_linux.h
index 7454369fa419..8b7874bb5a34 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux.h
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.h
@@ -13,15 +13,15 @@ 
 #define SANITIZER_LINUX_H
 
 #include "sanitizer_platform.h"
-#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||                \
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
     SANITIZER_SOLARIS
-#include "sanitizer_common.h"
-#include "sanitizer_internal_defs.h"
-#include "sanitizer_platform_limits_freebsd.h"
-#include "sanitizer_platform_limits_netbsd.h"
-#include "sanitizer_platform_limits_posix.h"
-#include "sanitizer_platform_limits_solaris.h"
-#include "sanitizer_posix.h"
+#  include "sanitizer_common.h"
+#  include "sanitizer_internal_defs.h"
+#  include "sanitizer_platform_limits_freebsd.h"
+#  include "sanitizer_platform_limits_netbsd.h"
+#  include "sanitizer_platform_limits_posix.h"
+#  include "sanitizer_platform_limits_solaris.h"
+#  include "sanitizer_posix.h"
 
 struct link_map;  // Opaque type returned by dlopen().
 struct utsname;
@@ -46,9 +46,9 @@  void ReadProcMaps(ProcSelfMapsBuff *proc_maps);
 
 // Syscall wrappers.
 uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
-uptr internal_sigaltstack(const void* ss, void* oss);
+uptr internal_sigaltstack(const void *ss, void *oss);
 uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
-    __sanitizer_sigset_t *oldset);
+                          __sanitizer_sigset_t *oldset);
 
 void SetSigProcMask(__sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset);
 void BlockSignals(__sanitizer_sigset_t *oldset = nullptr);
@@ -65,10 +65,10 @@  struct ScopedBlockSignals {
 
 #  if SANITIZER_GLIBC
 uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp);
-#endif
+#  endif
 
 // Linux-only syscalls.
-#if SANITIZER_LINUX
+#  if SANITIZER_LINUX
 uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
 #    if defined(__x86_64__)
 uptr internal_arch_prctl(int option, uptr arg2);
@@ -83,33 +83,33 @@  void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
         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
+#    endif
 int internal_uname(struct utsname *buf);
-#elif SANITIZER_FREEBSD
+#  elif SANITIZER_FREEBSD
 uptr internal_procctl(int type, int id, int cmd, void *data);
 void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
-#elif SANITIZER_NETBSD
+#  elif SANITIZER_NETBSD
 void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg);
-#endif  // SANITIZER_LINUX
+#  endif  // SANITIZER_LINUX
 
 // This class reads thread IDs from /proc/<pid>/task using only syscalls.
 class ThreadLister {
  public:
   explicit ThreadLister(pid_t pid);
-  ~ThreadLister();
   enum Result {
     Error,
     Incomplete,
     Ok,
   };
   Result ListThreads(InternalMmapVector<tid_t> *threads);
+  const char *LoadStatus(tid_t tid);
 
  private:
-  bool IsAlive(int tid);
+  bool IsAlive(tid_t tid);
 
-  pid_t pid_;
-  int descriptor_ = -1;
+  InternalScopedString task_path_;
+  InternalScopedString status_path_;
   InternalMmapVector<char> buffer_;
 };
 
@@ -135,36 +135,60 @@  inline void ReleaseMemoryPagesToOSAndZeroFill(uptr beg, uptr end) {
   ReleaseMemoryPagesToOS(beg, end);
 }
 
-#if SANITIZER_ANDROID
-
-#if defined(__aarch64__)
-# define __get_tls() \
-    ({ void** __v; __asm__("mrs %0, tpidr_el0" : "=r"(__v)); __v; })
-#elif defined(__arm__)
-# define __get_tls() \
-    ({ void** __v; __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(__v)); __v; })
-#elif defined(__mips__)
+#  if SANITIZER_ANDROID
+
+#    if defined(__aarch64__)
+#      define __get_tls()                           \
+        ({                                          \
+          void **__v;                               \
+          __asm__("mrs %0, tpidr_el0" : "=r"(__v)); \
+          __v;                                      \
+        })
+#    elif defined(__arm__)
+#      define __get_tls()                                    \
+        ({                                                   \
+          void **__v;                                        \
+          __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(__v)); \
+          __v;                                               \
+        })
+#    elif defined(__mips__)
 // On mips32r1, this goes via a kernel illegal instruction trap that's
 // optimized for v1.
-# define __get_tls() \
-    ({ register void** __v asm("v1"); \
-       __asm__(".set    push\n" \
-               ".set    mips32r2\n" \
-               "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; })
-#elif defined(__x86_64__)
-# define __get_tls() \
-    ({ void** __v; __asm__("mov %%fs:0, %0" : "=r"(__v)); __v; })
-#else
-#error "Unsupported architecture."
-#endif
+#      define __get_tls()                \
+        ({                               \
+          register void **__v asm("v1"); \
+          __asm__(                       \
+              ".set    push\n"           \
+              ".set    mips32r2\n"       \
+              "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;                                    \
+        })
+#    elif defined(__x86_64__)
+#      define __get_tls()                        \
+        ({                                       \
+          void **__v;                            \
+          __asm__("mov %%fs:0, %0" : "=r"(__v)); \
+          __v;                                   \
+        })
+#    else
+#      error "Unsupported architecture."
+#    endif
 
 // The Android Bionic team has allocated a TLS slot for sanitizers starting
 // with Q, given that Android currently doesn't support ELF TLS. It is used to
@@ -175,7 +199,7 @@  ALWAYS_INLINE uptr *get_android_tls_ptr() {
   return reinterpret_cast<uptr *>(&__get_tls()[TLS_SLOT_SANITIZER]);
 }
 
-#endif  // SANITIZER_ANDROID
+#  endif  // SANITIZER_ANDROID
 
 }  // namespace __sanitizer
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
index 62b5f092cb32..525bc1038619 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cpp
@@ -16,89 +16,105 @@ 
 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
     SANITIZER_SOLARIS
 
-#include "sanitizer_allocator_internal.h"
-#include "sanitizer_atomic.h"
-#include "sanitizer_common.h"
-#include "sanitizer_file.h"
-#include "sanitizer_flags.h"
-#include "sanitizer_freebsd.h"
-#include "sanitizer_getauxval.h"
-#include "sanitizer_glibc_version.h"
-#include "sanitizer_linux.h"
-#include "sanitizer_placement_new.h"
-#include "sanitizer_procmaps.h"
-#include "sanitizer_solaris.h"
-
-#if SANITIZER_NETBSD
-#define _RTLD_SOURCE  // for __lwp_gettcb_fast() / __lwp_getprivate_fast()
-#endif
+#  include "sanitizer_allocator_internal.h"
+#  include "sanitizer_atomic.h"
+#  include "sanitizer_common.h"
+#  include "sanitizer_file.h"
+#  include "sanitizer_flags.h"
+#  include "sanitizer_getauxval.h"
+#  include "sanitizer_glibc_version.h"
+#  include "sanitizer_linux.h"
+#  include "sanitizer_placement_new.h"
+#  include "sanitizer_procmaps.h"
+#  include "sanitizer_solaris.h"
+
+#  if SANITIZER_NETBSD
+#    define _RTLD_SOURCE  // for __lwp_gettcb_fast() / __lwp_getprivate_fast()
+#  endif
 
-#include <dlfcn.h>  // for dlsym()
-#include <link.h>
-#include <pthread.h>
-#include <signal.h>
-#include <sys/mman.h>
-#include <sys/resource.h>
-#include <syslog.h>
+#  include <dlfcn.h>  // for dlsym()
+#  include <link.h>
+#  include <pthread.h>
+#  include <signal.h>
+#  include <sys/mman.h>
+#  include <sys/resource.h>
+#  include <syslog.h>
 
-#if !defined(ElfW)
-#define ElfW(type) Elf_##type
-#endif
+#  if SANITIZER_GLIBC
+#    include <gnu/libc-version.h>
+#  endif
+
+#  if !defined(ElfW)
+#    define ElfW(type) Elf_##type
+#  endif
 
-#if SANITIZER_FREEBSD
-#include <pthread_np.h>
-#include <osreldate.h>
-#include <sys/sysctl.h>
-#define pthread_getattr_np pthread_attr_get_np
+#  if SANITIZER_FREEBSD
+#    include <pthread_np.h>
+#    include <sys/auxv.h>
+#    include <sys/sysctl.h>
+#    define pthread_getattr_np pthread_attr_get_np
 // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
 // that, it was never implemented. So just define it to zero.
-#undef MAP_NORESERVE
-#define MAP_NORESERVE 0
-#endif
+#    undef MAP_NORESERVE
+#    define MAP_NORESERVE 0
+extern const Elf_Auxinfo *__elf_aux_vector;
+extern "C" int __sys_sigaction(int signum, const struct sigaction *act,
+                               struct sigaction *oldact);
+#  endif
 
-#if SANITIZER_NETBSD
-#include <sys/sysctl.h>
-#include <sys/tls.h>
-#include <lwp.h>
-#endif
+#  if SANITIZER_NETBSD
+#    include <lwp.h>
+#    include <sys/sysctl.h>
+#    include <sys/tls.h>
+#  endif
 
-#if SANITIZER_SOLARIS
-#include <stddef.h>
-#include <stdlib.h>
-#include <thread.h>
-#endif
+#  if SANITIZER_SOLARIS
+#    include <stddef.h>
+#    include <stdlib.h>
+#    include <thread.h>
+#  endif
 
-#if SANITIZER_ANDROID
-#include <android/api-level.h>
-#if !defined(CPU_COUNT) && !defined(__aarch64__)
-#include <dirent.h>
-#include <fcntl.h>
+#  if SANITIZER_ANDROID
+#    include <android/api-level.h>
+#    if !defined(CPU_COUNT) && !defined(__aarch64__)
+#      include <dirent.h>
+#      include <fcntl.h>
 struct __sanitizer::linux_dirent {
-  long           d_ino;
-  off_t          d_off;
+  long d_ino;
+  off_t d_off;
   unsigned short d_reclen;
-  char           d_name[];
+  char d_name[];
 };
-#endif
-#endif
+#    endif
+#  endif
 
-#if !SANITIZER_ANDROID
-#include <elf.h>
-#include <unistd.h>
-#endif
+#  if !SANITIZER_ANDROID
+#    include <elf.h>
+#    include <unistd.h>
+#  endif
 
 namespace __sanitizer {
 
-SANITIZER_WEAK_ATTRIBUTE int
-real_sigaction(int signum, const void *act, void *oldact);
+SANITIZER_WEAK_ATTRIBUTE int real_sigaction(int signum, const void *act,
+                                            void *oldact);
 
 int internal_sigaction(int signum, const void *act, void *oldact) {
-#if !SANITIZER_GO
+#  if SANITIZER_FREEBSD
+  // On FreeBSD, call the sigaction syscall directly (part of libsys in FreeBSD
+  // 15) since the libc version goes via a global interposing table. Due to
+  // library initialization order the table can be relocated after the call to
+  // InitializeDeadlySignals() which then crashes when dereferencing the
+  // uninitialized pointer in libc.
+  return __sys_sigaction(signum, (const struct sigaction *)act,
+                         (struct sigaction *)oldact);
+#  else
+#    if !SANITIZER_GO
   if (&real_sigaction)
     return real_sigaction(signum, act, oldact);
-#endif
+#    endif
   return sigaction(signum, (const struct sigaction *)act,
                    (struct sigaction *)oldact);
+#  endif
 }
 
 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
@@ -111,7 +127,7 @@  void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
     CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
 
     // Find the mapping that contains a stack variable.
-    MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+    MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
     if (proc_maps.Error()) {
       *stack_top = *stack_bottom = 0;
       return;
@@ -119,7 +135,8 @@  void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
     MemoryMappedSegment segment;
     uptr prev_end = 0;
     while (proc_maps.Next(&segment)) {
-      if ((uptr)&rl < segment.end) break;
+      if ((uptr)&rl < segment.end)
+        break;
       prev_end = segment.end;
     }
     CHECK((uptr)&rl >= segment.start && (uptr)&rl < segment.end);
@@ -127,7 +144,8 @@  void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
     // Get stacksize from rlimit, but clip it so that it does not overlap
     // with other mappings.
     uptr stacksize = rl.rlim_cur;
-    if (stacksize > segment.end - prev_end) stacksize = segment.end - prev_end;
+    if (stacksize > segment.end - prev_end)
+      stacksize = segment.end - prev_end;
     // When running with unlimited stack size, we still want to set some limit.
     // The unlimited stack size is caused by 'ulimit -s unlimited'.
     // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
@@ -135,60 +153,52 @@  void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
       stacksize = kMaxThreadStackSize;
     *stack_top = segment.end;
     *stack_bottom = segment.end - stacksize;
+
+    uptr maxAddr = GetMaxUserVirtualAddress();
+    // Edge case: the stack mapping on some systems may be off-by-one e.g.,
+    //     fffffffdf000-1000000000000 rw-p 00000000 00:00 0 [stack]
+    // instead of:
+    //     fffffffdf000- ffffffffffff
+    // The out-of-range stack_top can result in an invalid shadow address
+    // calculation, since those usually assume the parameters are in range.
+    if (*stack_top == maxAddr + 1)
+      *stack_top = maxAddr;
+    else
+      CHECK_LE(*stack_top, maxAddr);
+
     return;
   }
   uptr stacksize = 0;
   void *stackaddr = nullptr;
-#if SANITIZER_SOLARIS
+#  if SANITIZER_SOLARIS
   stack_t ss;
   CHECK_EQ(thr_stksegment(&ss), 0);
   stacksize = ss.ss_size;
   stackaddr = (char *)ss.ss_sp - stacksize;
-#else  // !SANITIZER_SOLARIS
+#  else   // !SANITIZER_SOLARIS
   pthread_attr_t attr;
   pthread_attr_init(&attr);
   CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
   internal_pthread_attr_getstack(&attr, &stackaddr, &stacksize);
   pthread_attr_destroy(&attr);
-#endif  // SANITIZER_SOLARIS
+#  endif  // SANITIZER_SOLARIS
 
   *stack_top = (uptr)stackaddr + stacksize;
   *stack_bottom = (uptr)stackaddr;
 }
 
-#if !SANITIZER_GO
+#  if !SANITIZER_GO
 bool SetEnv(const char *name, const char *value) {
   void *f = dlsym(RTLD_NEXT, "setenv");
   if (!f)
     return false;
-  typedef int(*setenv_ft)(const char *name, const char *value, int overwrite);
+  typedef int (*setenv_ft)(const char *name, const char *value, int overwrite);
   setenv_ft setenv_f;
   CHECK_EQ(sizeof(setenv_f), sizeof(f));
   internal_memcpy(&setenv_f, &f, sizeof(f));
   return setenv_f(name, value, 1) == 0;
 }
-#endif
-
-__attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
-                                                   int *patch) {
-#ifdef _CS_GNU_LIBC_VERSION
-  char buf[64];
-  uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf));
-  if (len >= sizeof(buf))
-    return false;
-  buf[len] = 0;
-  static const char kGLibC[] = "glibc ";
-  if (internal_strncmp(buf, kGLibC, sizeof(kGLibC) - 1) != 0)
-    return false;
-  const char *p = buf + sizeof(kGLibC) - 1;
-  *major = internal_simple_strtoll(p, &p, 10);
-  *minor = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0;
-  *patch = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0;
-  return true;
-#else
-  return false;
-#endif
-}
+#  endif
 
 // True if we can use dlpi_tls_data. glibc before 2.25 may leave NULL (BZ
 // #19826) so dlpi_tls_data cannot be used.
@@ -198,136 +208,196 @@  __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
 // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=254774
 __attribute__((unused)) static int g_use_dlpi_tls_data;
 
-#if SANITIZER_GLIBC && !SANITIZER_GO
-__attribute__((unused)) static size_t g_tls_size;
-void InitTlsSize() {
-  int major, minor, patch;
-  g_use_dlpi_tls_data =
-      GetLibcVersion(&major, &minor, &patch) && major == 2 && minor >= 25;
-
-#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);
-#endif
+#  if SANITIZER_GLIBC && !SANITIZER_GO
+static void GetGLibcVersion(int *major, int *minor, int *patch) {
+  const char *p = gnu_get_libc_version();
+  *major = internal_simple_strtoll(p, &p, 10);
+  // Caller does not expect anything else.
+  CHECK_EQ(*major, 2);
+  *minor = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0;
+  *patch = (*p == '.') ? internal_simple_strtoll(p + 1, &p, 10) : 0;
 }
-#else
-void InitTlsSize() { }
-#endif  // SANITIZER_GLIBC && !SANITIZER_GO
-
-// On glibc x86_64, ThreadDescriptorSize() needs to be precise due to the usage
-// of g_tls_size. On other targets, ThreadDescriptorSize() is only used by lsan
-// to get the pointer to thread-specific data keys in the thread control block.
-#if (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_SOLARIS) && \
-    !SANITIZER_ANDROID && !SANITIZER_GO
-// sizeof(struct pthread) from glibc.
-static atomic_uintptr_t thread_descriptor_size;
 
 static uptr ThreadDescriptorSizeFallback() {
-  uptr val = 0;
-#if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
+#    if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || \
+        SANITIZER_RISCV64
   int major;
   int minor;
   int patch;
-  if (GetLibcVersion(&major, &minor, &patch) && major == 2) {
-    /* sizeof(struct pthread) values from various glibc versions.  */
-    if (SANITIZER_X32)
-      val = 1728; // Assume only one particular version for x32.
-    // For ARM sizeof(struct pthread) changed in Glibc 2.23.
-    else if (SANITIZER_ARM)
-      val = minor <= 22 ? 1120 : 1216;
-    else if (minor <= 3)
-      val = FIRST_32_SECOND_64(1104, 1696);
-    else if (minor == 4)
-      val = FIRST_32_SECOND_64(1120, 1728);
-    else if (minor == 5)
-      val = FIRST_32_SECOND_64(1136, 1728);
-    else if (minor <= 9)
-      val = FIRST_32_SECOND_64(1136, 1712);
-    else if (minor == 10)
-      val = FIRST_32_SECOND_64(1168, 1776);
-    else if (minor == 11 || (minor == 12 && patch == 1))
-      val = FIRST_32_SECOND_64(1168, 2288);
-    else if (minor <= 14)
-      val = FIRST_32_SECOND_64(1168, 2304);
-    else if (minor < 32)  // Unknown version
-      val = FIRST_32_SECOND_64(1216, 2304);
-    else  // minor == 32
-      val = FIRST_32_SECOND_64(1344, 2496);
-  }
-#elif defined(__s390__) || defined(__sparc__)
+  GetGLibcVersion(&major, &minor, &patch);
+#    endif
+
+#    if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
+  /* sizeof(struct pthread) values from various glibc versions.  */
+  if (SANITIZER_X32)
+    return 1728;  // Assume only one particular version for x32.
+  // For ARM sizeof(struct pthread) changed in Glibc 2.23.
+  if (SANITIZER_ARM)
+    return minor <= 22 ? 1120 : 1216;
+  if (minor <= 3)
+    return FIRST_32_SECOND_64(1104, 1696);
+  if (minor == 4)
+    return FIRST_32_SECOND_64(1120, 1728);
+  if (minor == 5)
+    return FIRST_32_SECOND_64(1136, 1728);
+  if (minor <= 9)
+    return FIRST_32_SECOND_64(1136, 1712);
+  if (minor == 10)
+    return FIRST_32_SECOND_64(1168, 1776);
+  if (minor == 11 || (minor == 12 && patch == 1))
+    return FIRST_32_SECOND_64(1168, 2288);
+  if (minor <= 14)
+    return FIRST_32_SECOND_64(1168, 2304);
+  if (minor < 32)  // Unknown version
+    return FIRST_32_SECOND_64(1216, 2304);
+  // minor == 32
+  return FIRST_32_SECOND_64(1344, 2496);
+#    endif
+
+#    if SANITIZER_RISCV64
+  // TODO: consider adding an optional runtime check for an unknown (untested)
+  // glibc version
+  if (minor <= 28)  // WARNING: the highest tested version is 2.29
+    return 1772;    // no guarantees for this one
+  if (minor <= 31)
+    return 1772;  // tested against glibc 2.29, 2.31
+  return 1936;    // tested against glibc 2.32
+#    endif
+
+#    if defined(__s390__) || defined(__sparc__)
   // The size of a prefix of TCB including pthread::{specific_1stblock,specific}
   // suffices. Just return offsetof(struct pthread, specific_used), which hasn't
   // changed since 2007-05. Technically this applies to i386/x86_64 as well but
   // we call _dl_get_tls_static_info and need the precise size of struct
   // pthread.
   return FIRST_32_SECOND_64(524, 1552);
-#elif defined(__mips__)
+#    endif
+
+#    if 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;
-  int patch;
-  if (GetLibcVersion(&major, &minor, &patch) && major == 2) {
-    // TODO: consider adding an optional runtime check for an unknown (untested)
-    // glibc version
-    if (minor <= 28)  // WARNING: the highest tested version is 2.29
-      val = 1772;     // no guarantees for this one
-    else if (minor <= 31)
-      val = 1772;  // tested against glibc 2.29, 2.31
-    else
-      val = 1936;  // tested against glibc 2.32
-  }
+  return FIRST_32_SECOND_64(1152, 1776);
+#    endif
 
-#elif defined(__aarch64__)
+#    if SANITIZER_LOONGARCH64
+  return 1856;  // from glibc 2.36
+#    endif
+
+#    if defined(__aarch64__)
   // The sizeof (struct pthread) is the same from GLIBC 2.17 to 2.22.
-  val = 1776;
-#elif defined(__powerpc64__)
-  val = 1776; // from glibc.ppc64le 2.20-8.fc21
-#endif
-  return val;
+  return 1776;
+#    endif
+
+#    if defined(__powerpc64__)
+  return 1776;  // from glibc.ppc64le 2.20-8.fc21
+#    endif
+}
+#  endif  // SANITIZER_GLIBC && !SANITIZER_GO
+
+#  if SANITIZER_FREEBSD && !SANITIZER_GO
+// FIXME: Implementation is very GLIBC specific, but it's used by FreeBSD.
+static uptr ThreadDescriptorSizeFallback() {
+#    if defined(__s390__) || defined(__sparc__)
+  // The size of a prefix of TCB including pthread::{specific_1stblock,specific}
+  // suffices. Just return offsetof(struct pthread, specific_used), which hasn't
+  // changed since 2007-05. Technically this applies to i386/x86_64 as well but
+  // we call _dl_get_tls_static_info and need the precise size of struct
+  // pthread.
+  return FIRST_32_SECOND_64(524, 1552);
+#    endif
+
+#    if defined(__mips__)
+  // TODO(sagarthakur): add more values as per different glibc versions.
+  return FIRST_32_SECOND_64(1152, 1776);
+#    endif
+
+#    if SANITIZER_LOONGARCH64
+  return 1856;  // from glibc 2.36
+#    endif
+
+#    if defined(__aarch64__)
+  // The sizeof (struct pthread) is the same from GLIBC 2.17 to 2.22.
+  return 1776;
+#    endif
+
+#    if defined(__powerpc64__)
+  return 1776;  // from glibc.ppc64le 2.20-8.fc21
+#    endif
+
+  return 0;
 }
+#  endif  // SANITIZER_FREEBSD && !SANITIZER_GO
+
+#  if (SANITIZER_FREEBSD || SANITIZER_GLIBC) && !SANITIZER_GO
+// On glibc x86_64, ThreadDescriptorSize() needs to be precise due to the usage
+// of g_tls_size. On other targets, ThreadDescriptorSize() is only used by lsan
+// to get the pointer to thread-specific data keys in the thread control block.
+// sizeof(struct pthread) from glibc.
+static uptr thread_descriptor_size;
 
-uptr ThreadDescriptorSize() {
-  uptr val = atomic_load_relaxed(&thread_descriptor_size);
-  if (val)
-    return val;
-  // _thread_db_sizeof_pthread is a GLIBC_PRIVATE symbol that is exported in
-  // glibc 2.34 and later.
-  if (unsigned *psizeof = static_cast<unsigned *>(
-          dlsym(RTLD_DEFAULT, "_thread_db_sizeof_pthread")))
-    val = *psizeof;
-  if (!val)
-    val = ThreadDescriptorSizeFallback();
-  atomic_store_relaxed(&thread_descriptor_size, val);
-  return val;
+uptr ThreadDescriptorSize() { return thread_descriptor_size; }
+
+#    if SANITIZER_GLIBC
+__attribute__((unused)) static size_t g_tls_size;
+#    endif
+
+void InitTlsSize() {
+#    if SANITIZER_GLIBC
+  int major, minor, patch;
+  GetGLibcVersion(&major, &minor, &patch);
+  g_use_dlpi_tls_data = major == 2 && minor >= 25;
+
+  if (major == 2 && minor >= 34) {
+    // _thread_db_sizeof_pthread is a GLIBC_PRIVATE symbol that is exported in
+    // glibc 2.34 and later.
+    if (unsigned *psizeof = static_cast<unsigned *>(
+            dlsym(RTLD_DEFAULT, "_thread_db_sizeof_pthread"))) {
+      thread_descriptor_size = *psizeof;
+    }
+  }
+
+#      if defined(__aarch64__) || defined(__x86_64__) || \
+          defined(__powerpc64__) || defined(__loongarch__)
+  auto *get_tls_static_info = (void (*)(size_t *, size_t *))dlsym(
+      RTLD_DEFAULT, "_dl_get_tls_static_info");
+  size_t tls_align;
+  // Can be null if static link.
+  if (get_tls_static_info)
+    get_tls_static_info(&g_tls_size, &tls_align);
+#      endif
+
+#    endif  // SANITIZER_GLIBC
+
+  if (!thread_descriptor_size)
+    thread_descriptor_size = ThreadDescriptorSizeFallback();
 }
 
-#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64 || \
-    SANITIZER_LOONGARCH64
+#    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() {
-#if defined(__mips__)
-  const uptr kTcbHead = 16; // sizeof (tcbhead_t)
-#elif defined(__powerpc64__)
-  const uptr kTcbHead = 88; // sizeof (tcbhead_t)
-#elif SANITIZER_RISCV64
+#      if defined(__mips__)
   const uptr kTcbHead = 16;  // sizeof (tcbhead_t)
-#elif SANITIZER_LOONGARCH64
+#      elif defined(__powerpc64__)
+  const uptr kTcbHead = 88;  // sizeof (tcbhead_t)
+#      elif SANITIZER_RISCV64
   const uptr kTcbHead = 16;  // sizeof (tcbhead_t)
-#endif
+#      elif SANITIZER_LOONGARCH64
+  const uptr kTcbHead = 16;  // sizeof (tcbhead_t)
+#      endif
   const uptr kTlsAlign = 16;
   const uptr kTlsPreTcbSize =
       RoundUpTo(ThreadDescriptorSize() + kTcbHead, kTlsAlign);
   return kTlsPreTcbSize;
 }
-#endif
-
+#    endif
+#  else   // (SANITIZER_FREEBSD || SANITIZER_GLIBC) && !SANITIZER_GO
+void InitTlsSize() {}
+uptr ThreadDescriptorSize() { return 0; }
+#  endif  // (SANITIZER_FREEBSD || SANITIZER_GLIBC) && !SANITIZER_GO
+
+#  if (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_SOLARIS) && \
+      !SANITIZER_ANDROID && !SANITIZER_GO
 namespace {
 struct TlsBlock {
   uptr begin, end, align;
@@ -336,7 +406,7 @@  struct TlsBlock {
 };
 }  // namespace
 
-#ifdef __s390__
+#    ifdef __s390__
 extern "C" uptr __tls_get_offset(void *arg);
 
 static uptr TlsGetOffset(uptr ti_module, uptr ti_offset) {
@@ -354,16 +424,16 @@  static uptr TlsGetOffset(uptr ti_module, uptr ti_offset) {
       : "memory", "cc", "0", "1", "3", "4", "5", "14");
   return r2;
 }
-#else
+#    else
 extern "C" void *__tls_get_addr(size_t *);
-#endif
+#    endif
 
 static size_t main_tls_modid;
 
 static int CollectStaticTlsBlocks(struct dl_phdr_info *info, size_t size,
                                   void *data) {
   size_t tls_modid;
-#if SANITIZER_SOLARIS
+#    if SANITIZER_SOLARIS
   // dlpi_tls_modid is only available since Solaris 11.4 SRU 10.  Use
   // dlinfo(RTLD_DI_LINKMAP) instead which works on all of Solaris 11.3,
   // 11.4, and Illumos.  The tlsmodid of the executable was changed to 1 in
@@ -376,27 +446,26 @@  static int CollectStaticTlsBlocks(struct dl_phdr_info *info, size_t size,
   Rt_map *map;
   dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map);
   tls_modid = map->rt_tlsmodid;
-#else
+#    else
   main_tls_modid = 1;
   tls_modid = info->dlpi_tls_modid;
-#endif
+#    endif
 
   if (tls_modid < main_tls_modid)
     return 0;
   uptr begin;
-#if !SANITIZER_SOLARIS
+#    if !SANITIZER_SOLARIS
   begin = (uptr)info->dlpi_tls_data;
-#endif
+#    endif
   if (!g_use_dlpi_tls_data) {
     // Call __tls_get_addr as a fallback. This forces TLS allocation on glibc
     // and FreeBSD.
-#ifdef __s390__
-    begin = (uptr)__builtin_thread_pointer() +
-            TlsGetOffset(tls_modid, 0);
-#else
+#    ifdef __s390__
+    begin = (uptr)__builtin_thread_pointer() + TlsGetOffset(tls_modid, 0);
+#    else
     size_t mod_and_off[2] = {tls_modid, 0};
     begin = (uptr)__tls_get_addr(mod_and_off);
-#endif
+#    endif
   }
   for (unsigned i = 0; i != info->dlpi_phnum; ++i)
     if (info->dlpi_phdr[i].p_type == PT_TLS) {
@@ -439,23 +508,21 @@  __attribute__((unused)) static void GetStaticTlsBoundary(uptr *addr, uptr *size,
   *addr = ranges[l].begin;
   *size = ranges[r - 1].end - ranges[l].begin;
 }
-#endif  // (x86_64 || i386 || mips || ...) && (SANITIZER_FREEBSD ||
-        // SANITIZER_LINUX) && !SANITIZER_ANDROID && !SANITIZER_GO
+#  endif  // (x86_64 || i386 || mips || ...) && (SANITIZER_FREEBSD ||
+          // SANITIZER_LINUX) && !SANITIZER_ANDROID && !SANITIZER_GO
 
-#if SANITIZER_NETBSD
-static struct tls_tcb * ThreadSelfTlsTcb() {
+#  if SANITIZER_NETBSD
+static struct tls_tcb *ThreadSelfTlsTcb() {
   struct tls_tcb *tcb = nullptr;
-#ifdef __HAVE___LWP_GETTCB_FAST
+#    ifdef __HAVE___LWP_GETTCB_FAST
   tcb = (struct tls_tcb *)__lwp_gettcb_fast();
-#elif defined(__HAVE___LWP_GETPRIVATE_FAST)
+#    elif defined(__HAVE___LWP_GETPRIVATE_FAST)
   tcb = (struct tls_tcb *)__lwp_getprivate_fast();
-#endif
+#    endif
   return tcb;
 }
 
-uptr ThreadSelf() {
-  return (uptr)ThreadSelfTlsTcb()->tcb_pthread;
-}
+uptr ThreadSelf() { return (uptr)ThreadSelfTlsTcb()->tcb_pthread; }
 
 int GetSizeFromHdr(struct dl_phdr_info *info, size_t size, void *data) {
   const Elf_Phdr *hdr = info->dlpi_phdr;
@@ -463,23 +530,23 @@  int GetSizeFromHdr(struct dl_phdr_info *info, size_t size, void *data) {
 
   for (; hdr != last_hdr; ++hdr) {
     if (hdr->p_type == PT_TLS && info->dlpi_tls_modid == 1) {
-      *(uptr*)data = hdr->p_memsz;
+      *(uptr *)data = hdr->p_memsz;
       break;
     }
   }
   return 0;
 }
-#endif  // SANITIZER_NETBSD
+#  endif  // SANITIZER_NETBSD
 
-#if SANITIZER_ANDROID
+#  if SANITIZER_ANDROID
 // Bionic provides this API since S.
 extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_get_static_tls_bounds(void **,
                                                                       void **);
-#endif
+#  endif
 
-#if !SANITIZER_GO
+#  if !SANITIZER_GO
 static void GetTls(uptr *addr, uptr *size) {
-#if SANITIZER_ANDROID
+#    if SANITIZER_ANDROID
   if (&__libc_get_static_tls_bounds) {
     void *start_addr;
     void *end_addr;
@@ -491,48 +558,48 @@  static void GetTls(uptr *addr, uptr *size) {
     *addr = 0;
     *size = 0;
   }
-#elif SANITIZER_GLIBC && defined(__x86_64__)
+#    elif SANITIZER_GLIBC && defined(__x86_64__)
   // For aarch64 and x86-64, use an O(1) approach which requires relatively
   // precise ThreadDescriptorSize. g_tls_size was initialized in InitTlsSize.
-#  if SANITIZER_X32
+#      if SANITIZER_X32
   asm("mov %%fs:8,%0" : "=r"(*addr));
-#  else
+#      else
   asm("mov %%fs:16,%0" : "=r"(*addr));
-#  endif
+#      endif
   *size = g_tls_size;
   *addr -= *size;
   *addr += ThreadDescriptorSize();
-#elif SANITIZER_GLIBC && defined(__aarch64__)
+#    elif SANITIZER_GLIBC && defined(__aarch64__)
   *addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
           ThreadDescriptorSize();
   *size = g_tls_size + ThreadDescriptorSize();
-#elif SANITIZER_GLIBC && defined(__loongarch__)
-#  ifdef __clang__
+#    elif SANITIZER_GLIBC && defined(__loongarch__)
+#      ifdef __clang__
   *addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
           ThreadDescriptorSize();
-#  else
+#      else
   asm("or %0,$tp,$zero" : "=r"(*addr));
   *addr -= ThreadDescriptorSize();
-#  endif
+#      endif
   *size = g_tls_size + ThreadDescriptorSize();
-#elif SANITIZER_GLIBC && defined(__powerpc64__)
+#    elif SANITIZER_GLIBC && defined(__powerpc64__)
   // Workaround for glibc<2.25(?). 2.27 is known to not need this.
   uptr tp;
   asm("addi %0,13,-0x7000" : "=r"(tp));
   const uptr pre_tcb_size = TlsPreTcbSize();
   *addr = tp - pre_tcb_size;
   *size = g_tls_size + pre_tcb_size;
-#elif SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_SOLARIS
+#    elif SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_SOLARIS
   uptr align;
   GetStaticTlsBoundary(addr, size, &align);
-#if defined(__x86_64__) || defined(__i386__) || defined(__s390__) || \
-    defined(__sparc__)
+#      if defined(__x86_64__) || defined(__i386__) || defined(__s390__) || \
+          defined(__sparc__)
   if (SANITIZER_GLIBC) {
-#if defined(__x86_64__) || defined(__i386__)
+#        if defined(__x86_64__) || defined(__i386__)
     align = Max<uptr>(align, 64);
-#else
+#        else
     align = Max<uptr>(align, 16);
-#endif
+#        endif
   }
   const uptr tp = RoundUpTo(*addr + *size, align);
 
@@ -551,26 +618,26 @@  static void GetTls(uptr *addr, uptr *size) {
   // because the number of bytes after pthread::specific is larger.
   *addr = tp - RoundUpTo(*size, align);
   *size = tp - *addr + ThreadDescriptorSize();
-#else
+#      else
   if (SANITIZER_GLIBC)
     *size += 1664;
   else if (SANITIZER_FREEBSD)
     *size += 128;  // RTLD_STATIC_TLS_EXTRA
-#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
+#        if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
   const uptr pre_tcb_size = TlsPreTcbSize();
   *addr -= pre_tcb_size;
   *size += pre_tcb_size;
-#else
+#        else
   // arm and aarch64 reserve two words at TP, so this underestimates the range.
   // However, this is sufficient for the purpose of finding the pointers to
   // thread-specific data keys.
   const uptr tcb_size = ThreadDescriptorSize();
   *addr -= tcb_size;
   *size += tcb_size;
-#endif
-#endif
-#elif SANITIZER_NETBSD
-  struct tls_tcb * const tcb = ThreadSelfTlsTcb();
+#        endif
+#      endif
+#    elif SANITIZER_NETBSD
+  struct tls_tcb *const tcb = ThreadSelfTlsTcb();
   *addr = 0;
   *size = 0;
   if (tcb != 0) {
@@ -583,56 +650,59 @@  static void GetTls(uptr *addr, uptr *size) {
       *addr = (uptr)tcb->tcb_dtv[1];
     }
   }
-#else
-#error "Unknown OS"
-#endif
+#    else
+#      error "Unknown OS"
+#    endif
 }
-#endif
+#  endif
 
-#if !SANITIZER_GO
+#  if !SANITIZER_GO
 uptr GetTlsSize() {
-#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
-    SANITIZER_SOLARIS
+#    if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
+        SANITIZER_SOLARIS
   uptr addr, size;
   GetTls(&addr, &size);
   return size;
-#else
+#    else
   return 0;
-#endif
+#    endif
 }
-#endif
+#  endif
 
-void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
-                          uptr *tls_addr, uptr *tls_size) {
-#if SANITIZER_GO
+void GetThreadStackAndTls(bool main, uptr *stk_begin, uptr *stk_end,
+                          uptr *tls_begin, uptr *tls_end) {
+#  if SANITIZER_GO
   // Stub implementation for Go.
-  *stk_addr = *stk_size = *tls_addr = *tls_size = 0;
-#else
-  GetTls(tls_addr, tls_size);
+  *stk_begin = 0;
+  *stk_end = 0;
+  *tls_begin = 0;
+  *tls_end = 0;
+#  else
+  uptr tls_addr = 0;
+  uptr tls_size = 0;
+  GetTls(&tls_addr, &tls_size);
+  *tls_begin = tls_addr;
+  *tls_end = tls_addr + tls_size;
 
   uptr stack_top, stack_bottom;
   GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
-  *stk_addr = stack_bottom;
-  *stk_size = stack_top - stack_bottom;
+  *stk_begin = stack_bottom;
+  *stk_end = stack_top;
 
   if (!main) {
     // If stack and tls intersect, make them non-intersecting.
-    if (*tls_addr > *stk_addr && *tls_addr < *stk_addr + *stk_size) {
-      if (*stk_addr + *stk_size < *tls_addr + *tls_size)
-        *tls_size = *stk_addr + *stk_size - *tls_addr;
-      *stk_size = *tls_addr - *stk_addr;
+    if (*tls_begin > *stk_begin && *tls_begin < *stk_end) {
+      if (*stk_end < *tls_end)
+        *tls_end = *stk_end;
+      *stk_end = *tls_begin;
     }
   }
-#endif
+#  endif
 }
 
-#if !SANITIZER_FREEBSD
+#  if !SANITIZER_FREEBSD
 typedef ElfW(Phdr) Elf_Phdr;
-#elif SANITIZER_WORDSIZE == 32 && __FreeBSD_version <= 902001  // v9.2
-#define Elf_Phdr XElf32_Phdr
-#define dl_phdr_info xdl_phdr_info
-#define dl_iterate_phdr(c, b) xdl_iterate_phdr((c), (b))
-#endif  // !SANITIZER_FREEBSD
+#  endif
 
 struct DlIteratePhdrData {
   InternalMmapVectorNoCtor<LoadedModule> *modules;
@@ -652,8 +722,7 @@  static int AddModuleSegments(const char *module_name, dl_phdr_info *info,
       uptr cur_end = cur_beg + phdr->p_memsz;
       bool executable = phdr->p_flags & PF_X;
       bool writable = phdr->p_flags & PF_W;
-      cur_module.addAddressRange(cur_beg, cur_end, executable,
-                                 writable);
+      cur_module.addAddressRange(cur_beg, cur_end, executable, writable);
     } else if (phdr->p_type == PT_NOTE) {
 #  ifdef NT_GNU_BUILD_ID
       uptr off = 0;
@@ -704,24 +773,24 @@  static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
   return 0;
 }
 
-#if SANITIZER_ANDROID && __ANDROID_API__ < 21
+#  if SANITIZER_ANDROID && __ANDROID_API__ < 21
 extern "C" __attribute__((weak)) int dl_iterate_phdr(
     int (*)(struct dl_phdr_info *, size_t, void *), void *);
-#endif
+#  endif
 
 static bool requiresProcmaps() {
-#if SANITIZER_ANDROID && __ANDROID_API__ <= 22
+#  if SANITIZER_ANDROID && __ANDROID_API__ <= 22
   // Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken.
   // The runtime check allows the same library to work with
   // both K and L (and future) Android releases.
   return AndroidGetApiLevel() <= ANDROID_LOLLIPOP_MR1;
-#else
+#  else
   return false;
-#endif
+#  endif
 }
 
 static void procmapsInit(InternalMmapVectorNoCtor<LoadedModule> *modules) {
-  MemoryMappingLayout memory_mapping(/*cache_enabled*/true);
+  MemoryMappingLayout memory_mapping(/*cache_enabled*/ true);
   memory_mapping.DumpListOfModules(modules);
 }
 
@@ -773,22 +842,19 @@  uptr GetRSS() {
   // We need the second number which is RSS in pages.
   char *pos = buf;
   // Skip the first number.
-  while (*pos >= '0' && *pos <= '9')
-    pos++;
+  while (*pos >= '0' && *pos <= '9') pos++;
   // Skip whitespaces.
-  while (!(*pos >= '0' && *pos <= '9') && *pos != 0)
-    pos++;
+  while (!(*pos >= '0' && *pos <= '9') && *pos != 0) pos++;
   // Read the number.
   uptr rss = 0;
-  while (*pos >= '0' && *pos <= '9')
-    rss = rss * 10 + *pos++ - '0';
+  while (*pos >= '0' && *pos <= '9') rss = rss * 10 + *pos++ - '0';
   return rss * GetPageSizeCached();
 }
 
 // sysconf(_SC_NPROCESSORS_{CONF,ONLN}) cannot be used on most platforms as
 // they allocate memory.
 u32 GetNumberOfCPUs() {
-#if SANITIZER_FREEBSD || SANITIZER_NETBSD
+#  if SANITIZER_FREEBSD || SANITIZER_NETBSD
   u32 ncpu;
   int req[2];
   uptr len = sizeof(ncpu);
@@ -796,7 +862,7 @@  u32 GetNumberOfCPUs() {
   req[1] = HW_NCPU;
   CHECK_EQ(internal_sysctl(req, 2, &ncpu, &len, NULL, 0), 0);
   return ncpu;
-#elif SANITIZER_ANDROID && !defined(CPU_COUNT) && !defined(__aarch64__)
+#  elif SANITIZER_ANDROID && !defined(CPU_COUNT) && !defined(__aarch64__)
   // Fall back to /sys/devices/system/cpu on Android when cpu_set_t doesn't
   // exist in sched.h. That is the case for toolchains generated with older
   // NDKs.
@@ -824,30 +890,26 @@  u32 GetNumberOfCPUs() {
       break;
     if (entry->d_ino != 0 && *d_type == DT_DIR) {
       if (entry->d_name[0] == 'c' && entry->d_name[1] == 'p' &&
-          entry->d_name[2] == 'u' &&
-          entry->d_name[3] >= '0' && entry->d_name[3] <= '9')
+          entry->d_name[2] == 'u' && entry->d_name[3] >= '0' &&
+          entry->d_name[3] <= '9')
         n_cpus++;
     }
     entry = (struct linux_dirent *)(((u8 *)entry) + entry->d_reclen);
   }
   internal_close(fd);
   return n_cpus;
-#elif SANITIZER_SOLARIS
+#  elif SANITIZER_SOLARIS
   return sysconf(_SC_NPROCESSORS_ONLN);
-#else
-#if defined(CPU_COUNT)
+#  else
   cpu_set_t CPUs;
   CHECK_EQ(sched_getaffinity(0, sizeof(cpu_set_t), &CPUs), 0);
   return CPU_COUNT(&CPUs);
-#else
-  return 1;
-#endif
-#endif
+#  endif
 }
 
-#if SANITIZER_LINUX
+#  if SANITIZER_LINUX
 
-#if SANITIZER_ANDROID
+#    if SANITIZER_ANDROID
 static atomic_uint8_t android_log_initialized;
 
 void AndroidLogInit() {
@@ -859,13 +921,15 @@  static bool ShouldLogAfterPrintf() {
   return atomic_load(&android_log_initialized, memory_order_acquire);
 }
 
-extern "C" SANITIZER_WEAK_ATTRIBUTE
-int async_safe_write_log(int pri, const char* tag, const char* msg);
-extern "C" SANITIZER_WEAK_ATTRIBUTE
-int __android_log_write(int prio, const char* tag, const char* msg);
+extern "C" SANITIZER_WEAK_ATTRIBUTE int async_safe_write_log(int pri,
+                                                             const char *tag,
+                                                             const char *msg);
+extern "C" SANITIZER_WEAK_ATTRIBUTE int __android_log_write(int prio,
+                                                            const char *tag,
+                                                            const char *msg);
 
 // ANDROID_LOG_INFO is 4, but can't be resolved at runtime.
-#define SANITIZER_ANDROID_LOG_INFO 4
+#      define SANITIZER_ANDROID_LOG_INFO 4
 
 // async_safe_write_log is a new public version of __libc_write_log that is
 // used behind syslog. It is preferable to syslog as it will not do any dynamic
@@ -884,14 +948,14 @@  void WriteOneLineToSyslog(const char *s) {
   }
 }
 
-extern "C" SANITIZER_WEAK_ATTRIBUTE
-void android_set_abort_message(const char *);
+extern "C" SANITIZER_WEAK_ATTRIBUTE void android_set_abort_message(
+    const char *);
 
 void SetAbortMessage(const char *str) {
   if (&android_set_abort_message)
     android_set_abort_message(str);
 }
-#else
+#    else
 void AndroidLogInit() {}
 
 static bool ShouldLogAfterPrintf() { return true; }
@@ -899,16 +963,16 @@  static bool ShouldLogAfterPrintf() { return true; }
 void WriteOneLineToSyslog(const char *s) { syslog(LOG_INFO, "%s", s); }
 
 void SetAbortMessage(const char *str) {}
-#endif  // SANITIZER_ANDROID
+#    endif  // SANITIZER_ANDROID
 
 void LogMessageOnPrintf(const char *str) {
   if (common_flags()->log_to_syslog && ShouldLogAfterPrintf())
     WriteToSyslog(str);
 }
 
-#endif  // SANITIZER_LINUX
+#  endif  // SANITIZER_LINUX
 
-#if SANITIZER_GLIBC && !SANITIZER_GO
+#  if SANITIZER_GLIBC && !SANITIZER_GO
 // glibc crashes when using clock_gettime from a preinit_array function as the
 // vDSO function pointers haven't been initialized yet. __progname is
 // initialized after the vDSO function pointers, so if it exists, is not null
@@ -919,8 +983,8 @@  inline bool CanUseVDSO() { return &__progname && __progname && *__progname; }
 // MonotonicNanoTime is a timing function that can leverage the vDSO by calling
 // clock_gettime. real_clock_gettime only exists if clock_gettime is
 // intercepted, so define it weakly and use it if available.
-extern "C" SANITIZER_WEAK_ATTRIBUTE
-int real_clock_gettime(u32 clk_id, void *tp);
+extern "C" SANITIZER_WEAK_ATTRIBUTE int real_clock_gettime(u32 clk_id,
+                                                           void *tp);
 u64 MonotonicNanoTime() {
   timespec ts;
   if (CanUseVDSO()) {
@@ -933,19 +997,26 @@  u64 MonotonicNanoTime() {
   }
   return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
 }
-#else
+#  else
 // Non-glibc & Go always use the regular function.
 u64 MonotonicNanoTime() {
   timespec ts;
   clock_gettime(CLOCK_MONOTONIC, &ts);
   return (u64)ts.tv_sec * (1000ULL * 1000 * 1000) + ts.tv_nsec;
 }
-#endif  // SANITIZER_GLIBC && !SANITIZER_GO
+#  endif  // SANITIZER_GLIBC && !SANITIZER_GO
 
 void ReExec() {
   const char *pathname = "/proc/self/exe";
 
-#if SANITIZER_NETBSD
+#  if SANITIZER_FREEBSD
+  for (const auto *aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
+    if (aux->a_type == AT_EXECPATH) {
+      pathname = static_cast<const char *>(aux->a_un.a_ptr);
+      break;
+    }
+  }
+#  elif SANITIZER_NETBSD
   static const int name[] = {
       CTL_KERN,
       KERN_PROC_ARGS,
@@ -958,14 +1029,14 @@  void ReExec() {
   len = sizeof(path);
   if (internal_sysctl(name, ARRAY_SIZE(name), path, &len, NULL, 0) != -1)
     pathname = path;
-#elif SANITIZER_SOLARIS
+#  elif SANITIZER_SOLARIS
   pathname = getexecname();
   CHECK_NE(pathname, NULL);
-#elif SANITIZER_USE_GETAUXVAL
+#  elif SANITIZER_USE_GETAUXVAL
   // Calling execve with /proc/self/exe sets that as $EXEC_ORIGIN. Binaries that
   // rely on that will fail to load shared libraries. Query AT_EXECFN instead.
   pathname = reinterpret_cast<const char *>(getauxval(AT_EXECFN));
-#endif
+#  endif
 
   uptr rv = internal_execve(pathname, GetArgv(), GetEnviron());
   int rverrno;
@@ -987,9 +1058,8 @@  void UnmapFromTo(uptr from, uptr to) {
 }
 
 uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
-                      uptr min_shadow_base_alignment,
-                      UNUSED uptr &high_mem_end) {
-  const uptr granularity = GetMmapGranularity();
+                      uptr min_shadow_base_alignment, UNUSED uptr &high_mem_end,
+                      uptr granularity) {
   const uptr alignment =
       Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment);
   const uptr left_padding =
@@ -1017,14 +1087,14 @@  static uptr MmapSharedNoReserve(uptr addr, uptr size) {
 
 static uptr MremapCreateAlias(uptr base_addr, uptr alias_addr,
                               uptr alias_size) {
-#if SANITIZER_LINUX
+#  if SANITIZER_LINUX
   return internal_mremap(reinterpret_cast<void *>(base_addr), 0, alias_size,
                          MREMAP_MAYMOVE | MREMAP_FIXED,
                          reinterpret_cast<void *>(alias_addr));
-#else
+#  else
   CHECK(false && "mremap is not supported outside of Linux");
   return 0;
-#endif
+#  endif
 }
 
 static void CreateAliases(uptr start_addr, uptr alias_size, uptr num_aliases) {
@@ -1069,12 +1139,12 @@  uptr MapDynamicShadowAndAliases(uptr shadow_size, uptr alias_size,
 }
 
 void InitializePlatformCommonFlags(CommonFlags *cf) {
-#if SANITIZER_ANDROID
+#  if SANITIZER_ANDROID
   if (&__libc_get_static_tls_bounds == nullptr)
     cf->detect_leaks = false;
-#endif
+#  endif
 }
 
-} // namespace __sanitizer
+}  // namespace __sanitizer
 
 #endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp b/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp
index 74db831b0aad..8523b540f2e5 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_s390.cpp
@@ -15,14 +15,14 @@ 
 
 #if SANITIZER_LINUX && SANITIZER_S390
 
-#include <dlfcn.h>
-#include <errno.h>
-#include <sys/syscall.h>
-#include <sys/utsname.h>
-#include <unistd.h>
+#  include <dlfcn.h>
+#  include <errno.h>
+#  include <sys/syscall.h>
+#  include <sys/utsname.h>
+#  include <unistd.h>
 
-#include "sanitizer_libc.h"
-#include "sanitizer_linux.h"
+#  include "sanitizer_libc.h"
+#  include "sanitizer_linux.h"
 
 namespace __sanitizer {
 
@@ -37,22 +37,19 @@  uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
     unsigned long fd;
     unsigned long offset;
   } params = {
-    (unsigned long)addr,
-    (unsigned long)length,
-    (unsigned long)prot,
-    (unsigned long)flags,
-    (unsigned long)fd,
-# ifdef __s390x__
-    (unsigned long)offset,
-# else
+      (unsigned long)addr,   (unsigned long)length, (unsigned long)prot,
+      (unsigned long)flags,  (unsigned long)fd,
+#  ifdef __s390x__
+      (unsigned long)offset,
+#  else
     (unsigned long)(offset / 4096),
-# endif
+#  endif
   };
-# ifdef __s390x__
+#  ifdef __s390x__
   return syscall(__NR_mmap, &params);
-# else
+#  else
   return syscall(__NR_mmap2, &params);
-# endif
+#  endif
 }
 
 uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
@@ -63,58 +60,54 @@  uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
   }
   CHECK_EQ(0, (uptr)child_stack % 16);
   // Minimum frame size.
-#ifdef __s390x__
+#  ifdef __s390x__
   child_stack = (char *)child_stack - 160;
-#else
+#  else
   child_stack = (char *)child_stack - 96;
-#endif
+#  endif
   // Terminate unwind chain.
   ((unsigned long *)child_stack)[0] = 0;
   // And pass parameters.
   ((unsigned long *)child_stack)[1] = (uptr)fn;
   ((unsigned long *)child_stack)[2] = (uptr)arg;
   register uptr res __asm__("r2");
-  register void *__cstack      __asm__("r2") = child_stack;
-  register long __flags        __asm__("r3") = flags;
-  register int * __ptidptr     __asm__("r4") = parent_tidptr;
-  register int * __ctidptr     __asm__("r5") = child_tidptr;
-  register void * __newtls     __asm__("r6") = newtls;
+  register void *__cstack __asm__("r2") = child_stack;
+  register long __flags __asm__("r3") = flags;
+  register int *__ptidptr __asm__("r4") = parent_tidptr;
+  register int *__ctidptr __asm__("r5") = child_tidptr;
+  register void *__newtls __asm__("r6") = newtls;
 
   __asm__ __volatile__(
-                       /* Clone. */
-                       "svc    %1\n"
-
-                       /* if (%r2 != 0)
-                        *   return;
-                        */
-#ifdef __s390x__
-                       "cghi   %%r2, 0\n"
-#else
-                       "chi    %%r2, 0\n"
-#endif
-                       "jne    1f\n"
-
-                       /* Call "fn(arg)". */
-#ifdef __s390x__
-                       "lmg    %%r1, %%r2, 8(%%r15)\n"
-#else
-                       "lm     %%r1, %%r2, 4(%%r15)\n"
-#endif
-                       "basr   %%r14, %%r1\n"
-
-                       /* Call _exit(%r2). */
-                       "svc %2\n"
-
-                       /* Return to parent. */
-                     "1:\n"
-                       : "=r" (res)
-                       : "i"(__NR_clone), "i"(__NR_exit),
-                         "r"(__cstack),
-                         "r"(__flags),
-                         "r"(__ptidptr),
-                         "r"(__ctidptr),
-                         "r"(__newtls)
-                       : "memory", "cc");
+      /* Clone. */
+      "svc    %1\n"
+
+  /* if (%r2 != 0)
+   *   return;
+   */
+#  ifdef __s390x__
+      "cghi   %%r2, 0\n"
+#  else
+      "chi    %%r2, 0\n"
+#  endif
+      "jne    1f\n"
+
+  /* Call "fn(arg)". */
+#  ifdef __s390x__
+      "lmg    %%r1, %%r2, 8(%%r15)\n"
+#  else
+      "lm     %%r1, %%r2, 4(%%r15)\n"
+#  endif
+      "basr   %%r14, %%r1\n"
+
+      /* Call _exit(%r2). */
+      "svc %2\n"
+
+      /* Return to parent. */
+      "1:\n"
+      : "=r"(res)
+      : "i"(__NR_clone), "i"(__NR_exit), "r"(__cstack), "r"(__flags),
+        "r"(__ptidptr), "r"(__ctidptr), "r"(__newtls)
+      : "memory", "cc");
   if (res >= (uptr)-4095) {
     errno = -res;
     return -1;
@@ -122,7 +115,7 @@  uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
   return res;
 }
 
-#if SANITIZER_S390_64
+#  if SANITIZER_S390_64
 static bool FixedCVE_2016_2143() {
   // Try to determine if the running kernel has a fix for CVE-2016-2143,
   // return false if in doubt (better safe than sorry).  Distros may want to
@@ -137,20 +130,20 @@  static bool FixedCVE_2016_2143() {
   // At least first 2 should be matched.
   if (ptr[0] != '.')
     return false;
-  minor = internal_simple_strtoll(ptr+1, &ptr, 10);
+  minor = internal_simple_strtoll(ptr + 1, &ptr, 10);
   // Third is optional.
   if (ptr[0] == '.')
-    patch = internal_simple_strtoll(ptr+1, &ptr, 10);
+    patch = internal_simple_strtoll(ptr + 1, &ptr, 10);
   if (major < 3) {
     if (major == 2 && minor == 6 && patch == 32 && ptr[0] == '-' &&
         internal_strstr(ptr, ".el6")) {
       // Check RHEL6
-      int r1 = internal_simple_strtoll(ptr+1, &ptr, 10);
-      if (r1 >= 657) // 2.6.32-657.el6 or later
+      int r1 = internal_simple_strtoll(ptr + 1, &ptr, 10);
+      if (r1 >= 657)  // 2.6.32-657.el6 or later
         return true;
       if (r1 == 642 && ptr[0] == '.') {
-        int r2 = internal_simple_strtoll(ptr+1, &ptr, 10);
-        if (r2 >= 9) // 2.6.32-642.9.1.el6 or later
+        int r2 = internal_simple_strtoll(ptr + 1, &ptr, 10);
+        if (r2 >= 9)  // 2.6.32-642.9.1.el6 or later
           return true;
       }
     }
@@ -166,12 +159,12 @@  static bool FixedCVE_2016_2143() {
     if (minor == 10 && patch == 0 && ptr[0] == '-' &&
         internal_strstr(ptr, ".el7")) {
       // Check RHEL7
-      int r1 = internal_simple_strtoll(ptr+1, &ptr, 10);
-      if (r1 >= 426) // 3.10.0-426.el7 or later
+      int r1 = internal_simple_strtoll(ptr + 1, &ptr, 10);
+      if (r1 >= 426)  // 3.10.0-426.el7 or later
         return true;
       if (r1 == 327 && ptr[0] == '.') {
-        int r2 = internal_simple_strtoll(ptr+1, &ptr, 10);
-        if (r2 >= 27) // 3.10.0-327.27.1.el7 or later
+        int r2 = internal_simple_strtoll(ptr + 1, &ptr, 10);
+        if (r2 >= 27)  // 3.10.0-327.27.1.el7 or later
           return true;
       }
     }
@@ -187,8 +180,8 @@  static bool FixedCVE_2016_2143() {
     if (minor == 4 && patch == 0 && ptr[0] == '-' &&
         internal_strstr(buf.version, "Ubuntu")) {
       // Check Ubuntu 16.04
-      int r1 = internal_simple_strtoll(ptr+1, &ptr, 10);
-      if (r1 >= 13) // 4.4.0-13 or later
+      int r1 = internal_simple_strtoll(ptr + 1, &ptr, 10);
+      if (r1 >= 13)  // 4.4.0-13 or later
         return true;
     }
     // Otherwise, OK if 4.5+.
@@ -211,18 +204,19 @@  void AvoidCVE_2016_2143() {
   if (GetEnv("SANITIZER_IGNORE_CVE_2016_2143"))
     return;
   Report(
-    "ERROR: Your kernel seems to be vulnerable to CVE-2016-2143.  Using ASan,\n"
-    "MSan, TSan, DFSan or LSan with such kernel can and will crash your\n"
-    "machine, or worse.\n"
-    "\n"
-    "If you are certain your kernel is not vulnerable (you have compiled it\n"
-    "yourself, or are using an unrecognized distribution kernel), you can\n"
-    "override this safety check by exporting SANITIZER_IGNORE_CVE_2016_2143\n"
-    "with any value.\n");
+      "ERROR: Your kernel seems to be vulnerable to CVE-2016-2143.  Using "
+      "ASan,\n"
+      "MSan, TSan, DFSan or LSan with such kernel can and will crash your\n"
+      "machine, or worse.\n"
+      "\n"
+      "If you are certain your kernel is not vulnerable (you have compiled it\n"
+      "yourself, or are using an unrecognized distribution kernel), you can\n"
+      "override this safety check by exporting SANITIZER_IGNORE_CVE_2016_2143\n"
+      "with any value.\n");
   Die();
 }
-#endif
+#  endif
 
-} // namespace __sanitizer
+}  // namespace __sanitizer
 
-#endif // SANITIZER_LINUX && SANITIZER_S390
+#endif  // SANITIZER_LINUX && SANITIZER_S390
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
index e1f83e4002a5..26d2e8d4ed76 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mac.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_mac.cpp
@@ -38,7 +38,7 @@ 
 extern char **environ;
 #  endif
 
-#  if defined(__has_include) && __has_include(<os/trace.h>) && defined(__BLOCKS__)
+#  if defined(__has_include) && __has_include(<os/trace.h>)
 #    define SANITIZER_OS_TRACE 1
 #    include <os/trace.h>
 #  else
@@ -71,15 +71,7 @@  extern char ***_NSGetArgv(void);
 #  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 <os/log.h>
 #  include <pthread.h>
 #  include <pthread/introspection.h>
 #  include <sched.h>
@@ -553,9 +545,6 @@  uptr GetTlsSize() {
   return 0;
 }
 
-void InitTlsSize() {
-}
-
 uptr TlsBaseAddr() {
   uptr segbase = 0;
 #if defined(__x86_64__)
@@ -580,21 +569,18 @@  uptr TlsSize() {
 #endif
 }
 
-void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
-                          uptr *tls_addr, uptr *tls_size) {
-#if !SANITIZER_GO
-  uptr stack_top, stack_bottom;
-  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
-  *stk_addr = stack_bottom;
-  *stk_size = stack_top - stack_bottom;
-  *tls_addr = TlsBaseAddr();
-  *tls_size = TlsSize();
-#else
-  *stk_addr = 0;
-  *stk_size = 0;
-  *tls_addr = 0;
-  *tls_size = 0;
-#endif
+void GetThreadStackAndTls(bool main, uptr *stk_begin, uptr *stk_end,
+                          uptr *tls_begin, uptr *tls_end) {
+#  if !SANITIZER_GO
+  GetThreadStackTopAndBottom(main, stk_end, stk_begin);
+  *tls_begin = TlsBaseAddr();
+  *tls_end = *tls_begin + TlsSize();
+#  else
+  *stk_begin = 0;
+  *stk_end = 0;
+  *tls_begin = 0;
+  *tls_end = 0;
+#  endif
 }
 
 void ListOfModules::init() {
@@ -796,7 +782,11 @@  void WriteOneLineToSyslog(const char *s) {
   if (GetMacosAlignedVersion() >= MacosVersion(10, 12)) {
     os_log_error(OS_LOG_DEFAULT, "%{public}s", s);
   } else {
+#pragma clang diagnostic push
+// as_log is deprecated.
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
     asl_log(nullptr, nullptr, ASL_LEVEL_ERR, "%s", s);
+#pragma clang diagnostic pop
   }
 #endif
 }
@@ -851,6 +841,9 @@  void LogFullErrorReport(const char *buffer) {
 #if !SANITIZER_GO
   // Log with os_trace. This will make it into the crash log.
 #if SANITIZER_OS_TRACE
+#pragma clang diagnostic push
+// os_trace is deprecated.
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
   if (GetMacosAlignedVersion() >= MacosVersion(10, 10)) {
     // os_trace requires the message (format parameter) to be a string literal.
     if (internal_strncmp(SanitizerToolName, "AddressSanitizer",
@@ -868,6 +861,7 @@  void LogFullErrorReport(const char *buffer) {
     if (common_flags()->log_to_syslog)
       os_trace("Consult syslog for more information.");
   }
+#pragma clang diagnostic pop
 #endif
 
   // Log to syslog.
@@ -1196,8 +1190,8 @@  uptr GetMaxVirtualAddress() {
 }
 
 uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
-                      uptr min_shadow_base_alignment, uptr &high_mem_end) {
-  const uptr granularity = GetMmapGranularity();
+                      uptr min_shadow_base_alignment, uptr &high_mem_end,
+                      uptr granularity) {
   const uptr alignment =
       Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment);
   const uptr left_padding =
@@ -1380,8 +1374,8 @@  void DumpProcessMap() {
   for (uptr i = 0; i < modules.size(); ++i) {
     char uuid_str[128];
     FormatUUID(uuid_str, sizeof(uuid_str), modules[i].uuid());
-    Printf("0x%zx-0x%zx %s (%s) %s\n", modules[i].base_address(),
-           modules[i].max_address(), modules[i].full_name(),
+    Printf("%p-%p %s (%s) %s\n", (void *)modules[i].base_address(),
+           (void *)modules[i].max_address(), modules[i].full_name(),
            ModuleArchToString(modules[i].arch()), uuid_str);
   }
   Printf("End of module map.\n");
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_mac.h
index 1cf2e298cc91..f0a97d098eea 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
index 4e58c02df835..1c07e68e55a7 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mallinfo.h
+++ b/libsanitizer/sanitizer_common/sanitizer_mallinfo.h
@@ -31,6 +31,10 @@  struct __sanitizer_struct_mallinfo {
   int v[10];
 };
 
+struct __sanitizer_struct_mallinfo2 {
+  uptr v[10];
+};
+
 #endif
 
 }  // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_mutex.cpp b/libsanitizer/sanitizer_common/sanitizer_mutex.cpp
index 40fe56661250..97085e895a34 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mutex.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_mutex.cpp
@@ -212,8 +212,10 @@  struct InternalDeadlockDetector {
     return initialized > 0;
   }
 };
-
-static THREADLOCAL InternalDeadlockDetector deadlock_detector;
+// This variable is used by the __tls_get_addr interceptor, so cannot use the
+// global-dynamic TLS model, as that would result in crashes.
+__attribute__((tls_model("initial-exec"))) static THREADLOCAL
+    InternalDeadlockDetector deadlock_detector;
 
 void CheckedMutex::LockImpl(uptr pc) { deadlock_detector.Lock(type_, pc); }
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_placement_new.h b/libsanitizer/sanitizer_common/sanitizer_placement_new.h
index 1ceb8b909268..c9b917b45346 100644
--- a/libsanitizer/sanitizer_common/sanitizer_placement_new.h
+++ b/libsanitizer/sanitizer_common/sanitizer_placement_new.h
@@ -17,8 +17,6 @@ 
 
 #include "sanitizer_internal_defs.h"
 
-inline void *operator new(__sanitizer::operator_new_size_type sz, void *p) {
-  return p;
-}
+inline void *operator new(__sanitizer::usize sz, void *p) { return p; }
 
 #endif  // SANITIZER_PLACEMENT_NEW_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform.h b/libsanitizer/sanitizer_common/sanitizer_platform.h
index 3e1b078a0212..57966403c92a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform.h
@@ -260,6 +260,17 @@ 
 #  define SANITIZER_ARM64 0
 #endif
 
+#if SANITIZER_WINDOWS64 && SANITIZER_ARM64
+#  define SANITIZER_WINDOWS_ARM64 1
+#  define SANITIZER_WINDOWS_x64 0
+#elif SANITIZER_WINDOWS64 && !SANITIZER_ARM64
+#  define SANITIZER_WINDOWS_ARM64 0
+#  define SANITIZER_WINDOWS_x64 1
+#else
+#  define SANITIZER_WINDOWS_ARM64 0
+#  define SANITIZER_WINDOWS_x64 0
+#endif
+
 #if SANITIZER_SOLARIS && SANITIZER_WORDSIZE == 32
 #  define SANITIZER_SOLARIS32 1
 #else
@@ -284,8 +295,8 @@ 
 // 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_RISCV64 && !SANITIZER_FUCHSIA) || SANITIZER_IOS || \
-      SANITIZER_DRIVERKIT
+#  if (SANITIZER_RISCV64 && !SANITIZER_FUCHSIA && !SANITIZER_LINUX) || \
+      SANITIZER_IOS || SANITIZER_DRIVERKIT
 #    define SANITIZER_CAN_USE_ALLOCATOR64 0
 #  elif defined(__mips64) || defined(__hexagon__)
 #    define SANITIZER_CAN_USE_ALLOCATOR64 0
@@ -311,7 +322,7 @@ 
 #  if SANITIZER_FUCHSIA
 #    define SANITIZER_MMAP_RANGE_SIZE (1ULL << 38)
 #  else
-#    define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 47)
+#    define SANITIZER_MMAP_RANGE_SIZE FIRST_32_SECOND_64(1ULL << 32, 1ULL << 56)
 #  endif
 #elif defined(__aarch64__)
 #  if SANITIZER_APPLE
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
index 8c7c00de6d12..3fd6b595ef19 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
@@ -84,6 +84,25 @@ 
 #define SI_NOT_MAC 1
 #endif
 
+#if SANITIZER_APPLE
+#  include <Availability.h>
+
+// aligned_alloc was introduced in OSX 10.15
+// Linking will fail when using an older SDK
+#  if defined(__MAC_10_15)
+// macOS 10.15 is greater than our minimal deployment target.  To ensure we
+// generate a weak reference so the dylib continues to work on older
+// systems, we need to forward declare the intercepted function as "weak
+// imports".
+SANITIZER_WEAK_IMPORT void *aligned_alloc(__sanitizer::usize __alignment,
+                                          __sanitizer::usize __size);
+#    define SI_MAC_SDK_10_15_AVAILABLE 1
+#  else
+#    define SI_MAC_SDK_10_15_AVAILABLE 0
+#  endif  // defined(__MAC_10_15)
+
+#endif  // SANITIZER_APPLE
+
 #if SANITIZER_IOS
 #define SI_IOS 1
 #else
@@ -183,6 +202,11 @@ 
 #define SANITIZER_INTERCEPT_FPUTS SI_POSIX
 #define SANITIZER_INTERCEPT_PUTS SI_POSIX
 
+#define SANITIZER_INTERCEPT_CREAT64 (SI_GLIBC || SI_SOLARIS32)
+#define SANITIZER_INTERCEPT_FCNTL64 (SI_GLIBC || SI_SOLARIS32)
+#define SANITIZER_INTERCEPT_OPEN64 (SI_GLIBC || SI_SOLARIS32)
+#define SANITIZER_INTERCEPT_OPENAT64 (SI_GLIBC || SI_SOLARIS32)
+
 #define SANITIZER_INTERCEPT_PREAD64 (SI_GLIBC || SI_SOLARIS32)
 #define SANITIZER_INTERCEPT_PWRITE64 (SI_GLIBC || SI_SOLARIS32)
 
@@ -191,7 +215,8 @@ 
 
 #define SANITIZER_INTERCEPT_PREADV \
   (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
-#define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PWRITEV \
+  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
 #define SANITIZER_INTERCEPT_PREADV64 SI_GLIBC
 #define SANITIZER_INTERCEPT_PWRITEV64 SI_GLIBC
 
@@ -273,8 +298,9 @@ 
 #if SI_LINUX_NOT_ANDROID &&                                                \
     (defined(__i386) || defined(__x86_64) || defined(__mips64) ||          \
      defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
-     defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64)
-#define SANITIZER_INTERCEPT_PTRACE 1
+     defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64 ||   \
+     defined(__sparc__))
+#  define SANITIZER_INTERCEPT_PTRACE 1
 #else
 #define SANITIZER_INTERCEPT_PTRACE 0
 #endif
@@ -301,7 +327,8 @@ 
 #define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME (SI_GLIBC || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_CONFSTR \
   (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
-#define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_SCHED_GETAFFINITY \
+  (SI_LINUX_NOT_ANDROID || SI_FREEBSD)
 #define SANITIZER_INTERCEPT_SCHED_GETPARAM SI_LINUX_NOT_ANDROID || SI_SOLARIS
 #define SANITIZER_INTERCEPT_STRERROR SI_POSIX
 #define SANITIZER_INTERCEPT_STRERROR_R SI_POSIX
@@ -462,7 +489,7 @@ 
   (SI_LINUX || SI_MAC || SI_WINDOWS || SI_FREEBSD || SI_NETBSD || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_RECV_RECVFROM SI_POSIX
 #define SANITIZER_INTERCEPT_SEND_SENDTO SI_POSIX
-#define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE SI_LINUX
+#define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE (SI_LINUX || SI_FREEBSD)
 
 #define SI_STAT_LINUX (SI_LINUX && __GLIBC_PREREQ(2, 33))
 #define SANITIZER_INTERCEPT_STAT                                        \
@@ -492,7 +519,8 @@ 
 #define SANITIZER_INTERCEPT_PVALLOC (SI_GLIBC || SI_ANDROID)
 #define SANITIZER_INTERCEPT_CFREE (SI_GLIBC && !SANITIZER_RISCV64)
 #define SANITIZER_INTERCEPT_REALLOCARRAY SI_POSIX
-#define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC)
+#define SANITIZER_INTERCEPT_ALIGNED_ALLOC \
+  (!SI_MAC || SI_MAC_SDK_10_15_AVAILABLE)
 #define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC && !SI_NETBSD)
 #define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID
 #define SANITIZER_INTERCEPT_WCSLEN 1
@@ -557,10 +585,8 @@ 
 #define SANITIZER_INTERCEPT_SHA1 SI_NETBSD
 #define SANITIZER_INTERCEPT_MD4 SI_NETBSD
 #define SANITIZER_INTERCEPT_RMD160 SI_NETBSD
-#define SANITIZER_INTERCEPT_MD5 (SI_NETBSD || SI_FREEBSD)
 #define SANITIZER_INTERCEPT_FSEEK (SI_NETBSD || SI_FREEBSD)
 #define SANITIZER_INTERCEPT_MD2 SI_NETBSD
-#define SANITIZER_INTERCEPT_SHA2 (SI_NETBSD || SI_FREEBSD)
 #define SANITIZER_INTERCEPT_CDB SI_NETBSD
 #define SANITIZER_INTERCEPT_VIS (SI_NETBSD || SI_FREEBSD)
 #define SANITIZER_INTERCEPT_POPEN SI_POSIX
@@ -594,10 +620,18 @@ 
 #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
 #define SANITIZER_INTERCEPT_CPUSET_GETAFFINITY SI_FREEBSD
-
+// FIXME: also available from musl 1.2.5
+#define SANITIZER_INTERCEPT_PREADV2 (SI_LINUX && __GLIBC_PREREQ(2, 26))
+#define SANITIZER_INTERCEPT_PWRITEV2 (SI_LINUX && __GLIBC_PREREQ(2, 26))
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && \
+    __MAC_OS_X_VERSION_MIN_REQUIRED >= 130000
+#  define SI_MAC_OS_DEPLOYMENT_MIN_13_00 1
+#else
+#  define SI_MAC_OS_DEPLOYMENT_MIN_13_00 0
+#endif
+#define SANITIZER_INTERCEPT_FREADLINK (SI_MAC && SI_MAC_OS_DEPLOYMENT_MIN_13_00)
 // This macro gives a way for downstream users to override the above
 // interceptor macros irrespective of the platform they are on. They have
 // to do two things:
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
index 38f968d533b1..4940062eeae4 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.cpp
@@ -475,6 +475,8 @@  CHECK_TYPE_SIZE(nfds_t);
 CHECK_TYPE_SIZE(sigset_t);
 
 COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction));
+COMPILER_CHECK(sizeof(__sanitizer_siginfo) == sizeof(siginfo_t));
+CHECK_SIZE_AND_OFFSET(siginfo_t, si_value);
 // Can't write checks for sa_handler and sa_sigaction due to them being
 // preprocessor macros.
 CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask);
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h
index b119f059007d..8ce73f206fd8 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_freebsd.h
@@ -301,11 +301,29 @@  struct __sanitizer_sigset_t {
 
 typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t;
 
+union __sanitizer_sigval {
+  int sival_int;
+  void *sival_ptr;
+};
+
 struct __sanitizer_siginfo {
-  // The size is determined by looking at sizeof of real siginfo_t on linux.
-  u64 opaque[128 / sizeof(u64)];
+  int si_signo;
+  int si_errno;
+  int si_code;
+  pid_t si_pid;
+  u32 si_uid;
+  int si_status;
+  void *si_addr;
+  union __sanitizer_sigval si_value;
+#  if SANITIZER_WORDSIZE == 64
+  char data[40];
+#  else
+  char data[32];
+#  endif
 };
 
+typedef __sanitizer_siginfo __sanitizer_siginfo_t;
+
 using __sanitizer_sighandler_ptr = void (*)(int sig);
 using __sanitizer_sigactionhandler_ptr = void (*)(int sig,
                                                   __sanitizer_siginfo *siginfo,
@@ -726,6 +744,8 @@  struct __sanitizer_cpuset {
 
 typedef struct __sanitizer_cpuset __sanitizer_cpuset_t;
 extern unsigned struct_cpuset_sz;
+
+typedef unsigned long long __sanitizer_eventfd_t;
 }  // namespace __sanitizer
 
 #  define CHECK_TYPE_SIZE(TYPE) \
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_linux.cpp
index c278c8797f75..bf0f355847cb 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_openbsd.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.cpp
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_openbsd.h
deleted file mode 100644
index e69de29bb2d1..000000000000
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
index 6d61d276d77e..c87d5ef42c92 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cpp
@@ -94,8 +94,9 @@ 
 #if SANITIZER_LINUX
 # include <utime.h>
 # include <sys/ptrace.h>
-#    if defined(__mips64) || defined(__aarch64__) || defined(__arm__) || \
-        defined(__hexagon__) || defined(__loongarch__) ||SANITIZER_RISCV64
+#    if defined(__mips64) || defined(__aarch64__) || defined(__arm__) ||       \
+        defined(__hexagon__) || defined(__loongarch__) || SANITIZER_RISCV64 || \
+        defined(__sparc__)
 #      include <asm/ptrace.h>
 #      ifdef __arm__
 typedef struct user_fpregs elf_fpregset_t;
@@ -117,15 +118,16 @@  typedef struct user_fpregs elf_fpregset_t;
 #if SANITIZER_LINUX
 #if SANITIZER_GLIBC
 #include <fstab.h>
-#include <net/if_ppp.h>
-#include <netax25/ax25.h>
-#include <netipx/ipx.h>
-#include <netrom/netrom.h>
-#include <obstack.h>
-#if HAVE_RPC_XDR_H
-# include <rpc/xdr.h>
-#endif
-#include <scsi/scsi.h>
+#      include <linux/filter.h>
+#      include <net/if_ppp.h>
+#      include <netax25/ax25.h>
+#      include <netipx/ipx.h>
+#      include <netrom/netrom.h>
+#      include <obstack.h>
+#      if HAVE_RPC_XDR_H
+#        include <rpc/xdr.h>
+#      endif
+#      include <scsi/scsi.h>
 #else
 #include <linux/if_ppp.h>
 #include <linux/kd.h>
@@ -358,11 +360,12 @@  unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
   const int wordexp_wrde_dooffs = WRDE_DOOFFS;
 #  endif  // !SANITIZER_ANDROID
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID &&                               \
-    (defined(__i386) || defined(__x86_64) || defined(__mips64) ||          \
-     defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
-     defined(__s390__) || defined(__loongarch__)|| SANITIZER_RISCV64)
-#if defined(__mips64) || defined(__powerpc64__) || defined(__arm__)
+#  if SANITIZER_LINUX && !SANITIZER_ANDROID &&                               \
+      (defined(__i386) || defined(__x86_64) || defined(__mips64) ||          \
+       defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
+       defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64 ||   \
+       defined(__sparc__))
+#    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);
 #elif SANITIZER_RISCV64
@@ -377,19 +380,22 @@  unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
 #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
+#    elif defined(__sparc__)
+  unsigned struct_user_regs_struct_sz = sizeof(struct sunos_regs);
+  unsigned struct_user_fpregs_struct_sz = sizeof(struct sunos_fp);
+#    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__ || __loongarch__
-#if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \
-    defined(__aarch64__) || defined(__arm__) || defined(__s390__) ||    \
-    defined(__loongarch__) || SANITIZER_RISCV64
+#    endif  // __mips64 || __powerpc64__ || __aarch64__ || __loongarch__
+#    if defined(__x86_64) || defined(__mips64) || defined(__powerpc64__) || \
+        defined(__aarch64__) || defined(__arm__) || defined(__s390__) ||    \
+        defined(__loongarch__) || SANITIZER_RISCV64 || defined(__sparc__)
   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__ || __loongarch__
-#ifdef __arm__
+  // || __s390__ || __loongarch__ || SANITIZER_RISCV64 || __sparc__
+#    ifdef __arm__
   unsigned struct_user_vfpregs_struct_sz = ARM_VFPREGS_SIZE;
 #else
   unsigned struct_user_vfpregs_struct_sz = 0;
@@ -531,9 +537,10 @@  unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
 
   unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
   unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
-#endif  // SANITIZER_GLIBC
+  unsigned struct_sock_fprog_sz = sizeof(struct sock_fprog);
+#  endif  // SANITIZER_GLIBC
 
-#if !SANITIZER_ANDROID && !SANITIZER_APPLE
+#  if !SANITIZER_ANDROID && !SANITIZER_APPLE
   unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
   unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
 #endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
index 58244c9944a0..e8c81aa8e281 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -523,6 +523,7 @@  typedef long __sanitizer_clock_t;
 
 #if SANITIZER_LINUX
 typedef int __sanitizer_clockid_t;
+typedef unsigned long long __sanitizer_eventfd_t;
 #endif
 
 #if SANITIZER_LINUX
@@ -854,10 +855,11 @@  typedef void __sanitizer_FILE;
 # define SANITIZER_HAS_STRUCT_FILE 0
 #endif
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID &&                               \
-    (defined(__i386) || defined(__x86_64) || defined(__mips64) ||          \
-     defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
-     defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64)
+#  if SANITIZER_LINUX && !SANITIZER_ANDROID &&                               \
+      (defined(__i386) || defined(__x86_64) || defined(__mips64) ||          \
+       defined(__powerpc64__) || defined(__aarch64__) || defined(__arm__) || \
+       defined(__s390__) || defined(__loongarch__) || SANITIZER_RISCV64 ||   \
+       defined(__sparc__))
 extern unsigned struct_user_regs_struct_sz;
 extern unsigned struct_user_fpregs_struct_sz;
 extern unsigned struct_user_fpxregs_struct_sz;
@@ -879,9 +881,24 @@  extern int ptrace_setsiginfo;
 extern int ptrace_getregset;
 extern int ptrace_setregset;
 extern int ptrace_geteventmsg;
-#endif
 
-#if SANITIZER_LINUX  && !SANITIZER_ANDROID
+// Helper for the ptrace interceptor.
+template <class T>
+inline T ptrace_data_arg(int request, T addr, T data) {
+#    if SANITIZER_LINUX && SANITIZER_SPARC
+  // As described in ptrace(2), the meanings of addr and data are reversed
+  // for the PTRACE_GETREGS, PTRACE_GETFPREGS, PTRACE_GETREGS, and
+  // PTRACE_GETFPREGS requests on Linux/sparc64.
+  if (request == ptrace_getregs || request == ptrace_getfpregs ||
+      request == ptrace_setregs || request == ptrace_setfpregs)
+    return addr;
+  else
+#    endif
+    return data;
+}
+#  endif
+
+#  if SANITIZER_LINUX && !SANITIZER_ANDROID
 extern unsigned struct_shminfo_sz;
 extern unsigned struct_shm_info_sz;
 extern int shmctl_ipc_stat;
@@ -1049,7 +1066,8 @@  extern unsigned struct_serial_struct_sz;
 extern unsigned struct_sockaddr_ax25_sz;
 extern unsigned struct_unimapdesc_sz;
 extern unsigned struct_unimapinit_sz;
-#endif  // SANITIZER_LINUX && !SANITIZER_ANDROID
+extern unsigned struct_sock_fprog_sz;
+#  endif  // SANITIZER_LINUX && !SANITIZER_ANDROID
 
 extern const unsigned long __sanitizer_bufsiz;
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cpp b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
index 8d2c5b2cefbe..69af6465a62c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_posix.cpp
@@ -54,12 +54,12 @@  void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
   return (void *)res;
 }
 
-void UnmapOrDie(void *addr, uptr size) {
+void UnmapOrDie(void *addr, uptr size, bool raw_report) {
   if (!addr || !size) return;
   uptr res = internal_munmap(addr, size);
   int reserrno;
   if (UNLIKELY(internal_iserror(res, &reserrno)))
-    ReportMunmapFailureAndDie(addr, size, reserrno);
+    ReportMunmapFailureAndDie(addr, size, reserrno, raw_report);
   DecreaseTotalMmap(size);
 }
 
@@ -85,8 +85,8 @@  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. 
+  // 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());
@@ -130,8 +130,8 @@  static void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem,
     if (tolerate_enomem && reserrno == ENOMEM)
       return nullptr;
     char mem_type[40];
-    internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
-                      fixed_addr);
+    internal_snprintf(mem_type, sizeof(mem_type), "memory at address %p",
+                      (void *)fixed_addr);
     ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
   }
   IncreaseTotalMmap(size);
@@ -353,7 +353,15 @@  bool ShouldMockFailureToOpen(const char *path) {
          internal_strncmp(path, "/proc/", 6) == 0;
 }
 
-#if SANITIZER_LINUX && !SANITIZER_ANDROID && !SANITIZER_GO
+bool OpenReadsVaArgs(int oflag) {
+#  ifdef O_TMPFILE
+  return (oflag & (O_CREAT | O_TMPFILE)) != 0;
+#  else
+  return (oflag & O_CREAT) != 0;
+#  endif
+}
+
+#  if SANITIZER_LINUX && !SANITIZER_ANDROID && !SANITIZER_GO
 int GetNamedMappingFd(const char *name, uptr size, int *flags) {
   if (!common_flags()->decorate_proc_maps || !name)
     return -1;
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.h b/libsanitizer/sanitizer_common/sanitizer_posix.h
index c5811dffea94..b5491c540dc0 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix.h
+++ b/libsanitizer/sanitizer_common/sanitizer_posix.h
@@ -28,6 +28,9 @@  namespace __sanitizer {
 // Don't use directly, use __sanitizer::OpenFile() instead.
 uptr internal_open(const char *filename, int flags);
 uptr internal_open(const char *filename, int flags, u32 mode);
+#  if SANITIZER_FREEBSD
+uptr internal_close_range(fd_t lowfd, fd_t highfd, int flags);
+#  endif
 uptr internal_close(fd_t fd);
 
 uptr internal_read(fd_t fd, void *buf, uptr count);
@@ -74,21 +77,21 @@  int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,
 // These functions call appropriate pthread_ functions directly, bypassing
 // the interceptor. They are weak and may not be present in some tools.
 SANITIZER_WEAK_ATTRIBUTE
-int real_pthread_create(void *th, void *attr, void *(*callback)(void *),
-                        void *param);
+int internal_pthread_create(void *th, void *attr, void *(*callback)(void *),
+                            void *param);
 SANITIZER_WEAK_ATTRIBUTE
-int real_pthread_join(void *th, void **ret);
-
-#define DEFINE_REAL_PTHREAD_FUNCTIONS                                          \
-  namespace __sanitizer {                                                      \
-  int real_pthread_create(void *th, void *attr, void *(*callback)(void *),     \
-                          void *param) {                                       \
-    return REAL(pthread_create)(th, attr, callback, param);                    \
-  }                                                                            \
-  int real_pthread_join(void *th, void **ret) {                                \
-    return REAL(pthread_join(th, ret));                                        \
-  }                                                                            \
-  }  // namespace __sanitizer
+int internal_pthread_join(void *th, void **ret);
+
+#  define DEFINE_INTERNAL_PTHREAD_FUNCTIONS                               \
+    namespace __sanitizer {                                               \
+    int internal_pthread_create(void *th, void *attr,                     \
+                                void *(*callback)(void *), void *param) { \
+      return REAL(pthread_create)(th, attr, callback, param);             \
+    }                                                                     \
+    int internal_pthread_join(void *th, void **ret) {                     \
+      return REAL(pthread_join)(th, ret);                                 \
+    }                                                                     \
+    }  // namespace __sanitizer
 
 int internal_pthread_attr_getstack(void *attr, void **addr, uptr *size);
 
@@ -108,6 +111,7 @@  bool IsStateDetached(int state);
 fd_t ReserveStandardFds(fd_t fd);
 
 bool ShouldMockFailureToOpen(const char *path);
+bool OpenReadsVaArgs(int oflag);
 
 // Create a non-file mapping with a given /proc/self/maps name.
 uptr MmapNamed(void *addr, uptr length, int prot, int flags, const char *name);
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
index e88e654eec5a..b1eb2009cf15 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp
@@ -91,12 +91,12 @@  static rlim_t getlim(int res) {
 
 static void setlim(int res, rlim_t lim) {
   struct rlimit rlim;
-  if (getrlimit(res, const_cast<struct rlimit *>(&rlim))) {
+  if (getrlimit(res, &rlim)) {
     Report("ERROR: %s getrlimit() failed %d\n", SanitizerToolName, errno);
     Die();
   }
   rlim.rlim_cur = lim;
-  if (setrlimit(res, const_cast<struct rlimit *>(&rlim))) {
+  if (setrlimit(res, &rlim)) {
     Report("ERROR: %s setrlimit() failed %d\n", SanitizerToolName, errno);
     Die();
   }
@@ -104,7 +104,27 @@  static void setlim(int res, rlim_t lim) {
 
 void DisableCoreDumperIfNecessary() {
   if (common_flags()->disable_coredump) {
-    setlim(RLIMIT_CORE, 0);
+    rlimit rlim;
+    CHECK_EQ(0, getrlimit(RLIMIT_CORE, &rlim));
+    // On Linux, if the kernel.core_pattern sysctl starts with a '|' (i.e. it
+    // is being piped to a coredump handler such as systemd-coredumpd), the
+    // kernel ignores RLIMIT_CORE (since we aren't creating a file in the file
+    // system) except for the magic value of 1, which disables coredumps when
+    // piping. 1 byte is too small for any kind of valid core dump, so it
+    // also disables coredumps if kernel.core_pattern creates files directly.
+    // While most piped coredump handlers do respect the crashing processes'
+    // RLIMIT_CORE, this is notable not the case for Debian's systemd-coredump
+    // due to a local patch that changes sysctl.d/50-coredump.conf to ignore
+    // the specified limit and instead use RLIM_INFINITY.
+    //
+    // The alternative to using RLIMIT_CORE=1 would be to use prctl() with the
+    // PR_SET_DUMPABLE flag, however that also prevents ptrace(), so makes it
+    // impossible to attach a debugger.
+    //
+    // Note: we use rlim_max in the Min() call here since that is the upper
+    // limit for what can be set without getting an EINVAL error.
+    rlim.rlim_cur = Min<rlim_t>(SANITIZER_LINUX ? 1 : 0, rlim.rlim_max);
+    CHECK_EQ(0, setrlimit(RLIMIT_CORE, &rlim));
   }
 }
 
@@ -268,26 +288,86 @@  bool SignalContext::IsStackOverflow() const {
 
 #endif  // SANITIZER_GO
 
+static void SetNonBlock(int fd) {
+  int res = fcntl(fd, F_GETFL, 0);
+  CHECK(!internal_iserror(res, nullptr));
+
+  res |= O_NONBLOCK;
+  res = fcntl(fd, F_SETFL, res);
+  CHECK(!internal_iserror(res, nullptr));
+}
+
 bool IsAccessibleMemoryRange(uptr beg, uptr size) {
-  uptr page_size = GetPageSizeCached();
-  // Checking too large memory ranges is slow.
-  CHECK_LT(size, page_size * 10);
-  int sock_pair[2];
-  if (pipe(sock_pair))
-    return false;
-  uptr bytes_written =
-      internal_write(sock_pair[1], reinterpret_cast<void *>(beg), size);
-  int write_errno;
-  bool result;
-  if (internal_iserror(bytes_written, &write_errno)) {
-    CHECK_EQ(EFAULT, write_errno);
-    result = false;
-  } else {
-    result = (bytes_written == size);
+  while (size) {
+    // `read` from `fds[0]` into a dummy buffer to free up the pipe buffer for
+    // more `write` is slower than just recreating a pipe.
+    int fds[2];
+    CHECK_EQ(0, pipe(fds));
+
+    auto cleanup = at_scope_exit([&]() {
+      internal_close(fds[0]);
+      internal_close(fds[1]);
+    });
+
+    SetNonBlock(fds[1]);
+
+    int write_errno;
+    uptr w = internal_write(fds[1], reinterpret_cast<char *>(beg), size);
+    if (internal_iserror(w, &write_errno)) {
+      if (write_errno == EINTR)
+        continue;
+      CHECK_EQ(EFAULT, write_errno);
+      return false;
+    }
+    size -= w;
+    beg += w;
+  }
+
+  return true;
+}
+
+bool TryMemCpy(void *dest, const void *src, uptr n) {
+  if (!n)
+    return true;
+  int fds[2];
+  CHECK_EQ(0, pipe(fds));
+
+  auto cleanup = at_scope_exit([&]() {
+    internal_close(fds[0]);
+    internal_close(fds[1]);
+  });
+
+  SetNonBlock(fds[0]);
+  SetNonBlock(fds[1]);
+
+  char *d = static_cast<char *>(dest);
+  const char *s = static_cast<const char *>(src);
+
+  while (n) {
+    int e;
+    uptr w = internal_write(fds[1], s, n);
+    if (internal_iserror(w, &e)) {
+      if (e == EINTR)
+        continue;
+      CHECK_EQ(EFAULT, e);
+      return false;
+    }
+    s += w;
+    n -= w;
+
+    while (w) {
+      uptr r = internal_read(fds[0], d, w);
+      if (internal_iserror(r, &e)) {
+        CHECK_EQ(EINTR, e);
+        continue;
+      }
+
+      d += r;
+      w -= r;
+    }
   }
-  internal_close(sock_pair[0]);
-  internal_close(sock_pair[1]);
-  return result;
+
+  return true;
 }
 
 void PlatformPrepareForSandboxing(void *args) {
@@ -307,9 +387,10 @@  static bool MmapFixed(uptr fixed_addr, uptr size, int additional_flags,
                 MAP_PRIVATE | MAP_FIXED | additional_flags | MAP_ANON, name);
   int reserrno;
   if (internal_iserror(p, &reserrno)) {
-    Report("ERROR: %s failed to "
-           "allocate 0x%zx (%zd) bytes at address %zx (errno: %d)\n",
-           SanitizerToolName, size, size, fixed_addr, reserrno);
+    Report(
+        "ERROR: %s failed to "
+        "allocate 0x%zx (%zd) bytes at address %p (errno: %d)\n",
+        SanitizerToolName, size, size, (void *)fixed_addr, reserrno);
     return false;
   }
   IncreaseTotalMmap(size);
@@ -462,7 +543,11 @@  pid_t StartSubprocess(const char *program, const char *const argv[],
       internal_close(stderr_fd);
     }
 
+#  if SANITIZER_FREEBSD
+    internal_close_range(3, ~static_cast<fd_t>(0), 0);
+#  else
     for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd);
+#  endif
 
     internal_execve(program, const_cast<char **>(&argv[0]),
                     const_cast<char *const *>(envp));
diff --git a/libsanitizer/sanitizer_common/sanitizer_printf.cpp b/libsanitizer/sanitizer_common/sanitizer_printf.cpp
index 62c1cf4abe42..24511720bd99 100644
--- a/libsanitizer/sanitizer_common/sanitizer_printf.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_printf.cpp
@@ -54,7 +54,7 @@  static int AppendNumber(char **buff, const char *buff_end, u64 absolute_value,
   uptr num_buffer[kMaxLen];
   int pos = 0;
   do {
-    RAW_CHECK_MSG((uptr)pos < kMaxLen, "AppendNumber buffer overflow");
+    RAW_CHECK_MSG((uptr)pos < kMaxLen, "AppendNumber buffer overflow",);
     num_buffer[pos++] = absolute_value % base;
     absolute_value /= base;
   } while (absolute_value > 0);
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_bsd.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_bsd.cpp
index 36a82c4ac966..ee3fd5b0a817 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_bsd.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_bsd.cpp
@@ -13,9 +13,6 @@ 
 #include "sanitizer_platform.h"
 #if SANITIZER_FREEBSD || SANITIZER_NETBSD
 #include "sanitizer_common.h"
-#if SANITIZER_FREEBSD
-#include "sanitizer_freebsd.h"
-#endif
 #include "sanitizer_procmaps.h"
 
 // clang-format off
@@ -29,29 +26,35 @@ 
 
 #include <limits.h>
 
-// Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode.
-#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
-#include <osreldate.h>
-#if __FreeBSD_version <= 902001 // v9.2
-#define kinfo_vmentry xkinfo_vmentry
-#endif
-#endif
-
 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);
+  const int Mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};
+
+  struct kinfo_proc *InfoProc;
+  uptr Len = sizeof(*InfoProc);
+  uptr Size = Len;
+  InfoProc = (struct kinfo_proc *)MmapOrDie(Size, "GetMemoryProfile()");
+  CHECK_EQ(
+      internal_sysctl(Mib, ARRAY_SIZE(Mib), nullptr, (uptr *)InfoProc, &Len, 0),
+      0);
+  cb(0, InfoProc->ki_rssize * GetPageSizeCached(), false, stats);
+  UnmapOrDie(InfoProc, Size, true);
+}
+#elif SANITIZER_NETBSD
+void GetMemoryProfile(fill_profile_f cb, uptr *stats) {
+  struct kinfo_proc2 *InfoProc;
+  uptr Len = sizeof(*InfoProc);
+  uptr Size = Len;
+  const int Mib[] = {CTL_KERN, KERN_PROC2, KERN_PROC_PID,
+                     getpid(), (int)Size,  1};
+  InfoProc = (struct kinfo_proc2 *)MmapOrDie(Size, "GetMemoryProfile()");
+  CHECK_EQ(
+      internal_sysctl(Mib, ARRAY_SIZE(Mib), nullptr, (uptr *)InfoProc, &Len, 0),
+      0);
+  cb(0, InfoProc->p_vm_rssize * GetPageSizeCached(), false, stats);
+  UnmapOrDie(InfoProc, Size, true);
 }
 #endif
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
index a7805ad1b083..7214a2b9ea46 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cpp
@@ -145,7 +145,7 @@  void MemoryMappingLayout::DumpListOfModules(
   }
 }
 
-#if SANITIZER_LINUX || SANITIZER_ANDROID || SANITIZER_SOLARIS || SANITIZER_NETBSD
+#if SANITIZER_LINUX || SANITIZER_ANDROID || SANITIZER_SOLARIS
 void GetMemoryProfile(fill_profile_f cb, uptr *stats) {
   char *smaps = nullptr;
   uptr smaps_cap = 0;
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cpp
index f2f384671211..5ff8d1832556 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();
     }
@@ -391,7 +433,9 @@  void MemoryMappingLayout::DumpListOfModules(
   MemoryMappedSegmentData data;
   segment.data_ = &data;
   while (Next(&segment)) {
-    if (segment.filename[0] == '\0') continue;
+    // skip the __PAGEZERO segment, its vmsize is 0
+    if (segment.filename[0] == '\0' || (segment.start == segment.end))
+      continue;
     LoadedModule *cur_module = nullptr;
     if (!modules->empty() &&
         0 == internal_strcmp(segment.filename, modules->back().full_name())) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp b/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
index eeb49e2afe34..80b8158f43db 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_solaris.cpp
@@ -11,6 +11,10 @@ 
 
 // Before Solaris 11.4, <procfs.h> doesn't work in a largefile environment.
 #undef _FILE_OFFSET_BITS
+
+// Avoid conflict between `_TIME_BITS` defined vs. `_FILE_OFFSET_BITS`
+// undefined in some Linux configurations.
+#undef _TIME_BITS
 #include "sanitizer_platform.h"
 #if SANITIZER_SOLARIS
 #  include <fcntl.h>
diff --git a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
index 520035469485..265a9925a15a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
+++ b/libsanitizer/sanitizer_common/sanitizer_ptrauth.h
@@ -9,31 +9,33 @@ 
 #ifndef SANITIZER_PTRAUTH_H
 #define SANITIZER_PTRAUTH_H
 
-#if __has_feature(ptrauth_calls)
-#include <ptrauth.h>
+#if __has_feature(ptrauth_intrinsics)
+#  include <ptrauth.h>
 #elif defined(__ARM_FEATURE_PAC_DEFAULT) && !defined(__APPLE__)
-inline unsigned long ptrauth_strip(void* __value, unsigned int __key) {
-  // On the stack the link register is protected with Pointer
-  // Authentication Code when compiled with -mbranch-protection.
-  // Let's stripping the PAC unconditionally because xpaclri is in
-  // the NOP space so will do nothing when it is not enabled or not available.
-  unsigned long ret;
-  asm volatile(
-      "mov x30, %1\n\t"
-      "hint #7\n\t"  // xpaclri
-      "mov %0, x30\n\t"
-      : "=r"(ret)
-      : "r"(__value)
-      : "x30");
-  return ret;
-}
-#define ptrauth_auth_data(__value, __old_key, __old_data) __value
-#define ptrauth_string_discriminator(__string) ((int)0)
+// On the stack the link register is protected with Pointer
+// Authentication Code when compiled with -mbranch-protection.
+// Let's stripping the PAC unconditionally because xpaclri is in
+// the NOP space so will do nothing when it is not enabled or not available.
+#  define ptrauth_strip(__value, __key) \
+    ({                                  \
+      __typeof(__value) ret;            \
+      asm volatile(                     \
+          "mov x30, %1\n\t"             \
+          "hint #7\n\t"                 \
+          "mov %0, x30\n\t"             \
+          "mov x30, xzr\n\t"            \
+          : "=r"(ret)                   \
+          : "r"(__value)                \
+          : "x30");                     \
+      ret;                              \
+    })
+#  define ptrauth_auth_data(__value, __old_key, __old_data) __value
+#  define ptrauth_string_discriminator(__string) ((int)0)
 #else
 // Copied from <ptrauth.h>
-#define ptrauth_strip(__value, __key) __value
-#define ptrauth_auth_data(__value, __old_key, __old_data) __value
-#define ptrauth_string_discriminator(__string) ((int)0)
+#  define ptrauth_strip(__value, __key) __value
+#  define ptrauth_auth_data(__value, __old_key, __old_data) __value
+#  define ptrauth_string_discriminator(__string) ((int)0)
 #endif
 
 #define STRIP_PAC_PC(pc) ((uptr)ptrauth_strip(pc, 0))
diff --git a/libsanitizer/sanitizer_common/sanitizer_redefine_builtins.h b/libsanitizer/sanitizer_common/sanitizer_redefine_builtins.h
index eba8e0fa0cc1..41e0613d6fc1 100644
--- a/libsanitizer/sanitizer_common/sanitizer_redefine_builtins.h
+++ b/libsanitizer/sanitizer_common/sanitizer_redefine_builtins.h
@@ -15,11 +15,13 @@ 
 #    define SANITIZER_REDEFINE_BUILTINS_H
 
 // The asm hack only works with GCC and Clang.
-#    if !defined(_WIN32) && defined(HAVE_AS_SYM_ASSIGN)
+#    if !defined(_WIN32)
 
-asm("memcpy = __sanitizer_internal_memcpy");
-asm("memmove = __sanitizer_internal_memmove");
-asm("memset = __sanitizer_internal_memset");
+asm(R"(
+    .set memcpy, __sanitizer_internal_memcpy
+    .set memmove, __sanitizer_internal_memmove
+    .set memset, __sanitizer_internal_memset
+    )");
 
 #      if defined(__cplusplus) && \
           !defined(SANITIZER_COMMON_REDEFINE_BUILTINS_IN_STD)
@@ -50,7 +52,7 @@  using vector = Define_SANITIZER_COMMON_NO_REDEFINE_BUILTINS_in_cpp_file;
 }  // namespace std
 
 #      endif  // __cpluplus
-#    endif    // !_WIN32 && HAVE_AS_SYM_ASSIGN
+#    endif    // !_WIN32
 
 #  endif  // SANITIZER_REDEFINE_BUILTINS_H
 #endif    // SANITIZER_COMMON_NO_REDEFINE_BUILTINS
diff --git a/libsanitizer/sanitizer_common/sanitizer_stack_store.cpp b/libsanitizer/sanitizer_common/sanitizer_stack_store.cpp
index 148470943b47..c11df0ddfde4 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stack_store.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stack_store.cpp
@@ -44,6 +44,9 @@  StackStore::Id StackStore::Store(const StackTrace &trace, uptr *pack) {
   uptr idx = 0;
   *pack = 0;
   uptr *stack_trace = Alloc(h.size + 1, &idx, pack);
+  // No more space.
+  if (stack_trace == nullptr)
+    return 0;
   *stack_trace = h.ToUptr();
   internal_memcpy(stack_trace + 1, trace.trace, h.size * sizeof(uptr));
   *pack += blocks_[GetBlockIdx(idx)].Stored(h.size + 1);
@@ -76,8 +79,10 @@  uptr *StackStore::Alloc(uptr count, uptr *idx, uptr *pack) {
     uptr block_idx = GetBlockIdx(start);
     uptr last_idx = GetBlockIdx(start + count - 1);
     if (LIKELY(block_idx == last_idx)) {
-      // Fits into the a single block.
-      CHECK_LT(block_idx, ARRAY_SIZE(blocks_));
+      // Fits into a single block.
+      // No more available blocks.  Indicate inability to allocate more memory.
+      if (block_idx >= ARRAY_SIZE(blocks_))
+        return nullptr;
       *idx = start;
       return blocks_[block_idx].GetOrCreate(this) + GetInBlockIdx(start);
     }
diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
index a746d4621936..3776e8c97057 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cpp
@@ -215,16 +215,16 @@  StackTrace StackDepotGet(u32 id) {
   return theDepot.Get(id);
 }
 
-void StackDepotLockAll() {
-  theDepot.LockAll();
+void StackDepotLockBeforeFork() {
+  theDepot.LockBeforeFork();
   compress_thread.LockAndStop();
   stackStore.LockAll();
 }
 
-void StackDepotUnlockAll() {
+void StackDepotUnlockAfterFork(bool fork_child) {
   stackStore.UnlockAll();
   compress_thread.Unlock();
-  theDepot.UnlockAll();
+  theDepot.UnlockAfterFork(fork_child);
 }
 
 void StackDepotPrintAll() {
diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepot.h b/libsanitizer/sanitizer_common/sanitizer_stackdepot.h
index cca6fd534688..82cf7578d0fb 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stackdepot.h
+++ b/libsanitizer/sanitizer_common/sanitizer_stackdepot.h
@@ -39,8 +39,8 @@  StackDepotHandle StackDepotPut_WithHandle(StackTrace stack);
 // Retrieves a stored stack trace by the id.
 StackTrace StackDepotGet(u32 id);
 
-void StackDepotLockAll();
-void StackDepotUnlockAll();
+void StackDepotLockBeforeFork();
+void StackDepotUnlockAfterFork(bool fork_child);
 void StackDepotPrintAll();
 void StackDepotStopBackgroundThread();
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepotbase.h b/libsanitizer/sanitizer_common/sanitizer_stackdepotbase.h
index 96d1ddc87fd0..279bc5de3bb9 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stackdepotbase.h
+++ b/libsanitizer/sanitizer_common/sanitizer_stackdepotbase.h
@@ -52,8 +52,8 @@  class StackDepotBase {
     };
   }
 
-  void LockAll();
-  void UnlockAll();
+  void LockBeforeFork();
+  void UnlockAfterFork(bool fork_child);
   void PrintAll();
 
   void TestOnlyUnmap() {
@@ -160,18 +160,33 @@  StackDepotBase<Node, kReservedBits, kTabSizeLog>::Get(u32 id) {
 }
 
 template <class Node, int kReservedBits, int kTabSizeLog>
-void StackDepotBase<Node, kReservedBits, kTabSizeLog>::LockAll() {
-  for (int i = 0; i < kTabSize; ++i) {
-    lock(&tab[i]);
-  }
+void StackDepotBase<Node, kReservedBits, kTabSizeLog>::LockBeforeFork() {
+  // Do not lock hash table. It's very expensive, but it's not rely needed. The
+  // parent process will neither lock nor unlock. Child process risks to be
+  // deadlocked on already locked buckets. To avoid deadlock we will unlock
+  // every locked buckets in `UnlockAfterFork`. This may affect consistency of
+  // the hash table, but the only issue is a few items inserted by parent
+  // process will be not found by child, and the child may insert them again,
+  // wasting some space in `stackStore`.
+
+  // We still need to lock nodes.
+  nodes.Lock();
 }
 
 template <class Node, int kReservedBits, int kTabSizeLog>
-void StackDepotBase<Node, kReservedBits, kTabSizeLog>::UnlockAll() {
+void StackDepotBase<Node, kReservedBits, kTabSizeLog>::UnlockAfterFork(
+    bool fork_child) {
+  nodes.Unlock();
+
+  // Only unlock in child process to avoid deadlock. See `LockBeforeFork`.
+  if (!fork_child)
+    return;
+
   for (int i = 0; i < kTabSize; ++i) {
     atomic_uint32_t *p = &tab[i];
     uptr s = atomic_load(p, memory_order_relaxed);
-    unlock(p, s & kUnlockMask);
+    if (s & kLockMask)
+      unlock(p, s & kUnlockMask);
   }
 }
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cpp
index 661495e23405..d24fae98213a 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_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
index 9a4c80fcfdd1..1a0e00d5d5af 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cpp
@@ -33,13 +33,14 @@  class StackTraceTextPrinter {
             stack_trace_fmt)) {}
 
   bool ProcessAddressFrames(uptr pc) {
-    SymbolizedStack *frames = symbolize_
-                                  ? Symbolizer::GetOrInit()->SymbolizePC(pc)
-                                  : SymbolizedStack::New(pc);
+    SymbolizedStackHolder symbolized_stack(
+        symbolize_ ? Symbolizer::GetOrInit()->SymbolizePC(pc)
+                   : SymbolizedStack::New(pc));
+    const SymbolizedStack *frames = symbolized_stack.get();
     if (!frames)
       return false;
 
-    for (SymbolizedStack *cur = frames; cur; cur = cur->next) {
+    for (const SymbolizedStack *cur = frames; cur; cur = cur->next) {
       uptr prev_len = output_->length();
       StackTracePrinter::GetOrInit()->RenderFrame(
           output_, stack_trace_fmt_, frame_num_++, cur->info.address,
@@ -51,19 +52,18 @@  class StackTraceTextPrinter {
 
       ExtendDedupToken(cur);
     }
-    frames->ClearAll();
     return true;
   }
 
  private:
   // Extend the dedup token by appending a new frame.
-  void ExtendDedupToken(SymbolizedStack *stack) {
+  void ExtendDedupToken(const SymbolizedStack *stack) {
     if (!dedup_token_)
       return;
 
     if (dedup_frames_-- > 0) {
       if (dedup_token_->length())
-        dedup_token_->AppendF("--");
+        dedup_token_->Append("--");
       if (stack->info.function)
         dedup_token_->Append(stack->info.function);
     }
@@ -99,7 +99,7 @@  void StackTrace::PrintTo(InternalScopedString *output) const {
                                 output, &dedup_token);
 
   if (trace == nullptr || size == 0) {
-    output->AppendF("    <empty stack>\n\n");
+    output->Append("    <empty stack>\n\n");
     return;
   }
 
@@ -111,7 +111,7 @@  void StackTrace::PrintTo(InternalScopedString *output) const {
   }
 
   // Always add a trailing empty line after stack trace.
-  output->AppendF("\n");
+  output->Append("\n");
 
   // Append deduplication token, if non-empty.
   if (dedup_token.length())
@@ -198,7 +198,7 @@  void __sanitizer_symbolize_pc(uptr pc, const char *fmt, char *out_buf,
   StackTraceTextPrinter printer(fmt, '\0', &output, nullptr);
   if (!printer.ProcessAddressFrames(pc)) {
     output.clear();
-    output.AppendF("<can't symbolize>");
+    output.Append("<can't symbolize>");
   }
   CopyStringToBuffer(output, out_buf, out_buf_size);
 }
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cpp
index 8db321051e1a..5631d132da74 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cpp
@@ -12,9 +12,11 @@ 
 
 #include "sanitizer_stacktrace_printer.h"
 
+#include "sanitizer_common.h"
 #include "sanitizer_file.h"
 #include "sanitizer_flags.h"
 #include "sanitizer_fuchsia.h"
+#include "sanitizer_symbolizer_markup.h"
 
 namespace __sanitizer {
 
@@ -25,15 +27,13 @@  StackTracePrinter *StackTracePrinter::GetOrInit() {
   if (stacktrace_printer)
     return stacktrace_printer;
 
-  stacktrace_printer =
-      new (GetGlobalLowLevelAllocator()) FormattedStackTracePrinter();
+  stacktrace_printer = StackTracePrinter::NewStackTracePrinter();
 
   CHECK(stacktrace_printer);
   return stacktrace_printer;
 }
 
-const char *FormattedStackTracePrinter::StripFunctionName(
-    const char *function) {
+const char *StackTracePrinter::StripFunctionName(const char *function) {
   if (!common_flags()->demangle)
     return function;
   if (!function)
@@ -62,6 +62,13 @@  const char *FormattedStackTracePrinter::StripFunctionName(
 // sanitizer_symbolizer_markup.cpp implements these differently.
 #if !SANITIZER_SYMBOLIZER_MARKUP
 
+StackTracePrinter *StackTracePrinter::NewStackTracePrinter() {
+  if (common_flags()->enable_symbolizer_markup)
+    return new (GetGlobalLowLevelAllocator()) MarkupStackTracePrinter();
+
+  return new (GetGlobalLowLevelAllocator()) FormattedStackTracePrinter();
+}
+
 static const char *DemangleFunctionName(const char *function) {
   if (!common_flags()->demangle)
     return function;
@@ -145,12 +152,12 @@  static void MaybeBuildIdToBuffer(const AddressInfo &info, bool PrefixSpace,
                                  InternalScopedString *buffer) {
   if (info.uuid_size) {
     if (PrefixSpace)
-      buffer->AppendF(" ");
-    buffer->AppendF("(BuildId: ");
+      buffer->Append(" ");
+    buffer->Append("(BuildId: ");
     for (uptr i = 0; i < info.uuid_size; ++i) {
       buffer->AppendF("%02x", info.uuid[i]);
     }
-    buffer->AppendF(")");
+    buffer->Append(")");
   }
 }
 
@@ -185,7 +192,7 @@  void FormattedStackTracePrinter::RenderFrame(InternalScopedString *buffer,
       buffer->AppendF("%u", frame_no);
       break;
     case 'p':
-      buffer->AppendF("0x%zx", address);
+      buffer->AppendF("%p", (void *)address);
       break;
     case 'm':
       buffer->AppendF("%s", StripPathPrefix(info->module, strip_path_prefix));
@@ -242,7 +249,7 @@  void FormattedStackTracePrinter::RenderFrame(InternalScopedString *buffer,
         MaybeBuildIdToBuffer(*info, /*PrefixSpace=*/true, buffer);
 #endif
       } else {
-        buffer->AppendF("(<unknown module>)");
+        buffer->Append("(<unknown module>)");
       }
       break;
     case 'M':
@@ -262,7 +269,7 @@  void FormattedStackTracePrinter::RenderFrame(InternalScopedString *buffer,
       break;
     default:
       Report("Unsupported specifier in stack frame format: %c (%p)!\n", *p,
-             (void *)p);
+             (const void *)p);
       Die();
     }
   }
@@ -316,7 +323,7 @@  void FormattedStackTracePrinter::RenderData(InternalScopedString *buffer,
         break;
       default:
         Report("Unsupported specifier in stack frame format: %c (%p)!\n", *p,
-               (void *)p);
+               (const void *)p);
         Die();
     }
   }
@@ -324,14 +331,15 @@  void FormattedStackTracePrinter::RenderData(InternalScopedString *buffer,
 
 #endif  // !SANITIZER_SYMBOLIZER_MARKUP
 
-void FormattedStackTracePrinter::RenderSourceLocation(
-    InternalScopedString *buffer, const char *file, int line, int column,
-    bool vs_style, const char *strip_path_prefix) {
+void StackTracePrinter::RenderSourceLocation(InternalScopedString *buffer,
+                                             const char *file, int line,
+                                             int column, bool vs_style,
+                                             const char *strip_path_prefix) {
   if (vs_style && line > 0) {
     buffer->AppendF("%s(%d", StripPathPrefix(file, strip_path_prefix), line);
     if (column > 0)
       buffer->AppendF(",%d", column);
-    buffer->AppendF(")");
+    buffer->Append(")");
     return;
   }
 
@@ -343,9 +351,10 @@  void FormattedStackTracePrinter::RenderSourceLocation(
   }
 }
 
-void FormattedStackTracePrinter::RenderModuleLocation(
-    InternalScopedString *buffer, const char *module, uptr offset,
-    ModuleArch arch, const char *strip_path_prefix) {
+void StackTracePrinter::RenderModuleLocation(InternalScopedString *buffer,
+                                             const char *module, uptr offset,
+                                             ModuleArch arch,
+                                             const char *strip_path_prefix) {
   buffer->AppendF("(%s", StripPathPrefix(module, strip_path_prefix));
   if (arch != kModuleArchUnknown) {
     buffer->AppendF(":%s", ModuleArchToString(arch));
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h
index 3e02333a8c8d..e39cb891575e 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h
@@ -25,27 +25,38 @@  class StackTracePrinter {
  public:
   static StackTracePrinter *GetOrInit();
 
-  virtual const char *StripFunctionName(const char *function) = 0;
+  // Strip interceptor prefixes from function name.
+  const char *StripFunctionName(const char *function);
 
   virtual void RenderFrame(InternalScopedString *buffer, const char *format,
                            int frame_no, uptr address, const AddressInfo *info,
-                           bool vs_style,
-                           const char *strip_path_prefix = "") = 0;
+                           bool vs_style, const char *strip_path_prefix = "") {
+    // Should be pure virtual, but we can't depend on __cxa_pure_virtual.
+    UNIMPLEMENTED();
+  }
 
-  virtual bool RenderNeedsSymbolization(const char *format) = 0;
+  virtual bool RenderNeedsSymbolization(const char *format) {
+    // Should be pure virtual, but we can't depend on __cxa_pure_virtual.
+    UNIMPLEMENTED();
+  }
 
-  virtual void RenderSourceLocation(InternalScopedString *buffer,
-                                    const char *file, int line, int column,
-                                    bool vs_style,
-                                    const char *strip_path_prefix) = 0;
+  void RenderSourceLocation(InternalScopedString *buffer, const char *file,
+                            int line, int column, bool vs_style,
+                            const char *strip_path_prefix);
 
-  virtual void RenderModuleLocation(InternalScopedString *buffer,
-                                    const char *module, uptr offset,
-                                    ModuleArch arch,
-                                    const char *strip_path_prefix) = 0;
+  void RenderModuleLocation(InternalScopedString *buffer, const char *module,
+                            uptr offset, ModuleArch arch,
+                            const char *strip_path_prefix);
   virtual void RenderData(InternalScopedString *buffer, const char *format,
                           const DataInfo *DI,
-                          const char *strip_path_prefix = "") = 0;
+                          const char *strip_path_prefix = "") {
+    // Should be pure virtual, but we can't depend on __cxa_pure_virtual.
+    UNIMPLEMENTED();
+  }
+
+ private:
+  // To be called from StackTracePrinter::GetOrInit
+  static StackTracePrinter *NewStackTracePrinter();
 
  protected:
   ~StackTracePrinter() {}
@@ -53,9 +64,6 @@  class StackTracePrinter {
 
 class FormattedStackTracePrinter : public StackTracePrinter {
  public:
-  // Strip interceptor prefixes from function name.
-  const char *StripFunctionName(const char *function) override;
-
   // Render the contents of "info" structure, which represents the contents of
   // stack frame "frame_no" and appends it to the "buffer". "format" is a
   // string with placeholders, which is copied to the output with
@@ -90,14 +98,6 @@  class FormattedStackTracePrinter : public StackTracePrinter {
 
   bool RenderNeedsSymbolization(const char *format) override;
 
-  void RenderSourceLocation(InternalScopedString *buffer, const char *file,
-                            int line, int column, bool vs_style,
-                            const char *strip_path_prefix) override;
-
-  void RenderModuleLocation(InternalScopedString *buffer, const char *module,
-                            uptr offset, ModuleArch arch,
-                            const char *strip_path_prefix) override;
-
   // Same as RenderFrame, but for data section (global variables).
   // Accepts %s, %l from above.
   // Also accepts:
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_sparc.cpp b/libsanitizer/sanitizer_common/sanitizer_stacktrace_sparc.cpp
index a2000798a390..74f435287af3 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_sparc.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_sparc.cpp
@@ -58,17 +58,16 @@  void BufferedStackTrace::UnwindFast(uptr pc, uptr bp, uptr stack_top,
   // Avoid infinite loop when frame == frame[0] by using frame > prev_frame.
   while (IsValidFrame(bp, stack_top, bottom) && IsAligned(bp, sizeof(uhwptr)) &&
          size < max_depth) {
-    uhwptr pc1 = ((uhwptr *)bp)[15];
+    // %o7 contains the address of the call instruction and not the
+    // return address, so we need to compensate.
+    uhwptr pc1 = GetNextInstructionPc(((uhwptr *)bp)[15]);
     // Let's assume that any pointer in the 0th page is invalid and
     // stop unwinding here.  If we're adding support for a platform
     // where this isn't true, we need to reconsider this check.
     if (pc1 < kPageSize)
       break;
-    if (pc1 != pc) {
-      // %o7 contains the address of the call instruction and not the
-      // return address, so we need to compensate.
-      trace_buffer[size++] = GetNextInstructionPc((uptr)pc1);
-    }
+    if (pc1 != pc)
+      trace_buffer[size++] = pc1;
     bottom = bp;
     bp = (uptr)((uhwptr *)bp)[14] + STACK_BIAS;
   }
diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
index 25c4af708560..945da99d41f4 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
@@ -137,10 +137,6 @@  class ThreadSuspender {
 };
 
 bool ThreadSuspender::SuspendThread(tid_t tid) {
-  // Are we already attached to this thread?
-  // Currently this check takes linear time, however the number of threads is
-  // usually small.
-  if (suspended_threads_list_.ContainsTid(tid)) return false;
   int pterrno;
   if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, nullptr, nullptr),
                        &pterrno)) {
@@ -217,17 +213,28 @@  bool ThreadSuspender::SuspendAllThreads() {
     switch (thread_lister.ListThreads(&threads)) {
       case ThreadLister::Error:
         ResumeAllThreads();
+        VReport(1, "Failed to list threads\n");
         return false;
       case ThreadLister::Incomplete:
+        VReport(1, "Incomplete list\n");
         retry = true;
         break;
       case ThreadLister::Ok:
         break;
     }
     for (tid_t tid : threads) {
+      // Are we already attached to this thread?
+      // Currently this check takes linear time, however the number of threads
+      // is usually small.
+      if (suspended_threads_list_.ContainsTid(tid))
+        continue;
       if (SuspendThread(tid))
         retry = true;
+      else
+        VReport(2, "%llu/status: %s\n", tid, thread_lister.LoadStatus(tid));
     }
+    if (retry)
+      VReport(1, "SuspendAllThreads retry: %d\n", i);
   }
   return suspended_threads_list_.ThreadCount();
 }
@@ -257,8 +264,8 @@  static void TracerThreadDieCallback() {
 static void TracerThreadSignalHandler(int signum, __sanitizer_siginfo *siginfo,
                                       void *uctx) {
   SignalContext ctx(siginfo, uctx);
-  Printf("Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n", signum,
-         ctx.addr, ctx.pc, ctx.sp);
+  Printf("Tracer caught signal %d: addr=%p pc=%p sp=%p\n", signum,
+         (void *)ctx.addr, (void *)ctx.pc, (void *)ctx.sp);
   ThreadSuspender *inst = thread_suspender_instance;
   if (inst) {
     if (signum == SIGABRT)
diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
index 701db72619a3..58a0cfdbf9d4 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_netbsd_libcdep.cpp
@@ -158,8 +158,8 @@  static void TracerThreadDieCallback() {
 static void TracerThreadSignalHandler(int signum, __sanitizer_siginfo *siginfo,
                                       void *uctx) {
   SignalContext ctx(siginfo, uctx);
-  Printf("Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n", signum,
-         ctx.addr, ctx.pc, ctx.sp);
+  Printf("Tracer caught signal %d: addr=%p pc=%p sp=%p\n", signum,
+         (void *)ctx.addr, (void *)ctx.pc, (void *)ctx.sp);
   ThreadSuspender *inst = thread_suspender_instance;
   if (inst) {
     if (signum == SIGABRT)
diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp b/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
index f3818526baab..62ebbb38feae 100644
--- a/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_suppressions.cpp
@@ -86,7 +86,7 @@  void SuppressionContext::ParseFromFile(const char *filename) {
   }
 
   Parse(file_contents);
-  UnmapOrDie(file_contents, contents_size);
+  UnmapOrDie(file_contents, buffer_size);
 }
 
 bool SuppressionContext::Match(const char *str, const char *type,
@@ -138,7 +138,10 @@  void SuppressionContext::Parse(const char *str) {
         }
       }
       if (type == suppression_types_num_) {
-        Printf("%s: failed to parse suppressions\n", SanitizerToolName);
+        Printf("%s: failed to parse suppressions.\n", SanitizerToolName);
+        Printf("Supported suppression types are:\n");
+        for (type = 0; type < suppression_types_num_; type++)
+          Printf("- %s\n", suppression_types_[type]);
         Die();
       }
       Suppression s;
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
index 7fb7928dce0d..bd89dc4e302f 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
@@ -64,6 +64,26 @@  struct SymbolizedStack {
   SymbolizedStack();
 };
 
+class SymbolizedStackHolder {
+  SymbolizedStack *Stack;
+
+  void clear() {
+    if (Stack)
+      Stack->ClearAll();
+  }
+
+ public:
+  explicit SymbolizedStackHolder(SymbolizedStack *Stack = nullptr)
+      : Stack(Stack) {}
+  ~SymbolizedStackHolder() { clear(); }
+  void reset(SymbolizedStack *S = nullptr) {
+    if (Stack != S)
+      clear();
+    Stack = S;
+  }
+  const SymbolizedStack *get() const { return Stack; }
+};
+
 // For now, DataInfo is used to describe global variable.
 struct DataInfo {
   // Owns all the string members. Storage for them is
@@ -154,6 +174,8 @@  class Symbolizer final {
 
   void InvalidateModuleList();
 
+  const ListOfModules &GetRefreshedListOfModules();
+
  private:
   // GetModuleNameAndOffsetForPC has to return a string to the caller.
   // Since the corresponding module might get unloaded later, we should create
@@ -163,17 +185,17 @@  class Symbolizer final {
   class ModuleNameOwner {
    public:
     explicit ModuleNameOwner(Mutex *synchronized_by)
-        : last_match_(nullptr), mu_(synchronized_by) {
+        : mu_(synchronized_by), last_match_(nullptr) {
       storage_.reserve(kInitialCapacity);
     }
     const char *GetOwnedCopy(const char *str);
 
    private:
     static const uptr kInitialCapacity = 1000;
-    InternalMmapVector<const char*> storage_;
-    const char *last_match_;
 
     Mutex *mu_;
+    const char *last_match_ SANITIZER_GUARDED_BY(mu_);
+    InternalMmapVector<const char *> storage_ SANITIZER_GUARDED_BY(*mu_);
   } module_names_;
 
   /// Platform-specific function for creating a Symbolizer object.
@@ -198,7 +220,7 @@  class Symbolizer final {
   // always synchronized.
   Mutex mu_;
 
-  IntrusiveList<SymbolizerTool> tools_;
+  IntrusiveList<SymbolizerTool> tools_ SANITIZER_GUARDED_BY(mu_);
 
   explicit Symbolizer(IntrusiveList<SymbolizerTool> tools);
 
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
index 81141023386e..74458028ae8f 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cpp
@@ -191,6 +191,13 @@  void Symbolizer::RefreshModules() {
   modules_fresh_ = true;
 }
 
+const ListOfModules &Symbolizer::GetRefreshedListOfModules() {
+  if (!modules_fresh_)
+    RefreshModules();
+
+  return modules_;
+}
+
 static const LoadedModule *SearchForModule(const ListOfModules &modules,
                                            uptr address) {
   for (uptr i = 0; i < modules.size(); i++) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
index f1cc0b5e1e8a..88536fc4e622 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_mac.cpp
@@ -30,7 +30,7 @@  namespace __sanitizer {
 bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
   Dl_info info;
   int result = dladdr((const void *)addr, &info);
-  if (!result) return false;
+  if (!result || !info.dli_sname) return false;
 
   // Compute offset if possible. `dladdr()` doesn't always ensure that `addr >=
   // sym_addr` so only compute the offset when this holds. Failure to find the
@@ -51,7 +51,7 @@  bool DlAddrSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
 bool DlAddrSymbolizer::SymbolizeData(uptr addr, DataInfo *datainfo) {
   Dl_info info;
   int result = dladdr((const void *)addr, &info);
-  if (!result) return false;
+  if (!result || !info.dli_sname) return false;
   const char *demangled = DemangleSwiftAndCXX(info.dli_sname);
   if (!demangled)
     demangled = info.dli_sname;
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
index d1b0f46004ef..31d91ef3c739 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.cpp
@@ -8,151 +8,155 @@ 
 //
 // This file is shared between various sanitizers' runtime libraries.
 //
-// Implementation of offline markup symbolizer.
+// This generic support for offline symbolizing is based on the
+// Fuchsia port.  We don't do any actual symbolization per se.
+// Instead, we emit text containing raw addresses and raw linkage
+// symbol names, embedded in Fuchsia's symbolization markup format.
+// See the spec at:
+// https://llvm.org/docs/SymbolizerMarkupFormat.html
 //===----------------------------------------------------------------------===//
 
-#include "sanitizer_platform.h"
-#if SANITIZER_SYMBOLIZER_MARKUP
-
-#if SANITIZER_FUCHSIA
-#include "sanitizer_symbolizer_fuchsia.h"
-#  endif
+#include "sanitizer_symbolizer_markup.h"
 
-#  include <limits.h>
-#  include <unwind.h>
-
-#  include "sanitizer_stacktrace.h"
-#  include "sanitizer_stacktrace_printer.h"
-#  include "sanitizer_symbolizer.h"
+#include "sanitizer_common.h"
+#include "sanitizer_symbolizer.h"
+#include "sanitizer_symbolizer_markup_constants.h"
 
 namespace __sanitizer {
 
-// This generic support for offline symbolizing is based on the
-// Fuchsia port.  We don't do any actual symbolization per se.
-// Instead, we emit text containing raw addresses and raw linkage
-// symbol names, embedded in Fuchsia's symbolization markup format.
-// Fuchsia's logging infrastructure emits enough information about
-// process memory layout that a post-processing filter can do the
-// symbolization and pretty-print the markup.  See the spec at:
-// https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md
-
-// This is used by UBSan for type names, and by ASan for global variable names.
-// It's expected to return a static buffer that will be reused on each call.
-const char *Symbolizer::Demangle(const char *name) {
-  static char buffer[kFormatDemangleMax];
-  internal_snprintf(buffer, sizeof(buffer), kFormatDemangle, name);
-  return buffer;
+void MarkupStackTracePrinter::RenderData(InternalScopedString *buffer,
+                                         const char *format, const DataInfo *DI,
+                                         const char *strip_path_prefix) {
+  RenderContext(buffer);
+  buffer->AppendF(kFormatData, reinterpret_cast<void *>(DI->start));
 }
 
-// This is used mostly for suppression matching.  Making it work
-// would enable "interceptor_via_lib" suppressions.  It's also used
-// once in UBSan to say "in module ..." in a message that also
-// includes an address in the module, so post-processing can already
-// pretty-print that so as to indicate the module.
-bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
-                                             uptr *module_address) {
+bool MarkupStackTracePrinter::RenderNeedsSymbolization(const char *format) {
   return false;
 }
 
-// This is mainly used by hwasan for online symbolization. This isn't needed
-// since hwasan can always just dump stack frames for offline symbolization.
-bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { return false; }
-
-// This is used in some places for suppression checking, which we
-// don't really support for Fuchsia.  It's also used in UBSan to
-// identify a PC location to a function name, so we always fill in
-// the function member with a string containing markup around the PC
-// value.
-// TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan
-// to render stack frames, but that should be changed to use
-// RenderStackFrame.
-SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
-  SymbolizedStack *s = SymbolizedStack::New(addr);
+// We don't support the stack_trace_format flag at all.
+void MarkupStackTracePrinter::RenderFrame(InternalScopedString *buffer,
+                                          const char *format, int frame_no,
+                                          uptr address, const AddressInfo *info,
+                                          bool vs_style,
+                                          const char *strip_path_prefix) {
+  CHECK(!RenderNeedsSymbolization(format));
+  RenderContext(buffer);
+  buffer->AppendF(kFormatFrame, frame_no, reinterpret_cast<void *>(address));
+}
+
+bool MarkupSymbolizerTool::SymbolizePC(uptr addr, SymbolizedStack *stack) {
   char buffer[kFormatFunctionMax];
-  internal_snprintf(buffer, sizeof(buffer), kFormatFunction, addr);
-  s->info.function = internal_strdup(buffer);
-  return s;
+  internal_snprintf(buffer, sizeof(buffer), kFormatFunction,
+                    reinterpret_cast<void *>(addr));
+  stack->info.function = internal_strdup(buffer);
+  return true;
 }
 
-// Always claim we succeeded, so that RenderDataInfo will be called.
-bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
+bool MarkupSymbolizerTool::SymbolizeData(uptr addr, DataInfo *info) {
   info->Clear();
   info->start = addr;
   return true;
 }
 
-// We ignore the format argument to __sanitizer_symbolize_global.
-void FormattedStackTracePrinter::RenderData(InternalScopedString *buffer,
-                                            const char *format,
-                                            const DataInfo *DI,
-                                            const char *strip_path_prefix) {
-  buffer->AppendF(kFormatData, DI->start);
+const char *MarkupSymbolizerTool::Demangle(const char *name) {
+  static char buffer[kFormatDemangleMax];
+  internal_snprintf(buffer, sizeof(buffer), kFormatDemangle, name);
+  return buffer;
 }
 
-bool FormattedStackTracePrinter::RenderNeedsSymbolization(const char *format) {
-  return false;
+// Fuchsia's implementation of symbolizer markup doesn't need to emit contextual
+// elements at this point.
+// Fuchsia's logging infrastructure emits enough information about
+// process memory layout that a post-processing filter can do the
+// symbolization and pretty-print the markup.
+#if !SANITIZER_FUCHSIA
+
+static bool ModulesEq(const LoadedModule &module,
+                      const RenderedModule &renderedModule) {
+  return module.base_address() == renderedModule.base_address &&
+         internal_memcmp(module.uuid(), renderedModule.uuid,
+                         module.uuid_size()) == 0 &&
+         internal_strcmp(module.full_name(), renderedModule.full_name) == 0;
 }
 
-// We don't support the stack_trace_format flag at all.
-void FormattedStackTracePrinter::RenderFrame(InternalScopedString *buffer,
-                                             const char *format, int frame_no,
-                                             uptr address,
-                                             const AddressInfo *info,
-                                             bool vs_style,
-                                             const char *strip_path_prefix) {
-  CHECK(!RenderNeedsSymbolization(format));
-  buffer->AppendF(kFormatFrame, frame_no, address);
-}
+static bool ModuleHasBeenRendered(
+    const LoadedModule &module,
+    const InternalMmapVectorNoCtor<RenderedModule> &renderedModules) {
+  for (const auto &renderedModule : renderedModules)
+    if (ModulesEq(module, renderedModule))
+      return true;
 
-Symbolizer *Symbolizer::PlatformInit() {
-  return new (symbolizer_allocator_) Symbolizer({});
+  return false;
 }
 
-void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); }
-
-void StartReportDeadlySignal() {}
-void ReportDeadlySignal(const SignalContext &sig, u32 tid,
-                        UnwindSignalStackCallbackType unwind,
-                        const void *unwind_context) {}
-
-#if SANITIZER_CAN_SLOW_UNWIND
-struct UnwindTraceArg {
-  BufferedStackTrace *stack;
-  u32 max_depth;
-};
-
-_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
-  UnwindTraceArg *arg = static_cast<UnwindTraceArg *>(param);
-  CHECK_LT(arg->stack->size, arg->max_depth);
-  uptr pc = _Unwind_GetIP(ctx);
-  if (pc < PAGE_SIZE) return _URC_NORMAL_STOP;
-  arg->stack->trace_buffer[arg->stack->size++] = pc;
-  return (arg->stack->size == arg->max_depth ? _URC_NORMAL_STOP
-                                             : _URC_NO_REASON);
+static void RenderModule(InternalScopedString *buffer,
+                         const LoadedModule &module, uptr moduleId) {
+  InternalScopedString buildIdBuffer;
+  for (uptr i = 0; i < module.uuid_size(); i++)
+    buildIdBuffer.AppendF("%02x", module.uuid()[i]);
+
+  buffer->AppendF(kFormatModule, moduleId, module.full_name(),
+                  buildIdBuffer.data());
+  buffer->Append("\n");
 }
 
-void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) {
-  CHECK_GE(max_depth, 2);
-  size = 0;
-  UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)};
-  _Unwind_Backtrace(Unwind_Trace, &arg);
-  CHECK_GT(size, 0);
-  // We need to pop a few frames so that pc is on top.
-  uptr to_pop = LocatePcInTrace(pc);
-  // trace_buffer[0] belongs to the current function so we always pop it,
-  // unless there is only 1 frame in the stack trace (1 frame is always better
-  // than 0!).
-  PopStackFrames(Min(to_pop, static_cast<uptr>(1)));
-  trace_buffer[0] = pc;
+static void RenderMmaps(InternalScopedString *buffer,
+                        const LoadedModule &module, uptr moduleId) {
+  InternalScopedString accessBuffer;
+
+  // All module mmaps are readable at least
+  for (const auto &range : module.ranges()) {
+    accessBuffer.Append("r");
+    if (range.writable)
+      accessBuffer.Append("w");
+    if (range.executable)
+      accessBuffer.Append("x");
+
+    //{{{mmap:%starting_addr:%size_in_hex:load:%moduleId:r%(w|x):%relative_addr}}}
+
+    // module.base_address == dlpi_addr
+    // range.beg == dlpi_addr + p_vaddr
+    // relative address == p_vaddr == range.beg - module.base_address
+    buffer->AppendF(kFormatMmap, reinterpret_cast<void *>(range.beg),
+                    range.end - range.beg, static_cast<int>(moduleId),
+                    accessBuffer.data(), range.beg - module.base_address());
+
+    buffer->Append("\n");
+    accessBuffer.clear();
+  }
 }
 
-void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
-  CHECK(context);
-  CHECK_GE(max_depth, 2);
-  UNREACHABLE("signal context doesn't exist");
+void MarkupStackTracePrinter::RenderContext(InternalScopedString *buffer) {
+  if (renderedModules_.size() == 0)
+    buffer->Append("{{{reset}}}\n");
+
+  const auto &modules = Symbolizer::GetOrInit()->GetRefreshedListOfModules();
+
+  for (const auto &module : modules) {
+    if (ModuleHasBeenRendered(module, renderedModules_))
+      continue;
+
+    // symbolizer markup id, used to refer to this modules from other contextual
+    // elements
+    uptr moduleId = renderedModules_.size();
+
+    RenderModule(buffer, module, moduleId);
+    RenderMmaps(buffer, module, moduleId);
+
+    renderedModules_.push_back({
+        internal_strdup(module.full_name()),
+        module.base_address(),
+        {},
+    });
+
+    // kModuleUUIDSize is the size of curModule.uuid
+    CHECK_GE(kModuleUUIDSize, module.uuid_size());
+    internal_memcpy(renderedModules_.back().uuid, module.uuid(),
+                    module.uuid_size());
+  }
 }
-#endif  // SANITIZER_CAN_SLOW_UNWIND
+#endif  // !SANITIZER_FUCHSIA
 
 }  // namespace __sanitizer
-
-#endif  // SANITIZER_SYMBOLIZER_MARKUP
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.h
new file mode 100644
index 000000000000..bc2ab24d625b
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup.h
@@ -0,0 +1,79 @@ 
+//===-- sanitizer_symbolizer_markup.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 shared between various sanitizers' runtime libraries.
+//
+//  Header for the offline markup symbolizer.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_SYMBOLIZER_MARKUP_H
+#define SANITIZER_SYMBOLIZER_MARKUP_H
+
+#include "sanitizer_common.h"
+#include "sanitizer_stacktrace_printer.h"
+#include "sanitizer_symbolizer.h"
+#include "sanitizer_symbolizer_internal.h"
+
+namespace __sanitizer {
+
+// Simplier view of a LoadedModule. It only holds information necessary to
+// identify unique modules.
+struct RenderedModule {
+  char *full_name;
+  uptr base_address;
+  u8 uuid[kModuleUUIDSize];  // BuildId
+};
+
+class MarkupStackTracePrinter : public StackTracePrinter {
+ public:
+  // We don't support the stack_trace_format flag at all.
+  void RenderFrame(InternalScopedString *buffer, const char *format,
+                   int frame_no, uptr address, const AddressInfo *info,
+                   bool vs_style, const char *strip_path_prefix = "") override;
+
+  bool RenderNeedsSymbolization(const char *format) override;
+
+  // We ignore the format argument to __sanitizer_symbolize_global.
+  void RenderData(InternalScopedString *buffer, const char *format,
+                  const DataInfo *DI,
+                  const char *strip_path_prefix = "") override;
+
+ private:
+  // Keeps track of the modules that have been rendered to avoid re-rendering
+  // them
+  InternalMmapVector<RenderedModule> renderedModules_;
+  void RenderContext(InternalScopedString *buffer);
+
+ protected:
+  ~MarkupStackTracePrinter() {}
+};
+
+class MarkupSymbolizerTool final : public SymbolizerTool {
+ public:
+  // This is used in some places for suppression checking, which we
+  // don't really support for Fuchsia.  It's also used in UBSan to
+  // identify a PC location to a function name, so we always fill in
+  // the function member with a string containing markup around the PC
+  // value.
+  // TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan
+  // to render stack frames, but that should be changed to use
+  // RenderStackFrame.
+  bool SymbolizePC(uptr addr, SymbolizedStack *stack) override;
+
+  // Always claim we succeeded, so that RenderDataInfo will be called.
+  bool SymbolizeData(uptr addr, DataInfo *info) override;
+
+  // May return NULL if demangling failed.
+  // This is used by UBSan for type names, and by ASan for global variable
+  // names. It's expected to return a static buffer that will be reused on each
+  // call.
+  const char *Demangle(const char *name) override;
+};
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_SYMBOLIZER_MARKUP_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_fuchsia.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup_constants.h
similarity index 69%
rename from libsanitizer/sanitizer_common/sanitizer_symbolizer_fuchsia.h
rename to libsanitizer/sanitizer_common/sanitizer_symbolizer_markup_constants.h
index c4061e38c6a4..a43661eaecf2 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_fuchsia.h
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup_constants.h
@@ -1,4 +1,5 @@ 
-//===-- sanitizer_symbolizer_fuchsia.h -----------------------------------===//
+//===-- sanitizer_symbolizer_markup_constants.h
+//-----------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -8,10 +9,10 @@ 
 //
 // This file is shared between various sanitizers' runtime libraries.
 //
-// Define Fuchsia's string formats and limits for the markup symbolizer.
+// Define string formats and limits for the markup symbolizer.
 //===----------------------------------------------------------------------===//
-#ifndef SANITIZER_SYMBOLIZER_FUCHSIA_H
-#define SANITIZER_SYMBOLIZER_FUCHSIA_H
+#ifndef SANITIZER_SYMBOLIZER_MARKUP_CONSTANTS_H
+#define SANITIZER_SYMBOLIZER_MARKUP_CONSTANTS_H
 
 #include "sanitizer_internal_defs.h"
 
@@ -32,11 +33,17 @@  constexpr uptr kFormatFunctionMax = 64;  // More than big enough for 64-bit hex.
 constexpr const char *kFormatData = "{{{data:%p}}}";
 
 // One frame in a backtrace (printed on a line by itself).
-constexpr const char *kFormatFrame = "{{{bt:%u:%p}}}";
+constexpr const char *kFormatFrame = "{{{bt:%d:%p}}}";
+
+// Module contextual element.
+constexpr const char *kFormatModule = "{{{module:%zu:%s:elf:%s}}}";
+
+// mmap for a module segment.
+constexpr const char *kFormatMmap = "{{{mmap:%p:0x%zx:load:%d:%s:0x%zx}}}";
 
 // Dump trigger element.
 #define FORMAT_DUMPFILE "{{{dumpfile:%s:%s}}}"
 
 }  // namespace __sanitizer
 
-#endif  // SANITIZER_SYMBOLIZER_FUCHSIA_H
+#endif  // SANITIZER_SYMBOLIZER_MARKUP_CONSTANTS_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup_fuchsia.cpp
new file mode 100644
index 000000000000..08b06c2faf30
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_markup_fuchsia.cpp
@@ -0,0 +1,85 @@ 
+//===-- sanitizer_symbolizer_markup_fuchsia.cpp ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between various sanitizers' runtime libraries.
+//
+// Fuchsia specific implementation of offline markup symbolizer.
+//===----------------------------------------------------------------------===//
+#include "sanitizer_platform.h"
+
+#if SANITIZER_SYMBOLIZER_MARKUP
+
+#  include "sanitizer_common.h"
+#  include "sanitizer_stacktrace_printer.h"
+#  include "sanitizer_symbolizer.h"
+#  include "sanitizer_symbolizer_markup.h"
+#  include "sanitizer_symbolizer_markup_constants.h"
+
+namespace __sanitizer {
+
+// This is used by UBSan for type names, and by ASan for global variable names.
+// It's expected to return a static buffer that will be reused on each call.
+const char *Symbolizer::Demangle(const char *name) {
+  static char buffer[kFormatDemangleMax];
+  internal_snprintf(buffer, sizeof(buffer), kFormatDemangle, name);
+  return buffer;
+}
+
+// This is used mostly for suppression matching.  Making it work
+// would enable "interceptor_via_lib" suppressions.  It's also used
+// once in UBSan to say "in module ..." in a message that also
+// includes an address in the module, so post-processing can already
+// pretty-print that so as to indicate the module.
+bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
+                                             uptr *module_address) {
+  return false;
+}
+
+// This is mainly used by hwasan for online symbolization. This isn't needed
+// since hwasan can always just dump stack frames for offline symbolization.
+bool Symbolizer::SymbolizeFrame(uptr addr, FrameInfo *info) { return false; }
+
+// This is used in some places for suppression checking, which we
+// don't really support for Fuchsia.  It's also used in UBSan to
+// identify a PC location to a function name, so we always fill in
+// the function member with a string containing markup around the PC
+// value.
+// TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan
+// to render stack frames, but that should be changed to use
+// RenderStackFrame.
+SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
+  SymbolizedStack *s = SymbolizedStack::New(addr);
+  char buffer[kFormatFunctionMax];
+  internal_snprintf(buffer, sizeof(buffer), kFormatFunction, addr);
+  s->info.function = internal_strdup(buffer);
+  return s;
+}
+
+// Always claim we succeeded, so that RenderDataInfo will be called.
+bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
+  info->Clear();
+  info->start = addr;
+  return true;
+}
+
+// Fuchsia only uses MarkupStackTracePrinter
+StackTracePrinter *StackTracePrinter::NewStackTracePrinter() {
+  return new (GetGlobalLowLevelAllocator()) MarkupStackTracePrinter();
+}
+
+void MarkupStackTracePrinter::RenderContext(InternalScopedString *) {}
+
+Symbolizer *Symbolizer::PlatformInit() {
+  return new (symbolizer_allocator_) Symbolizer({});
+}
+
+void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); }
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_SYMBOLIZER_MARKUP
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
index d92349c04fff..0ddc24802d21 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp
@@ -12,6 +12,7 @@ 
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_platform.h"
+#include "sanitizer_symbolizer_markup.h"
 #if SANITIZER_POSIX
 #  include <dlfcn.h>  // for dlsym()
 #  include <errno.h>
@@ -340,15 +341,14 @@  __sanitizer_symbolize_set_inline_frames(bool InlineFrames);
 class InternalSymbolizer final : public SymbolizerTool {
  public:
   static InternalSymbolizer *get(LowLevelAllocator *alloc) {
-    if (&__sanitizer_symbolize_set_demangle)
-      CHECK(__sanitizer_symbolize_set_demangle(common_flags()->demangle));
-    if (&__sanitizer_symbolize_set_inline_frames)
-      CHECK(__sanitizer_symbolize_set_inline_frames(
-          common_flags()->symbolize_inline_frames));
-    // These are essential, we don't have InternalSymbolizer without them.
-    if (&__sanitizer_symbolize_code && &__sanitizer_symbolize_data)
-      return new (*alloc) InternalSymbolizer();
-    return 0;
+    // These one is the most used one, so we will use it to detect a presence of
+    // internal symbolizer.
+    if (&__sanitizer_symbolize_code == nullptr)
+      return nullptr;
+    CHECK(__sanitizer_symbolize_set_demangle(common_flags()->demangle));
+    CHECK(__sanitizer_symbolize_set_inline_frames(
+        common_flags()->symbolize_inline_frames));
+    return new (*alloc) InternalSymbolizer();
   }
 
   bool SymbolizePC(uptr addr, SymbolizedStack *stack) override {
@@ -370,8 +370,6 @@  class InternalSymbolizer final : public SymbolizerTool {
   }
 
   bool SymbolizeFrame(uptr addr, FrameInfo *info) override {
-    if (&__sanitizer_symbolize_frame == nullptr)
-      return false;
     bool result = __sanitizer_symbolize_frame(info->module, info->module_offset,
                                               buffer_, sizeof(buffer_));
     if (result)
@@ -379,14 +377,10 @@  class InternalSymbolizer final : public SymbolizerTool {
     return result;
   }
 
-  void Flush() override {
-    if (&__sanitizer_symbolize_flush)
-      __sanitizer_symbolize_flush();
-  }
+  void Flush() override { __sanitizer_symbolize_flush(); }
 
   const char *Demangle(const char *name) override {
-    if (&__sanitizer_symbolize_demangle &&
-        __sanitizer_symbolize_demangle(name, buffer_, sizeof(buffer_))) {
+    if (__sanitizer_symbolize_demangle(name, buffer_, sizeof(buffer_))) {
       char *res_buff = nullptr;
       ExtractToken(buffer_, "", &res_buff);
       return res_buff;
@@ -475,6 +469,12 @@  static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
     VReport(2, "Symbolizer is disabled.\n");
     return;
   }
+  if (common_flags()->enable_symbolizer_markup) {
+    VReport(2, "Using symbolizer markup");
+    SymbolizerTool *tool = new (*allocator) MarkupSymbolizerTool();
+    CHECK(tool);
+    list->push_back(tool);
+  }
   if (IsAllocatorOutOfMemory()) {
     VReport(2, "Cannot use internal symbolizer: out of memory\n");
   } else if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
index 3e4417ae3f57..351e00db6fb2 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report.cpp
@@ -28,6 +28,33 @@ 
 namespace __sanitizer {
 
 #if !SANITIZER_GO
+
+static bool FrameIsInternal(const SymbolizedStack *frame) {
+  if (!frame)
+    return true;
+  const char *file = frame->info.file;
+  const char *module = frame->info.module;
+  // On Gentoo, the path is g++-*, so there's *not* a missing /.
+  if (file && (internal_strstr(file, "/compiler-rt/lib/") ||
+               internal_strstr(file, "/include/c++/") ||
+               internal_strstr(file, "/include/g++")))
+    return true;
+  if (file && internal_strstr(file, "\\compiler-rt\\lib\\"))
+    return true;
+  if (module && (internal_strstr(module, "libclang_rt.")))
+    return true;
+  if (module && (internal_strstr(module, "clang_rt.")))
+    return true;
+  return false;
+}
+
+const SymbolizedStack *SkipInternalFrames(const SymbolizedStack *frames) {
+  for (const SymbolizedStack *f = frames; f; f = f->next)
+    if (!FrameIsInternal(f))
+      return f;
+  return nullptr;
+}
+
 void ReportErrorSummary(const char *error_type, const AddressInfo &info,
                         const char *alt_tool_name) {
   if (!common_flags()->print_summary) return;
@@ -75,16 +102,33 @@  void ReportErrorSummary(const char *error_type, const StackTrace *stack,
 #if !SANITIZER_GO
   if (!common_flags()->print_summary)
     return;
-  if (stack->size == 0) {
-    ReportErrorSummary(error_type);
-    return;
+
+  // Find first non-internal stack frame.
+  for (uptr i = 0; i < stack->size; ++i) {
+    uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[i]);
+    SymbolizedStackHolder symbolized_stack(
+        Symbolizer::GetOrInit()->SymbolizePC(pc));
+    if (const SymbolizedStack *frame = symbolized_stack.get()) {
+      if (const SymbolizedStack *summary_frame = SkipInternalFrames(frame)) {
+        ReportErrorSummary(error_type, summary_frame->info, alt_tool_name);
+        return;
+      }
+    }
   }
-  // Currently, we include the first stack frame into the report summary.
-  // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
-  uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
-  SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
-  ReportErrorSummary(error_type, frame->info, alt_tool_name);
-  frame->ClearAll();
+
+  // Fallback to the top one.
+  if (stack->size) {
+    uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
+    SymbolizedStackHolder symbolized_stack(
+        Symbolizer::GetOrInit()->SymbolizePC(pc));
+    if (const SymbolizedStack *frame = symbolized_stack.get()) {
+      ReportErrorSummary(error_type, frame->info, alt_tool_name);
+      return;
+    }
+  }
+
+  // Fallback to a summary without location.
+  ReportErrorSummary(error_type);
 #endif
 }
 
@@ -183,12 +227,15 @@  static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid,
          SanitizerToolName, kDescription, (void *)sig.addr, (void *)sig.pc,
          (void *)sig.bp, (void *)sig.sp, tid);
   Printf("%s", d.Default());
-  InternalMmapVector<BufferedStackTrace> stack_buffer(1);
-  BufferedStackTrace *stack = stack_buffer.data();
-  stack->Reset();
-  unwind(sig, unwind_context, stack);
-  stack->Print();
-  ReportErrorSummary(kDescription, stack);
+  // Avoid SEGVs in the unwinder when bp couldn't be determined.
+  if (sig.bp) {
+    InternalMmapVector<BufferedStackTrace> stack_buffer(1);
+    BufferedStackTrace *stack = stack_buffer.data();
+    stack->Reset();
+    unwind(sig, unwind_context, stack);
+    stack->Print();
+    ReportErrorSummary(kDescription, stack);
+  }
 }
 
 static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_report_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report_fuchsia.cpp
new file mode 100644
index 000000000000..fb49cfbb3047
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_report_fuchsia.cpp
@@ -0,0 +1,33 @@ 
+//===-- sanitizer_symbolizer_report_fuchsia.cpp
+//-----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of the report functions for fuchsia.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#if SANITIZER_SYMBOLIZER_MARKUP
+
+#  include "sanitizer_common.h"
+
+namespace __sanitizer {
+void StartReportDeadlySignal() {}
+
+void ReportDeadlySignal(const SignalContext &sig, u32 tid,
+                        UnwindSignalStackCallbackType unwind,
+                        const void *unwind_context) {}
+
+void HandleDeadlySignal(void *siginfo, void *context, u32 tid,
+                        UnwindSignalStackCallbackType unwind,
+                        const void *unwind_context) {}
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_SYMBOLIZER_MARKUP
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
index aae3e76ea229..1ff8b8f1bab4 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cpp
@@ -65,12 +65,13 @@  void InitializeDbgHelpIfNeeded() {
   HMODULE dbghelp = LoadLibraryA("dbghelp.dll");
   CHECK(dbghelp && "failed to load dbghelp.dll");
 
-#define DBGHELP_IMPORT(name)                                                  \
-  do {                                                                        \
-    name =                                                                    \
-        reinterpret_cast<decltype(::name) *>(GetProcAddress(dbghelp, #name)); \
-    CHECK(name != nullptr);                                                   \
-  } while (0)
+#  define DBGHELP_IMPORT(name)                     \
+    do {                                           \
+      name = reinterpret_cast<decltype(::name) *>( \
+          (void *)GetProcAddress(dbghelp, #name)); \
+      CHECK(name != nullptr);                      \
+    } while (0)
+
   DBGHELP_IMPORT(StackWalk64);
   DBGHELP_IMPORT(SymCleanup);
   DBGHELP_IMPORT(SymFromAddr);
diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_arg_retval.cpp b/libsanitizer/sanitizer_common/sanitizer_thread_arg_retval.cpp
index bddb28521408..754fd7b65a1d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_thread_arg_retval.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_thread_arg_retval.cpp
@@ -23,6 +23,9 @@  void ThreadArgRetval::CreateLocked(uptr thread, bool detached,
   Data& t = data_[thread];
   t = {};
   t.gen = gen_++;
+  static_assert(sizeof(gen_) == sizeof(u32) && kInvalidGen == UINT32_MAX);
+  if (gen_ == kInvalidGen)
+    gen_ = 0;
   t.detached = detached;
   t.args = args;
 }
@@ -53,16 +56,28 @@  void ThreadArgRetval::Finish(uptr thread, void* retval) {
 u32 ThreadArgRetval::BeforeJoin(uptr thread) const {
   __sanitizer::Lock lock(&mtx_);
   auto t = data_.find(thread);
-  CHECK(t);
-  CHECK(!t->second.detached);
-  return t->second.gen;
+  if (t && !t->second.detached) {
+    return t->second.gen;
+  }
+  if (!common_flags()->detect_invalid_join)
+    return kInvalidGen;
+  const char* reason = "unknown";
+  if (!t) {
+    reason = "already joined";
+  } else if (t->second.detached) {
+    reason = "detached";
+  }
+  Report("ERROR: %s: Joining %s thread, aborting.\n", SanitizerToolName,
+         reason);
+  Die();
 }
 
 void ThreadArgRetval::AfterJoin(uptr thread, u32 gen) {
   __sanitizer::Lock lock(&mtx_);
   auto t = data_.find(thread);
   if (!t || gen != t->second.gen) {
-    // Thread was reused and erased by any other event.
+    // Thread was reused and erased by any other event, or we had an invalid
+    // join.
     return;
   }
   CHECK(!t->second.detached);
diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_arg_retval.h b/libsanitizer/sanitizer_common/sanitizer_thread_arg_retval.h
index c77021beb67d..0e6d35131c23 100644
--- a/libsanitizer/sanitizer_common/sanitizer_thread_arg_retval.h
+++ b/libsanitizer/sanitizer_common/sanitizer_thread_arg_retval.h
@@ -93,6 +93,7 @@  class SANITIZER_MUTEX ThreadArgRetval {
   // will keep pointers alive forever, missing leaks caused by cancelation.
 
  private:
+  static const u32 kInvalidGen = UINT32_MAX;
   struct Data {
     Args args;
     u32 gen;  // Avoid collision if thread id re-used.
diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_history.cpp b/libsanitizer/sanitizer_common/sanitizer_thread_history.cpp
new file mode 100644
index 000000000000..0f5bec3ca083
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_thread_history.cpp
@@ -0,0 +1,72 @@ 
+//===-- sanitizer_thread_history.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_thread_history.h"
+
+#include "sanitizer_stackdepot.h"
+namespace __sanitizer {
+
+void PrintThreadHistory(ThreadRegistry &registry, InternalScopedString &out) {
+  ThreadRegistryLock l(&registry);
+  // Stack traces are largest part of printout and they often the same for
+  // multiple threads, so we will deduplicate them.
+  InternalMmapVector<const ThreadContextBase *> stacks;
+
+  registry.RunCallbackForEachThreadLocked(
+      [](ThreadContextBase *context, void *arg) {
+        static_cast<decltype(&stacks)>(arg)->push_back(context);
+      },
+      &stacks);
+
+  Sort(stacks.data(), stacks.size(),
+       [](const ThreadContextBase *a, const ThreadContextBase *b) {
+         if (a->stack_id < b->stack_id)
+           return true;
+         if (a->stack_id > b->stack_id)
+           return false;
+         return a->unique_id < b->unique_id;
+       });
+
+  auto describe_thread = [&](const ThreadContextBase *context) {
+    if (!context) {
+      out.Append("T-1");
+      return;
+    }
+    out.AppendF("T%llu/%llu", context->unique_id, context->os_id);
+    if (internal_strlen(context->name))
+      out.AppendF(" (%s)", context->name);
+  };
+
+  auto get_parent =
+      [&](const ThreadContextBase *context) -> const ThreadContextBase * {
+    if (!context)
+      return nullptr;
+    ThreadContextBase *parent = registry.GetThreadLocked(context->parent_tid);
+    if (!parent)
+      return nullptr;
+    if (parent->unique_id >= context->unique_id)
+      return nullptr;
+    return parent;
+  };
+
+  const ThreadContextBase *prev = nullptr;
+  for (const ThreadContextBase *context : stacks) {
+    if (prev && prev->stack_id != context->stack_id)
+      StackDepotGet(prev->stack_id).PrintTo(&out);
+    prev = context;
+    out.Append("Thread ");
+    describe_thread(context);
+    out.Append(" was created by ");
+    describe_thread(get_parent(context));
+    out.Append("\n");
+  }
+  if (prev)
+    StackDepotGet(prev->stack_id).PrintTo(&out);
+}
+
+}  // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_history.h b/libsanitizer/sanitizer_common/sanitizer_thread_history.h
new file mode 100644
index 000000000000..2995f6015fe5
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_thread_history.h
@@ -0,0 +1,24 @@ 
+//===-- sanitizer_thread_history.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Utility to print thread histroy from ThreadRegistry.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_THREAD_HISTORY_H
+#define SANITIZER_THREAD_HISTORY_H
+
+#include "sanitizer_thread_registry.h"
+
+namespace __sanitizer {
+
+void PrintThreadHistory(ThreadRegistry& registry, InternalScopedString& out);
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_THREAD_HISTORY_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
index 741e0731c415..cdc24f4a8869 100644
--- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cpp
@@ -18,9 +18,17 @@ 
 namespace __sanitizer {
 
 ThreadContextBase::ThreadContextBase(u32 tid)
-    : tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0),
-      status(ThreadStatusInvalid), detached(false),
-      thread_type(ThreadType::Regular), parent_tid(0), next(0) {
+    : tid(tid),
+      unique_id(0),
+      reuse_count(),
+      os_id(0),
+      user_id(0),
+      status(ThreadStatusInvalid),
+      detached(false),
+      thread_type(ThreadType::Regular),
+      parent_tid(0),
+      stack_id(0),
+      next(0) {
   name[0] = '\0';
   atomic_store(&thread_destroyed, 0, memory_order_release);
 }
@@ -39,8 +47,7 @@  void ThreadContextBase::SetName(const char *new_name) {
 }
 
 void ThreadContextBase::SetDead() {
-  CHECK(status == ThreadStatusRunning ||
-        status == ThreadStatusFinished);
+  CHECK(status == ThreadStatusRunning || status == ThreadStatusFinished);
   status = ThreadStatusDead;
   user_id = 0;
   OnDead();
@@ -68,7 +75,8 @@  void ThreadContextBase::SetFinished() {
   // for a thread that never actually started.  In that case the thread
   // should go to ThreadStatusFinished regardless of whether it was created
   // as detached.
-  if (!detached || status == ThreadStatusCreated) status = ThreadStatusFinished;
+  if (!detached || status == ThreadStatusCreated)
+    status = ThreadStatusFinished;
   OnFinished();
 }
 
@@ -81,14 +89,17 @@  void ThreadContextBase::SetStarted(tid_t _os_id, ThreadType _thread_type,
 }
 
 void ThreadContextBase::SetCreated(uptr _user_id, u64 _unique_id,
-                                   bool _detached, u32 _parent_tid, void *arg) {
+                                   bool _detached, u32 _parent_tid,
+                                   u32 _stack_tid, void *arg) {
   status = ThreadStatusCreated;
   user_id = _user_id;
   unique_id = _unique_id;
   detached = _detached;
   // Parent tid makes no sense for the main thread.
-  if (tid != kMainTid)
+  if (tid != kMainTid) {
     parent_tid = _parent_tid;
+    stack_id = _stack_tid;
+  }
   OnCreated(arg);
 }
 
@@ -124,8 +135,10 @@  void ThreadRegistry::GetNumberOfThreads(uptr *total, uptr *running,
   ThreadRegistryLock l(this);
   if (total)
     *total = threads_.size();
-  if (running) *running = running_threads_;
-  if (alive) *alive = alive_threads_;
+  if (running)
+    *running = running_threads_;
+  if (alive)
+    *alive = alive_threads_;
 }
 
 uptr ThreadRegistry::GetMaxAliveThreads() {
@@ -134,7 +147,7 @@  uptr ThreadRegistry::GetMaxAliveThreads() {
 }
 
 u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
-                                 void *arg) {
+                                 u32 stack_tid, void *arg) {
   ThreadRegistryLock l(this);
   u32 tid = kInvalidTid;
   ThreadContextBase *tctx = QuarantinePop();
@@ -150,8 +163,10 @@  u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
     Report("%s: Thread limit (%u threads) exceeded. Dying.\n",
            SanitizerToolName, max_threads_);
 #else
-    Printf("race: limit on %u simultaneously alive goroutines is exceeded,"
-        " dying\n", max_threads_);
+    Printf(
+        "race: limit on %u simultaneously alive goroutines is exceeded,"
+        " dying\n",
+        max_threads_);
 #endif
     Die();
   }
@@ -170,8 +185,8 @@  u32 ThreadRegistry::CreateThread(uptr user_id, bool detached, u32 parent_tid,
     // positives later (e.g. if we join a wrong thread).
     CHECK(live_.try_emplace(user_id, tid).second);
   }
-  tctx->SetCreated(user_id, total_threads_++, detached,
-                   parent_tid, arg);
+  tctx->SetCreated(user_id, total_threads_++, detached, parent_tid, stack_tid,
+                   arg);
   return tid;
 }
 
@@ -196,8 +211,8 @@  u32 ThreadRegistry::FindThread(FindThreadCallback cb, void *arg) {
   return kInvalidTid;
 }
 
-ThreadContextBase *
-ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) {
+ThreadContextBase *ThreadRegistry::FindThreadContextLocked(
+    FindThreadCallback cb, void *arg) {
   CheckLocked();
   for (u32 tid = 0; tid < threads_.size(); tid++) {
     ThreadContextBase *tctx = threads_[tid];
@@ -210,7 +225,7 @@  ThreadRegistry::FindThreadContextLocked(FindThreadCallback cb, void *arg) {
 static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx,
                                             void *arg) {
   return (tctx->os_id == (uptr)arg && tctx->status != ThreadStatusInvalid &&
-      tctx->status != ThreadStatusDead);
+          tctx->status != ThreadStatusDead);
 }
 
 ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
index 2c7e5c276fa1..e06abb3932da 100644
--- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
+++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
@@ -52,6 +52,7 @@  class ThreadContextBase {
   ThreadType thread_type;
 
   u32 parent_tid;
+  u32 stack_id;
   ThreadContextBase *next;  // For storing thread contexts in a list.
 
   atomic_uint32_t thread_destroyed; // To address race of Joined vs Finished
@@ -63,7 +64,7 @@  class ThreadContextBase {
   void SetFinished();
   void SetStarted(tid_t _os_id, ThreadType _thread_type, void *arg);
   void SetCreated(uptr _user_id, u64 _unique_id, bool _detached,
-                  u32 _parent_tid, void *arg);
+                  u32 _parent_tid, u32 _stack_tid, void *arg);
   void Reset();
 
   void SetDestroyed();
@@ -101,12 +102,16 @@  class SANITIZER_MUTEX ThreadRegistry {
 
   // Should be guarded by ThreadRegistryLock.
   ThreadContextBase *GetThreadLocked(u32 tid) {
-    return threads_.empty() ? nullptr : threads_[tid];
+    return tid < threads_.size() ? threads_[tid] : nullptr;
   }
 
   u32 NumThreadsLocked() const { return threads_.size(); }
 
-  u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg);
+  u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, u32 stack_tid,
+                   void *arg);
+  u32 CreateThread(uptr user_id, bool detached, u32 parent_tid, void *arg) {
+    return CreateThread(user_id, detached, parent_tid, 0, arg);
+  }
 
   typedef void (*ThreadCallback)(ThreadContextBase *tctx, void *arg);
   // Invokes callback with a specified arg for each thread context.
diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
index 252979f1c2ba..e08bcb435ca8 100644
--- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cpp
@@ -14,6 +14,8 @@ 
 
 #include "sanitizer_allocator_interface.h"
 #include "sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_flags.h"
 #include "sanitizer_platform_interceptors.h"
 
@@ -66,7 +68,7 @@  static DTLS::DTVBlock *DTLS_NextBlock(atomic_uintptr_t *cur) {
 }
 
 static DTLS::DTV *DTLS_Find(uptr id) {
-  VReport(2, "__tls_get_addr: DTLS_Find %p %zd\n", (void *)&dtls, id);
+  VReport(3, "__tls_get_addr: DTLS_Find %p %zd\n", (void *)&dtls, id);
   static constexpr uptr kPerBlock = ARRAY_SIZE(DTLS::DTVBlock::dtvs);
   DTLS::DTVBlock *cur = DTLS_NextBlock(&dtls.dtv_block);
   if (!cur)
@@ -110,6 +112,21 @@  SANITIZER_WEAK_ATTRIBUTE
 const void *__sanitizer_get_allocated_begin(const void *p);
 }
 
+SANITIZER_INTERFACE_WEAK_DEF(uptr, __sanitizer_get_dtls_size,
+                             const void *tls_begin) {
+  const void *start = __sanitizer_get_allocated_begin(tls_begin);
+  if (!start)
+    return 0;
+  CHECK_LE(start, tls_begin);
+  uptr tls_size = __sanitizer_get_allocated_size(start);
+  VReport(2, "__tls_get_addr: glibc DTLS suspected; tls={%p,0x%zx}\n",
+          tls_begin, tls_size);
+  uptr offset =
+      (reinterpret_cast<uptr>(tls_begin) - reinterpret_cast<uptr>(start));
+  CHECK_LE(offset, tls_size);
+  return tls_size - offset;
+}
+
 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;
@@ -117,44 +134,42 @@  DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
   uptr dso_id = arg->dso_id;
   DTLS::DTV *dtv = DTLS_Find(dso_id);
   if (!dtv || dtv->beg)
-    return 0;
-  uptr tls_size = 0;
+    return nullptr;
+  CHECK_LE(static_tls_begin, static_tls_end);
   uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset - kDtvOffset;
   VReport(2,
-          "__tls_get_addr: %p {0x%zx,0x%zx} => %p; tls_beg: 0x%zx; sp: %p "
+          "__tls_get_addr: %p {0x%zx,0x%zx} => %p; tls_beg: %p; sp: %p "
           "num_live_dtls %zd\n",
-          (void *)arg, arg->dso_id, arg->offset, res, tls_beg, (void *)&tls_beg,
+          (void *)arg, arg->dso_id, arg->offset, res, (void *)tls_beg,
+          (void *)&tls_beg,
           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.24 suspected; tls={0x%zx,0x%zx}\n",
-            tls_beg, tls_size);
-  } else if (tls_beg >= static_tls_begin && tls_beg < static_tls_end) {
+  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 (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");
-    // This may happen inside the DTOR of main thread, so just ignore it.
-    tls_size = 0;
+    VReport(2, "__tls_get_addr: static tls: %p\n", (void *)tls_beg);
+    dtv->beg = tls_beg;
+    dtv->size = 0;
+    return nullptr;
   }
+  if (uptr tls_size =
+          __sanitizer_get_dtls_size(reinterpret_cast<void *>(tls_beg))) {
+    dtv->beg = tls_beg;
+    dtv->size = tls_size;
+    return dtv;
+  }
+  VReport(2, "__tls_get_addr: Can't guess glibc version\n");
+  // This may happen inside the DTOR a thread, or async signal handlers before
+  // thread initialization, so just ignore it.
+  //
+  // If the unknown block is dynamic TLS, unlikely we will be able to recognize
+  // it in future, mark it as done with '{tls_beg, 0}'.
+  //
+  // If the block is static TLS, possible reason of failed detection is nullptr
+  // in `static_tls_begin`. Regardless of reasons, the future handling of static
+  // TLS is still '{tls_beg, 0}'.
   dtv->beg = tls_beg;
-  dtv->size = tls_size;
-  return dtv;
-}
-
-void DTLS_on_libc_memalign(void *ptr, uptr size) {
-  if (!common_flags()->intercept_tls_get_addr) return;
-  VReport(2, "DTLS_on_libc_memalign: %p 0x%zx\n", ptr, size);
-  dtls.last_memalign_ptr = reinterpret_cast<uptr>(ptr);
-  dtls.last_memalign_size = size;
+  dtv->size = 0;
+  return nullptr;
 }
 
 DTLS *DTLS_Get() { return &dtls; }
@@ -165,7 +180,9 @@  bool DTLSInDestruction(DTLS *dtls) {
 }
 
 #else
-void DTLS_on_libc_memalign(void *ptr, uptr size) {}
+SANITIZER_INTERFACE_WEAK_DEF(uptr, __sanitizer_get_dtls_size, const void *) {
+  return 0;
+}
 DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res,
   unsigned long, unsigned long) { return 0; }
 DTLS *DTLS_Get() { return 0; }
diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
index 0ddab61deb10..2ef767296e17 100644
--- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
+++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
@@ -55,10 +55,6 @@  struct DTLS {
   static_assert(sizeof(DTVBlock) <= 4096UL, "Unexpected block size");
 
   atomic_uintptr_t dtv_block;
-
-  // Auxiliary fields, don't access them outside sanitizer_tls_get_addr.cpp
-  uptr last_memalign_size;
-  uptr last_memalign_ptr;
 };
 
 template <typename Fn>
diff --git a/libsanitizer/sanitizer_common/sanitizer_unwind_fuchsia.cpp b/libsanitizer/sanitizer_common/sanitizer_unwind_fuchsia.cpp
new file mode 100644
index 000000000000..f3eb8591dcbc
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_unwind_fuchsia.cpp
@@ -0,0 +1,66 @@ 
+//===------------------ sanitizer_unwind_fuchsia.cpp
+//---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+/// Sanitizer unwind Fuchsia specific functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FUCHSIA
+
+#  include <limits.h>
+#  include <unwind.h>
+
+#  include "sanitizer_common.h"
+#  include "sanitizer_stacktrace.h"
+
+namespace __sanitizer {
+
+#  if SANITIZER_CAN_SLOW_UNWIND
+struct UnwindTraceArg {
+  BufferedStackTrace *stack;
+  u32 max_depth;
+};
+
+_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
+  UnwindTraceArg *arg = static_cast<UnwindTraceArg *>(param);
+  CHECK_LT(arg->stack->size, arg->max_depth);
+  uptr pc = _Unwind_GetIP(ctx);
+  if (pc < GetPageSizeCached())
+    return _URC_NORMAL_STOP;
+  arg->stack->trace_buffer[arg->stack->size++] = pc;
+  return (arg->stack->size == arg->max_depth ? _URC_NORMAL_STOP
+                                             : _URC_NO_REASON);
+}
+
+void BufferedStackTrace::UnwindSlow(uptr pc, u32 max_depth) {
+  CHECK_GE(max_depth, 2);
+  size = 0;
+  UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)};
+  _Unwind_Backtrace(Unwind_Trace, &arg);
+  CHECK_GT(size, 0);
+  // We need to pop a few frames so that pc is on top.
+  uptr to_pop = LocatePcInTrace(pc);
+  // trace_buffer[0] belongs to the current function so we always pop it,
+  // unless there is only 1 frame in the stack trace (1 frame is always better
+  // than 0!).
+  PopStackFrames(Min(to_pop, static_cast<uptr>(1)));
+  trace_buffer[0] = pc;
+}
+
+void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
+  CHECK(context);
+  CHECK_GE(max_depth, 2);
+  UNREACHABLE("signal context doesn't exist");
+}
+#  endif  //  SANITIZER_CAN_SLOW_UNWIND
+
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_FUCHSIA
diff --git a/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp b/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
index afcd01dae0b7..6fc18396ca63 100644
--- a/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_unwind_win.cpp
@@ -70,10 +70,17 @@  void BufferedStackTrace::UnwindSlow(uptr pc, void *context, u32 max_depth) {
   stack_frame.AddrStack.Offset = ctx.Rsp;
 #      endif
 #    else
+#      if SANITIZER_ARM
+  int machine_type = IMAGE_FILE_MACHINE_ARM;
+  stack_frame.AddrPC.Offset = ctx.Pc;
+  stack_frame.AddrFrame.Offset = ctx.R11;
+  stack_frame.AddrStack.Offset = ctx.Sp;
+#      else
   int machine_type = IMAGE_FILE_MACHINE_I386;
   stack_frame.AddrPC.Offset = ctx.Eip;
   stack_frame.AddrFrame.Offset = ctx.Ebp;
   stack_frame.AddrStack.Offset = ctx.Esp;
+#      endif
 #    endif
   stack_frame.AddrPC.Mode = AddrModeFlat;
   stack_frame.AddrFrame.Mode = AddrModeFlat;
diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cpp b/libsanitizer/sanitizer_common/sanitizer_win.cpp
index 06e496523eea..ea513d5f263f 100644
--- a/libsanitizer/sanitizer_common/sanitizer_win.cpp
+++ b/libsanitizer/sanitizer_common/sanitizer_win.cpp
@@ -144,7 +144,7 @@  void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
   return rv;
 }
 
-void UnmapOrDie(void *addr, uptr size) {
+void UnmapOrDie(void *addr, uptr size, bool raw_report) {
   if (!size || !addr)
     return;
 
@@ -156,10 +156,7 @@  void UnmapOrDie(void *addr, uptr size) {
   // fails try MEM_DECOMMIT.
   if (VirtualFree(addr, 0, MEM_RELEASE) == 0) {
     if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
-      Report("ERROR: %s failed to "
-             "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n",
-             SanitizerToolName, size, size, addr, GetLastError());
-      CHECK("unable to unmap" && 0);
+      ReportMunmapFailureAndDie(addr, size, GetLastError(), raw_report);
     }
   }
 }
@@ -279,8 +276,8 @@  void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) {
       MEM_COMMIT, PAGE_READWRITE);
   if (p == 0) {
     char mem_type[30];
-    internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
-                      fixed_addr);
+    internal_snprintf(mem_type, sizeof(mem_type), "memory at address %p",
+                      (void *)fixed_addr);
     ReportMmapFailureAndDie(size, mem_type, "allocate", GetLastError());
   }
   return p;
@@ -311,8 +308,8 @@  void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) {
       MEM_COMMIT, PAGE_READWRITE);
   if (p == 0) {
     char mem_type[30];
-    internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
-                      fixed_addr);
+    internal_snprintf(mem_type, sizeof(mem_type), "memory at address %p",
+                      (void *)fixed_addr);
     return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate");
   }
   return p;
@@ -387,9 +384,8 @@  bool DontDumpShadowMemory(uptr addr, uptr length) {
 }
 
 uptr MapDynamicShadow(uptr shadow_size_bytes, uptr shadow_scale,
-                      uptr min_shadow_base_alignment,
-                      UNUSED uptr &high_mem_end) {
-  const uptr granularity = GetMmapGranularity();
+                      uptr min_shadow_base_alignment, UNUSED uptr &high_mem_end,
+                      uptr granularity) {
   const uptr alignment =
       Max<uptr>(granularity << shadow_scale, 1ULL << min_shadow_base_alignment);
   const uptr left_padding =
@@ -877,24 +873,18 @@  uptr GetTlsSize() {
   return 0;
 }
 
-void InitTlsSize() {
-}
-
-void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
-                          uptr *tls_addr, uptr *tls_size) {
-#if SANITIZER_GO
-  *stk_addr = 0;
-  *stk_size = 0;
-  *tls_addr = 0;
-  *tls_size = 0;
-#else
-  uptr stack_top, stack_bottom;
-  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
-  *stk_addr = stack_bottom;
-  *stk_size = stack_top - stack_bottom;
-  *tls_addr = 0;
-  *tls_size = 0;
-#endif
+void GetThreadStackAndTls(bool main, uptr *stk_begin, uptr *stk_end,
+                          uptr *tls_begin, uptr *tls_end) {
+#  if SANITIZER_GO
+  *stk_begin = 0;
+  *stk_end = 0;
+  *tls_begin = 0;
+  *tls_end = 0;
+#  else
+  GetThreadStackTopAndBottom(main, stk_end, stk_begin);
+  *tls_begin = 0;
+  *tls_end = 0;
+#  endif
 }
 
 void ReportFile::Write(const char *buffer, uptr length) {
@@ -978,6 +968,11 @@  bool IsAccessibleMemoryRange(uptr beg, uptr size) {
   return true;
 }
 
+bool TryMemCpy(void *dest, const void *src, uptr n) {
+  // TODO: implement.
+  return false;
+}
+
 bool SignalContext::IsStackOverflow() const {
   return (DWORD)GetType() == EXCEPTION_STACK_OVERFLOW;
 }
@@ -996,8 +991,13 @@  void SignalContext::InitPcSpBp() {
   sp = (uptr)context_record->Rsp;
 #    endif
 #  else
+#    if SANITIZER_ARM
+  bp = (uptr)context_record->R11;
+  sp = (uptr)context_record->Sp;
+#    else
   bp = (uptr)context_record->Ebp;
   sp = (uptr)context_record->Esp;
+#    endif
 #  endif
 }
 
@@ -1038,7 +1038,52 @@  SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
 }
 
 void SignalContext::DumpAllRegisters(void *context) {
-  // FIXME: Implement this.
+  CONTEXT *ctx = (CONTEXT *)context;
+#  if defined(_M_X64)
+  Report("Register values:\n");
+  Printf("rax = %llx  ", ctx->Rax);
+  Printf("rbx = %llx  ", ctx->Rbx);
+  Printf("rcx = %llx  ", ctx->Rcx);
+  Printf("rdx = %llx  ", ctx->Rdx);
+  Printf("\n");
+  Printf("rdi = %llx  ", ctx->Rdi);
+  Printf("rsi = %llx  ", ctx->Rsi);
+  Printf("rbp = %llx  ", ctx->Rbp);
+  Printf("rsp = %llx  ", ctx->Rsp);
+  Printf("\n");
+  Printf("r8  = %llx  ", ctx->R8);
+  Printf("r9  = %llx  ", ctx->R9);
+  Printf("r10 = %llx  ", ctx->R10);
+  Printf("r11 = %llx  ", ctx->R11);
+  Printf("\n");
+  Printf("r12 = %llx  ", ctx->R12);
+  Printf("r13 = %llx  ", ctx->R13);
+  Printf("r14 = %llx  ", ctx->R14);
+  Printf("r15 = %llx  ", ctx->R15);
+  Printf("\n");
+#  elif defined(_M_IX86)
+  Report("Register values:\n");
+  Printf("eax = %lx  ", ctx->Eax);
+  Printf("ebx = %lx  ", ctx->Ebx);
+  Printf("ecx = %lx  ", ctx->Ecx);
+  Printf("edx = %lx  ", ctx->Edx);
+  Printf("\n");
+  Printf("edi = %lx  ", ctx->Edi);
+  Printf("esi = %lx  ", ctx->Esi);
+  Printf("ebp = %lx  ", ctx->Ebp);
+  Printf("esp = %lx  ", ctx->Esp);
+  Printf("\n");
+#  elif defined(_M_ARM64)
+  Report("Register values:\n");
+  for (int i = 0; i <= 30; i++) {
+    Printf("x%d%s = %llx", i < 10 ? " " : "", ctx->X[i]);
+    if (i % 4 == 3)
+      Printf("\n");
+  }
+#  else
+  // TODO
+  (void)ctx;
+#  endif
 }
 
 int SignalContext::GetType() const {
diff --git a/libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.cpp b/libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.cpp
deleted file mode 100644
index 1562c161a762..000000000000
--- a/libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.cpp
+++ /dev/null
@@ -1,101 +0,0 @@ 
-//===-- sanitizer_win_dll_thunk.cpp ---------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// This file defines a family of thunks that should be statically linked into
-// the DLLs that have instrumentation in order to delegate the calls to the
-// shared runtime that lives in the main binary.
-// See https://github.com/google/sanitizers/issues/209 for the details.
-//===----------------------------------------------------------------------===//
-
-#ifdef SANITIZER_DLL_THUNK
-#include "sanitizer_win_defs.h"
-#include "sanitizer_win_dll_thunk.h"
-#include "interception/interception.h"
-
-extern "C" {
-void *WINAPI GetModuleHandleA(const char *module_name);
-void abort();
-}
-
-namespace __sanitizer {
-uptr dllThunkGetRealAddrOrDie(const char *name) {
-  uptr ret =
-      __interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name);
-  if (!ret)
-    abort();
-  return ret;
-}
-
-int dllThunkIntercept(const char* main_function, uptr dll_function) {
-  uptr wrapper = dllThunkGetRealAddrOrDie(main_function);
-  if (!__interception::OverrideFunction(dll_function, wrapper, 0))
-    abort();
-  return 0;
-}
-
-int dllThunkInterceptWhenPossible(const char* main_function,
-    const char* default_function, uptr dll_function) {
-  uptr wrapper = __interception::InternalGetProcAddress(
-    (void *)GetModuleHandleA(0), main_function);
-  if (!wrapper)
-    wrapper = dllThunkGetRealAddrOrDie(default_function);
-  if (!__interception::OverrideFunction(dll_function, wrapper, 0))
-    abort();
-  return 0;
-}
-} // namespace __sanitizer
-
-// Include Sanitizer Common interface.
-#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name)
-#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
-#include "sanitizer_common_interface.inc"
-
-#pragma section(".DLLTH$A", read)
-#pragma section(".DLLTH$Z", read)
-
-typedef void (*DllThunkCB)();
-extern "C" {
-__declspec(allocate(".DLLTH$A")) DllThunkCB __start_dll_thunk;
-__declspec(allocate(".DLLTH$Z")) DllThunkCB __stop_dll_thunk;
-}
-
-// Disable compiler warnings that show up if we declare our own version
-// of a compiler intrinsic (e.g. strlen).
-#pragma warning(disable: 4391)
-#pragma warning(disable: 4392)
-
-extern "C" int __dll_thunk_init() {
-  static bool flag = false;
-  // __dll_thunk_init is expected to be called by only one thread.
-  if (flag) return 0;
-  flag = true;
-
-  for (DllThunkCB *it = &__start_dll_thunk; it < &__stop_dll_thunk; ++it)
-    if (*it)
-      (*it)();
-
-  // In DLLs, the callbacks are expected to return 0,
-  // otherwise CRT initialization fails.
-  return 0;
-}
-
-// We want to call dll_thunk_init before C/C++ initializers / constructors are
-// executed, otherwise functions like memset might be invoked.
-#pragma section(".CRT$XIB", long, read)
-__declspec(allocate(".CRT$XIB")) int (*__dll_thunk_preinit)() =
-    __dll_thunk_init;
-
-static void WINAPI dll_thunk_thread_init(void *mod, unsigned long reason,
-                                         void *reserved) {
-  if (reason == /*DLL_PROCESS_ATTACH=*/1) __dll_thunk_init();
-}
-
-#pragma section(".CRT$XLAB", long, read)
-__declspec(allocate(".CRT$XLAB")) void (WINAPI *__dll_thunk_tls_init)(void *,
-    unsigned long, void *) = dll_thunk_thread_init;
-
-#endif // SANITIZER_DLL_THUNK
diff --git a/libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.h b/libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.h
deleted file mode 100644
index 639d91a2edae..000000000000
--- a/libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.h
+++ /dev/null
@@ -1,181 +0,0 @@ 
-//===-- sanitizer_win_dll_thunk.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 header provide helper macros to delegate calls to the shared runtime
-// that lives in the main executable. It should be included to dll_thunks that
-// will be linked to the dlls, when the sanitizer is a static library included
-// in the main executable.
-//===----------------------------------------------------------------------===//
-#ifndef SANITIZER_WIN_DLL_THUNK_H
-#define SANITIZER_WIN_DLL_THUNK_H
-#include "sanitizer_internal_defs.h"
-
-namespace __sanitizer {
-uptr dllThunkGetRealAddrOrDie(const char *name);
-
-int dllThunkIntercept(const char* main_function, uptr dll_function);
-
-int dllThunkInterceptWhenPossible(const char* main_function,
-    const char* default_function, uptr dll_function);
-}
-
-extern "C" int __dll_thunk_init();
-
-// ----------------- Function interception helper macros -------------------- //
-// Override dll_function with main_function from main executable.
-#define INTERCEPT_OR_DIE(main_function, dll_function)                          \
-  static int intercept_##dll_function() {                                      \
-    return __sanitizer::dllThunkIntercept(main_function, (__sanitizer::uptr)   \
-        dll_function);                                                         \
-  }                                                                            \
-  __pragma(section(".DLLTH$M", long, read))                                    \
-  __declspec(allocate(".DLLTH$M")) int (*__dll_thunk_##dll_function)() =       \
-    intercept_##dll_function;
-
-// Try to override dll_function with main_function from main executable.
-// If main_function is not present, override dll_function with default_function.
-#define INTERCEPT_WHEN_POSSIBLE(main_function, default_function, dll_function) \
-  static int intercept_##dll_function() {                                      \
-    return __sanitizer::dllThunkInterceptWhenPossible(main_function,           \
-        default_function, (__sanitizer::uptr)dll_function);                    \
-  }                                                                            \
-  __pragma(section(".DLLTH$M", long, read))                                    \
-  __declspec(allocate(".DLLTH$M")) int (*__dll_thunk_##dll_function)() =       \
-    intercept_##dll_function;
-
-// -------------------- Function interception macros ------------------------ //
-// Special case of hooks -- ASan own interface functions.  Those are only called
-// after __asan_init, thus an empty implementation is sufficient.
-#define INTERCEPT_SANITIZER_FUNCTION(name)                                     \
-  extern "C" __declspec(noinline) void name() {                                \
-    volatile int prevent_icf = (__LINE__ << 8) ^ __COUNTER__;                  \
-    static const char function_name[] = #name;                                 \
-    for (const char* ptr = &function_name[0]; *ptr; ++ptr)                     \
-      prevent_icf ^= *ptr;                                                     \
-    (void)prevent_icf;                                                         \
-    __debugbreak();                                                            \
-  }                                                                            \
-  INTERCEPT_OR_DIE(#name, name)
-
-// Special case of hooks -- Weak functions, could be redefined in the main
-// executable, but that is not necessary, so we shouldn't die if we can not find
-// a reference. Instead, when the function is not present in the main executable
-// we consider the default impl provided by asan library.
-#define INTERCEPT_SANITIZER_WEAK_FUNCTION(name)                                \
-  extern "C" __declspec(noinline) void name() {                                \
-    volatile int prevent_icf = (__LINE__ << 8) ^ __COUNTER__;                  \
-    static const char function_name[] = #name;                                 \
-    for (const char* ptr = &function_name[0]; *ptr; ++ptr)                     \
-      prevent_icf ^= *ptr;                                                     \
-    (void)prevent_icf;                                                         \
-    __debugbreak();                                                            \
-  }                                                                            \
-  INTERCEPT_WHEN_POSSIBLE(#name, STRINGIFY(WEAK_EXPORT_NAME(name)), name)
-
-// We can't define our own version of strlen etc. because that would lead to
-// link-time or even type mismatch errors.  Instead, we can declare a function
-// just to be able to get its address.  Me may miss the first few calls to the
-// functions since it can be called before __dll_thunk_init, but that would lead
-// to false negatives in the startup code before user's global initializers,
-// which isn't a big deal.
-#define INTERCEPT_LIBRARY_FUNCTION(name)                                       \
-  extern "C" void name();                                                      \
-  INTERCEPT_OR_DIE(STRINGIFY(WRAP(name)), name)
-
-// Use these macros for functions that could be called before __dll_thunk_init()
-// is executed and don't lead to errors if defined (free, malloc, etc).
-#define INTERCEPT_WRAP_V_V(name)                                               \
-  extern "C" void name() {                                                     \
-    typedef decltype(name) *fntype;                                            \
-    static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
-    fn();                                                                      \
-  }                                                                            \
-  INTERCEPT_OR_DIE(#name, name);
-
-#define INTERCEPT_WRAP_V_W(name)                                               \
-  extern "C" void name(void *arg) {                                            \
-    typedef decltype(name) *fntype;                                            \
-    static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
-    fn(arg);                                                                   \
-  }                                                                            \
-  INTERCEPT_OR_DIE(#name, name);
-
-#define INTERCEPT_WRAP_V_WW(name)                                              \
-  extern "C" void name(void *arg1, void *arg2) {                               \
-    typedef decltype(name) *fntype;                                            \
-    static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
-    fn(arg1, arg2);                                                            \
-  }                                                                            \
-  INTERCEPT_OR_DIE(#name, name);
-
-#define INTERCEPT_WRAP_V_WWW(name)                                             \
-  extern "C" void name(void *arg1, void *arg2, void *arg3) {                   \
-    typedef decltype(name) *fntype;                                            \
-    static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
-    fn(arg1, arg2, arg3);                                                      \
-  }                                                                            \
-  INTERCEPT_OR_DIE(#name, name);
-
-#define INTERCEPT_WRAP_W_V(name)                                               \
-  extern "C" void *name() {                                                    \
-    typedef decltype(name) *fntype;                                            \
-    static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
-    return fn();                                                               \
-  }                                                                            \
-  INTERCEPT_OR_DIE(#name, name);
-
-#define INTERCEPT_WRAP_W_W(name)                                               \
-  extern "C" void *name(void *arg) {                                           \
-    typedef decltype(name) *fntype;                                            \
-    static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
-    return fn(arg);                                                            \
-  }                                                                            \
-  INTERCEPT_OR_DIE(#name, name);
-
-#define INTERCEPT_WRAP_W_WW(name)                                              \
-  extern "C" void *name(void *arg1, void *arg2) {                              \
-    typedef decltype(name) *fntype;                                            \
-    static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
-    return fn(arg1, arg2);                                                     \
-  }                                                                            \
-  INTERCEPT_OR_DIE(#name, name);
-
-#define INTERCEPT_WRAP_W_WWW(name)                                             \
-  extern "C" void *name(void *arg1, void *arg2, void *arg3) {                  \
-    typedef decltype(name) *fntype;                                            \
-    static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
-    return fn(arg1, arg2, arg3);                                               \
-  }                                                                            \
-  INTERCEPT_OR_DIE(#name, name);
-
-#define INTERCEPT_WRAP_W_WWWW(name)                                            \
-  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) {      \
-    typedef decltype(name) *fntype;                                            \
-    static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
-    return fn(arg1, arg2, arg3, arg4);                                         \
-  }                                                                            \
-  INTERCEPT_OR_DIE(#name, name);
-
-#define INTERCEPT_WRAP_W_WWWWW(name)                                           \
-  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4,        \
-                        void *arg5) {                                          \
-    typedef decltype(name) *fntype;                                            \
-    static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
-    return fn(arg1, arg2, arg3, arg4, arg5);                                   \
-  }                                                                            \
-  INTERCEPT_OR_DIE(#name, name);
-
-#define INTERCEPT_WRAP_W_WWWWWW(name)                                          \
-  extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4,        \
-                        void *arg5, void *arg6) {                              \
-    typedef decltype(name) *fntype;                                            \
-    static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name);   \
-    return fn(arg1, arg2, arg3, arg4, arg5, arg6);                             \
-  }                                                                            \
-  INTERCEPT_OR_DIE(#name, name);
-
-#endif // SANITIZER_WIN_DLL_THUNK_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cpp b/libsanitizer/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cpp
deleted file mode 100644
index 87c032c6e61b..000000000000
--- a/libsanitizer/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cpp
+++ /dev/null
@@ -1,26 +0,0 @@ 
-//===-- santizer_win_dynamic_runtime_thunk.cpp ----------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines things that need to be present in the application modules
-// to interact with Sanitizer Common, when it is included in a dll.
-//
-//===----------------------------------------------------------------------===//
-#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK
-#define SANITIZER_IMPORT_INTERFACE 1
-#include "sanitizer_win_defs.h"
-// Define weak alias for all weak functions imported from sanitizer common.
-#define INTERFACE_FUNCTION(Name)
-#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name)
-#include "sanitizer_common_interface.inc"
-#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK
-
-namespace __sanitizer {
-// Add one, otherwise unused, external symbol to this object file so that the
-// Visual C++ linker includes it and reads the .drective section.
-void ForceWholeArchiveIncludeForSanitizerCommon() {}
-}
diff --git a/libsanitizer/sanitizer_common/sanitizer_win_immortalize.h b/libsanitizer/sanitizer_common/sanitizer_win_immortalize.h
new file mode 100644
index 000000000000..808cd2f771fe
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_win_immortalize.h
@@ -0,0 +1,71 @@ 
+//===-- sanitizer_win_immortalize.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 shared between AddressSanitizer, and interception.
+//
+// Windows-specific thread-safe and pre-CRT global initialization safe
+// infrastructure to create an object whose destructor is never called.
+//===----------------------------------------------------------------------===//
+#if SANITIZER_WINDOWS
+#  pragma once
+// Requires including sanitizer_placement_new.h (which is not allowed to be
+// included in headers).
+
+#  include "sanitizer_win_defs.h"
+// These types are required to satisfy XFG which requires that the names of the
+// types for indirect calls to be correct as well as the name of the original
+// type for any typedefs.
+
+// TODO: There must be a better way to do this
+#  ifndef _WINDOWS_
+typedef void* PVOID;
+typedef int BOOL;
+typedef union _RTL_RUN_ONCE {
+  PVOID ptr;
+} INIT_ONCE, *PINIT_ONCE;
+
+extern "C" {
+__declspec(dllimport) int WINAPI InitOnceExecuteOnce(
+    PINIT_ONCE, BOOL(WINAPI*)(PINIT_ONCE, PVOID, PVOID*), void*, void*);
+}
+#  endif
+
+namespace __sanitizer {
+template <class Ty>
+BOOL WINAPI immortalize_impl(PINIT_ONCE, PVOID storage_ptr, PVOID*) noexcept {
+  // Ty must provide a placement new operator
+  new (storage_ptr) Ty();
+  return 1;
+}
+
+template <class Ty, typename Arg>
+BOOL WINAPI immortalize_impl(PINIT_ONCE, PVOID storage_ptr,
+                             PVOID* param) noexcept {
+  // Ty must provide a placement new operator
+  new (storage_ptr) Ty(*((Arg*)param));
+  return 1;
+}
+
+template <class Ty>
+Ty& immortalize() {  // return a reference to an object that will live forever
+  static INIT_ONCE flag;
+  alignas(Ty) static unsigned char storage[sizeof(Ty)];
+  InitOnceExecuteOnce(&flag, immortalize_impl<Ty>, &storage, nullptr);
+  return reinterpret_cast<Ty&>(storage);
+}
+
+template <class Ty, typename Arg>
+Ty& immortalize(
+    Arg arg) {  // return a reference to an object that will live forever
+  static INIT_ONCE flag;
+  alignas(Ty) static unsigned char storage[sizeof(Ty)];
+  InitOnceExecuteOnce(&flag, immortalize_impl<Ty, Arg>, &storage, &arg);
+  return reinterpret_cast<Ty&>(storage);
+}
+}  // namespace __sanitizer
+#endif  // SANITIZER_WINDOWS
diff --git a/libsanitizer/sanitizer_common/sanitizer_win_interception.cpp b/libsanitizer/sanitizer_common/sanitizer_win_interception.cpp
new file mode 100644
index 000000000000..c93a411ff2d6
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_win_interception.cpp
@@ -0,0 +1,156 @@ 
+//===-- sanitizer_win_interception.cpp --------------------    --*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Windows-specific export surface to provide interception for parts of the
+// runtime that are always statically linked, both for overriding user-defined
+// functions as well as registering weak functions that the ASAN runtime should
+// use over defaults.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_WINDOWS
+#  include <stddef.h>
+
+#  include "interception/interception.h"
+#  include "sanitizer_addrhashmap.h"
+#  include "sanitizer_common.h"
+#  include "sanitizer_internal_defs.h"
+#  include "sanitizer_placement_new.h"
+#  include "sanitizer_win_immortalize.h"
+#  include "sanitizer_win_interception.h"
+
+using namespace __sanitizer;
+
+extern "C" void *__ImageBase;
+
+namespace __sanitizer {
+
+static uptr GetSanitizerDllExport(const char *export_name) {
+  const uptr function_address =
+      __interception::InternalGetProcAddress(&__ImageBase, export_name);
+  if (function_address == 0) {
+    Report("ERROR: Failed to find sanitizer DLL export '%s'\n", export_name);
+    CHECK("Failed to find sanitizer DLL export" && 0);
+  }
+  return function_address;
+}
+
+struct WeakCallbackList {
+  explicit constexpr WeakCallbackList(RegisterWeakFunctionCallback cb)
+      : callback(cb), next(nullptr) {}
+
+  static void *operator new(size_t size) { return InternalAlloc(size); }
+
+  static void operator delete(void *p) { InternalFree(p); }
+
+  RegisterWeakFunctionCallback callback;
+  WeakCallbackList *next;
+};
+using WeakCallbackMap = AddrHashMap<WeakCallbackList *, 11>;
+
+static WeakCallbackMap *GetWeakCallbackMap() {
+  return &immortalize<WeakCallbackMap>();
+}
+
+void AddRegisterWeakFunctionCallback(uptr export_address,
+                                     RegisterWeakFunctionCallback cb) {
+  WeakCallbackMap::Handle h_find_or_create(GetWeakCallbackMap(), export_address,
+                                           false, true);
+  CHECK(h_find_or_create.exists());
+  if (h_find_or_create.created()) {
+    *h_find_or_create = new WeakCallbackList(cb);
+  } else {
+    (*h_find_or_create)->next = new WeakCallbackList(cb);
+  }
+}
+
+static void RunWeakFunctionCallbacks(uptr export_address) {
+  WeakCallbackMap::Handle h_find(GetWeakCallbackMap(), export_address, false,
+                                 false);
+  if (!h_find.exists()) {
+    return;
+  }
+
+  WeakCallbackList *list = *h_find;
+  do {
+    list->callback();
+  } while ((list = list->next));
+}
+
+}  // namespace __sanitizer
+
+extern "C" __declspec(dllexport) bool __cdecl __sanitizer_override_function(
+    const char *export_name, const uptr user_function,
+    uptr *const old_user_function) {
+  CHECK(export_name);
+  CHECK(user_function);
+
+  const uptr sanitizer_function = GetSanitizerDllExport(export_name);
+
+  const bool function_overridden = __interception::OverrideFunction(
+      user_function, sanitizer_function, old_user_function);
+  if (!function_overridden) {
+    Report(
+        "ERROR: Failed to override local function at '%p' with sanitizer "
+        "function '%s'\n",
+        user_function, export_name);
+    CHECK("Failed to replace local function with sanitizer version." && 0);
+  }
+
+  return function_overridden;
+}
+
+extern "C"
+    __declspec(dllexport) bool __cdecl __sanitizer_override_function_by_addr(
+        const uptr source_function, const uptr target_function,
+        uptr *const old_target_function) {
+  CHECK(source_function);
+  CHECK(target_function);
+
+  const bool function_overridden = __interception::OverrideFunction(
+      target_function, source_function, old_target_function);
+  if (!function_overridden) {
+    Report(
+        "ERROR: Failed to override function at '%p' with function at "
+        "'%p'\n",
+        target_function, source_function);
+    CHECK("Failed to apply function override." && 0);
+  }
+
+  return function_overridden;
+}
+
+extern "C"
+    __declspec(dllexport) bool __cdecl __sanitizer_register_weak_function(
+        const char *export_name, const uptr user_function,
+        uptr *const old_user_function) {
+  CHECK(export_name);
+  CHECK(user_function);
+
+  const uptr sanitizer_function = GetSanitizerDllExport(export_name);
+
+  const bool function_overridden = __interception::OverrideFunction(
+      sanitizer_function, user_function, old_user_function);
+  if (!function_overridden) {
+    Report(
+        "ERROR: Failed to register local function at '%p' to be used in "
+        "place of sanitizer function '%s'\n.",
+        user_function, export_name);
+    CHECK("Failed to register weak function." && 0);
+  }
+
+  // Note that thread-safety of RunWeakFunctionCallbacks in InitializeFlags
+  // depends on __sanitizer_register_weak_functions being called during the
+  // loader lock.
+  RunWeakFunctionCallbacks(sanitizer_function);
+
+  return function_overridden;
+}
+
+#endif  // SANITIZER_WINDOWS
diff --git a/libsanitizer/sanitizer_common/sanitizer_win_interception.h b/libsanitizer/sanitizer_common/sanitizer_win_interception.h
new file mode 100644
index 000000000000..04b7e910a1dd
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_win_interception.h
@@ -0,0 +1,32 @@ 
+//===-- sanitizer_win_interception.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
+//
+//===----------------------------------------------------------------------===//
+//
+// Windows-specific export surface to provide interception for parts of the
+// runtime that are always statically linked, both for overriding user-defined
+// functions as well as registering weak functions that the ASAN runtime should
+// use over defaults.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_WIN_INTERCEPTION_H
+#define SANITIZER_WIN_INTERCEPTION_H
+
+#include "sanitizer_platform.h"
+#if SANITIZER_WINDOWS
+
+#  include "sanitizer_common.h"
+#  include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+using RegisterWeakFunctionCallback = void (*)();
+void AddRegisterWeakFunctionCallback(uptr export_address,
+                                     RegisterWeakFunctionCallback cb);
+}  // namespace __sanitizer
+
+#endif  // SANITIZER_WINDOWS
+#endif  // SANITIZER_WIN_INTERCEPTION_H
\ No newline at end of file
diff --git a/libsanitizer/sanitizer_common/sanitizer_win_thunk_interception.cpp b/libsanitizer/sanitizer_common/sanitizer_win_thunk_interception.cpp
new file mode 100644
index 000000000000..16ba155630b0
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_win_thunk_interception.cpp
@@ -0,0 +1,110 @@ 
+//===-- sanitizer_win_thunk_interception.cpp -----------------------  -----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines things that need to be present in the application modules
+// to interact with sanitizer DLL correctly and cannot be implemented using the
+// default "import library" generated when linking the DLL.
+//
+// This includes the common infrastructure required to intercept local functions
+// that must be replaced with sanitizer-aware versions, as well as the
+// registration of weak functions with the sanitizer DLL. With this in-place,
+// other sanitizer components can simply write to the .INTR and .WEAK sections.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(SANITIZER_STATIC_RUNTIME_THUNK) || \
+    defined(SANITIZER_DYNAMIC_RUNTIME_THUNK)
+#  include "sanitizer_win_thunk_interception.h"
+
+extern "C" void abort();
+
+namespace __sanitizer {
+
+int override_function(const char *export_name, const uptr user_function) {
+  if (!__sanitizer_override_function(export_name, user_function)) {
+    abort();
+  }
+
+  return 0;
+}
+
+int register_weak(const char *export_name, const uptr user_function) {
+  if (!__sanitizer_register_weak_function(export_name, user_function)) {
+    abort();
+  }
+
+  return 0;
+}
+
+void initialize_thunks(const sanitizer_thunk *first,
+                       const sanitizer_thunk *last) {
+  for (const sanitizer_thunk *it = first; it < last; ++it) {
+    if (*it) {
+      (*it)();
+    }
+  }
+}
+}  // namespace __sanitizer
+
+#  define INTERFACE_FUNCTION(Name)
+#  define INTERFACE_WEAK_FUNCTION(Name) REGISTER_WEAK_FUNCTION(Name)
+#  include "sanitizer_common_interface.inc"
+
+#  pragma section(".INTR$A", read)  // intercept begin
+#  pragma section(".INTR$Z", read)  // intercept end
+#  pragma section(".WEAK$A", read)  // weak begin
+#  pragma section(".WEAK$Z", read)  // weak end
+
+extern "C" {
+__declspec(allocate(
+    ".INTR$A")) sanitizer_thunk __sanitizer_intercept_thunk_begin;
+__declspec(allocate(".INTR$Z")) sanitizer_thunk __sanitizer_intercept_thunk_end;
+
+__declspec(allocate(
+    ".WEAK$A")) sanitizer_thunk __sanitizer_register_weak_thunk_begin;
+__declspec(allocate(
+    ".WEAK$Z")) sanitizer_thunk __sanitizer_register_weak_thunk_end;
+}
+
+extern "C" int __sanitizer_thunk_init() {
+  // __sanitizer_static_thunk_init is expected to be called by only one thread.
+  static bool flag = false;
+  if (flag) {
+    return 0;
+  }
+  flag = true;
+
+  __sanitizer::initialize_thunks(&__sanitizer_intercept_thunk_begin,
+                                 &__sanitizer_intercept_thunk_end);
+  __sanitizer::initialize_thunks(&__sanitizer_register_weak_thunk_begin,
+                                 &__sanitizer_register_weak_thunk_end);
+
+  // In DLLs, the callbacks are expected to return 0,
+  // otherwise CRT initialization fails.
+  return 0;
+}
+
+// We want to call dll_thunk_init before C/C++ initializers / constructors are
+// executed, otherwise functions like memset might be invoked.
+#  pragma section(".CRT$XIB", long, read)
+__declspec(allocate(".CRT$XIB")) int (*__sanitizer_thunk_init_ptr)() =
+    __sanitizer_thunk_init;
+
+static void WINAPI sanitizer_thunk_thread_init(void *mod, unsigned long reason,
+                                               void *reserved) {
+  if (reason == /*DLL_PROCESS_ATTACH=*/1)
+    __sanitizer_thunk_init();
+}
+
+#  pragma section(".CRT$XLAB", long, read)
+__declspec(allocate(".CRT$XLAB")) void(
+    WINAPI *__sanitizer_thunk_thread_init_ptr)(void *, unsigned long, void *) =
+    sanitizer_thunk_thread_init;
+
+#endif  // defined(SANITIZER_STATIC_RUNTIME_THUNK) ||
+        // defined(SANITIZER_DYNAMIC_RUNTIME_THUNK)
\ No newline at end of file
diff --git a/libsanitizer/sanitizer_common/sanitizer_win_thunk_interception.h b/libsanitizer/sanitizer_common/sanitizer_win_thunk_interception.h
new file mode 100644
index 000000000000..278450d68ac5
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_win_thunk_interception.h
@@ -0,0 +1,88 @@ 
+//===-- sanitizer_win_thunk_interception.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 header provide helper macros and functions to delegate calls to the
+// shared runtime that lives in the sanitizer DLL.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_WIN_THUNK_INTERCEPTION_H
+#define SANITIZER_WIN_THUNK_INTERCEPTION_H
+#include <stdint.h>
+
+#include "sanitizer_internal_defs.h"
+
+extern "C" {
+__declspec(dllimport) bool __cdecl __sanitizer_override_function(
+    const char *export_name, __sanitizer::uptr user_function,
+    __sanitizer::uptr *old_function = nullptr);
+__declspec(dllimport) bool __cdecl __sanitizer_override_function_by_addr(
+    __sanitizer::uptr source_function, __sanitizer::uptr target_function,
+    __sanitizer::uptr *old_target_function = nullptr);
+__declspec(dllimport) bool __cdecl __sanitizer_register_weak_function(
+    const char *export_name, __sanitizer::uptr user_function,
+    __sanitizer::uptr *old_function = nullptr);
+}
+
+using sanitizer_thunk = int (*)();
+
+namespace __sanitizer {
+int override_function(const char *export_name, uptr user_function);
+int register_weak(const char *export_name, uptr user_function);
+void initialize_thunks(const sanitizer_thunk *begin,
+                       const sanitizer_thunk *end);
+}  // namespace __sanitizer
+
+// -------------------- Function interception macros ------------------------ //
+// We can't define our own version of strlen etc. because that would lead to
+// link-time or even type mismatch errors.  Instead, we can declare a function
+// just to be able to get its address.  Me may miss the first few calls to the
+// functions since it can be called before __dll_thunk_init, but that would lead
+// to false negatives in the startup code before user's global initializers,
+// which isn't a big deal.
+// Use .INTR segment to register function pointers that are iterated over during
+// startup that will replace local_function with sanitizer_export.
+
+#define INTERCEPT_LIBRARY_FUNCTION(local_function, sanitizer_export)   \
+  extern "C" void local_function();                                    \
+  static int intercept_##local_function() {                            \
+    return __sanitizer::override_function(                             \
+        sanitizer_export,                                              \
+        reinterpret_cast<__sanitizer::uptr>(local_function));          \
+  }                                                                    \
+  __pragma(section(".INTR$M", long, read)) __declspec(allocate(        \
+      ".INTR$M")) int (*__sanitizer_static_thunk_##local_function)() = \
+      intercept_##local_function;
+
+// ------------------ Weak symbol registration macros ---------------------- //
+// Use .WEAK segment to register function pointers that are iterated over during
+// startup that will replace sanitizer_export with local_function
+#ifdef __clang__
+#  define REGISTER_WEAK_OPTNONE __attribute__((optnone))
+#  define REGISTER_WEAK_FUNCTION_ADDRESS(fn) __builtin_function_start(fn)
+#else
+#  define REGISTER_WEAK_OPTNONE
+#  define REGISTER_WEAK_FUNCTION_ADDRESS(fn) &fn
+#endif
+
+#define REGISTER_WEAK_FUNCTION(local_function)                          \
+  extern "C" void local_function();                                     \
+  extern "C" void WEAK_EXPORT_NAME(local_function)();                   \
+  WIN_WEAK_IMPORT_DEF(local_function)                                   \
+  REGISTER_WEAK_OPTNONE static int register_weak_##local_function() {   \
+    if ((uintptr_t)REGISTER_WEAK_FUNCTION_ADDRESS(local_function) !=    \
+        (uintptr_t)REGISTER_WEAK_FUNCTION_ADDRESS(                      \
+            WEAK_EXPORT_NAME(local_function))) {                        \
+      return __sanitizer::register_weak(                                \
+          SANITIZER_STRINGIFY(WEAK_EXPORT_NAME(local_function)),        \
+          reinterpret_cast<__sanitizer::uptr>(local_function));         \
+    }                                                                   \
+    return 0;                                                           \
+  }                                                                     \
+  __pragma(section(".WEAK$M", long, read)) __declspec(allocate(         \
+      ".WEAK$M")) int (*__sanitizer_register_weak_##local_function)() = \
+      register_weak_##local_function;
+#endif  // SANITIZER_WIN_STATIC_RUNTIME_THUNK_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_win_weak_interception.cpp b/libsanitizer/sanitizer_common/sanitizer_win_weak_interception.cpp
deleted file mode 100644
index b14bbf76d9a7..000000000000
--- a/libsanitizer/sanitizer_common/sanitizer_win_weak_interception.cpp
+++ /dev/null
@@ -1,94 +0,0 @@ 
-//===-- sanitizer_win_weak_interception.cpp -------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// This module should be included in the sanitizer when it is implemented as a
-// shared library on Windows (dll), in order to delegate the calls of weak
-// functions to the implementation in the main executable when a strong
-// definition is provided.
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_platform.h"
-#if SANITIZER_WINDOWS && SANITIZER_DYNAMIC
-#include "sanitizer_win_weak_interception.h"
-#include "sanitizer_allocator_interface.h"
-#include "sanitizer_interface_internal.h"
-#include "sanitizer_win_defs.h"
-#include "interception/interception.h"
-
-extern "C" {
-void *WINAPI GetModuleHandleA(const char *module_name);
-void abort();
-}
-
-namespace __sanitizer {
-// Try to get a pointer to real_function in the main module and override
-// dll_function with that pointer. If the function isn't found, nothing changes.
-int interceptWhenPossible(uptr dll_function, const char *real_function) {
-  uptr real = __interception::InternalGetProcAddress(
-      (void *)GetModuleHandleA(0), real_function);
-  if (real && !__interception::OverrideFunction((uptr)dll_function, real, 0))
-    abort();
-  return 0;
-}
-} // namespace __sanitizer
-
-// Declare weak hooks.
-extern "C" {
-void __sanitizer_on_print(const char *str);
-void __sanitizer_weak_hook_memcmp(uptr called_pc, const void *s1,
-                                  const void *s2, uptr n, int result);
-void __sanitizer_weak_hook_strcmp(uptr called_pc, const char *s1,
-                                  const char *s2, int result);
-void __sanitizer_weak_hook_strncmp(uptr called_pc, const char *s1,
-                                   const char *s2, uptr n, int result);
-void __sanitizer_weak_hook_strstr(uptr called_pc, const char *s1,
-                                  const char *s2, char *result);
-}
-
-// Include Sanitizer Common interface.
-#define INTERFACE_FUNCTION(Name)
-#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
-#include "sanitizer_common_interface.inc"
-
-#pragma section(".WEAK$A", read)
-#pragma section(".WEAK$Z", read)
-
-typedef void (*InterceptCB)();
-extern "C" {
-__declspec(allocate(".WEAK$A")) InterceptCB __start_weak_list;
-__declspec(allocate(".WEAK$Z")) InterceptCB __stop_weak_list;
-}
-
-static int weak_intercept_init() {
-  static bool flag = false;
-  // weak_interception_init is expected to be called by only one thread.
-  if (flag) return 0;
-  flag = true;
-
-  for (InterceptCB *it = &__start_weak_list; it < &__stop_weak_list; ++it)
-    if (*it)
-      (*it)();
-
-  // In DLLs, the callbacks are expected to return 0,
-  // otherwise CRT initialization fails.
-  return 0;
-}
-
-#pragma section(".CRT$XIB", long, read)
-__declspec(allocate(".CRT$XIB")) int (*__weak_intercept_preinit)() =
-    weak_intercept_init;
-
-static void WINAPI weak_intercept_thread_init(void *mod, unsigned long reason,
-                                              void *reserved) {
-  if (reason == /*DLL_PROCESS_ATTACH=*/1) weak_intercept_init();
-}
-
-#pragma section(".CRT$XLAB", long, read)
-__declspec(allocate(".CRT$XLAB")) void(WINAPI *__weak_intercept_tls_init)(
-    void *, unsigned long, void *) = weak_intercept_thread_init;
-
-#endif // SANITIZER_WINDOWS && SANITIZER_DYNAMIC
diff --git a/libsanitizer/sanitizer_common/sanitizer_win_weak_interception.h b/libsanitizer/sanitizer_common/sanitizer_win_weak_interception.h
deleted file mode 100644
index 5e4d8b8def3e..000000000000
--- a/libsanitizer/sanitizer_common/sanitizer_win_weak_interception.h
+++ /dev/null
@@ -1,32 +0,0 @@ 
-//===-- sanitizer_win_weak_interception.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 header provide helper macros to delegate calls of weak functions to the
-// implementation in the main executable when a strong definition is present.
-//===----------------------------------------------------------------------===//
-#ifndef SANITIZER_WIN_WEAK_INTERCEPTION_H
-#define SANITIZER_WIN_WEAK_INTERCEPTION_H
-#include "sanitizer_internal_defs.h"
-
-namespace __sanitizer {
-int interceptWhenPossible(uptr dll_function, const char *real_function);
-}
-
-// ----------------- Function interception helper macros -------------------- //
-// Weak functions, could be redefined in the main executable, but that is not
-// necessary, so we shouldn't die if we can not find a reference.
-#define INTERCEPT_WEAK(Name) interceptWhenPossible((uptr) Name, #Name);
-
-#define INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)                                \
-  static int intercept_##Name() {                                              \
-    return __sanitizer::interceptWhenPossible((__sanitizer::uptr) Name, #Name);\
-  }                                                                            \
-  __pragma(section(".WEAK$M", long, read))                                     \
-  __declspec(allocate(".WEAK$M")) int (*__weak_intercept_##Name)() =           \
-      intercept_##Name;
-
-#endif // SANITIZER_WIN_WEAK_INTERCEPTION_H
diff --git a/libsanitizer/tsan/tsan_defs.h b/libsanitizer/tsan/tsan_defs.h
index 1ffa3d6aec40..270d441dc90b 100644
--- a/libsanitizer/tsan/tsan_defs.h
+++ b/libsanitizer/tsan/tsan_defs.h
@@ -30,7 +30,7 @@ 
 #  define __MM_MALLOC_H
 #  include <emmintrin.h>
 #  include <smmintrin.h>
-#  define VECTOR_ALIGNED ALIGNED(16)
+#  define VECTOR_ALIGNED alignas(16)
 typedef __m128i m128;
 #else
 #  define VECTOR_ALIGNED
diff --git a/libsanitizer/tsan/tsan_dispatch_defs.h b/libsanitizer/tsan/tsan_dispatch_defs.h
index 54c0b0ba4b40..8d38beb0b0a2 100644
--- a/libsanitizer/tsan/tsan_dispatch_defs.h
+++ b/libsanitizer/tsan/tsan_dispatch_defs.h
@@ -56,13 +56,6 @@  extern const dispatch_block_t _dispatch_data_destructor_munmap;
 # define DISPATCH_NOESCAPE
 #endif
 
-#if SANITIZER_APPLE
-# define SANITIZER_WEAK_IMPORT extern "C" __attribute((weak_import))
-#else
-# define SANITIZER_WEAK_IMPORT extern "C" __attribute((weak))
-#endif
-
-
 // Data types used in dispatch APIs
 typedef unsigned long size_t;
 typedef unsigned long uintptr_t;
diff --git a/libsanitizer/tsan/tsan_interceptors_mac.cpp b/libsanitizer/tsan/tsan_interceptors_mac.cpp
index e4f9e2915ced..9db0eebd9236 100644
--- a/libsanitizer/tsan/tsan_interceptors_mac.cpp
+++ b/libsanitizer/tsan/tsan_interceptors_mac.cpp
@@ -94,6 +94,10 @@  static constexpr morder kMacFailureOrder = mo_relaxed;
   m_orig(int32_t, uint32_t, a32, f##32##OrigBarrier,                           \
     __tsan_atomic32_##tsan_atomic_f, kMacOrderBarrier)
 
+
+#pragma clang diagnostic push
+// OSAtomic* functions are deprecated.
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
 OSATOMIC_INTERCEPTORS_ARITHMETIC(OSAtomicAdd, fetch_add,
                                  OSATOMIC_INTERCEPTOR_PLUS_X)
 OSATOMIC_INTERCEPTORS_ARITHMETIC(OSAtomicIncrement, fetch_add,
@@ -123,6 +127,9 @@  OSATOMIC_INTERCEPTORS_BITWISE(OSAtomicXor, fetch_xor,
         kMacOrderBarrier, kMacFailureOrder);                                \
   }
 
+#pragma clang diagnostic push
+// OSAtomicCompareAndSwap* functions are deprecated.
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
 OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwapInt, __tsan_atomic32, a32, int)
 OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwapLong, __tsan_atomic64, a64,
                           long_t)
@@ -132,6 +139,7 @@  OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwap32, __tsan_atomic32, a32,
                           int32_t)
 OSATOMIC_INTERCEPTORS_CAS(OSAtomicCompareAndSwap64, __tsan_atomic64, a64,
                           int64_t)
+#pragma clang diagnostic pop
 
 #define OSATOMIC_INTERCEPTOR_BITOP(f, op, clear, mo)             \
   TSAN_INTERCEPTOR(bool, f, uint32_t n, volatile void *ptr) {    \
diff --git a/libsanitizer/tsan/tsan_interceptors_posix.cpp b/libsanitizer/tsan/tsan_interceptors_posix.cpp
index 80f86ca98ed9..423d97e94d81 100644
--- a/libsanitizer/tsan/tsan_interceptors_posix.cpp
+++ b/libsanitizer/tsan/tsan_interceptors_posix.cpp
@@ -12,13 +12,15 @@ 
 // sanitizer_common/sanitizer_common_interceptors.inc
 //===----------------------------------------------------------------------===//
 
+#include "sanitizer_common/sanitizer_allocator_dlsym.h"
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_errno.h"
+#include "sanitizer_common/sanitizer_glibc_version.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_linux.h"
 #include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
 #include "sanitizer_common/sanitizer_platform_limits_posix.h"
-#include "sanitizer_common/sanitizer_placement_new.h"
 #include "sanitizer_common/sanitizer_posix.h"
 #include "sanitizer_common/sanitizer_stacktrace.h"
 #include "sanitizer_common/sanitizer_tls_get_addr.h"
@@ -207,7 +209,7 @@  struct AtExitCtx {
 struct InterceptorContext {
   // The object is 64-byte aligned, because we want hot data to be located
   // in a single cache line if possible (it's accessed in every interceptor).
-  ALIGNED(64) LibIgnore libignore;
+  alignas(64) LibIgnore libignore;
   __sanitizer_sigaction sigactions[kSigCount];
 #if !SANITIZER_APPLE && !SANITIZER_NETBSD
   unsigned finalize_key;
@@ -219,7 +221,7 @@  struct InterceptorContext {
   InterceptorContext() : libignore(LINKER_INITIALIZED), atexit_mu(MutexTypeAtExit), AtExitStack() {}
 };
 
-static ALIGNED(64) char interceptor_placeholder[sizeof(InterceptorContext)];
+alignas(64) static char interceptor_placeholder[sizeof(InterceptorContext)];
 InterceptorContext *interceptor_ctx() {
   return reinterpret_cast<InterceptorContext*>(&interceptor_placeholder[0]);
 }
@@ -251,6 +253,13 @@  SANITIZER_WEAK_CXX_DEFAULT_IMPL void OnPotentiallyBlockingRegionBegin() {}
 SANITIZER_WEAK_CXX_DEFAULT_IMPL void OnPotentiallyBlockingRegionEnd() {}
 #endif
 
+// FIXME: Use for `in_symbolizer()` as well. As-is we can't use
+// `DlSymAllocator`, because it uses the primary allocator only. Symbolizer
+// requires support of the secondary allocator for larger blocks.
+struct DlsymAlloc : public DlSymAllocator<DlsymAlloc> {
+  static bool UseImpl() { return (ctx && !ctx->initialized); }
+};
+
 }  // namespace __tsan
 
 static ThreadSignalContext *SigCtx(ThreadState *thr) {
@@ -660,6 +669,8 @@  TSAN_INTERCEPTOR(void, _longjmp, uptr *env, int val) {
 TSAN_INTERCEPTOR(void*, malloc, uptr size) {
   if (in_symbolizer())
     return InternalAlloc(size);
+  if (DlsymAlloc::Use())
+    return DlsymAlloc::Allocate(size);
   void *p = 0;
   {
     SCOPED_INTERCEPTOR_RAW(malloc, size);
@@ -677,12 +688,14 @@  TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) {
   return user_memalign(thr, pc, align, sz);
 }
 
-TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
+TSAN_INTERCEPTOR(void *, calloc, uptr n, uptr size) {
   if (in_symbolizer())
-    return InternalCalloc(size, n);
+    return InternalCalloc(n, size);
+  if (DlsymAlloc::Use())
+    return DlsymAlloc::Callocate(n, size);
   void *p = 0;
   {
-    SCOPED_INTERCEPTOR_RAW(calloc, size, n);
+    SCOPED_INTERCEPTOR_RAW(calloc, n, size);
     p = user_calloc(thr, pc, size, n);
   }
   invoke_malloc_hook(p, n * size);
@@ -692,6 +705,8 @@  TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
 TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) {
   if (in_symbolizer())
     return InternalRealloc(p, size);
+  if (DlsymAlloc::Use() || DlsymAlloc::PointerIsMine(p))
+    return DlsymAlloc::Realloc(p, size);
   if (p)
     invoke_free_hook(p);
   {
@@ -702,13 +717,13 @@  TSAN_INTERCEPTOR(void*, realloc, void *p, uptr size) {
   return p;
 }
 
-TSAN_INTERCEPTOR(void*, reallocarray, void *p, uptr size, uptr n) {
+TSAN_INTERCEPTOR(void *, reallocarray, void *p, uptr n, uptr size) {
   if (in_symbolizer())
-    return InternalReallocArray(p, size, n);
+    return InternalReallocArray(p, n, size);
   if (p)
     invoke_free_hook(p);
   {
-    SCOPED_INTERCEPTOR_RAW(reallocarray, p, size, n);
+    SCOPED_INTERCEPTOR_RAW(reallocarray, p, n, size);
     p = user_reallocarray(thr, pc, p, size, n);
   }
   invoke_malloc_hook(p, size);
@@ -716,20 +731,24 @@  TSAN_INTERCEPTOR(void*, reallocarray, void *p, uptr size, uptr n) {
 }
 
 TSAN_INTERCEPTOR(void, free, void *p) {
-  if (p == 0)
+  if (UNLIKELY(!p))
     return;
   if (in_symbolizer())
     return InternalFree(p);
+  if (DlsymAlloc::PointerIsMine(p))
+    return DlsymAlloc::Free(p);
   invoke_free_hook(p);
   SCOPED_INTERCEPTOR_RAW(free, p);
   user_free(thr, pc, p);
 }
 
 TSAN_INTERCEPTOR(void, cfree, void *p) {
-  if (p == 0)
+  if (UNLIKELY(!p))
     return;
   if (in_symbolizer())
     return InternalFree(p);
+  if (DlsymAlloc::PointerIsMine(p))
+    return DlsymAlloc::Free(p);
   invoke_free_hook(p);
   SCOPED_INTERCEPTOR_RAW(cfree, p);
   user_free(thr, pc, p);
@@ -1087,7 +1106,18 @@  TSAN_INTERCEPTOR(int, pthread_join, void *th, void **ret) {
   return res;
 }
 
-DEFINE_REAL_PTHREAD_FUNCTIONS
+// DEFINE_INTERNAL_PTHREAD_FUNCTIONS
+namespace __sanitizer {
+int internal_pthread_create(void *th, void *attr, void *(*callback)(void *),
+                            void *param) {
+  ScopedIgnoreInterceptors ignore;
+  return REAL(pthread_create)(th, attr, callback, param);
+}
+int internal_pthread_join(void *th, void **ret) {
+  ScopedIgnoreInterceptors ignore;
+  return REAL(pthread_join)(th, ret);
+}
+}  // namespace __sanitizer
 
 TSAN_INTERCEPTOR(int, pthread_detach, void *th) {
   SCOPED_INTERCEPTOR_RAW(pthread_detach, th);
@@ -1340,7 +1370,7 @@  TSAN_INTERCEPTOR(int, pthread_mutex_destroy, void *m) {
 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);
+  int res = BLOCK_REAL(pthread_mutex_lock)(m);
   if (res == errno_EOWNERDEAD)
     MutexRepair(thr, pc, (uptr)m);
   if (res == 0 || res == errno_EOWNERDEAD)
@@ -1380,6 +1410,22 @@  TSAN_INTERCEPTOR(int, pthread_mutex_unlock, void *m) {
   return res;
 }
 
+#if SANITIZER_LINUX
+TSAN_INTERCEPTOR(int, pthread_mutex_clocklock, void *m,
+                 __sanitizer_clockid_t clock, void *abstime) {
+  SCOPED_TSAN_INTERCEPTOR(pthread_mutex_clocklock, m, clock, abstime);
+  MutexPreLock(thr, pc, (uptr)m);
+  int res = BLOCK_REAL(pthread_mutex_clocklock)(m, clock, abstime);
+  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;
+}
+#endif
+
 #if SANITIZER_GLIBC
 #  if !__GLIBC_PREREQ(2, 34)
 // glibc 2.34 applies a non-default version for the two functions. They are no
@@ -1387,7 +1433,7 @@  TSAN_INTERCEPTOR(int, pthread_mutex_unlock, void *m) {
 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);
+  int res = BLOCK_REAL(__pthread_mutex_lock)(m);
   if (res == errno_EOWNERDEAD)
     MutexRepair(thr, pc, (uptr)m);
   if (res == 0 || res == errno_EOWNERDEAD)
@@ -1430,7 +1476,7 @@  TSAN_INTERCEPTOR(int, pthread_spin_destroy, void *m) {
 TSAN_INTERCEPTOR(int, pthread_spin_lock, void *m) {
   SCOPED_TSAN_INTERCEPTOR(pthread_spin_lock, m);
   MutexPreLock(thr, pc, (uptr)m);
-  int res = REAL(pthread_spin_lock)(m);
+  int res = BLOCK_REAL(pthread_spin_lock)(m);
   if (res == 0) {
     MutexPostLock(thr, pc, (uptr)m);
   }
@@ -1505,7 +1551,7 @@  TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) {
 TSAN_INTERCEPTOR(int, pthread_rwlock_wrlock, void *m) {
   SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_wrlock, m);
   MutexPreLock(thr, pc, (uptr)m);
-  int res = REAL(pthread_rwlock_wrlock)(m);
+  int res = BLOCK_REAL(pthread_rwlock_wrlock)(m);
   if (res == 0) {
     MutexPostLock(thr, pc, (uptr)m);
   }
@@ -1597,57 +1643,60 @@  TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
     FdAccess(thr, pc, fd);
   return REAL(__fxstat)(version, fd, buf);
 }
-#define TSAN_MAYBE_INTERCEPT___FXSTAT TSAN_INTERCEPT(__fxstat)
+
+TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
+  SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf);
+  if (fd > 0)
+    FdAccess(thr, pc, fd);
+  return REAL(__fxstat64)(version, fd, buf);
+}
+#define TSAN_MAYBE_INTERCEPT___FXSTAT TSAN_INTERCEPT(__fxstat); TSAN_INTERCEPT(__fxstat64)
 #else
 #define TSAN_MAYBE_INTERCEPT___FXSTAT
 #endif
 
+#if !SANITIZER_GLIBC || __GLIBC_PREREQ(2, 33)
 TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
-#if SANITIZER_GLIBC
-  SCOPED_TSAN_INTERCEPTOR(__fxstat, 0, fd, buf);
-  if (fd > 0)
-    FdAccess(thr, pc, fd);
-  return REAL(__fxstat)(0, fd, buf);
-#else
   SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf);
   if (fd > 0)
     FdAccess(thr, pc, fd);
   return REAL(fstat)(fd, buf);
-#endif
 }
-
-#if SANITIZER_GLIBC
-TSAN_INTERCEPTOR(int, __fxstat64, int version, int fd, void *buf) {
-  SCOPED_TSAN_INTERCEPTOR(__fxstat64, version, fd, buf);
-  if (fd > 0)
-    FdAccess(thr, pc, fd);
-  return REAL(__fxstat64)(version, fd, buf);
-}
-#define TSAN_MAYBE_INTERCEPT___FXSTAT64 TSAN_INTERCEPT(__fxstat64)
+#  define TSAN_MAYBE_INTERCEPT_FSTAT TSAN_INTERCEPT(fstat)
 #else
-#define TSAN_MAYBE_INTERCEPT___FXSTAT64
+#  define TSAN_MAYBE_INTERCEPT_FSTAT
 #endif
 
-#if SANITIZER_GLIBC
+#if __GLIBC_PREREQ(2, 33)
 TSAN_INTERCEPTOR(int, fstat64, int fd, void *buf) {
-  SCOPED_TSAN_INTERCEPTOR(__fxstat64, 0, fd, buf);
+  SCOPED_TSAN_INTERCEPTOR(fstat64, fd, buf);
   if (fd > 0)
     FdAccess(thr, pc, fd);
-  return REAL(__fxstat64)(0, fd, buf);
+  return REAL(fstat64)(fd, buf);
 }
-#define TSAN_MAYBE_INTERCEPT_FSTAT64 TSAN_INTERCEPT(fstat64)
+#  define TSAN_MAYBE_INTERCEPT_FSTAT64 TSAN_INTERCEPT(fstat64)
 #else
-#define TSAN_MAYBE_INTERCEPT_FSTAT64
+#  define TSAN_MAYBE_INTERCEPT_FSTAT64
 #endif
 
 TSAN_INTERCEPTOR(int, open, const char *name, int oflag, ...) {
-  va_list ap;
-  va_start(ap, oflag);
-  mode_t mode = va_arg(ap, int);
-  va_end(ap);
+  mode_t mode = 0;
+  if (OpenReadsVaArgs(oflag)) {
+    va_list ap;
+    va_start(ap, oflag);
+    mode = va_arg(ap, int);
+    va_end(ap);
+  }
+
   SCOPED_TSAN_INTERCEPTOR(open, name, oflag, mode);
   READ_STRING(thr, pc, name, 0);
-  int fd = REAL(open)(name, oflag, mode);
+
+  int fd;
+  if (OpenReadsVaArgs(oflag))
+    fd = REAL(open)(name, oflag, mode);
+  else
+    fd = REAL(open)(name, oflag);
+
   if (fd >= 0)
     FdFileCreate(thr, pc, fd);
   return fd;
@@ -2657,6 +2706,25 @@  static USED void syscall_fd_release(uptr pc, int fd) {
   FdRelease(thr, pc, fd);
 }
 
+static USED void sycall_blocking_start() {
+  DPrintf("sycall_blocking_start()\n");
+  ThreadState *thr = cur_thread();
+  EnterBlockingFunc(thr);
+  // When we are in a "blocking call", we process signals asynchronously
+  // (right when they arrive). In this context we do not expect to be
+  // executing any user/runtime code. The known interceptor sequence when
+  // this is not true is: pthread_join -> munmap(stack). It's fine
+  // to ignore munmap in this case -- we handle stack shadow separately.
+  thr->ignore_interceptors++;
+}
+
+static USED void sycall_blocking_end() {
+  DPrintf("sycall_blocking_end()\n");
+  ThreadState *thr = cur_thread();
+  thr->ignore_interceptors--;
+  atomic_store(&thr->in_blocking_func, 0, memory_order_relaxed);
+}
+
 static void syscall_pre_fork(uptr pc) { ForkBefore(cur_thread(), pc); }
 
 static void syscall_post_fork(uptr pc, int pid) {
@@ -2711,6 +2779,9 @@  static void syscall_post_fork(uptr pc, int pid) {
 #define COMMON_SYSCALL_POST_FORK(res) \
   syscall_post_fork(GET_CALLER_PC(), res)
 
+#define COMMON_SYSCALL_BLOCKING_START() sycall_blocking_start()
+#define COMMON_SYSCALL_BLOCKING_END() sycall_blocking_end()
+
 #include "sanitizer_common/sanitizer_common_syscalls.inc"
 #include "sanitizer_common/sanitizer_syscalls_netbsd.inc"
 
@@ -2845,8 +2916,21 @@  void InitializeInterceptors() {
   REAL(memcpy) = internal_memcpy;
 #endif
 
+  __interception::DoesNotSupportStaticLinking();
+
   new(interceptor_ctx()) InterceptorContext();
 
+  // Interpose __tls_get_addr before the common interposers. This is needed
+  // because dlsym() may call malloc on failure which could result in other
+  // interposed functions being called that could eventually make use of TLS.
+#ifdef NEED_TLS_GET_ADDR
+#  if !SANITIZER_S390
+  TSAN_INTERCEPT(__tls_get_addr);
+#  else
+  TSAN_INTERCEPT(__tls_get_addr_internal);
+  TSAN_INTERCEPT(__tls_get_offset);
+#  endif
+#endif
   InitializeCommonInterceptors();
   InitializeSignalInterceptors();
   InitializeLibdispatchInterceptors();
@@ -2902,6 +2986,9 @@  void InitializeInterceptors() {
   TSAN_INTERCEPT(pthread_mutex_trylock);
   TSAN_INTERCEPT(pthread_mutex_timedlock);
   TSAN_INTERCEPT(pthread_mutex_unlock);
+#if SANITIZER_LINUX
+  TSAN_INTERCEPT(pthread_mutex_clocklock);
+#endif
 #if SANITIZER_GLIBC
 #  if !__GLIBC_PREREQ(2, 34)
   TSAN_INTERCEPT(__pthread_mutex_lock);
@@ -2931,10 +3018,9 @@  void InitializeInterceptors() {
 
   TSAN_INTERCEPT(pthread_once);
 
-  TSAN_INTERCEPT(fstat);
   TSAN_MAYBE_INTERCEPT___FXSTAT;
+  TSAN_MAYBE_INTERCEPT_FSTAT;
   TSAN_MAYBE_INTERCEPT_FSTAT64;
-  TSAN_MAYBE_INTERCEPT___FXSTAT64;
   TSAN_INTERCEPT(open);
   TSAN_MAYBE_INTERCEPT_OPEN64;
   TSAN_INTERCEPT(creat);
@@ -2991,15 +3077,6 @@  void InitializeInterceptors() {
   TSAN_INTERCEPT(__cxa_atexit);
   TSAN_INTERCEPT(_exit);
 
-#ifdef NEED_TLS_GET_ADDR
-#if !SANITIZER_S390
-  TSAN_INTERCEPT(__tls_get_addr);
-#else
-  TSAN_INTERCEPT(__tls_get_addr_internal);
-  TSAN_INTERCEPT(__tls_get_offset);
-#endif
-#endif
-
   TSAN_MAYBE_INTERCEPT__LWP_EXIT;
   TSAN_MAYBE_INTERCEPT_THR_EXIT;
 
diff --git a/libsanitizer/tsan/tsan_interface_ann.cpp b/libsanitizer/tsan/tsan_interface_ann.cpp
index 5154662034c5..befd6a369026 100644
--- a/libsanitizer/tsan/tsan_interface_ann.cpp
+++ b/libsanitizer/tsan/tsan_interface_ann.cpp
@@ -76,7 +76,7 @@  struct DynamicAnnContext {
 };
 
 static DynamicAnnContext *dyn_ann_ctx;
-static char dyn_ann_ctx_placeholder[sizeof(DynamicAnnContext)] ALIGNED(64);
+alignas(64) static char dyn_ann_ctx_placeholder[sizeof(DynamicAnnContext)];
 
 static void AddExpectRace(ExpectRace *list,
     char *f, int l, uptr addr, uptr size, char *desc) {
diff --git a/libsanitizer/tsan/tsan_mman.cpp b/libsanitizer/tsan/tsan_mman.cpp
index 6f118e0979e2..0ea83fb3b598 100644
--- a/libsanitizer/tsan/tsan_mman.cpp
+++ b/libsanitizer/tsan/tsan_mman.cpp
@@ -9,17 +9,19 @@ 
 // This file is a part of ThreadSanitizer (TSan), a race detector.
 //
 //===----------------------------------------------------------------------===//
+#include "tsan_mman.h"
+
 #include "sanitizer_common/sanitizer_allocator_checks.h"
 #include "sanitizer_common/sanitizer_allocator_interface.h"
 #include "sanitizer_common/sanitizer_allocator_report.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_errno.h"
 #include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+#include "tsan_flags.h"
 #include "tsan_interface.h"
-#include "tsan_mman.h"
-#include "tsan_rtl.h"
 #include "tsan_report.h"
-#include "tsan_flags.h"
+#include "tsan_rtl.h"
 
 namespace __tsan {
 
@@ -52,7 +54,7 @@  struct MapUnmapCallback {
   }
 };
 
-static char allocator_placeholder[sizeof(Allocator)] ALIGNED(64);
+alignas(64) static char allocator_placeholder[sizeof(Allocator)];
 Allocator *allocator() {
   return reinterpret_cast<Allocator*>(&allocator_placeholder);
 }
@@ -73,7 +75,7 @@  struct GlobalProc {
         internal_alloc_mtx(MutexTypeInternalAlloc) {}
 };
 
-static char global_proc_placeholder[sizeof(GlobalProc)] ALIGNED(64);
+alignas(64) static char global_proc_placeholder[sizeof(GlobalProc)];
 GlobalProc *global_proc() {
   return reinterpret_cast<GlobalProc*>(&global_proc_placeholder);
 }
@@ -115,12 +117,21 @@  ScopedGlobalProcessor::~ScopedGlobalProcessor() {
   gp->mtx.Unlock();
 }
 
-void AllocatorLock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
+void AllocatorLockBeforeFork() SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
   global_proc()->internal_alloc_mtx.Lock();
   InternalAllocatorLock();
-}
-
-void AllocatorUnlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
+#if !SANITIZER_APPLE
+  // OS X allocates from hooks, see 6a3958247a.
+  allocator()->ForceLock();
+  StackDepotLockBeforeFork();
+#endif
+}
+
+void AllocatorUnlockAfterFork(bool child) SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
+#if !SANITIZER_APPLE
+  StackDepotUnlockAfterFork(child);
+  allocator()->ForceUnlock();
+#endif
   InternalAllocatorUnlock();
   global_proc()->internal_alloc_mtx.Unlock();
 }
@@ -241,7 +252,7 @@  void *user_reallocarray(ThreadState *thr, uptr pc, void *p, uptr size, uptr n) {
     if (AllocatorMayReturnNull())
       return SetErrnoOnNull(nullptr);
     GET_STACK_TRACE_FATAL(thr, pc);
-    ReportReallocArrayOverflow(size, n, &stack);
+    ReportReallocArrayOverflow(n, size, &stack);
   }
   return user_realloc(thr, pc, p, size * n);
 }
diff --git a/libsanitizer/tsan/tsan_mman.h b/libsanitizer/tsan/tsan_mman.h
index 2095f28c0253..f01bbc4d1571 100644
--- a/libsanitizer/tsan/tsan_mman.h
+++ b/libsanitizer/tsan/tsan_mman.h
@@ -24,8 +24,8 @@  void ReplaceSystemMalloc();
 void AllocatorProcStart(Processor *proc);
 void AllocatorProcFinish(Processor *proc);
 void AllocatorPrintStats();
-void AllocatorLock();
-void AllocatorUnlock();
+void AllocatorLockBeforeFork();
+void AllocatorUnlockAfterFork(bool child);
 void GlobalProcessorLock();
 void GlobalProcessorUnlock();
 
diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h
index d9ed3979b69e..377f8aeb8d66 100644
--- a/libsanitizer/tsan/tsan_platform.h
+++ b/libsanitizer/tsan/tsan_platform.h
@@ -413,18 +413,18 @@  struct MappingRiscv64_39 {
 
 /*
 C/C++ on linux/riscv64 (48-bit VMA)
-0000 0000 1000 - 0500 0000 0000: main binary                      ( 5 TB)
+0000 0000 1000 - 0400 0000 0000: main binary                      ( 4 TB)
 0500 0000 0000 - 2000 0000 0000: -
 2000 0000 0000 - 4000 0000 0000: shadow memory                    (32 TB)
 4000 0000 0000 - 4800 0000 0000: metainfo                         ( 8 TB)
 4800 0000 0000 - 5555 5555 5000: -
 5555 5555 5000 - 5a00 0000 0000: main binary (PIE)                (~5 TB)
 5a00 0000 0000 - 7a00 0000 0000: -
-7a00 0000 0000 - 7fff ffff ffff: libraries and main thread stack  ( 5 TB)
+7a00 0000 0000 - 7fff ffff ffff: libraries and main thread stack  ( 6 TB)
 */
 struct MappingRiscv64_48 {
   static const uptr kLoAppMemBeg = 0x000000001000ull;
-  static const uptr kLoAppMemEnd = 0x050000000000ull;
+  static const uptr kLoAppMemEnd = 0x040000000000ull;
   static const uptr kShadowBeg = 0x200000000000ull;
   static const uptr kShadowEnd = 0x400000000000ull;
   static const uptr kMetaShadowBeg = 0x400000000000ull;
@@ -622,6 +622,35 @@  struct MappingGoAarch64 {
   static const uptr kShadowAdd = 0x200000000000ull;
 };
 
+/* Go on linux/loongarch64 (47-bit VMA)
+0000 0000 1000 - 0000 1000 0000: executable
+0000 1000 0000 - 00c0 0000 0000: -
+00c0 0000 0000 - 00e0 0000 0000: heap
+00e0 0000 0000 - 2000 0000 0000: -
+2000 0000 0000 - 2800 0000 0000: shadow
+2800 0000 0000 - 3000 0000 0000: -
+3000 0000 0000 - 3200 0000 0000: metainfo (memory blocks and sync objects)
+3200 0000 0000 - 8000 0000 0000: -
+*/
+struct MappingGoLoongArch64_47 {
+  static const uptr kMetaShadowBeg = 0x300000000000ull;
+  static const uptr kMetaShadowEnd = 0x320000000000ull;
+  static const uptr kShadowBeg = 0x200000000000ull;
+  static const uptr kShadowEnd = 0x280000000000ull;
+  static const uptr kLoAppMemBeg = 0x000000001000ull;
+  static const uptr kLoAppMemEnd = 0x00e000000000ull;
+  static const uptr kMidAppMemBeg = 0;
+  static const uptr kMidAppMemEnd = 0;
+  static const uptr kHiAppMemBeg = 0;
+  static const uptr kHiAppMemEnd = 0;
+  static const uptr kHeapMemBeg = 0;
+  static const uptr kHeapMemEnd = 0;
+  static const uptr kVdsoBeg = 0;
+  static const uptr kShadowMsk = 0;
+  static const uptr kShadowXor = 0;
+  static const uptr kShadowAdd = 0x200000000000ull;
+};
+
 /*
 Go on linux/mips64 (47-bit VMA)
 0000 0000 1000 - 0000 1000 0000: executable
@@ -697,6 +726,8 @@  ALWAYS_INLINE auto SelectMapping(Arg arg) {
   return Func::template Apply<MappingGoS390x>(arg);
 #  elif defined(__aarch64__)
   return Func::template Apply<MappingGoAarch64>(arg);
+#  elif defined(__loongarch_lp64)
+  return Func::template Apply<MappingGoLoongArch64_47>(arg);
 #  elif SANITIZER_WINDOWS
   return Func::template Apply<MappingGoWindows>(arg);
 #  else
@@ -765,6 +796,7 @@  void ForEachMapping() {
   Func::template Apply<MappingGoPPC64_46>();
   Func::template Apply<MappingGoPPC64_47>();
   Func::template Apply<MappingGoAarch64>();
+  Func::template Apply<MappingGoLoongArch64_47>();
   Func::template Apply<MappingGoMips64_47>();
   Func::template Apply<MappingGoS390x>();
 }
@@ -967,7 +999,7 @@  struct RestoreAddrImpl {
         Mapping::kMidAppMemEnd, Mapping::kHiAppMemBeg, Mapping::kHiAppMemEnd,
         Mapping::kHeapMemBeg,   Mapping::kHeapMemEnd,
     };
-    const uptr indicator = 0x0f0000000000ull;
+    const uptr indicator = 0x0e0000000000ull;
     const uptr ind_lsb = 1ull << LeastSignificantSetBitIndex(indicator);
     for (uptr i = 0; i < ARRAY_SIZE(ranges); i += 2) {
       uptr beg = ranges[i];
@@ -992,7 +1024,7 @@  inline uptr RestoreAddr(uptr addr) {
 
 void InitializePlatform();
 void InitializePlatformEarly();
-void CheckAndProtect();
+bool CheckAndProtect(bool protect, bool ignore_heap, bool print_warnings);
 void InitializeShadowMemoryPlatform();
 void WriteMemoryProfile(char *buf, uptr buf_size, u64 uptime_ns);
 int ExtractResolvFDs(void *state, int *fds, int nfd);
diff --git a/libsanitizer/tsan/tsan_platform_linux.cpp b/libsanitizer/tsan/tsan_platform_linux.cpp
index 369509ed0a60..3e08a1bece98 100644
--- a/libsanitizer/tsan/tsan_platform_linux.cpp
+++ b/libsanitizer/tsan/tsan_platform_linux.cpp
@@ -214,6 +214,97 @@  void InitializeShadowMemoryPlatform() {
 
 #endif  // #if !SANITIZER_GO
 
+#  if !SANITIZER_GO
+static void ReExecIfNeeded(bool ignore_heap) {
+  // Go maps shadow memory lazily and works fine with limited address space.
+  // Unlimited stack is not a problem as well, because the executable
+  // is not compiled with -pie.
+  bool reexec = false;
+  // TSan doesn't play well with unlimited stack size (as stack
+  // overlaps with shadow memory). If we detect unlimited stack size,
+  // we re-exec the program with limited stack size as a best effort.
+  if (StackSizeIsUnlimited()) {
+    const uptr kMaxStackSize = 32 * 1024 * 1024;
+    VReport(1,
+            "Program is run with unlimited stack size, which wouldn't "
+            "work with ThreadSanitizer.\n"
+            "Re-execing with stack size limited to %zd bytes.\n",
+            kMaxStackSize);
+    SetStackSizeLimitInBytes(kMaxStackSize);
+    reexec = true;
+  }
+
+  if (!AddressSpaceIsUnlimited()) {
+    Report(
+        "WARNING: Program is run with limited virtual address space,"
+        " which wouldn't work with ThreadSanitizer.\n");
+    Report("Re-execing with unlimited virtual address space.\n");
+    SetAddressSpaceUnlimited();
+    reexec = true;
+  }
+
+#    if SANITIZER_LINUX
+#      if SANITIZER_ANDROID && (defined(__aarch64__) || defined(__x86_64__))
+  // ASLR personality check.
+  int old_personality = personality(0xffffffff);
+  bool aslr_on =
+      (old_personality != -1) && ((old_personality & ADDR_NO_RANDOMIZE) == 0);
+
+  // 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.
+  if (aslr_on) {
+    VReport(1,
+            "WARNING: Program is run with randomized virtual address "
+            "space, which wouldn't work with ThreadSanitizer on Android.\n"
+            "Re-execing with fixed virtual address space.\n");
+    CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
+    reexec = true;
+  }
+#      endif
+
+  if (reexec) {
+    // Don't check the address space since we're going to re-exec anyway.
+  } else if (!CheckAndProtect(false, ignore_heap, false)) {
+    // ASLR personality check.
+    // N.B. 'personality' is sometimes forbidden by sandboxes, so we only call
+    // this as a last resort (when the memory mapping is incompatible and TSan
+    // would fail anyway).
+    int old_personality = personality(0xffffffff);
+    bool aslr_on =
+        (old_personality != -1) && ((old_personality & ADDR_NO_RANDOMIZE) == 0);
+
+    if (aslr_on) {
+      // Disable ASLR if the memory layout was incompatible.
+      // Alternatively, we could just keep re-execing until we get lucky
+      // with a compatible randomized layout, but the risk is that if it's
+      // not an ASLR-related issue, we will be stuck in an infinite loop of
+      // re-execing (unless we change ReExec to pass a parameter of the
+      // number of retries allowed.)
+      VReport(1,
+              "WARNING: ThreadSanitizer: memory layout is incompatible, "
+              "possibly due to high-entropy ASLR.\n"
+              "Re-execing with fixed virtual address space.\n"
+              "N.B. reducing ASLR entropy is preferable.\n");
+      CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
+      reexec = true;
+    } else {
+      Printf(
+          "FATAL: ThreadSanitizer: memory layout is incompatible, "
+          "even though ASLR is disabled.\n"
+          "Please file a bug.\n");
+      DumpProcessMap();
+      Die();
+    }
+  }
+#    endif  // SANITIZER_LINUX
+
+  if (reexec)
+    ReExec();
+}
+#  endif
+
 void InitializePlatformEarly() {
   vmaSize =
     (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1);
@@ -238,7 +329,13 @@  void InitializePlatformEarly() {
     Printf("FATAL: Found %zd - Supported 47\n", vmaSize);
     Die();
   }
-# endif
+#    else
+  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) {
@@ -278,6 +375,11 @@  void InitializePlatformEarly() {
   }
 #    endif
 #  endif
+
+#  if !SANITIZER_GO
+  // Heap has not been allocated yet
+  ReExecIfNeeded(false);
+#  endif
 }
 
 void InitializePlatform() {
@@ -288,53 +390,34 @@  void InitializePlatform() {
   // is not compiled with -pie.
 #if !SANITIZER_GO
   {
-    bool reexec = false;
-    // TSan doesn't play well with unlimited stack size (as stack
-    // overlaps with shadow memory). If we detect unlimited stack size,
-    // we re-exec the program with limited stack size as a best effort.
-    if (StackSizeIsUnlimited()) {
-      const uptr kMaxStackSize = 32 * 1024 * 1024;
-      VReport(1, "Program is run with unlimited stack size, which wouldn't "
-                 "work with ThreadSanitizer.\n"
-                 "Re-execing with stack size limited to %zd bytes.\n",
-              kMaxStackSize);
-      SetStackSizeLimitInBytes(kMaxStackSize);
-      reexec = true;
-    }
-
-    if (!AddressSpaceIsUnlimited()) {
-      Report("WARNING: Program is run with limited virtual address space,"
-             " which wouldn't work with ThreadSanitizer.\n");
-      Report("Re-execing with unlimited virtual address space.\n");
-      SetAddressSpaceUnlimited();
-      reexec = true;
-    }
-#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 "
-              "space, which wouldn't work with ThreadSanitizer.\n"
-              "Re-execing with fixed virtual address space.\n");
-      CHECK_NE(personality(old_personality | ADDR_NO_RANDOMIZE), -1);
-      reexec = true;
-    }
-
-#endif
-#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__loongarch_lp64))
+#    if SANITIZER_LINUX && (defined(__aarch64__) || defined(__loongarch_lp64))
     // Initialize the xor key used in {sig}{set,long}jump.
     InitializeLongjmpXorKey();
-#endif
-    if (reexec)
-      ReExec();
+#    endif
+  }
+
+  // We called ReExecIfNeeded() in InitializePlatformEarly(), but there are
+  // intervening allocations that result in an edge case:
+  // 1) InitializePlatformEarly(): memory layout is compatible
+  // 2) Intervening allocations happen
+  // 3) InitializePlatform(): memory layout is incompatible and fails
+  //    CheckAndProtect()
+#    if !SANITIZER_GO
+  // Heap has already been allocated
+  ReExecIfNeeded(true);
+#    endif
+
+  // Earlier initialization steps already re-exec'ed until we got a compatible
+  // memory layout, so we don't expect any more issues here.
+  if (!CheckAndProtect(true, true, true)) {
+    Printf(
+        "FATAL: ThreadSanitizer: unexpectedly found incompatible memory "
+        "layout.\n");
+    Printf("FATAL: Please file a bug.\n");
+    DumpProcessMap();
+    Die();
   }
 
-  CheckAndProtect();
-  InitTlsSize();
 #endif  // !SANITIZER_GO
 }
 
diff --git a/libsanitizer/tsan/tsan_platform_mac.cpp b/libsanitizer/tsan/tsan_platform_mac.cpp
index 1aac0fb27520..eb344df168ab 100644
--- a/libsanitizer/tsan/tsan_platform_mac.cpp
+++ b/libsanitizer/tsan/tsan_platform_mac.cpp
@@ -46,8 +46,8 @@ 
 namespace __tsan {
 
 #if !SANITIZER_GO
-static char main_thread_state[sizeof(ThreadState)] ALIGNED(
-    SANITIZER_CACHE_LINE_SIZE);
+alignas(SANITIZER_CACHE_LINE_SIZE) static char main_thread_state[sizeof(
+    ThreadState)];
 static ThreadState *dead_thread_state;
 static pthread_key_t thread_state_key;
 
@@ -239,7 +239,10 @@  static uptr longjmp_xor_key = 0;
 void InitializePlatform() {
   DisableCoreDumperIfNecessary();
 #if !SANITIZER_GO
-  CheckAndProtect();
+  if (!CheckAndProtect(true, true, true)) {
+    Printf("FATAL: ThreadSanitizer: found incompatible memory layout.\n");
+    Die();
+  }
 
   InitializeThreadStateStorage();
 
diff --git a/libsanitizer/tsan/tsan_platform_posix.cpp b/libsanitizer/tsan/tsan_platform_posix.cpp
index e7dcd664dc0d..7d5a992dc665 100644
--- a/libsanitizer/tsan/tsan_platform_posix.cpp
+++ b/libsanitizer/tsan/tsan_platform_posix.cpp
@@ -94,22 +94,51 @@  static void ProtectRange(uptr beg, uptr end) {
   }
 }
 
-void CheckAndProtect() {
+// CheckAndProtect will check if the memory layout is compatible with TSan.
+// Optionally (if 'protect' is true), it will set the memory regions between
+// app memory to be inaccessible.
+// 'ignore_heap' means it will not consider heap memory allocations to be a
+// conflict. Set this based on whether we are calling CheckAndProtect before
+// or after the allocator has initialized the heap.
+bool CheckAndProtect(bool protect, bool ignore_heap, bool print_warnings) {
   // Ensure that the binary is indeed compiled with -pie.
   MemoryMappingLayout proc_maps(true);
   MemoryMappedSegment segment;
   while (proc_maps.Next(&segment)) {
-    if (IsAppMem(segment.start)) continue;
+    if (segment.start >= HeapMemBeg() && segment.end <= HeapEnd()) {
+      if (ignore_heap) {
+        continue;
+      } else {
+        return false;
+      }
+    }
+
+    // Note: IsAppMem includes if it is heap memory, hence we must
+    // put this check after the heap bounds check.
+    if (IsAppMem(segment.start) && IsAppMem(segment.end - 1))
+      continue;
+
+    // Guard page after the heap end
     if (segment.start >= HeapMemEnd() && segment.start < HeapEnd()) continue;
+
     if (segment.protection == 0)  // Zero page or mprotected.
       continue;
+
     if (segment.start >= VdsoBeg())  // vdso
       break;
-    Printf("FATAL: ThreadSanitizer: unexpected memory mapping 0x%zx-0x%zx\n",
-           segment.start, segment.end);
-    Die();
+
+    // Debug output can break tests. Suppress this message in most cases.
+    if (print_warnings)
+      Printf(
+          "WARNING: ThreadSanitizer: unexpected memory mapping 0x%zx-0x%zx\n",
+          segment.start, segment.end);
+
+    return false;
   }
 
+  if (!protect)
+    return true;
+
 #    if SANITIZER_IOS && !SANITIZER_IOSSIM
   ProtectRange(HeapMemEnd(), ShadowBeg());
   ProtectRange(ShadowEnd(), MetaShadowBeg());
@@ -135,8 +164,10 @@  void CheckAndProtect() {
   // Older s390x kernels may not support 5-level page tables.
   TryProtectRange(user_addr_max_l4, user_addr_max_l5);
 #endif
+
+  return true;
 }
-#endif
+#  endif
 
 }  // namespace __tsan
 
diff --git a/libsanitizer/tsan/tsan_preinit.cpp b/libsanitizer/tsan/tsan_preinit.cpp
index 205bdbf93b20..69700f2dde24 100644
--- a/libsanitizer/tsan/tsan_preinit.cpp
+++ b/libsanitizer/tsan/tsan_preinit.cpp
@@ -16,11 +16,9 @@ 
 
 #if SANITIZER_CAN_USE_PREINIT_ARRAY
 
-// The symbol is called __local_tsan_preinit, because it's not intended to be
-// exported.
-// This code linked into the main executable when -fsanitize=thread is in
-// the link flags. It can only use exported interface functions.
-__attribute__((section(".preinit_array"), used))
-void (*__local_tsan_preinit)(void) = __tsan_init;
+// This section is linked into the main executable when -fsanitize=thread is
+// specified to perform initialization at a very early stage.
+__attribute__((section(".preinit_array"), used)) static auto preinit =
+    __tsan_init;
 
 #endif
diff --git a/libsanitizer/tsan/tsan_report.cpp b/libsanitizer/tsan/tsan_report.cpp
index 35cb6710a54f..22ba428cc58b 100644
--- a/libsanitizer/tsan/tsan_report.cpp
+++ b/libsanitizer/tsan/tsan_report.cpp
@@ -273,26 +273,10 @@  static ReportStack *ChooseSummaryStack(const ReportDesc *rep) {
   return 0;
 }
 
-static bool FrameIsInternal(const SymbolizedStack *frame) {
-  if (frame == 0)
-    return false;
-  const char *file = frame->info.file;
-  const char *module = frame->info.module;
-  if (file != 0 &&
-      (internal_strstr(file, "tsan_interceptors_posix.cpp") ||
-       internal_strstr(file, "tsan_interceptors_memintrinsics.cpp") ||
-       internal_strstr(file, "sanitizer_common_interceptors.inc") ||
-       internal_strstr(file, "tsan_interface_")))
-    return true;
-  if (module != 0 && (internal_strstr(module, "libclang_rt.tsan_")))
-    return true;
-  return false;
-}
-
-static SymbolizedStack *SkipTsanInternalFrames(SymbolizedStack *frames) {
-  while (FrameIsInternal(frames) && frames->next)
-    frames = frames->next;
-  return frames;
+static const SymbolizedStack *SkipTsanInternalFrames(SymbolizedStack *frames) {
+  if (const SymbolizedStack *f = SkipInternalFrames(frames))
+    return f;
+  return frames;  // Fallback to the top frame.
 }
 
 void PrintReport(const ReportDesc *rep) {
@@ -366,7 +350,7 @@  void PrintReport(const ReportDesc *rep) {
     Printf("  And %d more similar thread leaks.\n\n", rep->count - 1);
 
   if (ReportStack *stack = ChooseSummaryStack(rep)) {
-    if (SymbolizedStack *frame = SkipTsanInternalFrames(stack->frames))
+    if (const SymbolizedStack *frame = SkipTsanInternalFrames(stack->frames))
       ReportErrorSummary(rep_typ_str, frame->info);
   }
 
diff --git a/libsanitizer/tsan/tsan_rtl.cpp b/libsanitizer/tsan/tsan_rtl.cpp
index fd9441dfcb53..5a2d39cd3060 100644
--- a/libsanitizer/tsan/tsan_rtl.cpp
+++ b/libsanitizer/tsan/tsan_rtl.cpp
@@ -35,8 +35,10 @@  extern "C" void __tsan_resume() {
   __tsan_resumed = 1;
 }
 
+#if SANITIZER_APPLE
 SANITIZER_WEAK_DEFAULT_IMPL
 void __tsan_test_only_on_fork() {}
+#endif
 
 namespace __tsan {
 
@@ -46,11 +48,10 @@  int (*on_finalize)(int);
 #endif
 
 #if !SANITIZER_GO && !SANITIZER_APPLE
-__attribute__((tls_model("initial-exec")))
-THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(
-    SANITIZER_CACHE_LINE_SIZE);
+alignas(SANITIZER_CACHE_LINE_SIZE) THREADLOCAL __attribute__((tls_model(
+    "initial-exec"))) char cur_thread_placeholder[sizeof(ThreadState)];
 #endif
-static char ctx_placeholder[sizeof(Context)] ALIGNED(SANITIZER_CACHE_LINE_SIZE);
+alignas(SANITIZER_CACHE_LINE_SIZE) static char ctx_placeholder[sizeof(Context)];
 Context *ctx;
 
 // Can be overriden by a front-end.
@@ -805,6 +806,7 @@  int Finalize(ThreadState *thr) {
 
 #if !SANITIZER_GO
 void ForkBefore(ThreadState* thr, uptr pc) SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
+  VReport(2, "BeforeFork tid: %llu\n", GetTid());
   GlobalProcessorLock();
   // Detaching from the slot makes OnUserFree skip writing to the shadow.
   // The slot will be locked so any attempts to use it will deadlock anyway.
@@ -813,7 +815,7 @@  void ForkBefore(ThreadState* thr, uptr pc) SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
   ctx->thread_registry.Lock();
   ctx->slot_mtx.Lock();
   ScopedErrorReportLock::Lock();
-  AllocatorLock();
+  AllocatorLockBeforeFork();
   // Suppress all reports in the pthread_atfork callbacks.
   // Reports will deadlock on the report_mtx.
   // We could ignore sync operations as well,
@@ -828,14 +830,17 @@  void ForkBefore(ThreadState* thr, uptr pc) SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
   // Disables memory write in OnUserAlloc/Free.
   thr->ignore_reads_and_writes++;
 
+#  if SANITIZER_APPLE
   __tsan_test_only_on_fork();
+#  endif
 }
 
-static void ForkAfter(ThreadState* thr) SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
+static void ForkAfter(ThreadState* thr,
+                      bool child) SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
   thr->suppress_reports--;  // Enabled in ForkBefore.
   thr->ignore_interceptors--;
   thr->ignore_reads_and_writes--;
-  AllocatorUnlock();
+  AllocatorUnlockAfterFork(child);
   ScopedErrorReportLock::Unlock();
   ctx->slot_mtx.Unlock();
   ctx->thread_registry.Unlock();
@@ -843,12 +848,13 @@  static void ForkAfter(ThreadState* thr) SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
   SlotAttachAndLock(thr);
   SlotUnlock(thr);
   GlobalProcessorUnlock();
+  VReport(2, "AfterFork tid: %llu\n", GetTid());
 }
 
-void ForkParentAfter(ThreadState* thr, uptr pc) { ForkAfter(thr); }
+void ForkParentAfter(ThreadState* thr, uptr pc) { ForkAfter(thr, false); }
 
 void ForkChildAfter(ThreadState* thr, uptr pc, bool start_thread) {
-  ForkAfter(thr);
+  ForkAfter(thr, true);
   u32 nthread = ctx->thread_registry.OnFork(thr->tid);
   VPrintf(1,
           "ThreadSanitizer: forked new process with pid %d,"
diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h
index de4ea0bb5f48..f48be8e0a4fe 100644
--- a/libsanitizer/tsan/tsan_rtl.h
+++ b/libsanitizer/tsan/tsan_rtl.h
@@ -136,7 +136,7 @@  struct TidEpoch {
   Epoch epoch;
 };
 
-struct TidSlot {
+struct alignas(SANITIZER_CACHE_LINE_SIZE) TidSlot {
   Mutex mtx;
   Sid sid;
   atomic_uint32_t raw_epoch;
@@ -153,10 +153,10 @@  struct TidSlot {
   }
 
   TidSlot();
-} ALIGNED(SANITIZER_CACHE_LINE_SIZE);
+};
 
 // This struct is stored in TLS.
-struct ThreadState {
+struct alignas(SANITIZER_CACHE_LINE_SIZE) ThreadState {
   FastState fast_state;
   int ignore_sync;
 #if !SANITIZER_GO
@@ -234,7 +234,7 @@  struct ThreadState {
   const ReportDesc *current_report;
 
   explicit ThreadState(Tid tid);
-} ALIGNED(SANITIZER_CACHE_LINE_SIZE);
+};
 
 #if !SANITIZER_GO
 #if SANITIZER_APPLE || SANITIZER_ANDROID
diff --git a/libsanitizer/tsan/tsan_rtl_aarch64.S b/libsanitizer/tsan/tsan_rtl_aarch64.S
index c6162659b876..7d920bee4a2d 100644
--- a/libsanitizer/tsan/tsan_rtl_aarch64.S
+++ b/libsanitizer/tsan/tsan_rtl_aarch64.S
@@ -2,6 +2,7 @@ 
 #if defined(__aarch64__)
 
 #include "sanitizer_common/sanitizer_asm.h"
+#include "builtins/assembly.h"
 
 #if !defined(__APPLE__)
 .section .text
@@ -16,6 +17,7 @@  ASM_HIDDEN(__tsan_setjmp)
 ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(setjmp))
 ASM_SYMBOL_INTERCEPTOR(setjmp):
   CFI_STARTPROC
+  BTI_C
 
   // Save frame/link register
   stp     x29, x30, [sp, -32]!
@@ -66,6 +68,7 @@  ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(setjmp))
 ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(_setjmp))
 ASM_SYMBOL_INTERCEPTOR(_setjmp):
   CFI_STARTPROC
+  BTI_C
 
   // Save frame/link register
   stp     x29, x30, [sp, -32]!
@@ -116,6 +119,7 @@  ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(_setjmp))
 ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(sigsetjmp))
 ASM_SYMBOL_INTERCEPTOR(sigsetjmp):
   CFI_STARTPROC
+  BTI_C
 
   // Save frame/link register
   stp     x29, x30, [sp, -32]!
@@ -168,6 +172,7 @@  ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(sigsetjmp))
 ASM_TYPE_FUNCTION(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp))
 ASM_SYMBOL_INTERCEPTOR(__sigsetjmp):
   CFI_STARTPROC
+  BTI_C
 
   // Save frame/link register
   stp     x29, x30, [sp, -32]!
@@ -217,4 +222,6 @@  ASM_SIZE(ASM_SYMBOL_INTERCEPTOR(__sigsetjmp))
 
 NO_EXEC_STACK_DIRECTIVE
 
+GNU_PROPERTY_BTI_PAC
+
 #endif
diff --git a/libsanitizer/tsan/tsan_rtl_access.cpp b/libsanitizer/tsan/tsan_rtl_access.cpp
index 8b20984a0100..cf07686d968d 100644
--- a/libsanitizer/tsan/tsan_rtl_access.cpp
+++ b/libsanitizer/tsan/tsan_rtl_access.cpp
@@ -672,22 +672,28 @@  void MemoryAccessRangeT(ThreadState* thr, uptr pc, uptr addr, uptr size) {
 
 #if SANITIZER_DEBUG
   if (!IsAppMem(addr)) {
-    Printf("Access to non app mem %zx\n", addr);
+    Printf("Access to non app mem start: %p\n", (void*)addr);
     DCHECK(IsAppMem(addr));
   }
   if (!IsAppMem(addr + size - 1)) {
-    Printf("Access to non app mem %zx\n", addr + size - 1);
+    Printf("Access to non app mem end: %p\n", (void*)(addr + size - 1));
     DCHECK(IsAppMem(addr + size - 1));
   }
   if (!IsShadowMem(shadow_mem)) {
-    Printf("Bad shadow addr %p (%zx)\n", static_cast<void*>(shadow_mem), addr);
+    Printf("Bad shadow start addr: %p (%p)\n", shadow_mem, (void*)addr);
     DCHECK(IsShadowMem(shadow_mem));
   }
-  if (!IsShadowMem(shadow_mem + size * kShadowCnt - 1)) {
-    Printf("Bad shadow addr %p (%zx)\n",
-           static_cast<void*>(shadow_mem + size * kShadowCnt - 1),
-           addr + size - 1);
-    DCHECK(IsShadowMem(shadow_mem + size * kShadowCnt - 1));
+
+  RawShadow* shadow_mem_end = reinterpret_cast<RawShadow*>(
+      reinterpret_cast<uptr>(shadow_mem) + size * kShadowMultiplier - 1);
+  if (!IsShadowMem(shadow_mem_end)) {
+    Printf("Bad shadow end addr: %p (%p)\n", shadow_mem_end,
+           (void*)(addr + size - 1));
+    Printf(
+        "Shadow start addr (ok): %p (%p); size: 0x%zx; kShadowMultiplier: "
+        "%zx\n",
+        shadow_mem, (void*)addr, size, kShadowMultiplier);
+    DCHECK(IsShadowMem(shadow_mem_end));
   }
 #endif
 
diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cpp b/libsanitizer/tsan/tsan_rtl_mutex.cpp
index 2e978852ea7d..2a8aa1915c9a 100644
--- a/libsanitizer/tsan/tsan_rtl_mutex.cpp
+++ b/libsanitizer/tsan/tsan_rtl_mutex.cpp
@@ -446,9 +446,9 @@  void Acquire(ThreadState *thr, uptr pc, uptr addr) {
   if (!s)
     return;
   SlotLocker locker(thr);
+  ReadLock lock(&s->mtx);
   if (!s->clock)
     return;
-  ReadLock lock(&s->mtx);
   thr->clock.Acquire(s->clock);
 }
 
diff --git a/libsanitizer/tsan/tsan_rtl_ppc64.S b/libsanitizer/tsan/tsan_rtl_ppc64.S
index 9e533a71a9c4..8285e21aa1ec 100644
--- a/libsanitizer/tsan/tsan_rtl_ppc64.S
+++ b/libsanitizer/tsan/tsan_rtl_ppc64.S
@@ -1,6 +1,5 @@ 
 #include "tsan_ppc_regs.h"
 
-        .machine altivec
         .section .text
         .hidden __tsan_setjmp
         .globl _setjmp
diff --git a/libsanitizer/tsan/tsan_rtl_thread.cpp b/libsanitizer/tsan/tsan_rtl_thread.cpp
index 77488f843285..8d29e25a6dd2 100644
--- a/libsanitizer/tsan/tsan_rtl_thread.cpp
+++ b/libsanitizer/tsan/tsan_rtl_thread.cpp
@@ -160,15 +160,21 @@  void ThreadStart(ThreadState *thr, Tid tid, tid_t os_id,
   }
   Free(thr->tctx->sync);
 
+#if !SANITIZER_GO
+  thr->is_inited = true;
+#endif
+
   uptr stk_addr = 0;
-  uptr stk_size = 0;
+  uptr stk_end = 0;
   uptr tls_addr = 0;
-  uptr tls_size = 0;
+  uptr tls_end = 0;
 #if !SANITIZER_GO
   if (thread_type != ThreadType::Fiber)
-    GetThreadStackAndTls(tid == kMainTid, &stk_addr, &stk_size, &tls_addr,
-                         &tls_size);
+    GetThreadStackAndTls(tid == kMainTid, &stk_addr, &stk_end, &tls_addr,
+                         &tls_end);
 #endif
+  uptr stk_size = stk_end - stk_addr;
+  uptr tls_size = tls_end - tls_addr;
   thr->stk_addr = stk_addr;
   thr->stk_size = stk_size;
   thr->tls_addr = tls_addr;
@@ -200,15 +206,11 @@  void ThreadStart(ThreadState *thr, Tid tid, tid_t os_id,
 }
 
 void ThreadContext::OnStarted(void *arg) {
-  thr = static_cast<ThreadState *>(arg);
   DPrintf("#%d: ThreadStart\n", tid);
-  new (thr) ThreadState(tid);
+  thr = new (arg) ThreadState(tid);
   if (common_flags()->detect_deadlocks)
     thr->dd_lt = ctx->dd->CreateLogicalThread(tid);
   thr->tctx = this;
-#if !SANITIZER_GO
-  thr->is_inited = true;
-#endif
 }
 
 void ThreadFinish(ThreadState *thr) {
diff --git a/libsanitizer/tsan/tsan_suppressions.cpp b/libsanitizer/tsan/tsan_suppressions.cpp
index 70642124990d..0559df06e7e2 100644
--- a/libsanitizer/tsan/tsan_suppressions.cpp
+++ b/libsanitizer/tsan/tsan_suppressions.cpp
@@ -42,7 +42,7 @@  const char *__tsan_default_suppressions() {
 
 namespace __tsan {
 
-ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
+alignas(64) static char suppression_placeholder[sizeof(SuppressionContext)];
 static SuppressionContext *suppression_ctx = nullptr;
 static const char *kSuppressionTypes[] = {
     kSuppressionRace,   kSuppressionRaceTop, kSuppressionMutex,
diff --git a/libsanitizer/tsan/tsan_vector_clock.h b/libsanitizer/tsan/tsan_vector_clock.h
index 63b206302190..51d98113d8e7 100644
--- a/libsanitizer/tsan/tsan_vector_clock.h
+++ b/libsanitizer/tsan/tsan_vector_clock.h
@@ -34,7 +34,7 @@  class VectorClock {
   VectorClock& operator=(const VectorClock& other);
 
  private:
-  Epoch clk_[kThreadSlotCount] VECTOR_ALIGNED;
+  VECTOR_ALIGNED Epoch clk_[kThreadSlotCount];
 };
 
 ALWAYS_INLINE Epoch VectorClock::Get(Sid sid) const {
diff --git a/libsanitizer/ubsan/ubsan_diag.cpp b/libsanitizer/ubsan/ubsan_diag.cpp
index aac270415318..2146ed3c2728 100644
--- a/libsanitizer/ubsan/ubsan_diag.cpp
+++ b/libsanitizer/ubsan/ubsan_diag.cpp
@@ -47,7 +47,7 @@  static void MaybePrintStackTrace(uptr pc, uptr bp) {
   if (!flags()->print_stacktrace)
     return;
 
-  BufferedStackTrace stack;
+  UNINITIALIZED BufferedStackTrace stack;
   ubsan_GetStackTrace(&stack, kStackTraceMax, pc, bp, nullptr,
                 common_flags()->fast_unwind_on_fatal);
   stack.Print();
@@ -88,7 +88,7 @@  static void MaybeReportErrorSummary(Location Loc, ErrorType Type) {
       AI.file = internal_strdup(SLoc.getFilename());
       AI.line = SLoc.getLine();
       AI.column = SLoc.getColumn();
-      AI.function = internal_strdup("");  // Avoid printing ?? as function name.
+      AI.function = nullptr;
       ReportErrorSummary(ErrorKind, AI, GetSanititizerToolName());
       AI.Clear();
       return;
@@ -402,7 +402,7 @@  ScopedReport::~ScopedReport() {
     Die();
 }
 
-ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
+alignas(64) static char suppression_placeholder[sizeof(SuppressionContext)];
 static SuppressionContext *suppression_ctx = nullptr;
 static const char kVptrCheck[] = "vptr_check";
 static const char *kSuppressionTypes[] = {
diff --git a/libsanitizer/ubsan/ubsan_diag.h b/libsanitizer/ubsan/ubsan_diag.h
index b444e971b228..c836647c98f3 100644
--- a/libsanitizer/ubsan/ubsan_diag.h
+++ b/libsanitizer/ubsan/ubsan_diag.h
@@ -18,26 +18,6 @@ 
 
 namespace __ubsan {
 
-class SymbolizedStackHolder {
-  SymbolizedStack *Stack;
-
-  void clear() {
-    if (Stack)
-      Stack->ClearAll();
-  }
-
-public:
-  explicit SymbolizedStackHolder(SymbolizedStack *Stack = nullptr)
-      : Stack(Stack) {}
-  ~SymbolizedStackHolder() { clear(); }
-  void reset(SymbolizedStack *S) {
-    if (Stack != S)
-      clear();
-    Stack = S;
-  }
-  const SymbolizedStack *get() const { return Stack; }
-};
-
 SymbolizedStack *getSymbolizedLocation(uptr PC);
 
 inline SymbolizedStack *getCallerLocation(uptr CallerPC) {
diff --git a/libsanitizer/ubsan/ubsan_diag_standalone.cpp b/libsanitizer/ubsan/ubsan_diag_standalone.cpp
index 5526ae051650..03dfde8908dd 100644
--- a/libsanitizer/ubsan/ubsan_diag_standalone.cpp
+++ b/libsanitizer/ubsan/ubsan_diag_standalone.cpp
@@ -29,7 +29,7 @@  extern "C" {
 SANITIZER_INTERFACE_ATTRIBUTE
 void __sanitizer_print_stack_trace() {
   GET_CURRENT_PC_BP;
-  BufferedStackTrace stack;
+  UNINITIALIZED BufferedStackTrace stack;
   stack.Unwind(pc, bp, nullptr, common_flags()->fast_unwind_on_fatal);
   stack.Print();
 }
diff --git a/libsanitizer/ubsan/ubsan_flags.cpp b/libsanitizer/ubsan/ubsan_flags.cpp
index 9a66bd37518b..25cefd46ce27 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 85ec961841ff..a419cf0b2b55 100644
--- a/libsanitizer/ubsan/ubsan_handlers.cpp
+++ b/libsanitizer/ubsan/ubsan_handlers.cpp
@@ -555,13 +555,11 @@  static void handleImplicitConversion(ImplicitConversionData *Data,
                                      ReportOptions Opts, ValueHandle Src,
                                      ValueHandle Dst) {
   SourceLocation Loc = Data->Loc.acquire();
-  ErrorType ET = ErrorType::GenericUB;
-
   const TypeDescriptor &SrcTy = Data->FromType;
   const TypeDescriptor &DstTy = Data->ToType;
-
   bool SrcSigned = SrcTy.isSignedIntegerTy();
   bool DstSigned = DstTy.isSignedIntegerTy();
+  ErrorType ET = ErrorType::GenericUB;
 
   switch (Data->Kind) {
   case ICCK_IntegerTruncation: { // Legacy, no longer used.
@@ -594,14 +592,23 @@  static void handleImplicitConversion(ImplicitConversionData *Data,
 
   ScopedReport R(Opts, Loc, ET);
 
+  // In the case we have a bitfield, we want to explicitly say so in the
+  // error message.
   // FIXME: is it possible to dump the values as hex with fixed width?
-
-  Diag(Loc, DL_Error, ET,
-       "implicit conversion from type %0 of value %1 (%2-bit, %3signed) to "
-       "type %4 changed the value to %5 (%6-bit, %7signed)")
-      << SrcTy << Value(SrcTy, Src) << SrcTy.getIntegerBitWidth()
-      << (SrcSigned ? "" : "un") << DstTy << Value(DstTy, Dst)
-      << DstTy.getIntegerBitWidth() << (DstSigned ? "" : "un");
+  if (Data->BitfieldBits)
+    Diag(Loc, DL_Error, ET,
+         "implicit conversion from type %0 of value %1 (%2-bit, %3signed) to "
+         "type %4 changed the value to %5 (%6-bit bitfield, %7signed)")
+        << SrcTy << Value(SrcTy, Src) << SrcTy.getIntegerBitWidth()
+        << (SrcSigned ? "" : "un") << DstTy << Value(DstTy, Dst)
+        << Data->BitfieldBits << (DstSigned ? "" : "un");
+  else
+    Diag(Loc, DL_Error, ET,
+         "implicit conversion from type %0 of value %1 (%2-bit, %3signed) to "
+         "type %4 changed the value to %5 (%6-bit, %7signed)")
+        << SrcTy << Value(SrcTy, Src) << SrcTy.getIntegerBitWidth()
+        << (SrcSigned ? "" : "un") << DstTy << Value(DstTy, Dst)
+        << DstTy.getIntegerBitWidth() << (DstSigned ? "" : "un");
 }
 
 void __ubsan::__ubsan_handle_implicit_conversion(ImplicitConversionData *Data,
@@ -626,13 +633,16 @@  static void handleInvalidBuiltin(InvalidBuiltinData *Data, ReportOptions Opts) {
 
   ScopedReport R(Opts, Loc, ET);
 
-  Diag(Loc, DL_Error, ET,
-       "passing zero to %0, which is not a valid argument")
-    << ((Data->Kind == BCK_CTZPassedZero) ? "ctz()" : "clz()");
+  if (Data->Kind == BCK_AssumePassedFalse)
+    Diag(Loc, DL_Error, ET, "assumption is violated during execution");
+  else
+    Diag(Loc, DL_Error, ET,
+         "passing zero to __builtin_%0(), which is not a valid argument")
+        << ((Data->Kind == BCK_CTZPassedZero) ? "ctz" : "clz");
 }
 
 void __ubsan::__ubsan_handle_invalid_builtin(InvalidBuiltinData *Data) {
-  GET_REPORT_OPTIONS(true);
+  GET_REPORT_OPTIONS(false);
   handleInvalidBuiltin(Data, Opts);
 }
 void __ubsan::__ubsan_handle_invalid_builtin_abort(InvalidBuiltinData *Data) {
@@ -894,21 +904,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 f717bc773b1b..4ffa1439a132 100644
--- a/libsanitizer/ubsan/ubsan_handlers.h
+++ b/libsanitizer/ubsan/ubsan_handlers.h
@@ -147,6 +147,7 @@  struct ImplicitConversionData {
   const TypeDescriptor &FromType;
   const TypeDescriptor &ToType;
   /* ImplicitConversionCheckKind */ unsigned char Kind;
+  unsigned int BitfieldBits;
 };
 
 /// \brief Implict conversion that changed the value.
@@ -158,6 +159,7 @@  RECOVERABLE(implicit_conversion, ImplicitConversionData *Data, ValueHandle Src,
 enum BuiltinCheckKind : unsigned char {
   BCK_CTZPassedZero,
   BCK_CLZPassedZero,
+  BCK_AssumePassedFalse,
 };
 
 struct InvalidBuiltinData {
@@ -215,20 +217,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_handlers_cxx.cpp b/libsanitizer/ubsan/ubsan_handlers_cxx.cpp
index 0317a3d1428c..206a0bb485a9 100644
--- a/libsanitizer/ubsan/ubsan_handlers_cxx.cpp
+++ b/libsanitizer/ubsan/ubsan_handlers_cxx.cpp
@@ -156,50 +156,6 @@  void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
     Diag(Loc, DL_Note, ET, "check failed in %0, vtable located in %1")
         << SrcModule << DstModule;
 }
-
-static bool handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
-                                       ValueHandle Function,
-                                       ValueHandle calleeRTTI,
-                                       ValueHandle fnRTTI, ReportOptions Opts) {
-  if (checkTypeInfoEquality(reinterpret_cast<void *>(calleeRTTI),
-                            reinterpret_cast<void *>(fnRTTI)))
-    return false;
-
-  SourceLocation CallLoc = Data->Loc.acquire();
-  ErrorType ET = ErrorType::FunctionTypeMismatch;
-
-  if (ignoreReport(CallLoc, Opts, ET))
-    return true;
-
-  ScopedReport R(Opts, CallLoc, ET);
-
-  SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));
-  const char *FName = FLoc.get()->info.function;
-  if (!FName)
-    FName = "(unknown)";
-
-  Diag(CallLoc, DL_Error, ET,
-       "call to function %0 through pointer to incorrect function type %1")
-      << FName << Data->Type;
-  Diag(FLoc, DL_Note, ET, "%0 defined here") << FName;
-  return true;
-}
-
-void __ubsan_handle_function_type_mismatch_v1(FunctionTypeMismatchData *Data,
-                                              ValueHandle Function,
-                                              ValueHandle calleeRTTI,
-                                              ValueHandle fnRTTI) {
-  GET_REPORT_OPTIONS(false);
-  handleFunctionTypeMismatch(Data, Function, calleeRTTI, fnRTTI, Opts);
-}
-
-void __ubsan_handle_function_type_mismatch_v1_abort(
-    FunctionTypeMismatchData *Data, ValueHandle Function,
-    ValueHandle calleeRTTI, ValueHandle fnRTTI) {
-  GET_REPORT_OPTIONS(true);
-  if (handleFunctionTypeMismatch(Data, Function, calleeRTTI, fnRTTI, Opts))
-    Die();
-}
 }  // namespace __ubsan
 
 #endif // CAN_SANITIZE_UB
diff --git a/libsanitizer/ubsan/ubsan_handlers_cxx.h b/libsanitizer/ubsan/ubsan_handlers_cxx.h
index f6f24e8d63ca..71695cbdc090 100644
--- a/libsanitizer/ubsan/ubsan_handlers_cxx.h
+++ b/libsanitizer/ubsan/ubsan_handlers_cxx.h
@@ -33,19 +33,6 @@  void __ubsan_handle_dynamic_type_cache_miss(
 extern "C" SANITIZER_INTERFACE_ATTRIBUTE
 void __ubsan_handle_dynamic_type_cache_miss_abort(
   DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash);
-
-struct FunctionTypeMismatchData;
-
-extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
-__ubsan_handle_function_type_mismatch_v1(FunctionTypeMismatchData *Data,
-                                         ValueHandle Val,
-                                         ValueHandle calleeRTTI,
-                                         ValueHandle fnRTTI);
-extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
-__ubsan_handle_function_type_mismatch_v1_abort(FunctionTypeMismatchData *Data,
-                                               ValueHandle Val,
-                                               ValueHandle calleeRTTI,
-                                               ValueHandle fnRTTI);
 }
 
 #endif // UBSAN_HANDLERS_CXX_H
diff --git a/libsanitizer/ubsan/ubsan_init.cpp b/libsanitizer/ubsan/ubsan_init.cpp
index 5802d58896f0..aea7ca00e3cb 100644
--- a/libsanitizer/ubsan/ubsan_init.cpp
+++ b/libsanitizer/ubsan/ubsan_init.cpp
@@ -43,8 +43,8 @@  static void CommonStandaloneInit() {
   SanitizerToolName = GetSanititizerToolName();
   CacheBinaryName();
   InitializeFlags();
-  __sanitizer::InitializePlatformEarly();
   __sanitizer_set_report_path(common_flags()->log_path);
+  __sanitizer::InitializePlatformEarly();
   AndroidLogInit();
   InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
   CommonInit();
diff --git a/libsanitizer/ubsan/ubsan_init_standalone_preinit.cpp b/libsanitizer/ubsan/ubsan_init_standalone_preinit.cpp
index fabbf919a402..8a2a631834b9 100644
--- a/libsanitizer/ubsan/ubsan_init_standalone_preinit.cpp
+++ b/libsanitizer/ubsan/ubsan_init_standalone_preinit.cpp
@@ -30,6 +30,6 @@  static void PreInitAsStandalone() {
 
 } // namespace __ubsan
 
-__attribute__((section(".preinit_array"), used)) void (*__local_ubsan_preinit)(
-    void) = __ubsan::PreInitAsStandalone;
+__attribute__((section(".preinit_array"), used)) static auto preinit =
+    __ubsan::PreInitAsStandalone;
 #endif // SANITIZER_CAN_USE_PREINIT_ARRAY
diff --git a/libsanitizer/ubsan/ubsan_interface.inc b/libsanitizer/ubsan/ubsan_interface.inc
index f95f71af3ed1..cb27feb5d7e9 100644
--- a/libsanitizer/ubsan/ubsan_interface.inc
+++ b/libsanitizer/ubsan/ubsan_interface.inc
@@ -21,8 +21,6 @@  INTERFACE_FUNCTION(__ubsan_handle_dynamic_type_cache_miss)
 INTERFACE_FUNCTION(__ubsan_handle_dynamic_type_cache_miss_abort)
 INTERFACE_FUNCTION(__ubsan_handle_float_cast_overflow)
 INTERFACE_FUNCTION(__ubsan_handle_float_cast_overflow_abort)
-INTERFACE_FUNCTION(__ubsan_handle_function_type_mismatch_v1)
-INTERFACE_FUNCTION(__ubsan_handle_function_type_mismatch_v1_abort)
 INTERFACE_FUNCTION(__ubsan_handle_function_type_mismatch)
 INTERFACE_FUNCTION(__ubsan_handle_function_type_mismatch_abort)
 INTERFACE_FUNCTION(__ubsan_handle_implicit_conversion)
diff --git a/libsanitizer/ubsan/ubsan_platform.h b/libsanitizer/ubsan/ubsan_platform.h
index ad3e883f0f35..d2cc2e10bd2f 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_signals_standalone.cpp b/libsanitizer/ubsan/ubsan_signals_standalone.cpp
index 354f847fab71..68edd3a1b206 100644
--- a/libsanitizer/ubsan/ubsan_signals_standalone.cpp
+++ b/libsanitizer/ubsan/ubsan_signals_standalone.cpp
@@ -66,6 +66,11 @@  void InitializeDeadlySignals() {
     return;
   is_initialized = true;
   InitializeSignalInterceptors();
+#if SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION
+  // REAL(sigaction_symname) is nullptr in a static link. Bail out.
+  if (!REAL(sigaction_symname))
+    return;
+#endif
   InstallDeadlySignalHandlers(&UBsanOnDeadlySignal);
 }
 
diff --git a/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp b/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp
index 468a8fcd603f..15788574dd99 100644
--- a/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp
+++ b/libsanitizer/ubsan/ubsan_type_hash_itanium.cpp
@@ -207,7 +207,7 @@  struct VtablePrefix {
   std::type_info *TypeInfo;
 };
 VtablePrefix *getVtablePrefix(void *Vtable) {
-  Vtable = ptrauth_auth_data(Vtable, ptrauth_key_cxx_vtable_pointer, 0);
+  Vtable = ptrauth_strip(Vtable, ptrauth_key_cxx_vtable_pointer);
   VtablePrefix *Vptr = reinterpret_cast<VtablePrefix*>(Vtable);
   VtablePrefix *Prefix = Vptr - 1;
   if (!IsAccessibleMemoryRange((uptr)Prefix, sizeof(VtablePrefix)))
diff --git a/libsanitizer/ubsan/ubsan_value.cpp b/libsanitizer/ubsan/ubsan_value.cpp
index dc61e5b939d9..6e88ebaf34d4 100644
--- a/libsanitizer/ubsan/ubsan_value.cpp
+++ b/libsanitizer/ubsan/ubsan_value.cpp
@@ -67,18 +67,21 @@  const char *__ubsan::getObjCClassName(ValueHandle Pointer) {
 
 SIntMax Value::getSIntValue() const {
   CHECK(getType().isSignedIntegerTy());
+  // Val was zero-extended to ValueHandle. Sign-extend from original width
+  // to SIntMax.
+  const unsigned ExtraBits =
+      sizeof(SIntMax) * 8 - getType().getIntegerBitCount();
   if (isInlineInt()) {
-    // Val was zero-extended to ValueHandle. Sign-extend from original width
-    // to SIntMax.
-    const unsigned ExtraBits =
-      sizeof(SIntMax) * 8 - getType().getIntegerBitWidth();
     return SIntMax(UIntMax(Val) << ExtraBits) >> ExtraBits;
   }
-  if (getType().getIntegerBitWidth() == 64)
-    return *reinterpret_cast<s64*>(Val);
+  if (getType().getIntegerBitWidth() == 64) {
+    return SIntMax(UIntMax(*reinterpret_cast<s64 *>(Val)) << ExtraBits) >>
+           ExtraBits;
+  }
 #if HAVE_INT128_T
   if (getType().getIntegerBitWidth() == 128)
-    return *reinterpret_cast<s128*>(Val);
+    return SIntMax(UIntMax(*reinterpret_cast<s128 *>(Val)) << ExtraBits) >>
+           ExtraBits;
 #else
   if (getType().getIntegerBitWidth() == 128)
     UNREACHABLE("libclang_rt.ubsan was built without __int128 support");
diff --git a/libsanitizer/ubsan/ubsan_value.h b/libsanitizer/ubsan/ubsan_value.h
index e0957276dd24..430c9ea0dc8d 100644
--- a/libsanitizer/ubsan/ubsan_value.h
+++ b/libsanitizer/ubsan/ubsan_value.h
@@ -103,6 +103,13 @@  public:
     /// representation is that of bitcasting the floating-point value to an
     /// integer type.
     TK_Float = 0x0001,
+    /// An _BitInt(N) type. Lowest bit is 1 for a signed value, 0 for an
+    /// unsigned value. Remaining bits are log_2(bit_width). The value
+    /// representation is the integer itself if it fits into a ValueHandle, and
+    /// a pointer to the integer otherwise. TypeName contains the true width
+    /// of the type for the signed _BitInt(N) type stored after zero bit after
+    /// TypeName as 32-bit unsigned integer.
+    TK_BitInt = 0x0002,
     /// Any other type. The value representation is unspecified.
     TK_Unknown = 0xffff
   };
@@ -113,10 +120,15 @@  public:
     return static_cast<Kind>(TypeKind);
   }
 
-  bool isIntegerTy() const { return getKind() == TK_Integer; }
+  bool isIntegerTy() const {
+    return getKind() == TK_Integer || getKind() == TK_BitInt;
+  }
+  bool isBitIntTy() const { return getKind() == TK_BitInt; }
+
   bool isSignedIntegerTy() const {
     return isIntegerTy() && (TypeInfo & 1);
   }
+  bool isSignedBitIntTy() const { return isBitIntTy() && (TypeInfo & 1); }
   bool isUnsignedIntegerTy() const {
     return isIntegerTy() && !(TypeInfo & 1);
   }
@@ -125,6 +137,25 @@  public:
     return 1 << (TypeInfo >> 1);
   }
 
+  const char *getBitIntBitCountPointer() const {
+    DCHECK(isBitIntTy());
+    DCHECK(isSignedBitIntTy());
+    // Scan Name for zero and return the next address
+    const char *p = getTypeName();
+    while (*p != '\0')
+      ++p;
+    // Return the next address
+    return p + 1;
+  }
+
+  unsigned getIntegerBitCount() const {
+    DCHECK(isIntegerTy());
+    if (isSignedBitIntTy())
+      return *reinterpret_cast<const u32 *>(getBitIntBitCountPointer());
+    else
+      return getIntegerBitWidth();
+  }
+
   bool isFloatTy() const { return getKind() == TK_Float; }
   unsigned getFloatBitWidth() const {
     CHECK(isFloatTy());
diff --git a/libsanitizer/ubsan/ubsan_win_dll_thunk.cpp b/libsanitizer/ubsan/ubsan_win_dll_thunk.cpp
deleted file mode 100644
index 5ac7fc3e08e4..000000000000
--- a/libsanitizer/ubsan/ubsan_win_dll_thunk.cpp
+++ /dev/null
@@ -1,20 +0,0 @@ 
-//===-- ubsan_win_dll_thunk.cpp -------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a family of thunks that should be statically linked into
-// the DLLs that have instrumentation in order to delegate the calls to the
-// shared runtime that lives in the main binary.
-// See https://github.com/google/sanitizers/issues/209 for the details.
-//===----------------------------------------------------------------------===//
-#ifdef SANITIZER_DLL_THUNK
-#include "sanitizer_common/sanitizer_win_dll_thunk.h"
-// Ubsan interface functions.
-#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name)
-#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
-#include "ubsan_interface.inc"
-#endif // SANITIZER_DLL_THUNK
diff --git a/libsanitizer/ubsan/ubsan_win_dynamic_runtime_thunk.cpp b/libsanitizer/ubsan/ubsan_win_runtime_thunk.cpp
similarity index 62%
rename from libsanitizer/ubsan/ubsan_win_dynamic_runtime_thunk.cpp
rename to libsanitizer/ubsan/ubsan_win_runtime_thunk.cpp
index 00722b4033a5..5ca7d6f385cf 100644
--- a/libsanitizer/ubsan/ubsan_win_dynamic_runtime_thunk.cpp
+++ b/libsanitizer/ubsan/ubsan_win_runtime_thunk.cpp
@@ -1,4 +1,4 @@ 
-//===-- ubsan_win_dynamic_runtime_thunk.cpp -------------------------------===//
+//===-- ubsan_win_runtime_thunk.cpp -----------------------------        --===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -10,11 +10,14 @@ 
 // to interact with Ubsan, when it is included in a dll.
 //
 //===----------------------------------------------------------------------===//
-#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK
+#if defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) ||                                \
+    defined(SANITIZER_STATIC_RUNTIME_THUNK)
 #define SANITIZER_IMPORT_INTERFACE 1
 #include "sanitizer_common/sanitizer_win_defs.h"
+#include "sanitizer_common/sanitizer_win_thunk_interception.h"
 // Define weak alias for all weak functions imported from ubsan.
 #define INTERFACE_FUNCTION(Name)
-#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name)
+#define INTERFACE_WEAK_FUNCTION(Name) REGISTER_WEAK_FUNCTION(Name)
 #include "ubsan_interface.inc"
-#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK
+#endif // defined(SANITIZER_DYNAMIC_RUNTIME_THUNK) ||
+       // defined(SANITIZER_STATIC_RUNTIME_THUNK)
diff --git a/libsanitizer/ubsan/ubsan_win_weak_interception.cpp b/libsanitizer/ubsan/ubsan_win_weak_interception.cpp
deleted file mode 100644
index 01db0c0ce78a..000000000000
--- a/libsanitizer/ubsan/ubsan_win_weak_interception.cpp
+++ /dev/null
@@ -1,23 +0,0 @@ 
-//===-- ubsan_win_weak_interception.cpp -----------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-// This module should be included in Ubsan when it is implemented as a shared
-// library on Windows (dll), in order to delegate the calls of weak functions to
-// the implementation in the main executable when a strong definition is
-// provided.
-//===----------------------------------------------------------------------===//
-#ifdef SANITIZER_DYNAMIC
-#include "sanitizer_common/sanitizer_win_weak_interception.h"
-#include "ubsan_flags.h"
-#include "ubsan_monitor.h"
-// Check if strong definitions for weak functions are present in the main
-// executable. If that is the case, override dll functions to point to strong
-// implementations.
-#define INTERFACE_FUNCTION(Name)
-#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
-#include "ubsan_interface.inc"
-#endif // SANITIZER_DYNAMIC