Merge c3cc767cf for LLVM update to 349610

Change-Id: I4af85ae176aedf4f6100c9b072a3f52848137634
diff --git a/cmake/Modules/CompilerRTUtils.cmake b/cmake/Modules/CompilerRTUtils.cmake
index d2cb486..c450032 100644
--- a/cmake/Modules/CompilerRTUtils.cmake
+++ b/cmake/Modules/CompilerRTUtils.cmake
@@ -337,7 +337,10 @@
 function(get_compiler_rt_target arch variable)
   string(FIND ${COMPILER_RT_DEFAULT_TARGET_TRIPLE} "-" dash_index)
   string(SUBSTRING ${COMPILER_RT_DEFAULT_TARGET_TRIPLE} ${dash_index} -1 triple_suffix)
-  if(ANDROID AND ${arch} STREQUAL "i386")
+  if(COMPILER_RT_DEFAULT_TARGET_ONLY)
+    # Use exact spelling when building only for the target specified to CMake.
+    set(target "${COMPILER_RT_DEFAULT_TARGET_TRIPLE}")
+  elseif(ANDROID AND ${arch} STREQUAL "i386")
     set(target "i686${COMPILER_RT_OS_SUFFIX}${triple_suffix}")
   else()
     set(target "${arch}${triple_suffix}")
diff --git a/cmake/Modules/HandleCompilerRT.cmake b/cmake/Modules/HandleCompilerRT.cmake
index 855d0ff..61b7792 100644
--- a/cmake/Modules/HandleCompilerRT.cmake
+++ b/cmake/Modules/HandleCompilerRT.cmake
@@ -4,12 +4,16 @@
   if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET)
     list(APPEND CLANG_COMMAND "--target=${CMAKE_CXX_COMPILER_TARGET}")
   endif()
+  get_property(SANITIZER_CXX_FLAGS CACHE CMAKE_CXX_FLAGS PROPERTY VALUE)
+  string(REPLACE " " ";" SANITIZER_CXX_FLAGS "${SANITIZER_CXX_FLAGS}")
+  list(APPEND CLANG_COMMAND ${SANITIZER_CXX_FLAGS})
   execute_process(
       COMMAND ${CLANG_COMMAND}
       RESULT_VARIABLE HAD_ERROR
       OUTPUT_VARIABLE LIBRARY_FILE
   )
   string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE)
+  file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE)
   string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}")
   if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}")
     message(STATUS "Found compiler-rt ${name} library: ${LIBRARY_FILE}")
diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake
index 8ab9f1f..7e9ad63 100644
--- a/cmake/config-ix.cmake
+++ b/cmake/config-ix.cmake
@@ -121,10 +121,12 @@
 
 # Look for terminfo library, used in unittests that depend on LLVMSupport.
 if(LLVM_ENABLE_TERMINFO)
-  foreach(library tinfo terminfo curses ncurses ncursesw)
+  foreach(library terminfo tinfo curses ncurses ncursesw)
+    string(TOUPPER ${library} library_suffix)
     check_library_exists(
-      ${library} setupterm "" COMPILER_RT_HAS_TERMINFO)
-    if(COMPILER_RT_HAS_TERMINFO)
+      ${library} setupterm "" COMPILER_RT_HAS_TERMINFO_${library_suffix})
+    if(COMPILER_RT_HAS_TERMINFO_${library_suffix})
+      set(COMPILER_RT_HAS_TERMINFO TRUE)
       set(COMPILER_RT_TERMINFO_LIB "${library}")
       break()
     endif()
@@ -639,7 +641,7 @@
 endif()
 
 if (COMPILER_RT_HAS_SANITIZER_COMMON AND XRAY_SUPPORTED_ARCH AND
-    OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|OpenBSD")
+    OS_NAME MATCHES "Darwin|Linux|FreeBSD|NetBSD|OpenBSD|Fuchsia")
   set(COMPILER_RT_HAS_XRAY TRUE)
 else()
   set(COMPILER_RT_HAS_XRAY FALSE)
diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h
index 93d6f29..51fba25 100644
--- a/lib/asan/asan_allocator.h
+++ b/lib/asan/asan_allocator.h
@@ -162,22 +162,29 @@
 static const uptr kRegionSizeLog = 20;
 static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
 # if SANITIZER_WORDSIZE == 32
-typedef FlatByteMap<kNumRegions> ByteMap;
+template <typename AddressSpaceView>
+using ByteMapASVT = FlatByteMap<kNumRegions, AddressSpaceView>;
 # elif SANITIZER_WORDSIZE == 64
-typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+template <typename AddressSpaceView>
+using ByteMapASVT =
+    TwoLevelByteMap<(kNumRegions >> 12), 1 << 12, AddressSpaceView>;
 # endif
 typedef CompactSizeClassMap SizeClassMap;
+template <typename AddressSpaceViewTy>
 struct AP32 {
   static const uptr kSpaceBeg = 0;
   static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
   static const uptr kMetadataSize = 16;
   typedef __asan::SizeClassMap SizeClassMap;
   static const uptr kRegionSizeLog = __asan::kRegionSizeLog;
-  typedef __asan::ByteMap ByteMap;
+  using AddressSpaceView = AddressSpaceViewTy;
+  using ByteMap = __asan::ByteMapASVT<AddressSpaceView>;
   typedef AsanMapUnmapCallback MapUnmapCallback;
   static const uptr kFlags = 0;
 };
-typedef SizeClassAllocator32<AP32> PrimaryAllocator;
+template <typename AddressSpaceView>
+using PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView> >;
+using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
 #endif  // SANITIZER_CAN_USE_ALLOCATOR64
 
 static const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses;
diff --git a/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc
index 4af94c5..a9c97d5 100644
--- a/lib/asan/asan_flags.inc
+++ b/lib/asan/asan_flags.inc
@@ -152,8 +152,6 @@
 ASAN_FLAG(bool, halt_on_error, true,
           "Crash the program after printing the first error report "
           "(WARNING: USE AT YOUR OWN RISK!)")
-ASAN_FLAG(bool, use_odr_indicator, false,
-          "Use special ODR indicator symbol for ODR violation detection")
 ASAN_FLAG(bool, allocator_frees_and_returns_null_on_realloc_zero, true,
           "realloc(p, 0) is equivalent to free(p) by default (Same as the "
           "POSIX standard). If set to false, realloc(p, 0) will return a "
diff --git a/lib/asan/asan_fuchsia.cc b/lib/asan/asan_fuchsia.cc
index 0b5bff4..34399c9 100644
--- a/lib/asan/asan_fuchsia.cc
+++ b/lib/asan/asan_fuchsia.cc
@@ -190,6 +190,13 @@
   AsanThread::TSDDtor(per_thread);
 }
 
+bool HandleDlopenInit() {
+  // Not supported on this platform.
+  static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
+                "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
+  return false;
+}
+
 }  // namespace __asan
 
 // These are declared (in extern "C") by <zircon/sanitizer.h>.
diff --git a/lib/asan/asan_globals.cc b/lib/asan/asan_globals.cc
index 898f7f4..146234a 100644
--- a/lib/asan/asan_globals.cc
+++ b/lib/asan/asan_globals.cc
@@ -83,9 +83,11 @@
 }
 
 static void ReportGlobal(const Global &g, const char *prefix) {
-  Report("%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu\n",
-         prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
-         g.module_name, g.has_dynamic_init);
+  Report(
+      "%s Global[%p]: beg=%p size=%zu/%zu name=%s module=%s dyn_init=%zu "
+      "odr_indicator=%p\n",
+      prefix, &g, (void *)g.beg, g.size, g.size_with_redzone, g.name,
+      g.module_name, g.has_dynamic_init, (void *)g.odr_indicator);
   if (g.location) {
     Report("  location (%p): name=%s[%p], %d %d\n", g.location,
            g.location->filename, g.location->filename, g.location->line_no,
@@ -133,6 +135,9 @@
 // this method in case compiler instruments global variables through their
 // local aliases.
 static void CheckODRViolationViaIndicator(const Global *g) {
+  // Instrumentation requests to skip ODR check.
+  if (g->odr_indicator == UINTPTR_MAX)
+    return;
   u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator);
   if (*odr_indicator == UNREGISTERED) {
     *odr_indicator = REGISTERED;
@@ -183,9 +188,7 @@
 // This routine chooses between two different methods of ODR violation
 // detection.
 static inline bool UseODRIndicator(const Global *g) {
-  // Use ODR indicator method iff use_odr_indicator flag is set and
-  // indicator symbol address is not 0.
-  return flags()->use_odr_indicator && g->odr_indicator > 0;
+  return g->odr_indicator > 0;
 }
 
 // Register a global variable.
@@ -248,7 +251,7 @@
   // implementation. It might not be worth doing anyway.
 
   // Release ODR indicator.
-  if (UseODRIndicator(g)) {
+  if (UseODRIndicator(g) && g->odr_indicator != UINTPTR_MAX) {
     u8 *odr_indicator = reinterpret_cast<u8 *>(g->odr_indicator);
     *odr_indicator = UNREGISTERED;
   }
diff --git a/lib/asan/asan_internal.h b/lib/asan/asan_internal.h
index 654878c..5786949 100644
--- a/lib/asan/asan_internal.h
+++ b/lib/asan/asan_internal.h
@@ -111,6 +111,11 @@
 
 void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name);
 
+// Returns `true` iff most of ASan init process should be skipped due to the
+// ASan library being loaded via `dlopen()`. Platforms may perform any
+// `dlopen()` specific initialization inside this function.
+bool HandleDlopenInit();
+
 // Add convenient macro for interface functions that may be represented as
 // weak hooks.
 #define ASAN_MALLOC_HOOK(ptr, size)                                   \
diff --git a/lib/asan/asan_linux.cc b/lib/asan/asan_linux.cc
index 625f32d..a150b19 100644
--- a/lib/asan/asan_linux.cc
+++ b/lib/asan/asan_linux.cc
@@ -248,6 +248,13 @@
   return dlsym(RTLD_NEXT, sym);
 }
 
+bool HandleDlopenInit() {
+  // Not supported on this platform.
+  static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
+                "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
+  return false;
+}
+
 } // namespace __asan
 
 #endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
diff --git a/lib/asan/asan_malloc_mac.cc b/lib/asan/asan_malloc_mac.cc
index 733ba2d..27281f1 100644
--- a/lib/asan/asan_malloc_mac.cc
+++ b/lib/asan/asan_malloc_mac.cc
@@ -61,4 +61,25 @@
 
 #include "sanitizer_common/sanitizer_malloc_mac.inc"
 
+namespace COMMON_MALLOC_NAMESPACE {
+bool HandleDlopenInit() {
+  static_assert(SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
+                "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be true");
+  // We have no reliable way of knowing how we are being loaded
+  // so make it a requirement on Apple platforms to set this environment
+  // variable to indicate that we want to perform initialization via
+  // dlopen().
+  auto init_str = GetEnv("APPLE_ASAN_INIT_FOR_DLOPEN");
+  if (!init_str)
+    return false;
+  if (internal_strncmp(init_str, "1", 1) != 0)
+    return false;
+  // When we are loaded via `dlopen()` path we still initialize the malloc zone
+  // so Symbolication clients (e.g. `leaks`) that load the ASan allocator can
+  // find an initialized malloc zone.
+  InitMallocZoneFields();
+  return true;
+}
+}  // namespace COMMON_MALLOC_NAMESPACE
+
 #endif
diff --git a/lib/asan/asan_malloc_win.cc b/lib/asan/asan_malloc_win.cc
index a094e05..8879364 100644
--- a/lib/asan/asan_malloc_win.cc
+++ b/lib/asan/asan_malloc_win.cc
@@ -141,6 +141,11 @@
 }
 
 ALLOCATION_FUNCTION_ATTRIBUTE
+size_t _msize_base(void *ptr) {
+  return _msize(ptr);
+}
+
+ALLOCATION_FUNCTION_ATTRIBUTE
 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.
@@ -235,6 +240,7 @@
   TryToOverrideFunction("_recalloc_base", (uptr)_recalloc);
   TryToOverrideFunction("_recalloc_crt", (uptr)_recalloc);
   TryToOverrideFunction("_msize", (uptr)_msize);
+  TryToOverrideFunction("_msize_base", (uptr)_msize);
   TryToOverrideFunction("_expand", (uptr)_expand);
   TryToOverrideFunction("_expand_base", (uptr)_expand);
 
diff --git a/lib/asan/asan_rtems.cc b/lib/asan/asan_rtems.cc
index a4af940..b48cc6a 100644
--- a/lib/asan/asan_rtems.cc
+++ b/lib/asan/asan_rtems.cc
@@ -213,6 +213,12 @@
   }
 }
 
+bool HandleDlopenInit() {
+  // Not supported on this platform.
+  static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
+                "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
+  return false;
+}
 }  // namespace __asan
 
 // These are declared (in extern "C") by <some_path/sanitizer.h>.
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index 0c63903..0ecbcd5 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -396,6 +396,14 @@
   // initialization steps look at flags().
   InitializeFlags();
 
+  // 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())) {
+    asan_init_is_running = false;
+    VReport(1, "AddressSanitizer init is being performed for dlopen().\n");
+    return;
+  }
+
   AsanCheckIncompatibleRT();
   AsanCheckDynamicRTPrereqs();
   AvoidCVE_2016_2143();
diff --git a/lib/asan/asan_win.cc b/lib/asan/asan_win.cc
index 5661d91..068f4a5 100644
--- a/lib/asan/asan_win.cc
+++ b/lib/asan/asan_win.cc
@@ -322,6 +322,13 @@
   return 0;
 }
 
+bool HandleDlopenInit() {
+  // Not supported on this platform.
+  static_assert(!SANITIZER_SUPPORTS_INIT_FOR_DLOPEN,
+                "Expected SANITIZER_SUPPORTS_INIT_FOR_DLOPEN to be false");
+  return false;
+}
+
 #if !ASAN_DYNAMIC
 // The CRT runs initializers in this order:
 // - C initializers, from XIA to XIZ
diff --git a/lib/asan/asan_win_dll_thunk.cc b/lib/asan/asan_win_dll_thunk.cc
index c6a313d..df593ab 100644
--- a/lib/asan/asan_win_dll_thunk.cc
+++ b/lib/asan/asan_win_dll_thunk.cc
@@ -48,6 +48,7 @@
 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)
 
diff --git a/lib/asan/scripts/asan_symbolize.py b/lib/asan/scripts/asan_symbolize.py
index 68b6f09..2dbb052 100755
--- a/lib/asan/scripts/asan_symbolize.py
+++ b/lib/asan/scripts/asan_symbolize.py
@@ -231,6 +231,10 @@
     """Overrides Symbolizer.symbolize."""
     if self.binary != binary:
       return None
+    if not os.path.exists(binary):
+      # If the binary doesn't exist atos will exit which will lead to IOError
+      # exceptions being raised later on so just don't try to symbolize.
+      return ['{} ({}:{}+{})'.format(addr, binary, self.arch, offset)]
     atos_line = self.atos.convert('0x%x' % int(offset, 16))
     while "got symbolicator for" in atos_line:
       atos_line = self.atos.readline()
@@ -473,7 +477,7 @@
     symbolized_line = self.symbolize_address(addr, binary, offset, arch)
     if not symbolized_line:
       if original_binary != binary:
-        symbolized_line = self.symbolize_address(addr, binary, offset, arch)
+        symbolized_line = self.symbolize_address(addr, original_binary, offset, arch)
     return self.get_symbolized_lines(symbolized_line)
 
 
diff --git a/lib/builtins/cpu_model.c b/lib/builtins/cpu_model.c
index 54f1add..fb2b899 100644
--- a/lib/builtins/cpu_model.c
+++ b/lib/builtins/cpu_model.c
@@ -462,12 +462,12 @@
   unsigned Features2 = 0;
   unsigned EAX, EBX;
 
-#define setFeature(F)              \
-  do {                             \
-    if (F < 32)                    \
-      Features |= 1 << F;          \
-    else if (F < 64)               \
-      Features2 |= 1 << (F - 32);  \
+#define setFeature(F)                       \
+  do {                                      \
+    if (F < 32)                             \
+      Features |= 1U << (F & 0x1f);         \
+    else if (F < 64)                        \
+      Features2 |= 1U << ((F - 32) & 0x1f); \
   } while (0)
 
   if ((EDX >> 15) & 1)
diff --git a/lib/builtins/divdf3.c b/lib/builtins/divdf3.c
index 04a4dc5..411c82e 100644
--- a/lib/builtins/divdf3.c
+++ b/lib/builtins/divdf3.c
@@ -21,36 +21,36 @@
 
 COMPILER_RT_ABI fp_t
 __divdf3(fp_t a, fp_t b) {
-    
+
     const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
     const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
     const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
-    
+
     rep_t aSignificand = toRep(a) & significandMask;
     rep_t bSignificand = toRep(b) & significandMask;
     int scale = 0;
-    
+
     // Detect if a or b is zero, denormal, infinity, or NaN.
     if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
-        
+
         const rep_t aAbs = toRep(a) & absMask;
         const rep_t bAbs = toRep(b) & absMask;
-        
+
         // NaN / anything = qNaN
         if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
         // anything / NaN = qNaN
         if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-        
+
         if (aAbs == infRep) {
             // infinity / infinity = NaN
             if (bAbs == infRep) return fromRep(qnanRep);
             // infinity / anything else = +/- infinity
             else return fromRep(aAbs | quotientSign);
         }
-        
+
         // anything else / infinity = +/- 0
         if (bAbs == infRep) return fromRep(quotientSign);
-        
+
         if (!aAbs) {
             // zero / zero = NaN
             if (!bAbs) return fromRep(qnanRep);
@@ -59,28 +59,28 @@
         }
         // anything else / zero = +/- infinity
         if (!bAbs) return fromRep(infRep | quotientSign);
-        
+
         // one or both of a or b is denormal, the other (if applicable) is a
         // normal number.  Renormalize one or both of a and b, and set scale to
         // include the necessary exponent adjustment.
         if (aAbs < implicitBit) scale += normalize(&aSignificand);
         if (bAbs < implicitBit) scale -= normalize(&bSignificand);
     }
-    
+
     // Or in the implicit significand bit.  (If we fell through from the
     // denormal path it was already set by normalize( ), but setting it twice
     // won't hurt anything.)
     aSignificand |= implicitBit;
     bSignificand |= implicitBit;
     int quotientExponent = aExponent - bExponent + scale;
-    
+
     // Align the significand of b as a Q31 fixed-point number in the range
     // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax
     // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2.  This
     // is accurate to about 3.5 binary digits.
     const uint32_t q31b = bSignificand >> 21;
     uint32_t recip32 = UINT32_C(0x7504f333) - q31b;
-    
+
     // Now refine the reciprocal estimate using a Newton-Raphson iteration:
     //
     //     x1 = x0 * (2 - x0 * b)
@@ -95,13 +95,13 @@
     recip32 = (uint64_t)recip32 * correction32 >> 31;
     correction32 = -((uint64_t)recip32 * q31b >> 32);
     recip32 = (uint64_t)recip32 * correction32 >> 31;
-    
+
     // recip32 might have overflowed to exactly zero in the preceding
     // computation if the high word of b is exactly 1.0.  This would sabotage
     // the full-width final stage of the computation that follows, so we adjust
     // recip32 downward by one bit.
     recip32--;
-    
+
     // We need to perform one more iteration to get us to 56 binary digits;
     // The last iteration needs to happen with extra precision.
     const uint32_t q63blo = bSignificand << 11;
@@ -110,14 +110,14 @@
     uint32_t cHi = correction >> 32;
     uint32_t cLo = correction;
     reciprocal = (uint64_t)recip32*cHi + ((uint64_t)recip32*cLo >> 32);
-    
+
     // We already adjusted the 32-bit estimate, now we need to adjust the final
     // 64-bit reciprocal estimate downward to ensure that it is strictly smaller
     // than the infinitely precise exact reciprocal.  Because the computation
     // of the Newton-Raphson step is truncating at every step, this adjustment
     // is small; most of the work is already done.
     reciprocal -= 2;
-    
+
     // The numerical reciprocal is accurate to within 2^-56, lies in the
     // interval [0.5, 1.0), and is strictly smaller than the true reciprocal
     // of b.  Multiplying a by this reciprocal thus gives a numerical q = a/b
@@ -127,12 +127,12 @@
     //    2. q is in the interval [0.5, 2.0)
     //    3. the error in q is bounded away from 2^-53 (actually, we have a
     //       couple of bits to spare, but this is all we need).
-    
+
     // We need a 64 x 64 multiply high to compute q, which isn't a basic
     // operation in C, so we need to be a little bit fussy.
     rep_t quotient, quotientLo;
     wideMultiply(aSignificand << 2, reciprocal, &quotient, &quotientLo);
-    
+
     // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
     // In either case, we are going to compute a residual of the form
     //
@@ -141,7 +141,7 @@
     // We know from the construction of q that r satisfies:
     //
     //     0 <= r < ulp(q)*b
-    // 
+    //
     // if r is greater than 1/2 ulp(q)*b, then q rounds up.  Otherwise, we
     // already have the correct result.  The exact halfway case cannot occur.
     // We also take this time to right shift quotient if it falls in the [1,2)
@@ -154,20 +154,20 @@
         quotient >>= 1;
         residual = (aSignificand << 52) - quotient * bSignificand;
     }
-    
+
     const int writtenExponent = quotientExponent + exponentBias;
-    
+
     if (writtenExponent >= maxExponent) {
         // If we have overflowed the exponent, return infinity.
         return fromRep(infRep | quotientSign);
     }
-    
+
     else if (writtenExponent < 1) {
         // Flush denormals to zero.  In the future, it would be nice to add
         // code to round them correctly.
         return fromRep(quotientSign);
     }
-    
+
     else {
         const bool round = (residual << 1) > bSignificand;
         // Clear the implicit bit
diff --git a/lib/builtins/divsf3.c b/lib/builtins/divsf3.c
index 65294d7..a74917f 100644
--- a/lib/builtins/divsf3.c
+++ b/lib/builtins/divsf3.c
@@ -21,36 +21,36 @@
 
 COMPILER_RT_ABI fp_t
 __divsf3(fp_t a, fp_t b) {
-    
+
     const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
     const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
     const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
-    
+
     rep_t aSignificand = toRep(a) & significandMask;
     rep_t bSignificand = toRep(b) & significandMask;
     int scale = 0;
-    
+
     // Detect if a or b is zero, denormal, infinity, or NaN.
     if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
-        
+
         const rep_t aAbs = toRep(a) & absMask;
         const rep_t bAbs = toRep(b) & absMask;
-        
+
         // NaN / anything = qNaN
         if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
         // anything / NaN = qNaN
         if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-        
+
         if (aAbs == infRep) {
             // infinity / infinity = NaN
             if (bAbs == infRep) return fromRep(qnanRep);
             // infinity / anything else = +/- infinity
             else return fromRep(aAbs | quotientSign);
         }
-        
+
         // anything else / infinity = +/- 0
         if (bAbs == infRep) return fromRep(quotientSign);
-        
+
         if (!aAbs) {
             // zero / zero = NaN
             if (!bAbs) return fromRep(qnanRep);
@@ -59,28 +59,28 @@
         }
         // anything else / zero = +/- infinity
         if (!bAbs) return fromRep(infRep | quotientSign);
-        
+
         // one or both of a or b is denormal, the other (if applicable) is a
         // normal number.  Renormalize one or both of a and b, and set scale to
         // include the necessary exponent adjustment.
         if (aAbs < implicitBit) scale += normalize(&aSignificand);
         if (bAbs < implicitBit) scale -= normalize(&bSignificand);
     }
-    
+
     // Or in the implicit significand bit.  (If we fell through from the
     // denormal path it was already set by normalize( ), but setting it twice
     // won't hurt anything.)
     aSignificand |= implicitBit;
     bSignificand |= implicitBit;
     int quotientExponent = aExponent - bExponent + scale;
-    
+
     // Align the significand of b as a Q31 fixed-point number in the range
     // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax
     // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2.  This
     // is accurate to about 3.5 binary digits.
     uint32_t q31b = bSignificand << 8;
     uint32_t reciprocal = UINT32_C(0x7504f333) - q31b;
-    
+
     // Now refine the reciprocal estimate using a Newton-Raphson iteration:
     //
     //     x1 = x0 * (2 - x0 * b)
@@ -95,7 +95,7 @@
     reciprocal = (uint64_t)reciprocal * correction >> 31;
     correction = -((uint64_t)reciprocal * q31b >> 32);
     reciprocal = (uint64_t)reciprocal * correction >> 31;
-    
+
     // Exhaustive testing shows that the error in reciprocal after three steps
     // is in the interval [-0x1.f58108p-31, 0x1.d0e48cp-29], in line with our
     // expectations.  We bump the reciprocal by a tiny value to force the error
@@ -103,7 +103,7 @@
     // be specific).  This also causes 1/1 to give a sensible approximation
     // instead of zero (due to overflow).
     reciprocal -= 2;
-    
+
     // The numerical reciprocal is accurate to within 2^-28, lies in the
     // interval [0x1.000000eep-1, 0x1.fffffffcp-1], and is strictly smaller
     // than the true reciprocal of b.  Multiplying a by this reciprocal thus
@@ -115,9 +115,9 @@
     //       from the fact that we truncate the product, and the 2^27 term
     //       is the error in the reciprocal of b scaled by the maximum
     //       possible value of a.  As a consequence of this error bound,
-    //       either q or nextafter(q) is the correctly rounded 
+    //       either q or nextafter(q) is the correctly rounded
     rep_t quotient = (uint64_t)reciprocal*(aSignificand << 1) >> 32;
-    
+
     // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
     // In either case, we are going to compute a residual of the form
     //
@@ -126,7 +126,7 @@
     // We know from the construction of q that r satisfies:
     //
     //     0 <= r < ulp(q)*b
-    // 
+    //
     // if r is greater than 1/2 ulp(q)*b, then q rounds up.  Otherwise, we
     // already have the correct result.  The exact halfway case cannot occur.
     // We also take this time to right shift quotient if it falls in the [1,2)
@@ -141,18 +141,18 @@
     }
 
     const int writtenExponent = quotientExponent + exponentBias;
-    
+
     if (writtenExponent >= maxExponent) {
         // If we have overflowed the exponent, return infinity.
         return fromRep(infRep | quotientSign);
     }
-    
+
     else if (writtenExponent < 1) {
         // Flush denormals to zero.  In the future, it would be nice to add
         // code to round them correctly.
         return fromRep(quotientSign);
     }
-    
+
     else {
         const bool round = (residual << 1) > bSignificand;
         // Clear the implicit bit
diff --git a/lib/builtins/gcc_personality_v0.c b/lib/builtins/gcc_personality_v0.c
index 0bc7656..68581ef 100644
--- a/lib/builtins/gcc_personality_v0.c
+++ b/lib/builtins/gcc_personality_v0.c
@@ -206,8 +206,8 @@
     if ( lsda == (uint8_t*) 0 )
         return continueUnwind(exceptionObject, context);
 
-    uintptr_t pc = _Unwind_GetIP(context)-1;
-    uintptr_t funcStart = _Unwind_GetRegionStart(context);
+    uintptr_t pc = (uintptr_t)_Unwind_GetIP(context)-1;
+    uintptr_t funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
     uintptr_t pcOffset = pc - funcStart;
 
     /* Parse LSDA header. */
@@ -249,4 +249,3 @@
     /* No landing pad found, continue unwinding. */
     return continueUnwind(exceptionObject, context);
 }
-
diff --git a/lib/esan/esan_sideline.h b/lib/esan/esan_sideline.h
index 04aff22..74551fb 100644
--- a/lib/esan/esan_sideline.h
+++ b/lib/esan/esan_sideline.h
@@ -17,6 +17,7 @@
 
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_platform_limits_freebsd.h"
 #include "sanitizer_common/sanitizer_platform_limits_posix.h"
 
 namespace __esan {
diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def
index 0417dda..9e212ef 100644
--- a/lib/fuzzer/FuzzerFlags.def
+++ b/lib/fuzzer/FuzzerFlags.def
@@ -17,7 +17,7 @@
 FUZZER_FLAG_INT(max_len, 0, "Maximum length of the test input. "
     "If 0, libFuzzer tries to guess a good value based on the corpus "
     "and reports it. ")
-FUZZER_FLAG_INT(len_control, 1000, "Try generating small inputs first, "
+FUZZER_FLAG_INT(len_control, 100, "Try generating small inputs first, "
   "then try larger inputs over time.  Specifies the rate at which the length "
   "limit is increased (smaller == faster).  If 0, immediately try inputs with "
   "size up to max_len.")
diff --git a/lib/fuzzer/tests/CMakeLists.txt b/lib/fuzzer/tests/CMakeLists.txt
index 2a29348..6abb72d 100644
--- a/lib/fuzzer/tests/CMakeLists.txt
+++ b/lib/fuzzer/tests/CMakeLists.txt
@@ -1,3 +1,5 @@
+include(CompilerRTCompile)
+
 set(LIBFUZZER_UNITTEST_CFLAGS
   ${COMPILER_RT_UNITTEST_CFLAGS}
   ${COMPILER_RT_GTEST_CFLAGS}
diff --git a/lib/hwasan/CMakeLists.txt b/lib/hwasan/CMakeLists.txt
index 0f81a4e..ca257df 100644
--- a/lib/hwasan/CMakeLists.txt
+++ b/lib/hwasan/CMakeLists.txt
@@ -145,6 +145,7 @@
             RTSanitizerCommonCoverage
             RTSanitizerCommonSymbolizer
             RTUbsan
+            RTUbsan_cxx
             # The only purpose of RTHWAsan_dynamic_version_script_dummy is to
             # carry a dependency of the shared runtime on the version script.
             # Replacing it with a straightforward
diff --git a/lib/hwasan/hwasan.cc b/lib/hwasan/hwasan.cc
index 7febaf7..9f2328d 100644
--- a/lib/hwasan/hwasan.cc
+++ b/lib/hwasan/hwasan.cc
@@ -159,11 +159,6 @@
                 request_fast_unwind);
 }
 
-void PrintWarning(uptr pc, uptr bp) {
-  GET_FATAL_STACK_TRACE_PC_BP(pc, bp);
-  ReportInvalidAccess(&stack, 0);
-}
-
 static void HWAsanCheckFailed(const char *file, int line, const char *cond,
                               u64 v1, u64 v2) {
   Report("HWAddressSanitizer CHECK failed: %s:%d \"%s\" (0x%zx, 0x%zx)\n", file,
@@ -234,8 +229,8 @@
 void InitFrameDescriptors(uptr b, uptr e) {
   FrameDescription *beg = reinterpret_cast<FrameDescription *>(b);
   FrameDescription *end = reinterpret_cast<FrameDescription *>(e);
-  // Must have at least one entry, which we can use for a linked list.
-  CHECK_GE(end - beg, 1U);
+  if (beg == end)
+    return;
   AllFrames.push_back({beg, end});
   if (Verbosity())
     for (FrameDescription *frame_descr = beg; frame_descr < end; frame_descr++)
@@ -288,6 +283,8 @@
 
   __sanitizer_set_report_path(common_flags()->log_path);
 
+  AndroidTestTlsSlot();
+
   DisableCoreDumperIfNecessary();
 
   __hwasan_shadow_init();
@@ -297,6 +294,7 @@
 
   MadviseShadow();
 
+  SetPrintfAndReportCallback(AppendToErrorMessageBuffer);
   // This may call libc -> needs initialized shadow.
   AndroidLogInit();
 
diff --git a/lib/hwasan/hwasan.h b/lib/hwasan/hwasan.h
index 2fbc87c..64b1f1a 100644
--- a/lib/hwasan/hwasan.h
+++ b/lib/hwasan/hwasan.h
@@ -104,8 +104,6 @@
   ~SymbolizerScope() { ExitSymbolizer(); }
 };
 
-void PrintWarning(uptr pc, uptr bp);
-
 void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
                    void *context, bool request_fast_unwind);
 
@@ -154,6 +152,10 @@
 
 void UpdateMemoryUsage();
 
+void AppendToErrorMessageBuffer(const char *buffer);
+
+void AndroidTestTlsSlot();
+
 }  // namespace __hwasan
 
 #define HWASAN_MALLOC_HOOK(ptr, size)       \
diff --git a/lib/hwasan/hwasan_allocator.cc b/lib/hwasan/hwasan_allocator.cc
index ddc0928..8fd2349 100644
--- a/lib/hwasan/hwasan_allocator.cc
+++ b/lib/hwasan/hwasan_allocator.cc
@@ -31,11 +31,36 @@
 static const tag_t kFallbackAllocTag = 0xBB;
 static const tag_t kFallbackFreeTag = 0xBC;
 
+enum RightAlignMode {
+  kRightAlignNever,
+  kRightAlignSometimes,
+  kRightAlignAlways
+};
+
+// These two variables are initialized from flags()->malloc_align_right
+// in HwasanAllocatorInit and are never changed afterwards.
+static RightAlignMode right_align_mode = kRightAlignNever;
+static bool right_align_8 = false;
+
+// Initialized in HwasanAllocatorInit, an never changed.
+static ALIGNED(16) u8 tail_magic[kShadowAlignment];
+
 bool HwasanChunkView::IsAllocated() const {
   return metadata_ && metadata_->alloc_context_id && metadata_->requested_size;
 }
 
+// Aligns the 'addr' right to the granule boundary.
+static uptr AlignRight(uptr addr, uptr requested_size) {
+  uptr tail_size = requested_size % kShadowAlignment;
+  if (!tail_size) return addr;
+  if (right_align_8)
+    return tail_size > 8 ? addr : addr + 8;
+  return addr + kShadowAlignment - tail_size;
+}
+
 uptr HwasanChunkView::Beg() const {
+  if (metadata_ && metadata_->right_aligned)
+    return AlignRight(block_, metadata_->requested_size);
   return block_;
 }
 uptr HwasanChunkView::End() const {
@@ -65,6 +90,31 @@
                        !flags()->disable_allocator_tagging);
   SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
   allocator.Init(common_flags()->allocator_release_to_os_interval_ms);
+  switch (flags()->malloc_align_right) {
+    case 0: break;
+    case 1:
+      right_align_mode = kRightAlignSometimes;
+      right_align_8 = false;
+      break;
+    case 2:
+      right_align_mode = kRightAlignAlways;
+      right_align_8 = false;
+      break;
+    case 8:
+      right_align_mode = kRightAlignSometimes;
+      right_align_8 = true;
+      break;
+    case 9:
+      right_align_mode = kRightAlignAlways;
+      right_align_8 = true;
+      break;
+    default:
+      Report("ERROR: unsupported value of malloc_align_right flag: %d\n",
+             flags()->malloc_align_right);
+      Die();
+  }
+  for (uptr i = 0; i < kShadowAlignment; i++)
+    tail_magic[i] = GetCurrentThread()->GenerateRandomTag();
 }
 
 void AllocatorSwallowThreadLocalCache(AllocatorCache *cache) {
@@ -110,12 +160,16 @@
       reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));
   meta->requested_size = static_cast<u32>(orig_size);
   meta->alloc_context_id = StackDepotPut(*stack);
+  meta->right_aligned = false;
   if (zeroise) {
     internal_memset(allocated, 0, size);
   } else if (flags()->max_malloc_fill_size > 0) {
     uptr fill_size = Min(size, (uptr)flags()->max_malloc_fill_size);
     internal_memset(allocated, flags()->malloc_fill_byte, fill_size);
   }
+  if (!right_align_mode)
+    internal_memcpy(reinterpret_cast<u8 *>(allocated) + orig_size, tail_magic,
+                    size - orig_size);
 
   void *user_ptr = allocated;
   if (flags()->tag_in_malloc &&
@@ -123,6 +177,16 @@
     user_ptr = (void *)TagMemoryAligned(
         (uptr)user_ptr, size, t ? t->GenerateRandomTag() : kFallbackAllocTag);
 
+  if ((orig_size % kShadowAlignment) && (alignment <= kShadowAlignment) &&
+      right_align_mode) {
+    uptr as_uptr = reinterpret_cast<uptr>(user_ptr);
+    if (right_align_mode == kRightAlignAlways ||
+        GetTagFromPointer(as_uptr) & 1) {  // use a tag bit as a random bit.
+      user_ptr = reinterpret_cast<void *>(AlignRight(as_uptr, orig_size));
+      meta->right_aligned = 1;
+    }
+  }
+
   HWASAN_MALLOC_HOOK(user_ptr, size);
   return user_ptr;
 }
@@ -143,33 +207,49 @@
     ReportInvalidFree(stack, reinterpret_cast<uptr>(tagged_ptr));
 
   void *untagged_ptr = UntagPtr(tagged_ptr);
+  void *aligned_ptr = reinterpret_cast<void *>(
+      RoundDownTo(reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment));
   Metadata *meta =
-      reinterpret_cast<Metadata *>(allocator.GetMetaData(untagged_ptr));
+      reinterpret_cast<Metadata *>(allocator.GetMetaData(aligned_ptr));
   uptr orig_size = meta->requested_size;
   u32 free_context_id = StackDepotPut(*stack);
   u32 alloc_context_id = meta->alloc_context_id;
+
+  // Check tail magic.
+  uptr tagged_size = TaggedSize(orig_size);
+  if (flags()->free_checks_tail_magic && !right_align_mode && orig_size) {
+    uptr tail_size = tagged_size - orig_size;
+    CHECK_LT(tail_size, kShadowAlignment);
+    void *tail_beg = reinterpret_cast<void *>(
+        reinterpret_cast<uptr>(aligned_ptr) + orig_size);
+    if (tail_size && internal_memcmp(tail_beg, tail_magic, tail_size))
+      ReportTailOverwritten(stack, reinterpret_cast<uptr>(tagged_ptr),
+                            orig_size, tail_size, tail_magic);
+  }
+
   meta->requested_size = 0;
   meta->alloc_context_id = 0;
   // This memory will not be reused by anyone else, so we are free to keep it
   // poisoned.
   Thread *t = GetCurrentThread();
   if (flags()->max_free_fill_size > 0) {
-    uptr fill_size = Min(orig_size, (uptr)flags()->max_free_fill_size);
-    internal_memset(untagged_ptr, flags()->free_fill_byte, fill_size);
+    uptr fill_size =
+        Min(TaggedSize(orig_size), (uptr)flags()->max_free_fill_size);
+    internal_memset(aligned_ptr, flags()->free_fill_byte, fill_size);
   }
   if (flags()->tag_in_free &&
       atomic_load_relaxed(&hwasan_allocator_tagging_enabled))
-    TagMemoryAligned((uptr)untagged_ptr, TaggedSize(orig_size),
+    TagMemoryAligned(reinterpret_cast<uptr>(aligned_ptr), TaggedSize(orig_size),
                      t ? t->GenerateRandomTag() : kFallbackFreeTag);
   if (t) {
-    allocator.Deallocate(t->allocator_cache(), untagged_ptr);
+    allocator.Deallocate(t->allocator_cache(), aligned_ptr);
     if (auto *ha = t->heap_allocations())
       ha->push({reinterpret_cast<uptr>(tagged_ptr), alloc_context_id,
                 free_context_id, static_cast<u32>(orig_size)});
   } else {
     SpinMutexLock l(&fallback_mutex);
     AllocatorCache *cache = &fallback_allocator_cache;
-    allocator.Deallocate(cache, untagged_ptr);
+    allocator.Deallocate(cache, aligned_ptr);
   }
 }
 
@@ -213,8 +293,14 @@
   const void *untagged_ptr = UntagPtr(tagged_ptr);
   if (!untagged_ptr) return 0;
   const void *beg = allocator.GetBlockBegin(untagged_ptr);
-  if (beg != untagged_ptr) return 0;
   Metadata *b = (Metadata *)allocator.GetMetaData(untagged_ptr);
+  if (b->right_aligned) {
+    if (beg != reinterpret_cast<void *>(RoundDownTo(
+                   reinterpret_cast<uptr>(untagged_ptr), kShadowAlignment)))
+      return 0;
+  } else {
+    if (beg != untagged_ptr) return 0;
+  }
   return b->requested_size;
 }
 
diff --git a/lib/hwasan/hwasan_allocator.h b/lib/hwasan/hwasan_allocator.h
index 119ead8..b3f2d6c 100644
--- a/lib/hwasan/hwasan_allocator.h
+++ b/lib/hwasan/hwasan_allocator.h
@@ -29,7 +29,8 @@
 namespace __hwasan {
 
 struct Metadata {
-  u32 requested_size;  // sizes are < 4G.
+  u32 requested_size : 31;  // sizes are < 2G.
+  u32 right_aligned  : 1;
   u32 alloc_context_id;
 };
 
@@ -54,7 +55,8 @@
   static const uptr kMetadataSize = sizeof(Metadata);
   typedef __sanitizer::CompactSizeClassMap SizeClassMap;
   static const uptr kRegionSizeLog = __hwasan::kRegionSizeLog;
-  typedef __hwasan::ByteMap ByteMap;
+  using AddressSpaceView = LocalAddressSpaceView;
+  using ByteMap = __hwasan::ByteMap;
   typedef HwasanMapUnmapCallback MapUnmapCallback;
   static const uptr kFlags = 0;
 };
diff --git a/lib/hwasan/hwasan_flags.inc b/lib/hwasan/hwasan_flags.inc
index f1b416d..b450ab9 100644
--- a/lib/hwasan/hwasan_flags.inc
+++ b/lib/hwasan/hwasan_flags.inc
@@ -37,6 +37,37 @@
     int, max_malloc_fill_size, 0x1000,  // By default, fill only the first 4K.
     "HWASan allocator flag. max_malloc_fill_size is the maximal amount of "
     "bytes that will be filled with malloc_fill_byte on malloc.")
+
+// Rules for malloc alignment on aarch64:
+//   * If the size is 16-aligned, then malloc should return 16-aligned memory.
+//   * Otherwise, malloc should return 8-alignment memory.
+// So,
+//   * If the size is 16-aligned, we don't need to do anything.
+//   * Otherwise we don't have to obey 16-alignment, just the 8-alignment.
+//   * We may want to break the 8-alignment rule to catch more buffer overflows
+//     but this will break valid code in some rare cases, like this:
+//     struct Foo {
+//       // accessed via atomic instructions that require 8-alignment.
+//       std::atomic<int64_t> atomic_stuff;
+//       ...
+//       char vla[1];  // the actual size of vla could be anything.
+//     }
+// Which means that the safe values for malloc_align_right are 0, 8, 9,
+// and the values 1 and 2 may require changes in otherwise valid code.
+
+HWASAN_FLAG(
+    int, malloc_align_right, 0,  // off by default
+    "HWASan allocator flag. "
+    "0 (default): allocations are always aligned left to 16-byte boundary; "
+    "1: allocations are sometimes aligned right to 1-byte boundary (risky); "
+    "2: allocations are always aligned right to 1-byte boundary (risky); "
+    "8: allocations are sometimes aligned right to 8-byte boundary; "
+    "9: allocations are always aligned right to 8-byte boundary."
+  )
+HWASAN_FLAG(bool, free_checks_tail_magic, 1,
+    "If set, free() will check the magic values "
+    "to the right of the allocated object "
+    "if the allocation size is not a divident of the granule size")
 HWASAN_FLAG(
     int, max_free_fill_size, 0,
     "HWASan allocator flag. max_free_fill_size is the maximal amount of "
diff --git a/lib/hwasan/hwasan_interceptors.cc b/lib/hwasan/hwasan_interceptors.cc
index fed4003..d20bdd9 100644
--- a/lib/hwasan/hwasan_interceptors.cc
+++ b/lib/hwasan/hwasan_interceptors.cc
@@ -92,42 +92,6 @@
 } while (0)
 
 
-
-#define HWASAN_READ_RANGE(ctx, offset, size) \
-  CHECK_UNPOISONED(offset, size)
-#define HWASAN_WRITE_RANGE(ctx, offset, size) \
-  CHECK_UNPOISONED(offset, size)
-
-
-
-// Check that [x, x+n) range is unpoisoned.
-#define CHECK_UNPOISONED_0(x, n)                                       \
-  do {                                                                 \
-    sptr __offset = __hwasan_test_shadow(x, n);                         \
-    if (__hwasan::IsInSymbolizer()) break;                              \
-    if (__offset >= 0) {                                               \
-      GET_CALLER_PC_BP_SP;                                             \
-      (void)sp;                                                        \
-      ReportInvalidAccessInsideAddressRange(__func__, x, n, __offset); \
-      __hwasan::PrintWarning(pc, bp);                                   \
-      if (__hwasan::flags()->halt_on_error) {                           \
-        Printf("Exiting\n");                                           \
-        Die();                                                         \
-      }                                                                \
-    }                                                                  \
-  } while (0)
-
-// Check that [x, x+n) range is unpoisoned unless we are in a nested
-// interceptor.
-#define CHECK_UNPOISONED(x, n)                             \
-  do {                                                     \
-    if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
-  } while (0)
-
-#define CHECK_UNPOISONED_STRING_OF_LEN(x, len, n)               \
-  CHECK_UNPOISONED((x),                                         \
-    common_flags()->strict_string_checks ? (len) + 1 : (n) )
-
 int __sanitizer_posix_memalign(void **memptr, uptr alignment, uptr size) {
   GET_MALLOC_STACK_TRACE;
   CHECK_NE(memptr, 0);
diff --git a/lib/hwasan/hwasan_linux.cc b/lib/hwasan/hwasan_linux.cc
index eef332f..af9378c 100644
--- a/lib/hwasan/hwasan_linux.cc
+++ b/lib/hwasan/hwasan_linux.cc
@@ -24,6 +24,7 @@
 #include "hwasan_thread.h"
 #include "hwasan_thread_list.h"
 
+#include <dlfcn.h>
 #include <elf.h>
 #include <link.h>
 #include <pthread.h>
@@ -283,6 +284,22 @@
 }
 #endif
 
+#if SANITIZER_ANDROID
+void AndroidTestTlsSlot() {
+  uptr kMagicValue = 0x010203040A0B0C0D;
+  *(uptr *)get_android_tls_ptr() = kMagicValue;
+  dlerror();
+  if (*(uptr *)get_android_tls_ptr() != kMagicValue) {
+    Printf(
+        "ERROR: Incompatible version of Android: TLS_SLOT_SANITIZER(6) is used "
+        "for dlerror().\n");
+    Die();
+  }
+}
+#else
+void AndroidTestTlsSlot() {}
+#endif
+
 Thread *GetCurrentThread() {
   auto *R = (StackAllocationsRingBuffer*)GetCurrentThreadLongPtr();
   return hwasanThreadList().GetThreadByBufferAddress((uptr)(R->Next()));
@@ -358,11 +375,10 @@
   GetStackTrace(stack, kStackTraceMax, StackTrace::GetNextInstructionPc(sig.pc),
                 sig.bp, uc, common_flags()->fast_unwind_on_fatal);
 
-  ReportTagMismatch(stack, ai.addr, ai.size, ai.is_store);
-
   ++hwasan_report_count;
-  if (flags()->halt_on_error || !ai.recover)
-    Die();
+
+  bool fatal = flags()->halt_on_error || !ai.recover;
+  ReportTagMismatch(stack, ai.addr, ai.size, ai.is_store, fatal);
 
 #if defined(__aarch64__)
   uc->uc_mcontext.pc += 4;
diff --git a/lib/hwasan/hwasan_report.cc b/lib/hwasan/hwasan_report.cc
index 57bd827..ea3e409 100644
--- a/lib/hwasan/hwasan_report.cc
+++ b/lib/hwasan/hwasan_report.cc
@@ -30,6 +30,49 @@
 
 namespace __hwasan {
 
+class ScopedReport {
+ public:
+  ScopedReport(bool fatal = false) : error_message_(1), fatal(fatal) {
+    BlockingMutexLock lock(&error_message_lock_);
+    error_message_ptr_ = fatal ? &error_message_ : nullptr;
+  }
+
+  ~ScopedReport() {
+    BlockingMutexLock lock(&error_message_lock_);
+    if (fatal) {
+      SetAbortMessage(error_message_.data());
+      Die();
+    }
+    error_message_ptr_ = nullptr;
+  }
+
+  static void MaybeAppendToErrorMessage(const char *msg) {
+    BlockingMutexLock lock(&error_message_lock_);
+    if (!error_message_ptr_)
+      return;
+    uptr len = internal_strlen(msg);
+    uptr old_size = error_message_ptr_->size();
+    error_message_ptr_->resize(old_size + len);
+    // overwrite old trailing '\0', keep new trailing '\0' untouched.
+    internal_memcpy(&(*error_message_ptr_)[old_size - 1], msg, len);
+  }
+ private:
+  ScopedErrorReportLock error_report_lock_;
+  InternalMmapVector<char> error_message_;
+  bool fatal;
+
+  static InternalMmapVector<char> *error_message_ptr_;
+  static BlockingMutex error_message_lock_;
+};
+
+InternalMmapVector<char> *ScopedReport::error_message_ptr_;
+BlockingMutex ScopedReport::error_message_lock_;
+
+// If there is an active ScopedReport, append to its error message.
+void AppendToErrorMessageBuffer(const char *buffer) {
+  ScopedReport::MaybeAppendToErrorMessage(buffer);
+}
+
 static StackTrace GetStackTraceFromId(u32 id) {
   CHECK(id);
   StackTrace res = StackDepotGet(id);
@@ -190,7 +233,7 @@
       t->Announce();
 
       // Temporary report section, needs to be improved.
-      Printf("Previosly allocated frames:\n");
+      Printf("Previously allocated frames:\n");
       auto *sa = (t == GetCurrentThread() && current_stack_allocations)
                      ? current_stack_allocations
                      : t->stack_allocations();
@@ -228,36 +271,8 @@
     Printf("HWAddressSanitizer can not describe address in more detail.\n");
 }
 
-void ReportInvalidAccess(StackTrace *stack, u32 origin) {
-  ScopedErrorReportLock l;
-
-  Decorator d;
-  Printf("%s", d.Warning());
-  Report("WARNING: HWAddressSanitizer: invalid access\n");
-  Printf("%s", d.Default());
-  stack->Print();
-  ReportErrorSummary("invalid-access", stack);
-}
-
 void ReportStats() {}
 
-void ReportInvalidAccessInsideAddressRange(const char *what, const void *start,
-                                           uptr size, uptr offset) {
-  ScopedErrorReportLock l;
-  SavedStackAllocations current_stack_allocations(
-      GetCurrentThread()->stack_allocations());
-
-  Decorator d;
-  Printf("%s", d.Warning());
-  Printf("%sTag mismatch in %s%s%s at offset %zu inside [%p, %zu)%s\n",
-         d.Warning(), d.Name(), what, d.Warning(), offset, start, size,
-         d.Default());
-  PrintAddressDescription((uptr)start + offset, 1,
-                          current_stack_allocations.get());
-  // if (__sanitizer::Verbosity())
-  //   DescribeMemoryRange(start, size);
-}
-
 static void PrintTagsAroundAddr(tag_t *tag_ptr) {
   Printf(
       "Memory tags around the buggy address (one tag corresponds to %zd "
@@ -283,7 +298,8 @@
 }
 
 void ReportInvalidFree(StackTrace *stack, uptr tagged_addr) {
-  ScopedErrorReportLock l;
+  ScopedReport R(flags()->halt_on_error);
+
   uptr untagged_addr = UntagAddr(tagged_addr);
   tag_t ptr_tag = GetTagFromPointer(tagged_addr);
   tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
@@ -305,12 +321,71 @@
   PrintTagsAroundAddr(tag_ptr);
 
   ReportErrorSummary(bug_type, stack);
-  Die();
+}
+
+void ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size,
+                           uptr tail_size, const u8 *expected) {
+  ScopedReport R(flags()->halt_on_error);
+  Decorator d;
+  uptr untagged_addr = UntagAddr(tagged_addr);
+  Printf("%s", d.Error());
+  const char *bug_type = "alocation-tail-overwritten";
+  Report("ERROR: %s: %s; heap object [%p,%p) of size %zd\n", SanitizerToolName,
+         bug_type, untagged_addr, untagged_addr + orig_size, orig_size);
+  Printf("\n%s", d.Default());
+  stack->Print();
+  HwasanChunkView chunk = FindHeapChunkByAddress(untagged_addr);
+  if (chunk.Beg()) {
+    Printf("%s", d.Allocation());
+    Printf("allocated here:\n");
+    Printf("%s", d.Default());
+    GetStackTraceFromId(chunk.GetAllocStackId()).Print();
+  }
+
+  InternalScopedString s(GetPageSizeCached() * 8);
+  CHECK_GT(tail_size, 0U);
+  CHECK_LT(tail_size, kShadowAlignment);
+  u8 *tail = reinterpret_cast<u8*>(untagged_addr + orig_size);
+  s.append("Tail contains: ");
+  for (uptr i = 0; i < kShadowAlignment - tail_size; i++)
+    s.append(".. ");
+  for (uptr i = 0; i < tail_size; i++)
+    s.append("%02x ", tail[i]);
+  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.append("%02x ", expected[i]);
+  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.append("%s ", expected[i] != tail[i] ? "^^" : "  ");
+
+  s.append("\nThis error occurs when a buffer overflow overwrites memory\n"
+    "to the right of a heap object, but within the %zd-byte granule, e.g.\n"
+    "   char *x = new char[20];\n"
+    "   x[25] = 42;\n"
+    "By default %s does not detect such bugs at the time of write,\n"
+    "but can detect them at the time of free/delete.\n"
+    "To disable this feature set HWASAN_OPTIONS=free_checks_tail_magic=0;\n"
+    "To enable checking at the time of access, set "
+    "HWASAN_OPTIONS=malloc_align_right to non-zero\n\n",
+    kShadowAlignment, SanitizerToolName);
+  Printf("%s", s.data());
+  GetCurrentThread()->Announce();
+
+  tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr));
+  PrintTagsAroundAddr(tag_ptr);
+
+  ReportErrorSummary(bug_type, stack);
 }
 
 void ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size,
-                       bool is_store) {
-  ScopedErrorReportLock l;
+                       bool is_store, bool fatal) {
+  ScopedReport R(fatal);
   SavedStackAllocations current_stack_allocations(
       GetCurrentThread()->stack_allocations());
 
diff --git a/lib/hwasan/hwasan_report.h b/lib/hwasan/hwasan_report.h
index 7a9eec8..10fb20c 100644
--- a/lib/hwasan/hwasan_report.h
+++ b/lib/hwasan/hwasan_report.h
@@ -21,13 +21,12 @@
 
 namespace __hwasan {
 
-void ReportInvalidAccess(StackTrace *stack, u32 origin);
 void ReportStats();
-void ReportInvalidAccessInsideAddressRange(const char *what, const void *start,
-                                           uptr size, uptr offset);
 void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size,
-                       bool is_store);
+                       bool is_store, bool fatal);
 void ReportInvalidFree(StackTrace *stack, uptr addr);
+void ReportTailOverwritten(StackTrace *stack, uptr addr, uptr orig_size,
+                           uptr tail_size, const u8 *expected);
 
 void ReportAtExitStatistics();
 
diff --git a/lib/lsan/lsan_allocator.h b/lib/lsan/lsan_allocator.h
index 7c70bb6..23ebc11 100644
--- a/lib/lsan/lsan_allocator.h
+++ b/lib/lsan/lsan_allocator.h
@@ -54,19 +54,25 @@
     defined(__arm__)
 static const uptr kRegionSizeLog = 20;
 static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
-typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+template <typename AddressSpaceView>
+using ByteMapASVT =
+    TwoLevelByteMap<(kNumRegions >> 12), 1 << 12, AddressSpaceView>;
 
+template <typename AddressSpaceViewTy>
 struct AP32 {
   static const uptr kSpaceBeg = 0;
   static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
   static const uptr kMetadataSize = sizeof(ChunkMetadata);
   typedef __sanitizer::CompactSizeClassMap SizeClassMap;
   static const uptr kRegionSizeLog = __lsan::kRegionSizeLog;
-  typedef __lsan::ByteMap ByteMap;
+  using AddressSpaceView = AddressSpaceViewTy;
+  using ByteMap = __lsan::ByteMapASVT<AddressSpaceView>;
   typedef NoOpMapUnmapCallback MapUnmapCallback;
   static const uptr kFlags = 0;
 };
-typedef SizeClassAllocator32<AP32> PrimaryAllocator;
+template <typename AddressSpaceView>
+using PrimaryAllocatorASVT = SizeClassAllocator32<AP32<AddressSpaceView>>;
+using PrimaryAllocator = PrimaryAllocatorASVT<LocalAddressSpaceView>;
 #elif defined(__x86_64__) || defined(__powerpc64__)
 # if defined(__powerpc64__)
 const uptr kAllocatorSpace = 0xa0000000000ULL;
diff --git a/lib/lsan/lsan_common_mac.cc b/lib/lsan/lsan_common_mac.cc
index 8dd247c..a355cea 100644
--- a/lib/lsan/lsan_common_mac.cc
+++ b/lib/lsan/lsan_common_mac.cc
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "sanitizer_common/sanitizer_platform.h"
+#include "sanitizer_common/sanitizer_libc.h"
 #include "lsan_common.h"
 
 #if CAN_SANITIZE_LEAKS && SANITIZER_MAC
@@ -116,7 +117,8 @@
 
 // Scans global variables for heap pointers.
 void ProcessGlobalRegions(Frontier *frontier) {
-  for (auto name : kSkippedSecNames) CHECK(ARRAY_SIZE(name) < kMaxSegName);
+  for (auto name : kSkippedSecNames)
+    CHECK(internal_strnlen(name, kMaxSegName + 1) <= kMaxSegName);
 
   MemoryMappingLayout memory_mapping(false);
   InternalMmapVector<LoadedModule> modules;
diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc
index 36f0497a..8b9fa65 100644
--- a/lib/msan/msan_allocator.cc
+++ b/lib/msan/msan_allocator.cc
@@ -57,7 +57,8 @@
     static const uptr kMetadataSize = sizeof(Metadata);
     typedef __sanitizer::CompactSizeClassMap SizeClassMap;
     static const uptr kRegionSizeLog = __msan::kRegionSizeLog;
-    typedef __msan::ByteMap ByteMap;
+    using AddressSpaceView = LocalAddressSpaceView;
+    using ByteMap = __msan::ByteMap;
     typedef MsanMapUnmapCallback MapUnmapCallback;
     static const uptr kFlags = 0;
   };
@@ -107,7 +108,8 @@
     static const uptr kMetadataSize = sizeof(Metadata);
     typedef __sanitizer::CompactSizeClassMap SizeClassMap;
     static const uptr kRegionSizeLog = __msan::kRegionSizeLog;
-    typedef __msan::ByteMap ByteMap;
+    using AddressSpaceView = LocalAddressSpaceView;
+    using ByteMap = __msan::ByteMap;
     typedef MsanMapUnmapCallback MapUnmapCallback;
     static const uptr kFlags = 0;
   };
diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc
index 07300f3..497f943 100644
--- a/lib/msan/msan_interceptors.cc
+++ b/lib/msan/msan_interceptors.cc
@@ -34,6 +34,7 @@
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_linux.h"
 #include "sanitizer_common/sanitizer_tls_get_addr.h"
+#include "sanitizer_common/sanitizer_vector.h"
 
 #if SANITIZER_NETBSD
 #define fstat __fstat50
@@ -1086,23 +1087,80 @@
   void *arg;
 };
 
-void MSanAtExitWrapper(void *arg) {
+struct InterceptorContext {
+  BlockingMutex atexit_mu;
+  Vector<struct MSanAtExitRecord *> AtExitStack;
+
+  InterceptorContext()
+      : AtExitStack() {
+  }
+};
+
+static ALIGNED(64) char interceptor_placeholder[sizeof(InterceptorContext)];
+InterceptorContext *interceptor_ctx() {
+  return reinterpret_cast<InterceptorContext*>(&interceptor_placeholder[0]);
+}
+
+void MSanAtExitWrapper() {
+  MSanAtExitRecord *r;
+  {
+    BlockingMutexLock l(&interceptor_ctx()->atexit_mu);
+
+    uptr element = interceptor_ctx()->AtExitStack.Size() - 1;
+    r = interceptor_ctx()->AtExitStack[element];
+    interceptor_ctx()->AtExitStack.PopBack();
+  }
+
+  UnpoisonParam(1);
+  ((void(*)())r->func)();
+  InternalFree(r);
+}
+
+void MSanCxaAtExitWrapper(void *arg) {
   UnpoisonParam(1);
   MSanAtExitRecord *r = (MSanAtExitRecord *)arg;
   r->func(r->arg);
   InternalFree(r);
 }
 
+static int setup_at_exit_wrapper(void(*f)(), void *arg, void *dso);
+
 // Unpoison argument shadow for C++ module destructors.
 INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
             void *dso_handle) {
   if (msan_init_is_running) return REAL(__cxa_atexit)(func, arg, dso_handle);
+  return setup_at_exit_wrapper((void(*)())func, arg, dso_handle);
+}
+
+// Unpoison argument shadow for C++ module destructors.
+INTERCEPTOR(int, atexit, void (*func)()) {
+  // Avoid calling real atexit as it is unrechable on at least on Linux.
+  if (msan_init_is_running)
+    return REAL(__cxa_atexit)((void (*)(void *a))func, 0, 0);
+  return setup_at_exit_wrapper((void(*)())func, 0, 0);
+}
+
+static int setup_at_exit_wrapper(void(*f)(), void *arg, void *dso) {
   ENSURE_MSAN_INITED();
   MSanAtExitRecord *r =
       (MSanAtExitRecord *)InternalAlloc(sizeof(MSanAtExitRecord));
-  r->func = func;
+  r->func = (void(*)(void *a))f;
   r->arg = arg;
-  return REAL(__cxa_atexit)(MSanAtExitWrapper, r, dso_handle);
+  int res;
+  if (!dso) {
+    // NetBSD does not preserve the 2nd argument if dso is equal to 0
+    // Store ctx in a local stack-like structure
+
+    BlockingMutexLock l(&interceptor_ctx()->atexit_mu);
+
+    res = REAL(__cxa_atexit)((void (*)(void *a))MSanAtExitWrapper, 0, 0);
+    if (!res) {
+      interceptor_ctx()->AtExitStack.PushBack(r);
+    }
+  } else {
+    res = REAL(__cxa_atexit)(MSanCxaAtExitWrapper, r, dso);
+  }
+  return res;
 }
 
 static void BeforeFork() {
@@ -1522,6 +1580,9 @@
 void InitializeInterceptors() {
   static int inited = 0;
   CHECK_EQ(inited, 0);
+
+  new(interceptor_ctx()) InterceptorContext();
+
   InitializeCommonInterceptors();
   InitializeSignalInterceptors();
 
@@ -1631,6 +1692,7 @@
 
   INTERCEPT_FUNCTION(pthread_join);
   INTERCEPT_FUNCTION(tzset);
+  INTERCEPT_FUNCTION(atexit);
   INTERCEPT_FUNCTION(__cxa_atexit);
   INTERCEPT_FUNCTION(shmat);
   INTERCEPT_FUNCTION(fork);
diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt
index ad3aba0..a8bd569 100644
--- a/lib/sanitizer_common/CMakeLists.txt
+++ b/lib/sanitizer_common/CMakeLists.txt
@@ -19,6 +19,7 @@
   sanitizer_netbsd.cc
   sanitizer_openbsd.cc
   sanitizer_persistent_allocator.cc
+  sanitizer_platform_limits_freebsd.cc
   sanitizer_platform_limits_linux.cc
   sanitizer_platform_limits_netbsd.cc
   sanitizer_platform_limits_openbsd.cc
@@ -144,6 +145,7 @@
   sanitizer_libignore.h
   sanitizer_linux.h
   sanitizer_list.h
+  sanitizer_local_address_space_view.h
   sanitizer_mac.h
   sanitizer_malloc_mac.inc
   sanitizer_mutex.h
diff --git a/lib/sanitizer_common/sanitizer_allocator.h b/lib/sanitizer_common/sanitizer_allocator.h
index 9655a22..8801716 100644
--- a/lib/sanitizer_common/sanitizer_allocator.h
+++ b/lib/sanitizer_common/sanitizer_allocator.h
@@ -14,13 +14,15 @@
 #ifndef SANITIZER_ALLOCATOR_H
 #define SANITIZER_ALLOCATOR_H
 
-#include "sanitizer_internal_defs.h"
 #include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_lfstack.h"
 #include "sanitizer_libc.h"
 #include "sanitizer_list.h"
+#include "sanitizer_local_address_space_view.h"
 #include "sanitizer_mutex.h"
-#include "sanitizer_lfstack.h"
 #include "sanitizer_procmaps.h"
+#include "sanitizer_type_traits.h"
 
 namespace __sanitizer {
 
diff --git a/lib/sanitizer_common/sanitizer_allocator_bytemap.h b/lib/sanitizer_common/sanitizer_allocator_bytemap.h
index 7df3e40..ef26941 100644
--- a/lib/sanitizer_common/sanitizer_allocator_bytemap.h
+++ b/lib/sanitizer_common/sanitizer_allocator_bytemap.h
@@ -15,9 +15,10 @@
 #endif
 
 // Maps integers in rage [0, kSize) to u8 values.
-template<u64 kSize>
+template <u64 kSize, typename AddressSpaceViewTy = LocalAddressSpaceView>
 class FlatByteMap {
  public:
+  using AddressSpaceView = AddressSpaceViewTy;
   void Init() {
     internal_memset(map_, 0, sizeof(map_));
   }
@@ -41,9 +42,12 @@
 // to kSize2-byte arrays. The secondary arrays are mmaped on demand.
 // Each value is initially zero and can be set to something else only once.
 // Setting and getting values from multiple threads is safe w/o extra locking.
-template <u64 kSize1, u64 kSize2, class MapUnmapCallback = NoOpMapUnmapCallback>
+template <u64 kSize1, u64 kSize2,
+          typename AddressSpaceViewTy = LocalAddressSpaceView,
+          class MapUnmapCallback = NoOpMapUnmapCallback>
 class TwoLevelByteMap {
  public:
+  using AddressSpaceView = AddressSpaceViewTy;
   void Init() {
     internal_memset(map1_, 0, sizeof(map1_));
     mu_.Init();
@@ -73,7 +77,8 @@
     CHECK_LT(idx, kSize1 * kSize2);
     u8 *map2 = Get(idx / kSize2);
     if (!map2) return 0;
-    return map2[idx % kSize2];
+    auto value_ptr = AddressSpaceView::Load(&map2[idx % kSize2]);
+    return *value_ptr;
   }
 
  private:
diff --git a/lib/sanitizer_common/sanitizer_allocator_internal.h b/lib/sanitizer_common/sanitizer_allocator_internal.h
index c0c03d3..30fc704 100644
--- a/lib/sanitizer_common/sanitizer_allocator_internal.h
+++ b/lib/sanitizer_common/sanitizer_allocator_internal.h
@@ -37,7 +37,8 @@
   static const uptr kMetadataSize = 0;
   typedef InternalSizeClassMap SizeClassMap;
   static const uptr kRegionSizeLog = kInternalAllocatorRegionSizeLog;
-  typedef __sanitizer::ByteMap ByteMap;
+  using AddressSpaceView = LocalAddressSpaceView;
+  using ByteMap = __sanitizer::ByteMap;
   typedef NoOpMapUnmapCallback MapUnmapCallback;
   static const uptr kFlags = 0;
 };
diff --git a/lib/sanitizer_common/sanitizer_allocator_primary32.h b/lib/sanitizer_common/sanitizer_allocator_primary32.h
index 67970e9..e5d6376 100644
--- a/lib/sanitizer_common/sanitizer_allocator_primary32.h
+++ b/lib/sanitizer_common/sanitizer_allocator_primary32.h
@@ -48,6 +48,7 @@
 template <class Params>
 class SizeClassAllocator32 {
  public:
+  using AddressSpaceView = typename Params::AddressSpaceView;
   static const uptr kSpaceBeg = Params::kSpaceBeg;
   static const u64 kSpaceSize = Params::kSpaceSize;
   static const uptr kMetadataSize = Params::kMetadataSize;
@@ -108,6 +109,9 @@
   typedef SizeClassAllocator32LocalCache<ThisT> AllocatorCache;
 
   void Init(s32 release_to_os_interval_ms) {
+    static_assert(
+        is_same<typename ByteMap::AddressSpaceView, AddressSpaceView>::value,
+        "AddressSpaceView type mismatch");
     possible_regions.Init();
     internal_memset(size_class_info_array, 0, sizeof(size_class_info_array));
   }
diff --git a/lib/sanitizer_common/sanitizer_allocator_secondary.h b/lib/sanitizer_common/sanitizer_allocator_secondary.h
index ab680b5..455fcf3 100644
--- a/lib/sanitizer_common/sanitizer_allocator_secondary.h
+++ b/lib/sanitizer_common/sanitizer_allocator_secondary.h
@@ -68,7 +68,8 @@
 // The main purpose of this allocator is to cover large and rare allocation
 // sizes not covered by more efficient allocators (e.g. SizeClassAllocator64).
 template <class MapUnmapCallback = NoOpMapUnmapCallback,
-          class PtrArrayT = DefaultLargeMmapAllocatorPtrArray>
+          class PtrArrayT = DefaultLargeMmapAllocatorPtrArray,
+          class AddressSpaceView = LocalAddressSpaceView>
 class LargeMmapAllocator {
  public:
   void InitLinkerInitialized() {
@@ -202,9 +203,10 @@
 
   void EnsureSortedChunks() {
     if (chunks_sorted_) return;
-    Sort(reinterpret_cast<uptr *>(chunks_), n_chunks_);
+    Header **chunks = AddressSpaceView::Load(chunks_, n_chunks_);
+    Sort(reinterpret_cast<uptr *>(chunks), n_chunks_);
     for (uptr i = 0; i < n_chunks_; i++)
-      chunks_[i]->chunk_idx = i;
+      AddressSpaceView::Load(chunks[i])->chunk_idx = i;
     chunks_sorted_ = true;
   }
 
@@ -272,12 +274,13 @@
   // The allocator must be locked when calling this function.
   void ForEachChunk(ForEachChunkCallback callback, void *arg) {
     EnsureSortedChunks();  // Avoid doing the sort while iterating.
+    Header **chunks = AddressSpaceView::Load(chunks_, n_chunks_);
     for (uptr i = 0; i < n_chunks_; i++) {
-      auto t = chunks_[i];
+      Header *t = chunks[i];
       callback(reinterpret_cast<uptr>(GetUser(t)), arg);
       // Consistency check: verify that the array did not change.
-      CHECK_EQ(chunks_[i], t);
-      CHECK_EQ(chunks_[i]->chunk_idx, i);
+      CHECK_EQ(chunks[i], t);
+      CHECK_EQ(AddressSpaceView::Load(chunks[i])->chunk_idx, i);
     }
   }
 
@@ -316,4 +319,3 @@
   } stats;
   StaticSpinMutex mutex_;
 };
-
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc
index e3f32c9..37743a0 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -77,7 +77,15 @@
 #define ctime __ctime50
 #define ctime_r __ctime_r50
 #define devname __devname50
+#define fgetpos __fgetpos50
+#define fsetpos __fsetpos50
+#define fts_children __fts_children60
+#define fts_close __fts_close60
+#define fts_open __fts_open60
+#define fts_read __fts_read60
+#define fts_set __fts_set60
 #define getitimer __getitimer50
+#define getmntinfo __getmntinfo13
 #define getpwent __getpwent50
 #define getpwnam __getpwnam50
 #define getpwnam_r __getpwnam_r50
@@ -109,6 +117,7 @@
 #define stat __stat50
 #define time __time50
 #define times __times13
+#define unvis __unvis50
 #define wait3 __wait350
 #define wait4 __wait450
 extern const unsigned short *_ctype_tab_;
@@ -4271,11 +4280,16 @@
 INTERCEPTOR(int, fstatvfs, int fd, void *buf) {
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs, fd, buf);
+  COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
   // FIXME: under ASan the call below may write to freed memory and corrupt
   // its metadata. See
   // https://github.com/google/sanitizers/issues/321.
   int res = REAL(fstatvfs)(fd, buf);
-  if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
+  if (!res) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
+    if (fd >= 0)
+      COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+  }
   return res;
 }
 #define INIT_STATVFS                  \
@@ -7264,9 +7278,1769 @@
 #define INIT_NETENT
 #endif
 
+#if SANITIZER_INTERCEPT_GETMNTINFO
+INTERCEPTOR(int, getmntinfo, void **mntbufp, int flags) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getmntinfo, mntbufp, flags);
+  int cnt = REAL(getmntinfo)(mntbufp, flags);
+  if (cnt > 0 && mntbufp) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, mntbufp, sizeof(void *));
+    if (*mntbufp)
+#if SANITIZER_NETBSD
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *mntbufp, cnt * struct_statvfs_sz);
+#else
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *mntbufp, cnt * struct_statfs_sz);
+#endif
+  }
+  return cnt;
+}
+#define INIT_GETMNTINFO COMMON_INTERCEPT_FUNCTION(getmntinfo)
+#else
+#define INIT_GETMNTINFO
+#endif
+
+#if SANITIZER_INTERCEPT_MI_VECTOR_HASH
+INTERCEPTOR(void, mi_vector_hash, const void *key, SIZE_T len, u32 seed,
+            u32 hashes[3]) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, mi_vector_hash, key, len, seed, hashes);
+  if (key)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, key, len);
+  REAL(mi_vector_hash)(key, len, seed, hashes);
+  if (hashes)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, hashes, sizeof(hashes[0]) * 3);
+}
+#define INIT_MI_VECTOR_HASH COMMON_INTERCEPT_FUNCTION(mi_vector_hash)
+#else
+#define INIT_MI_VECTOR_HASH
+#endif
+
+#if SANITIZER_INTERCEPT_SETVBUF
+INTERCEPTOR(int, setvbuf, __sanitizer_FILE *stream, char *buf, int mode,
+  SIZE_T size) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, setvbuf, stream, buf, mode, size);
+  int ret = REAL(setvbuf)(stream, buf, mode, size);
+  if (buf)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, size);
+  if (stream)
+      unpoison_file(stream);
+  return ret;
+}
+
+INTERCEPTOR(void, setbuf, __sanitizer_FILE *stream, char *buf) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, setbuf, stream, buf);
+  REAL(setbuf)(stream, buf);
+  if (buf) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer_bufsiz);
+  }
+  if (stream)
+      unpoison_file(stream);
+}
+
+INTERCEPTOR(void, setbuffer, __sanitizer_FILE *stream, char *buf, int mode) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, setbuffer, stream, buf, mode);
+  REAL(setbuffer)(stream, buf, mode);
+  if (buf) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, __sanitizer_bufsiz);
+  }
+  if (stream)
+    unpoison_file(stream);
+}
+
+INTERCEPTOR(void, setlinebuf, __sanitizer_FILE *stream) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, setlinebuf, stream);
+  REAL(setlinebuf)(stream);
+  if (stream)
+    unpoison_file(stream);
+}
+#define INIT_SETVBUF COMMON_INTERCEPT_FUNCTION(setvbuf); \
+    COMMON_INTERCEPT_FUNCTION(setbuf); \
+    COMMON_INTERCEPT_FUNCTION(setbuffer); \
+    COMMON_INTERCEPT_FUNCTION(setlinebuf)
+#else
+#define INIT_SETVBUF
+#endif
+
+#if SANITIZER_INTERCEPT_GETVFSSTAT
+INTERCEPTOR(int, getvfsstat, void *buf, SIZE_T bufsize, int flags) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, getvfsstat, buf, bufsize, flags);
+  int ret = REAL(getvfsstat)(buf, bufsize, flags);
+  if (buf && ret > 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, ret * struct_statvfs_sz);
+  return ret;
+}
+#define INIT_GETVFSSTAT COMMON_INTERCEPT_FUNCTION(getvfsstat)
+#else
+#define INIT_GETVFSSTAT
+#endif
+
+#if SANITIZER_INTERCEPT_REGEX
+INTERCEPTOR(int, regcomp, void *preg, const char *pattern, int cflags) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, regcomp, preg, pattern, cflags);
+  if (pattern)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, pattern, REAL(strlen)(pattern) + 1);
+  int res = REAL(regcomp)(preg, pattern, cflags);
+  if (!res)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, preg, struct_regex_sz);
+  return res;
+}
+INTERCEPTOR(int, regexec, const void *preg, const char *string, SIZE_T nmatch,
+            struct __sanitizer_regmatch *pmatch[], int eflags) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, regexec, preg, string, nmatch, pmatch, eflags);
+  if (preg)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, preg, struct_regex_sz);
+  if (string)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, string, REAL(strlen)(string) + 1);
+  int res = REAL(regexec)(preg, string, nmatch, pmatch, eflags);
+  if (!res && pmatch)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pmatch, nmatch * struct_regmatch_sz);
+  return res;
+}
+INTERCEPTOR(SIZE_T, regerror, int errcode, const void *preg, char *errbuf,
+            SIZE_T errbuf_size) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, regerror, errcode, preg, errbuf, errbuf_size);
+  if (preg)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, preg, struct_regex_sz);
+  SIZE_T res = REAL(regerror)(errcode, preg, errbuf, errbuf_size);
+  if (errbuf)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, errbuf, REAL(strlen)(errbuf) + 1);
+  return res;
+}
+INTERCEPTOR(void, regfree, const void *preg) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, regfree, preg);
+  if (preg)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, preg, struct_regex_sz);
+  REAL(regfree)(preg);
+}
+INTERCEPTOR(SSIZE_T, regnsub, char *buf, SIZE_T bufsiz, const char *sub,
+            const struct __sanitizer_regmatch *rm, const char *str) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, regnsub, buf, bufsiz, sub, rm, str);
+  if (sub)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, sub, REAL(strlen)(sub) + 1);
+  // The implementation demands and hardcodes 10 elements
+  if (rm)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, rm, 10 * struct_regmatch_sz);
+  if (str)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, str, REAL(strlen)(str) + 1);
+  SSIZE_T res = REAL(regnsub)(buf, bufsiz, sub, rm, str);
+  if (res > 0 && buf)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, REAL(strlen)(buf) + 1);
+  return res;
+}
+INTERCEPTOR(SSIZE_T, regasub, char **buf, const char *sub,
+            const struct __sanitizer_regmatch *rm, const char *sstr) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, regasub, buf, sub, rm, sstr);
+  if (sub)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, sub, REAL(strlen)(sub) + 1);
+  // Hardcode 10 elements as this is hardcoded size
+  if (rm)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, rm, 10 * struct_regmatch_sz);
+  if (sstr)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, sstr, REAL(strlen)(sstr) + 1);
+  SSIZE_T res = REAL(regasub)(buf, sub, rm, sstr);
+  if (res > 0 && buf) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sizeof(char *));
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *buf, REAL(strlen)(*buf) + 1);
+  }
+  return res;
+}
+#define INIT_REGEX                                                             \
+  COMMON_INTERCEPT_FUNCTION(regcomp);                                          \
+  COMMON_INTERCEPT_FUNCTION(regexec);                                          \
+  COMMON_INTERCEPT_FUNCTION(regerror);                                         \
+  COMMON_INTERCEPT_FUNCTION(regfree);                                          \
+  COMMON_INTERCEPT_FUNCTION(regnsub);                                          \
+  COMMON_INTERCEPT_FUNCTION(regasub);
+#else
+#define INIT_REGEX
+#endif
+
+#if SANITIZER_INTERCEPT_FTS
+INTERCEPTOR(void *, fts_open, char *const *path_argv, int options,
+            int (*compar)(void **, void **)) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fts_open, path_argv, options, compar);
+  if (path_argv) {
+    for (char *const *pa = path_argv; ; ++pa) {
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, pa, sizeof(char **));
+      if (!*pa)
+        break;
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, *pa, REAL(strlen)(*pa) + 1);
+    }
+  }
+  // TODO(kamil): handle compar callback
+  void *fts = REAL(fts_open)(path_argv, options, compar);
+  if (fts)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, fts, struct_FTS_sz);
+  return fts;
+}
+
+INTERCEPTOR(void *, fts_read, void *ftsp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fts_read, ftsp);
+  if (ftsp)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, ftsp, struct_FTS_sz);
+  void *ftsent = REAL(fts_read)(ftsp);
+  if (ftsent)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ftsent, struct_FTSENT_sz);
+  return ftsent;
+}
+
+INTERCEPTOR(void *, fts_children, void *ftsp, int options) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fts_children, ftsp, options);
+  if (ftsp)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, ftsp, struct_FTS_sz);
+  void *ftsent = REAL(fts_children)(ftsp, options);
+  if (ftsent)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ftsent, struct_FTSENT_sz);
+  return ftsent;
+}
+
+INTERCEPTOR(int, fts_set, void *ftsp, void *f, int options) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fts_set, ftsp, f, options);
+  if (ftsp)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, ftsp, struct_FTS_sz);
+  if (f)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, f, struct_FTSENT_sz);
+  return REAL(fts_set)(ftsp, f, options);
+}
+
+INTERCEPTOR(int, fts_close, void *ftsp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fts_close, ftsp);
+  if (ftsp)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, ftsp, struct_FTS_sz);
+  return REAL(fts_close)(ftsp);
+}
+#define INIT_FTS                                                               \
+  COMMON_INTERCEPT_FUNCTION(fts_open);                                         \
+  COMMON_INTERCEPT_FUNCTION(fts_read);                                         \
+  COMMON_INTERCEPT_FUNCTION(fts_children);                                     \
+  COMMON_INTERCEPT_FUNCTION(fts_set);                                          \
+  COMMON_INTERCEPT_FUNCTION(fts_close);
+#else
+#define INIT_FTS
+#endif
+
+#if SANITIZER_INTERCEPT_SYSCTL
+INTERCEPTOR(int, sysctl, int *name, unsigned int namelen, void *oldp,
+            SIZE_T *oldlenp, void *newp, SIZE_T newlen) {
+  void *ctx;
+  if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+    return internal_sysctl(name, namelen, oldp, oldlenp, newp, newlen);
+  COMMON_INTERCEPTOR_ENTER(ctx, sysctl, name, namelen, oldp, oldlenp, newp,
+                           newlen);
+  if (name)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, name, namelen * sizeof(*name));
+  if (oldlenp)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, oldlenp, sizeof(*oldlenp));
+  if (newp && newlen)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, newp, newlen);
+  int res = REAL(sysctl)(name, namelen, oldp, oldlenp, newp, newlen);
+  if (!res) {
+    if (oldlenp) {
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldlenp, sizeof(*oldlenp));
+      if (oldp)
+        COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldp, *oldlenp);
+    }
+  }
+  return res;
+}
+
+INTERCEPTOR(int, sysctlbyname, char *sname, void *oldp, SIZE_T *oldlenp,
+            void *newp, SIZE_T newlen) {
+  void *ctx;
+  if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
+    return internal_sysctlbyname(sname, oldp, oldlenp, newp, newlen);
+  COMMON_INTERCEPTOR_ENTER(ctx, sysctlbyname, sname, oldp, oldlenp, newp,
+                           newlen);
+  if (sname)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, sname, REAL(strlen)(sname) + 1);
+  if (oldlenp)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, oldlenp, sizeof(*oldlenp));
+  if (newp && newlen)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, newp, newlen);
+  int res = REAL(sysctlbyname)(sname, oldp, oldlenp, newp, newlen);
+  if (!res) {
+    if (oldlenp) {
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldlenp, sizeof(*oldlenp));
+      if (oldp)
+        COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldp, *oldlenp);
+    }
+  }
+  return res;
+}
+
+INTERCEPTOR(int, sysctlnametomib, const char *sname, int *name,
+            SIZE_T *namelenp) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, sysctlnametomib, sname, name, namelenp);
+  if (sname)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, sname, REAL(strlen)(sname) + 1);
+  if (namelenp)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, namelenp, sizeof(*namelenp));
+  int res = REAL(sysctlnametomib)(sname, name, namelenp);
+  if (!res) {
+    if (namelenp) {
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelenp, sizeof(*namelenp));
+      if (name)
+        COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, *namelenp * sizeof(*name));
+    }
+  }
+  return res;
+}
+
+#define INIT_SYSCTL                        \
+  COMMON_INTERCEPT_FUNCTION(sysctl);       \
+  COMMON_INTERCEPT_FUNCTION(sysctlbyname); \
+  COMMON_INTERCEPT_FUNCTION(sysctlnametomib);
+#else
+#define INIT_SYSCTL
+#endif
+
+#if SANITIZER_INTERCEPT_ASYSCTL
+INTERCEPTOR(void *, asysctl, const int *name, SIZE_T namelen, SIZE_T *len) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, asysctl, name, namelen, len);
+  if (name)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, name, sizeof(*name) * namelen);
+  void *res = REAL(asysctl)(name, namelen, len);
+  if (res && len) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, len, sizeof(*len));
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, *len);
+  }
+  return res;
+}
+
+INTERCEPTOR(void *, asysctlbyname, const char *sname, SIZE_T *len) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, asysctlbyname, sname, len);
+  if (sname)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, sname, REAL(strlen)(sname) + 1);
+  void *res = REAL(asysctlbyname)(sname, len);
+  if (res && len) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, len, sizeof(*len));
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, *len);
+  }
+  return res;
+}
+#define INIT_ASYSCTL                           \
+  COMMON_INTERCEPT_FUNCTION(asysctl);          \
+  COMMON_INTERCEPT_FUNCTION(asysctlbyname);
+#else
+#define INIT_ASYSCTL
+#endif
+
+#if SANITIZER_INTERCEPT_SYSCTLGETMIBINFO
+INTERCEPTOR(int, sysctlgetmibinfo, char *sname, int *name,
+            unsigned int *namelenp, char *cname, SIZE_T *csz, void **rnode,
+            int v) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, sysctlgetmibinfo, sname, name, namelenp, cname,
+                           csz, rnode, v);
+  if (sname)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, sname, REAL(strlen)(sname) + 1);
+  if (namelenp)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, namelenp, sizeof(*namelenp));
+  if (csz)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, csz, sizeof(*csz));
+  // Skip rnode, it's rarely used and not trivial to sanitize
+  // It's also used mostly internally
+  int res = REAL(sysctlgetmibinfo)(sname, name, namelenp, cname, csz, rnode, v);
+  if (!res) {
+    if (namelenp) {
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, namelenp, sizeof(*namelenp));
+      if (name)
+        COMMON_INTERCEPTOR_WRITE_RANGE(ctx, name, *namelenp * sizeof(*name));
+    }
+    if (csz) {
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, csz, sizeof(*csz));
+      if (cname)
+        COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cname, *csz);
+    }
+  }
+  return res;
+}
+#define INIT_SYSCTLGETMIBINFO                  \
+  COMMON_INTERCEPT_FUNCTION(sysctlgetmibinfo);
+#else
+#define INIT_SYSCTLGETMIBINFO
+#endif
+
+#if SANITIZER_INTERCEPT_NL_LANGINFO
+INTERCEPTOR(char *, nl_langinfo, long item) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, nl_langinfo, item);
+  char *ret = REAL(nl_langinfo)(item);
+  if (ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, REAL(strlen)(ret) + 1);
+  return ret;
+}
+#define INIT_NL_LANGINFO COMMON_INTERCEPT_FUNCTION(nl_langinfo)
+#else
+#define INIT_NL_LANGINFO
+#endif
+
+#if SANITIZER_INTERCEPT_MODCTL
+INTERCEPTOR(int, modctl, int operation, void *argp) {
+  void *ctx;
+  int ret;
+  COMMON_INTERCEPTOR_ENTER(ctx, modctl, operation, argp);
+
+  if (operation == modctl_load) {
+    if (argp) {
+      __sanitizer_modctl_load_t *ml = (__sanitizer_modctl_load_t *)argp;
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, ml, sizeof(*ml));
+      if (ml->ml_filename)
+        COMMON_INTERCEPTOR_READ_RANGE(ctx, ml->ml_filename,
+                                      REAL(strlen)(ml->ml_filename) + 1);
+      if (ml->ml_props)
+        COMMON_INTERCEPTOR_READ_RANGE(ctx, ml->ml_props, ml->ml_propslen);
+    }
+    ret = REAL(modctl)(operation, argp);
+  } else if (operation == modctl_unload) {
+    if (argp) {
+      const char *name = (const char *)argp;
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
+    }
+    ret = REAL(modctl)(operation, argp);
+  } else if (operation == modctl_stat) {
+    uptr iov_len;
+    struct __sanitizer_iovec *iov = (struct __sanitizer_iovec *)argp;
+    if (iov) {
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, iov, sizeof(*iov));
+      iov_len = iov->iov_len;
+    }
+    ret = REAL(modctl)(operation, argp);
+    if (iov)
+      COMMON_INTERCEPTOR_WRITE_RANGE(
+          ctx, iov->iov_base, Min(iov_len,  iov->iov_len));
+  } else if (operation == modctl_exists)
+    ret = REAL(modctl)(operation, argp);
+  else
+    ret = REAL(modctl)(operation, argp);
+
+  return ret;
+}
+#define INIT_MODCTL COMMON_INTERCEPT_FUNCTION(modctl)
+#else
+#define INIT_MODCTL
+#endif
+
+#if SANITIZER_INTERCEPT_STRTONUM
+INTERCEPTOR(long long, strtonum, const char *nptr, long long minval,
+            long long maxval, const char **errstr) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strtonum, nptr, minval, maxval, errstr);
+
+  // TODO(kamil): Implement strtoll as a common inteceptor
+  char *real_endptr;
+  long long ret = (long long)REAL(strtoimax)(nptr, &real_endptr, 10);
+  StrtolFixAndCheck(ctx, nptr, nullptr, real_endptr, 10);
+
+  ret = REAL(strtonum)(nptr, minval, maxval, errstr);
+  if (errstr) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, errstr, sizeof(const char *));
+     if (*errstr)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *errstr, REAL(strlen)(*errstr) + 1);
+  }
+  return ret;
+}
+#define INIT_STRTONUM COMMON_INTERCEPT_FUNCTION(strtonum)
+#else
+#define INIT_STRTONUM
+#endif
+
+#if SANITIZER_INTERCEPT_FPARSELN
+INTERCEPTOR(char *, fparseln, __sanitizer_FILE *stream, SIZE_T *len,
+            SIZE_T *lineno, const char delim[3], int flags) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fparseln, stream, len, lineno, delim, flags);
+  if (lineno)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, lineno, sizeof(*lineno));
+  if (delim)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, delim, sizeof(delim[0]) * 3);
+  char *ret = REAL(fparseln)(stream, len, lineno, delim, flags);
+  if (ret) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, REAL(strlen)(ret) + 1);
+    if (len)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, len, sizeof(*len));
+    if (lineno)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, lineno, sizeof(*lineno));
+  }
+  return ret;
+}
+#define INIT_FPARSELN COMMON_INTERCEPT_FUNCTION(fparseln)
+#else
+#define INIT_FPARSELN
+#endif
+
+#if SANITIZER_INTERCEPT_STATVFS1
+INTERCEPTOR(int, statvfs1, const char *path, void *buf, int flags) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, statvfs1, path, buf, flags);
+  if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+  int res = REAL(statvfs1)(path, buf, flags);
+  if (!res) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
+  return res;
+}
+INTERCEPTOR(int, fstatvfs1, int fd, void *buf, int flags) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fstatvfs1, fd, buf, flags);
+  COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd);
+  int res = REAL(fstatvfs1)(fd, buf, flags);
+  if (!res) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, struct_statvfs_sz);
+    if (fd >= 0)
+      COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, fd);
+  }
+  return res;
+}
+#define INIT_STATVFS1                  \
+  COMMON_INTERCEPT_FUNCTION(statvfs1);  \
+  COMMON_INTERCEPT_FUNCTION(fstatvfs1);
+#else
+#define INIT_STATVFS1
+#endif
+
+#if SANITIZER_INTERCEPT_STRTOI
+INTERCEPTOR(INTMAX_T, strtoi, const char *nptr, char **endptr, int base,
+            INTMAX_T low, INTMAX_T high, int *rstatus) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strtoi, nptr, endptr, base, low, high, rstatus);
+  char *real_endptr;
+  INTMAX_T ret = REAL(strtoi)(nptr, &real_endptr, base, low, high, rstatus);
+  StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
+  if (rstatus)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rstatus, sizeof(*rstatus));
+  return ret;
+}
+
+INTERCEPTOR(UINTMAX_T, strtou, const char *nptr, char **endptr, int base,
+            UINTMAX_T low, UINTMAX_T high, int *rstatus) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strtou, nptr, endptr, base, low, high, rstatus);
+  char *real_endptr;
+  UINTMAX_T ret = REAL(strtou)(nptr, &real_endptr, base, low, high, rstatus);
+  StrtolFixAndCheck(ctx, nptr, endptr, real_endptr, base);
+  if (rstatus)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rstatus, sizeof(*rstatus));
+  return ret;
+}
+#define INIT_STRTOI                                                            \
+  COMMON_INTERCEPT_FUNCTION(strtoi);                                           \
+  COMMON_INTERCEPT_FUNCTION(strtou)
+#else
+#define INIT_STRTOI
+#endif
+
+#if SANITIZER_INTERCEPT_CAPSICUM
+#define CAP_RIGHTS_INIT_INTERCEPTOR(cap_rights_init, rights, ...)          \
+  {                                                                        \
+    void *ctx;                                                             \
+    COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_init, rights, ##__VA_ARGS__); \
+    if (rights)                                                            \
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights));         \
+    __sanitizer_cap_rights_t *ret =                                        \
+        REAL(cap_rights_init)(rights, ##__VA_ARGS__);                      \
+    if (ret)                                                               \
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, sizeof(*ret));              \
+    return ret;                                                            \
+  }
+
+#define CAP_RIGHTS_SET_INTERCEPTOR(cap_rights_set, rights, ...)           \
+  {                                                                       \
+    void *ctx;                                                            \
+    COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_set, rights, ##__VA_ARGS__); \
+    if (rights)                                                           \
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights));        \
+    __sanitizer_cap_rights_t *ret =                                       \
+        REAL(cap_rights_set)(rights, ##__VA_ARGS__);                      \
+    if (ret)                                                              \
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, sizeof(*ret));             \
+    return ret;                                                           \
+  }
+
+#define CAP_RIGHTS_CLEAR_INTERCEPTOR(cap_rights_clear, rights, ...)         \
+  {                                                                         \
+    void *ctx;                                                              \
+    COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_clear, rights, ##__VA_ARGS__); \
+    if (rights)                                                             \
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights));          \
+    __sanitizer_cap_rights_t *ret =                                         \
+        REAL(cap_rights_clear)(rights, ##__VA_ARGS__);                      \
+    if (ret)                                                                \
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, sizeof(*ret));               \
+    return ret;                                                             \
+  }
+
+#define CAP_RIGHTS_IS_SET_INTERCEPTOR(cap_rights_is_set, rights, ...)        \
+  {                                                                          \
+    void *ctx;                                                               \
+    COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_is_set, rights, ##__VA_ARGS__); \
+    if (rights)                                                              \
+      COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights));           \
+    return REAL(cap_rights_is_set)(rights, ##__VA_ARGS__);                   \
+  }
+
+INTERCEPTOR(__sanitizer_cap_rights_t *, cap_rights_init,
+            __sanitizer_cap_rights_t *rights) {
+  CAP_RIGHTS_INIT_INTERCEPTOR(cap_rights_init, rights);
+}
+
+INTERCEPTOR(__sanitizer_cap_rights_t *, cap_rights_set,
+            __sanitizer_cap_rights_t *rights) {
+  CAP_RIGHTS_SET_INTERCEPTOR(cap_rights_set, rights);
+}
+
+INTERCEPTOR(__sanitizer_cap_rights_t *, cap_rights_clear,
+            __sanitizer_cap_rights_t *rights) {
+  CAP_RIGHTS_CLEAR_INTERCEPTOR(cap_rights_clear, rights);
+}
+
+INTERCEPTOR(bool, cap_rights_is_set,
+            __sanitizer_cap_rights_t *rights) {
+  CAP_RIGHTS_IS_SET_INTERCEPTOR(cap_rights_is_set, rights);
+}
+
+INTERCEPTOR(int, cap_rights_limit, int fd,
+            const __sanitizer_cap_rights_t *rights) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_limit, fd, rights);
+  if (rights)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights));
+
+  return REAL(cap_rights_limit)(fd, rights);
+}
+
+INTERCEPTOR(int, cap_rights_get, int fd, __sanitizer_cap_rights_t *rights) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_get, fd, rights);
+  int ret = REAL(cap_rights_get)(fd, rights);
+  if (!ret && rights)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, rights, sizeof(*rights));
+
+  return ret;
+}
+
+INTERCEPTOR(bool, cap_rights_is_valid, const __sanitizer_cap_rights_t *rights) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_is_valid, rights);
+  if (rights)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, rights, sizeof(*rights));
+
+  return REAL(cap_rights_is_valid(rights));
+}
+
+INTERCEPTOR(__sanitizer_cap_rights *, cap_rights_merge,
+  __sanitizer_cap_rights *dst, const __sanitizer_cap_rights *src) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_merge, dst, src);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+
+  __sanitizer_cap_rights *ret = REAL(cap_rights_merge)(dst, src);
+  if (dst)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst));
+
+  return ret;
+}
+
+INTERCEPTOR(__sanitizer_cap_rights *, cap_rights_remove,
+  __sanitizer_cap_rights *dst, const __sanitizer_cap_rights *src) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_remove, dst, src);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, sizeof(*src));
+
+  __sanitizer_cap_rights *ret = REAL(cap_rights_remove)(dst, src);
+  if (dst)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(*dst));
+
+  return ret;
+}
+
+INTERCEPTOR(bool, cap_rights_contains, const __sanitizer_cap_rights *big,
+  const __sanitizer_cap_rights *little) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cap_rights_contains, big, little);
+  if (little)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, little, sizeof(*little));
+  if (big)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, big, sizeof(*big));
+
+  return REAL(cap_rights_contains)(big, little);
+}
+
+INTERCEPTOR(int, cap_ioctls_limit, int fd, const uptr *cmds, SIZE_T ncmds) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cap_ioctls_limit, fd, cmds, ncmds);
+  if (cmds)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, cmds, sizeof(*cmds) * ncmds);
+
+  return REAL(cap_ioctls_limit)(fd, cmds, ncmds);
+}
+
+INTERCEPTOR(int, cap_ioctls_get, int fd, uptr *cmds, SIZE_T maxcmds) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cap_ioctls_get, fd, cmds, maxcmds);
+  int ret = REAL(cap_ioctls_get)(fd, cmds, maxcmds);
+  if (!ret && cmds)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cmds, sizeof(*cmds) * maxcmds);
+
+  return ret;
+}
+#define INIT_CAPSICUM                          \
+  COMMON_INTERCEPT_FUNCTION(cap_rights_init); \
+  COMMON_INTERCEPT_FUNCTION(cap_rights_set); \
+  COMMON_INTERCEPT_FUNCTION(cap_rights_clear); \
+  COMMON_INTERCEPT_FUNCTION(cap_rights_is_set); \
+  COMMON_INTERCEPT_FUNCTION(cap_rights_get);   \
+  COMMON_INTERCEPT_FUNCTION(cap_rights_limit); \
+  COMMON_INTERCEPT_FUNCTION(cap_rights_contains); \
+  COMMON_INTERCEPT_FUNCTION(cap_rights_remove); \
+  COMMON_INTERCEPT_FUNCTION(cap_rights_merge); \
+  COMMON_INTERCEPT_FUNCTION(cap_rights_is_valid); \
+  COMMON_INTERCEPT_FUNCTION(cap_ioctls_get);   \
+  COMMON_INTERCEPT_FUNCTION(cap_ioctls_limit)
+#else
+#define INIT_CAPSICUM
+#endif
+
+#if SANITIZER_INTERCEPT_SHA1
+INTERCEPTOR(void, SHA1Init, void *context) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, SHA1Init, context);
+  REAL(SHA1Init)(context);
+  if (context)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, SHA1_CTX_sz);
+}
+INTERCEPTOR(void, SHA1Update, void *context, const u8 *data, unsigned len) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, SHA1Update, context, data, len);
+  if (data && len > 0)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
+  if (context)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA1_CTX_sz);
+  REAL(SHA1Update)(context, data, len);
+  if (context)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, SHA1_CTX_sz);
+}
+INTERCEPTOR(void, SHA1Final, u8 digest[20], void *context) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, SHA1Final, digest, context);
+  if (context)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA1_CTX_sz);
+  REAL(SHA1Final)(digest, context);
+  if (digest)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(u8) * 20);
+}
+INTERCEPTOR(void, SHA1Transform, u32 state[5], u8 buffer[64]) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, SHA1Transform, state, buffer);
+  if (state)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, state, sizeof(u32) * 5);
+  if (buffer)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, sizeof(u8) * 64);
+  REAL(SHA1Transform)(state, buffer);
+  if (state)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, state, sizeof(u32) * 5);
+}
+INTERCEPTOR(char *, SHA1End, void *context, char *buf) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, SHA1End, context, buf);
+  if (context)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, context, SHA1_CTX_sz);
+  char *ret = REAL(SHA1End)(context, buf);
+  if (ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA1_return_length);
+  return ret;
+}
+INTERCEPTOR(char *, SHA1File, char *filename, char *buf) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, SHA1File, filename, buf);
+  if (filename)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1);
+  char *ret = REAL(SHA1File)(filename, buf);
+  if (ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA1_return_length);
+  return ret;
+}
+INTERCEPTOR(char *, SHA1FileChunk, char *filename, char *buf, OFF_T offset,
+  OFF_T length) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, SHA1FileChunk, filename, buf, offset, length);
+  if (filename)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1);
+  char *ret = REAL(SHA1FileChunk)(filename, buf, offset, length);
+  if (ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA1_return_length);
+  return ret;
+}
+INTERCEPTOR(char *, SHA1Data, u8 *data, SIZE_T len, char *buf) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, SHA1Data, data, len, buf);
+  if (data)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
+  char *ret = REAL(SHA1Data)(data, len, buf);
+  if (ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, SHA1_return_length);
+  return ret;
+}
+#define INIT_SHA1                                                              \
+  COMMON_INTERCEPT_FUNCTION(SHA1Init);                                         \
+  COMMON_INTERCEPT_FUNCTION(SHA1Update);                                       \
+  COMMON_INTERCEPT_FUNCTION(SHA1Final);                                        \
+  COMMON_INTERCEPT_FUNCTION(SHA1Transform);                                    \
+  COMMON_INTERCEPT_FUNCTION(SHA1End);                                          \
+  COMMON_INTERCEPT_FUNCTION(SHA1File);                                         \
+  COMMON_INTERCEPT_FUNCTION(SHA1FileChunk);                                    \
+  COMMON_INTERCEPT_FUNCTION(SHA1Data)
+#else
+#define INIT_SHA1
+#endif
+
+#if SANITIZER_INTERCEPT_MD4
+INTERCEPTOR(void, MD4Init, void *context) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, MD4Init, context);
+  REAL(MD4Init)(context);
+  if (context)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD4_CTX_sz);
+}
+
+INTERCEPTOR(void, MD4Update, void *context, const unsigned char *data,
+            unsigned int len) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, MD4Update, context, data, len);
+  if (data && len > 0)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
+  if (context)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD4_CTX_sz);
+  REAL(MD4Update)(context, data, len);
+  if (context)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD4_CTX_sz);
+}
+
+INTERCEPTOR(void, MD4Final, unsigned char digest[16], void *context) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, MD4Final, digest, context);
+  if (context)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD4_CTX_sz);
+  REAL(MD4Final)(digest, context);
+  if (digest)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(unsigned char) * 16);
+}
+
+INTERCEPTOR(char *, MD4End, void *context, char *buf) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, MD4End, context, buf);
+  if (context)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD4_CTX_sz);
+  char *ret = REAL(MD4End)(context, buf);
+  if (ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD4_return_length);
+  return ret;
+}
+
+INTERCEPTOR(char *, MD4File, const char *filename, char *buf) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, MD4File, filename, buf);
+  if (filename)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1);
+  char *ret = REAL(MD4File)(filename, buf);
+  if (ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD4_return_length);
+  return ret;
+}
+
+INTERCEPTOR(char *, MD4Data, const unsigned char *data, unsigned int len,
+            char *buf) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, MD4Data, data, len, buf);
+  if (data && len > 0)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
+  char *ret = REAL(MD4Data)(data, len, buf);
+  if (ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD4_return_length);
+  return ret;
+}
+
+#define INIT_MD4                                                               \
+  COMMON_INTERCEPT_FUNCTION(MD4Init);                                          \
+  COMMON_INTERCEPT_FUNCTION(MD4Update);                                        \
+  COMMON_INTERCEPT_FUNCTION(MD4Final);                                         \
+  COMMON_INTERCEPT_FUNCTION(MD4End);                                           \
+  COMMON_INTERCEPT_FUNCTION(MD4File);                                          \
+  COMMON_INTERCEPT_FUNCTION(MD4Data)
+#else
+#define INIT_MD4
+#endif
+
+#if SANITIZER_INTERCEPT_RMD160
+INTERCEPTOR(void, RMD160Init, void *context) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, RMD160Init, context);
+  REAL(RMD160Init)(context);
+  if (context)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, RMD160_CTX_sz);
+}
+INTERCEPTOR(void, RMD160Update, void *context, const u8 *data, unsigned len) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, RMD160Update, context, data, len);
+  if (data && len > 0)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
+  if (context)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, context, RMD160_CTX_sz);
+  REAL(RMD160Update)(context, data, len);
+  if (context)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, RMD160_CTX_sz);
+}
+INTERCEPTOR(void, RMD160Final, u8 digest[20], void *context) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, RMD160Final, digest, context);
+  if (context)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, context, RMD160_CTX_sz);
+  REAL(RMD160Final)(digest, context);
+  if (digest)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(u8) * 20);
+}
+INTERCEPTOR(void, RMD160Transform, u32 state[5], u16 buffer[16]) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, RMD160Transform, state, buffer);
+  if (state)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, state, sizeof(u32) * 5);
+  if (buffer)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, buffer, sizeof(u32) * 16);
+  REAL(RMD160Transform)(state, buffer);
+  if (state)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, state, sizeof(u32) * 5);
+}
+INTERCEPTOR(char *, RMD160End, void *context, char *buf) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, RMD160End, context, buf);
+  if (context)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, context, RMD160_CTX_sz);
+  char *ret = REAL(RMD160End)(context, buf);
+  if (ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, RMD160_return_length);
+  return ret;
+}
+INTERCEPTOR(char *, RMD160File, char *filename, char *buf) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, RMD160File, filename, buf);
+  if (filename)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1);
+  char *ret = REAL(RMD160File)(filename, buf);
+  if (ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, RMD160_return_length);
+  return ret;
+}
+INTERCEPTOR(char *, RMD160FileChunk, char *filename, char *buf, OFF_T offset,
+  OFF_T length) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, RMD160FileChunk, filename, buf, offset, length);
+  if (filename)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1);
+  char *ret = REAL(RMD160FileChunk)(filename, buf, offset, length);
+  if (ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, RMD160_return_length);
+  return ret;
+}
+INTERCEPTOR(char *, RMD160Data, u8 *data, SIZE_T len, char *buf) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, RMD160Data, data, len, buf);
+  if (data && len > 0)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
+  char *ret = REAL(RMD160Data)(data, len, buf);
+  if (ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, RMD160_return_length);
+  return ret;
+}
+#define INIT_RMD160                                                            \
+  COMMON_INTERCEPT_FUNCTION(RMD160Init);                                       \
+  COMMON_INTERCEPT_FUNCTION(RMD160Update);                                     \
+  COMMON_INTERCEPT_FUNCTION(RMD160Final);                                      \
+  COMMON_INTERCEPT_FUNCTION(RMD160Transform);                                  \
+  COMMON_INTERCEPT_FUNCTION(RMD160End);                                        \
+  COMMON_INTERCEPT_FUNCTION(RMD160File);                                       \
+  COMMON_INTERCEPT_FUNCTION(RMD160FileChunk);                                  \
+  COMMON_INTERCEPT_FUNCTION(RMD160Data)
+#else
+#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, REAL(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;
+  COMMON_INTERCEPTOR_ENTER(ctx, fseek, stream, offset, whence);
+  return REAL(fseek)(stream, offset, whence);
+}
+INTERCEPTOR(int, fseeko, __sanitizer_FILE *stream, OFF_T offset, int whence) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fseeko, stream, offset, whence);
+  return REAL(fseeko)(stream, offset, whence);
+}
+INTERCEPTOR(long int, ftell, __sanitizer_FILE *stream) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, ftell, stream);
+  return REAL(ftell)(stream);
+}
+INTERCEPTOR(OFF_T, ftello, __sanitizer_FILE *stream) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, ftello, stream);
+  return REAL(ftello)(stream);
+}
+INTERCEPTOR(void, rewind, __sanitizer_FILE *stream) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, rewind, stream);
+  return REAL(rewind)(stream);
+}
+INTERCEPTOR(int, fgetpos, __sanitizer_FILE *stream, void *pos) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fgetpos, stream, pos);
+  int ret = REAL(fgetpos)(stream, pos);
+  if (pos && !ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, pos, fpos_t_sz);
+  return ret;
+}
+INTERCEPTOR(int, fsetpos, __sanitizer_FILE *stream, const void *pos) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, fsetpos, stream, pos);
+  if (pos)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, pos, fpos_t_sz);
+  return REAL(fsetpos)(stream, pos);
+}
+#define INIT_FSEEK \
+  COMMON_INTERCEPT_FUNCTION(fseek); \
+  COMMON_INTERCEPT_FUNCTION(fseeko); \
+  COMMON_INTERCEPT_FUNCTION(ftell); \
+  COMMON_INTERCEPT_FUNCTION(ftello); \
+  COMMON_INTERCEPT_FUNCTION(rewind); \
+  COMMON_INTERCEPT_FUNCTION(fgetpos); \
+  COMMON_INTERCEPT_FUNCTION(fsetpos)
+#else
+#define INIT_FSEEK
+#endif
+
+#if SANITIZER_INTERCEPT_MD2
+INTERCEPTOR(void, MD2Init, void *context) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, MD2Init, context);
+  REAL(MD2Init)(context);
+  if (context)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD2_CTX_sz);
+}
+
+INTERCEPTOR(void, MD2Update, void *context, const unsigned char *data,
+            unsigned int len) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, MD2Update, context, data, len);
+  if (data && len > 0)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
+  if (context)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD2_CTX_sz);
+  REAL(MD2Update)(context, data, len);
+  if (context)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, context, MD2_CTX_sz);
+}
+
+INTERCEPTOR(void, MD2Final, unsigned char digest[16], void *context) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, MD2Final, digest, context);
+  if (context)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD2_CTX_sz);
+  REAL(MD2Final)(digest, context);
+  if (digest)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, digest, sizeof(unsigned char) * 16);
+}
+
+INTERCEPTOR(char *, MD2End, void *context, char *buf) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, MD2End, context, buf);
+  if (context)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, context, MD2_CTX_sz);
+  char *ret = REAL(MD2End)(context, buf);
+  if (ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD2_return_length);
+  return ret;
+}
+
+INTERCEPTOR(char *, MD2File, const char *filename, char *buf) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, MD2File, filename, buf);
+  if (filename)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, filename, REAL(strlen)(filename) + 1);
+  char *ret = REAL(MD2File)(filename, buf);
+  if (ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD2_return_length);
+  return ret;
+}
+
+INTERCEPTOR(char *, MD2Data, const unsigned char *data, unsigned int len,
+            char *buf) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, MD2Data, data, len, buf);
+  if (data && len > 0)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, data, len);
+  char *ret = REAL(MD2Data)(data, len, buf);
+  if (ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, MD2_return_length);
+  return ret;
+}
+
+#define INIT_MD2                                                               \
+  COMMON_INTERCEPT_FUNCTION(MD2Init);                                          \
+  COMMON_INTERCEPT_FUNCTION(MD2Update);                                        \
+  COMMON_INTERCEPT_FUNCTION(MD2Final);                                         \
+  COMMON_INTERCEPT_FUNCTION(MD2End);                                           \
+  COMMON_INTERCEPT_FUNCTION(MD2File);                                          \
+  COMMON_INTERCEPT_FUNCTION(MD2Data)
+#else
+#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[SHA##LEN##_digest_length], \
+  void *context) { \
+    void *ctx; \
+    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, REAL(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, REAL(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;
+  COMMON_INTERCEPTOR_ENTER(ctx, vis, dst, c, flag, nextc);
+  char *end = REAL(vis)(dst, c, flag, nextc);
+  // dst is NULL terminated and end points to the NULL char
+  if (dst && end)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, end - dst + 1);
+  return end;
+}
+INTERCEPTOR(char *, nvis, char *dst, SIZE_T dlen, int c, int flag, int nextc) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, nvis, dst, dlen, c, flag, nextc);
+  char *end = REAL(nvis)(dst, dlen, c, flag, nextc);
+  // nvis cannot make sure the dst is NULL terminated
+  if (dst && end)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, end - dst + 1);
+  return end;
+}
+INTERCEPTOR(int, strvis, char *dst, const char *src, int flag) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strvis, dst, src, flag);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1);
+  int len = REAL(strvis)(dst, src, flag);
+  if (dst)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, len + 1);
+  return len;
+}
+INTERCEPTOR(int, stravis, char **dst, const char *src, int flag) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, stravis, dst, src, flag);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1);
+  int len = REAL(stravis)(dst, src, flag);
+  if (dst) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(char *));
+    if (*dst)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *dst, len + 1);
+  }
+  return len;
+}
+INTERCEPTOR(int, strnvis, char *dst, SIZE_T dlen, const char *src, int flag) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strnvis, dst, dlen, src, flag);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1);
+  int len = REAL(strnvis)(dst, dlen, src, flag);
+  // The interface will be valid even if there is no space for NULL char
+  if (dst && len > 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, len + 1);
+  return len;
+}
+INTERCEPTOR(int, strvisx, char *dst, const char *src, SIZE_T len, int flag) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strvisx, dst, src, len, flag);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len);
+  int ret = REAL(strvisx)(dst, src, len, flag);
+  if (dst)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1);
+  return ret;
+}
+INTERCEPTOR(int, strnvisx, char *dst, SIZE_T dlen, const char *src, SIZE_T len,
+            int flag) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strnvisx, dst, dlen, src, len, flag);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len);
+  int ret = REAL(strnvisx)(dst, dlen, src, len, flag);
+  if (dst && ret >= 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1);
+  return ret;
+}
+INTERCEPTOR(int, strenvisx, char *dst, SIZE_T dlen, const char *src, SIZE_T len,
+            int flag, int *cerr_ptr) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strenvisx, dst, dlen, src, len, flag, cerr_ptr);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len);
+  // FIXME: only need to be checked when "flag | VIS_NOLOCALE" doesn't hold
+  // according to the implementation
+  if (cerr_ptr)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, cerr_ptr, sizeof(int));
+  int ret = REAL(strenvisx)(dst, dlen, src, len, flag, cerr_ptr);
+  if (dst && ret >= 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1);
+  if (cerr_ptr)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cerr_ptr, sizeof(int));
+  return ret;
+}
+INTERCEPTOR(char *, svis, char *dst, int c, int flag, int nextc,
+            const char *extra) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, svis, dst, c, flag, nextc, extra);
+  if (extra)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1);
+  char *end = REAL(svis)(dst, c, flag, nextc, extra);
+  if (dst && end)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, end - dst + 1);
+  return end;
+}
+INTERCEPTOR(char *, snvis, char *dst, SIZE_T dlen, int c, int flag, int nextc,
+            const char *extra) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, snvis, dst, dlen, c, flag, nextc, extra);
+  if (extra)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1);
+  char *end = REAL(snvis)(dst, dlen, c, flag, nextc, extra);
+  if (dst && end)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst,
+                                   Min((SIZE_T)(end - dst + 1), dlen));
+  return end;
+}
+INTERCEPTOR(int, strsvis, char *dst, const char *src, int flag,
+            const char *extra) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strsvis, dst, src, flag, extra);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1);
+  if (extra)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1);
+  int len = REAL(strsvis)(dst, src, flag, extra);
+  if (dst)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, len + 1);
+  return len;
+}
+INTERCEPTOR(int, strsnvis, char *dst, SIZE_T dlen, const char *src, int flag,
+            const char *extra) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strsnvis, dst, dlen, src, flag, extra);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1);
+  if (extra)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1);
+  int len = REAL(strsnvis)(dst, dlen, src, flag, extra);
+  // The interface will be valid even if there is no space for NULL char
+  if (dst && len >= 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, len + 1);
+  return len;
+}
+INTERCEPTOR(int, strsvisx, char *dst, const char *src, SIZE_T len, int flag,
+            const char *extra) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strsvisx, dst, src, len, flag, extra);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len);
+  if (extra)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1);
+  int ret = REAL(strsvisx)(dst, src, len, flag, extra);
+  if (dst)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1);
+  return ret;
+}
+INTERCEPTOR(int, strsnvisx, char *dst, SIZE_T dlen, const char *src, SIZE_T len,
+            int flag, const char *extra) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strsnvisx, dst, dlen, src, len, flag, extra);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len);
+  if (extra)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1);
+  int ret = REAL(strsnvisx)(dst, dlen, src, len, flag, extra);
+  if (dst && ret >= 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1);
+  return ret;
+}
+INTERCEPTOR(int, strsenvisx, char *dst, SIZE_T dlen, const char *src,
+            SIZE_T len, int flag, const char *extra, int *cerr_ptr) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strsenvisx, dst, dlen, src, len, flag, extra,
+                           cerr_ptr);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len);
+  if (extra)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1);
+  // FIXME: only need to be checked when "flag | VIS_NOLOCALE" doesn't hold
+  // according to the implementation
+  if (cerr_ptr)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, cerr_ptr, sizeof(int));
+  int ret = REAL(strsenvisx)(dst, dlen, src, len, flag, extra, cerr_ptr);
+  if (dst && ret >= 0)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1);
+  if (cerr_ptr)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cerr_ptr, sizeof(int));
+  return ret;
+}
+INTERCEPTOR(int, unvis, char *cp, int c, int *astate, int flag) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, unvis, cp, c, astate, flag);
+  if (astate)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, astate, sizeof(*astate));
+  int ret = REAL(unvis)(cp, c, astate, flag);
+  if (ret == unvis_valid || ret == unvis_validpush) {
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cp, sizeof(*cp));
+  }
+  return ret;
+}
+INTERCEPTOR(int, strunvis, char *dst, const char *src) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strunvis, dst, src);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1);
+  int ret = REAL(strunvis)(dst, src);
+  if (ret != -1)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1);
+  return ret;
+}
+INTERCEPTOR(int, strnunvis, char *dst, SIZE_T dlen, const char *src) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strnunvis, dst, dlen, src);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1);
+  int ret = REAL(strnunvis)(dst, dlen, src);
+  if (ret != -1)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1);
+  return ret;
+}
+INTERCEPTOR(int, strunvisx, char *dst, const char *src, int flag) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strunvisx, dst, src, flag);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1);
+  int ret = REAL(strunvisx)(dst, src, flag);
+  if (ret != -1)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1);
+  return ret;
+}
+INTERCEPTOR(int, strnunvisx, char *dst, SIZE_T dlen, const char *src,
+            int flag) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, strnunvisx, dst, dlen, src, flag);
+  if (src)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1);
+  int ret = REAL(strnunvisx)(dst, dlen, src, flag);
+  if (ret != -1)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1);
+  return ret;
+}
+#define INIT_VIS                                                               \
+  COMMON_INTERCEPT_FUNCTION(vis);                                              \
+  COMMON_INTERCEPT_FUNCTION(nvis);                                             \
+  COMMON_INTERCEPT_FUNCTION(strvis);                                           \
+  COMMON_INTERCEPT_FUNCTION(stravis);                                          \
+  COMMON_INTERCEPT_FUNCTION(strnvis);                                          \
+  COMMON_INTERCEPT_FUNCTION(strvisx);                                          \
+  COMMON_INTERCEPT_FUNCTION(strnvisx);                                         \
+  COMMON_INTERCEPT_FUNCTION(strenvisx);                                        \
+  COMMON_INTERCEPT_FUNCTION(svis);                                             \
+  COMMON_INTERCEPT_FUNCTION(snvis);                                            \
+  COMMON_INTERCEPT_FUNCTION(strsvis);                                          \
+  COMMON_INTERCEPT_FUNCTION(strsnvis);                                         \
+  COMMON_INTERCEPT_FUNCTION(strsvisx);                                         \
+  COMMON_INTERCEPT_FUNCTION(strsnvisx);                                        \
+  COMMON_INTERCEPT_FUNCTION(strsenvisx);                                       \
+  COMMON_INTERCEPT_FUNCTION(unvis);                                            \
+  COMMON_INTERCEPT_FUNCTION(strunvis);                                         \
+  COMMON_INTERCEPT_FUNCTION(strnunvis);                                        \
+  COMMON_INTERCEPT_FUNCTION(strunvisx);                                        \
+  COMMON_INTERCEPT_FUNCTION(strnunvisx)
+#else
+#define INIT_VIS
+#endif
+
+#if SANITIZER_INTERCEPT_CDB
+INTERCEPTOR(struct __sanitizer_cdbr *, cdbr_open, const char *path, int flags) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cdbr_open, path, flags);
+  if (path)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
+  struct __sanitizer_cdbr *cdbr = REAL(cdbr_open)(path, flags);
+  if (cdbr)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbr, sizeof(*cdbr));
+  return cdbr;
+}
+
+INTERCEPTOR(struct __sanitizer_cdbr *, cdbr_open_mem, void *base, SIZE_T size,
+  int flags, void (*unmap)(void *, void *, SIZE_T), void *cookie) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cdbr_open_mem, base, size, flags, unmap,
+    cookie);
+  if (base && size)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, base, size);
+  struct __sanitizer_cdbr *cdbr =
+    REAL(cdbr_open_mem)(base, size, flags, unmap, cookie);
+  if (cdbr)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbr, sizeof(*cdbr));
+  return cdbr;
+}
+
+INTERCEPTOR(u32, cdbr_entries, struct __sanitizer_cdbr *cdbr) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cdbr_entries, cdbr);
+  if (cdbr)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbr, sizeof(*cdbr));
+  return REAL(cdbr_entries)(cdbr);
+}
+
+INTERCEPTOR(int, cdbr_get, struct __sanitizer_cdbr *cdbr, u32 index,
+            const void **data, SIZE_T *datalen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cdbr_get, cdbr, index, data, datalen);
+  if (cdbr)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbr, sizeof(*cdbr));
+  int ret = REAL(cdbr_get)(cdbr, index, data, datalen);
+  if (!ret) {
+    if (data)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(*data));
+    if (datalen)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datalen, sizeof(*datalen));
+    if (data && datalen)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *data, *datalen);
+  }
+  return ret;
+}
+
+INTERCEPTOR(int, cdbr_find, struct __sanitizer_cdbr *cdbr, const void *key,
+            SIZE_T keylen, const void **data, SIZE_T *datalen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cdbr_find, cdbr, key, keylen, data, datalen);
+  if (cdbr)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbr, sizeof(*cdbr));
+  if (key)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, key, keylen);
+  int ret = REAL(cdbr_find)(cdbr, key, keylen, data, datalen);
+  if (!ret) {
+    if (data)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, data, sizeof(*data));
+    if (datalen)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, datalen, sizeof(*datalen));
+    if (data && datalen)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *data, *datalen);
+  }
+  return ret;
+}
+
+INTERCEPTOR(void, cdbr_close, struct __sanitizer_cdbr *cdbr) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cdbr_close, cdbr);
+  if (cdbr)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbr, sizeof(*cdbr));
+  REAL(cdbr_close)(cdbr);
+}
+
+INTERCEPTOR(struct __sanitizer_cdbw *, cdbw_open) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cdbw_open);
+  struct __sanitizer_cdbw *ret = REAL(cdbw_open)();
+  if (ret)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ret, sizeof(*ret));
+  return ret;
+}
+
+INTERCEPTOR(int, cdbw_put, struct __sanitizer_cdbw *cdbw, const void *key,
+  SIZE_T keylen, const void *data, SIZE_T datalen) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cdbw_put, cdbw, key, keylen, data, datalen);
+  if (cdbw)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbw, sizeof(*cdbw));
+  if (data && datalen)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, data, datalen);
+  if (key && keylen)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, key, keylen);
+  int ret = REAL(cdbw_put)(cdbw, key, keylen, data, datalen);
+  if (!ret && cdbw)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbw, sizeof(*cdbw));
+  return ret;
+}
+
+INTERCEPTOR(int, cdbw_put_data, struct __sanitizer_cdbw *cdbw, const void *data,
+  SIZE_T datalen, u32 *index) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cdbw_put_data, cdbw, data, datalen, index);
+  if (cdbw)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbw, sizeof(*cdbw));
+  if (data && datalen)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, data, datalen);
+  int ret = REAL(cdbw_put_data)(cdbw, data, datalen, index);
+  if (!ret) {
+    if (index)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, index, sizeof(*index));
+    if (cdbw)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbw, sizeof(*cdbw));
+  }
+  return ret;
+}
+
+INTERCEPTOR(int, cdbw_put_key, struct __sanitizer_cdbw *cdbw, const void *key,
+  SIZE_T keylen, u32 index) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cdbw_put_key, cdbw, key, keylen, index);
+  if (cdbw)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbw, sizeof(*cdbw));
+  if (key && keylen)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, key, keylen);
+  int ret = REAL(cdbw_put_key)(cdbw, key, keylen, index);
+  if (!ret && cdbw)
+    COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbw, sizeof(*cdbw));
+  return ret;
+}
+
+INTERCEPTOR(int, cdbw_output, struct __sanitizer_cdbw *cdbw, int output,
+  const char descr[16], u32 (*seedgen)(void)) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cdbw_output, cdbw, output, descr, seedgen);
+  COMMON_INTERCEPTOR_FD_ACCESS(ctx, output);
+  if (cdbw)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbw, sizeof(*cdbw));
+  if (descr)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, descr, internal_strnlen(descr, 16));
+  if (seedgen)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, (void *)seedgen, sizeof(seedgen));
+  int ret = REAL(cdbw_output)(cdbw, output, descr, seedgen);
+  if (!ret) {
+    if (cdbw)
+      COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cdbw, sizeof(*cdbw));
+    if (output >= 0)
+      COMMON_INTERCEPTOR_FD_ACQUIRE(ctx, output);
+  }
+  return ret;
+}
+
+INTERCEPTOR(void, cdbw_close, struct __sanitizer_cdbw *cdbw) {
+  void *ctx;
+  COMMON_INTERCEPTOR_ENTER(ctx, cdbw_close, cdbw);
+  if (cdbw)
+    COMMON_INTERCEPTOR_READ_RANGE(ctx, cdbw, sizeof(*cdbw));
+  REAL(cdbw_close)(cdbw);
+}
+
+#define INIT_CDB \
+  COMMON_INTERCEPT_FUNCTION(cdbr_open); \
+  COMMON_INTERCEPT_FUNCTION(cdbr_open_mem); \
+  COMMON_INTERCEPT_FUNCTION(cdbr_entries); \
+  COMMON_INTERCEPT_FUNCTION(cdbr_get); \
+  COMMON_INTERCEPT_FUNCTION(cdbr_find); \
+  COMMON_INTERCEPT_FUNCTION(cdbr_close); \
+  COMMON_INTERCEPT_FUNCTION(cdbw_open); \
+  COMMON_INTERCEPT_FUNCTION(cdbw_put); \
+  COMMON_INTERCEPT_FUNCTION(cdbw_put_data); \
+  COMMON_INTERCEPT_FUNCTION(cdbw_put_key); \
+  COMMON_INTERCEPT_FUNCTION(cdbw_output); \
+  COMMON_INTERCEPT_FUNCTION(cdbw_close)
+#else
+#define INIT_CDB
+#endif
+
 static void InitializeCommonInterceptors() {
   static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1];
-  interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap();
+  interceptor_metadata_map =
+      new ((void *)&metadata_mem) MetadataHashMap();  // NOLINT
 
   INIT_MMAP;
   INIT_MMAP64;
@@ -7517,6 +9291,31 @@
   INIT_TTYENT;
   INIT_PROTOENT;
   INIT_NETENT;
+  INIT_GETMNTINFO;
+  INIT_MI_VECTOR_HASH;
+  INIT_SETVBUF;
+  INIT_GETVFSSTAT;
+  INIT_REGEX;
+  INIT_FTS;
+  INIT_SYSCTL;
+  INIT_ASYSCTL;
+  INIT_SYSCTLGETMIBINFO;
+  INIT_NL_LANGINFO;
+  INIT_MODCTL;
+  INIT_STRTONUM;
+  INIT_FPARSELN;
+  INIT_STATVFS1;
+  INIT_STRTOI;
+  INIT_CAPSICUM;
+  INIT_SHA1;
+  INIT_MD4;
+  INIT_RMD160;
+  INIT_MD5;
+  INIT_FSEEK;
+  INIT_MD2;
+  INIT_SHA2;
+  INIT_VIS;
+  INIT_CDB;
 
   INIT___PRINTF_CHK;
 }
diff --git a/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc b/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc
index f27b95f..9ff8798 100644
--- a/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_fuchsia.cc
@@ -31,6 +31,7 @@
 #include "sanitizer_atomic.h"
 #include "sanitizer_common.h"
 #include "sanitizer_internal_defs.h"
+#include "sanitizer_symbolizer_fuchsia.h"
 
 #include <zircon/process.h>
 #include <zircon/sanitizer.h>
@@ -101,7 +102,7 @@
       // uses the `dumpfile` symbolizer markup element to highlight the
       // dump.  See the explanation for this in:
       // https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md
-      Printf("SanitizerCoverage: {{{dumpfile:%s:%s}}} with up to %u PCs\n",
+      Printf("SanitizerCoverage: " FORMAT_DUMPFILE " with up to %u PCs\n",
              kSancovSinkName, vmo_name_, next_index_ - 1);
     }
   }
diff --git a/lib/sanitizer_common/sanitizer_file.h b/lib/sanitizer_common/sanitizer_file.h
index 9a12ab7..52e6ef8 100644
--- a/lib/sanitizer_common/sanitizer_file.h
+++ b/lib/sanitizer_common/sanitizer_file.h
@@ -66,9 +66,6 @@
 bool WriteToFile(fd_t fd, const void *buff, uptr buff_size,
                  uptr *bytes_written = nullptr, error_t *error_p = nullptr);
 
-bool RenameFile(const char *oldpath, const char *newpath,
-                error_t *error_p = nullptr);
-
 // Scoped file handle closer.
 struct FileCloser {
   explicit FileCloser(fd_t fd) : fd(fd) {}
diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc
index cfe8af8..8e0d724 100644
--- a/lib/sanitizer_common/sanitizer_flags.inc
+++ b/lib/sanitizer_common/sanitizer_flags.inc
@@ -103,7 +103,7 @@
             "handle_*=1 will be upgraded to handle_*=2.")
 COMMON_FLAG(bool, use_sigaltstack, true,
             "If set, uses alternate stack for signal handling.")
-COMMON_FLAG(bool, detect_deadlocks, false,
+COMMON_FLAG(bool, detect_deadlocks, true,
             "If set, deadlock detection is enabled.")
 COMMON_FLAG(
     uptr, clear_shadow_mmap_threshold, 64 * 1024,
diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc
index 5122efd..0698666 100644
--- a/lib/sanitizer_common/sanitizer_fuchsia.cc
+++ b/lib/sanitizer_common/sanitizer_fuchsia.cc
@@ -120,8 +120,9 @@
   if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
     return;
   while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) {
-    zx_status_t status = _zx_futex_wait(reinterpret_cast<zx_futex_t *>(m),
-                                        MtxSleeping, ZX_TIME_INFINITE);
+    zx_status_t status =
+        _zx_futex_wait(reinterpret_cast<zx_futex_t *>(m), MtxSleeping,
+                       ZX_HANDLE_INVALID, ZX_TIME_INFINITE);
     if (status != ZX_ERR_BAD_STATE)  // Normal race.
       CHECK_EQ(status, ZX_OK);
   }
diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h
index 397bc4c..14258d6 100644
--- a/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -197,7 +197,9 @@
 // This header should NOT include any other headers to avoid portability issues.
 
 // Common defs.
+#ifndef INLINE
 #define INLINE inline
+#endif
 #define INTERFACE_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
 #define SANITIZER_WEAK_DEFAULT_IMPL \
   extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index aff9a6f..6cfb615 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -433,7 +433,7 @@
 
 unsigned int internal_sleep(unsigned int seconds) {
   struct timespec ts;
-  ts.tv_sec = 1;
+  ts.tv_sec = seconds;
   ts.tv_nsec = 0;
   int res = internal_syscall(SYSCALL(nanosleep), &ts, &ts);
   if (res) return ts.tv_sec;
@@ -772,7 +772,8 @@
   return sysctl(name, namelen, oldp, (size_t *)oldlenp, (void *)newp,
                 (size_t)newlen);
 #else
-  return sysctl(name, namelen, oldp, (size_t *)oldlenp, newp, (size_t)newlen);
+  return internal_syscall(SYSCALL(__sysctl), name, namelen, oldp,
+                          (size_t *)oldlenp, newp, (size_t)newlen);
 #endif
 }
 
@@ -1076,6 +1077,14 @@
   return EXEC_PAGESIZE;
 #elif SANITIZER_USE_GETAUXVAL
   return getauxval(AT_PAGESZ);
+#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;
 #else
   return sysconf(_SC_PAGESIZE);  // EXEC_PAGESIZE may not be trustworthy.
 #endif
diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h
index 8322f4e..6f5387e 100644
--- a/lib/sanitizer_common/sanitizer_linux.h
+++ b/lib/sanitizer_common/sanitizer_linux.h
@@ -18,6 +18,7 @@
     SANITIZER_OPENBSD || 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_openbsd.h"
 #include "sanitizer_platform_limits_posix.h"
diff --git a/lib/sanitizer_common/sanitizer_local_address_space_view.h b/lib/sanitizer_common/sanitizer_local_address_space_view.h
new file mode 100644
index 0000000..9fbf593
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_local_address_space_view.h
@@ -0,0 +1,53 @@
+//===-- sanitizer_local_address_space_view.h --------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// `LocalAddressSpaceView` provides the local (i.e. target and current address
+// space are the same) implementation of the `AddressSpaveView` interface which
+// provides a simple interface to load memory from another process (i.e.
+// out-of-process)
+//
+// The `AddressSpaveView` interface requires that the type can be used as a
+// template parameter to objects that wish to be able to operate in an
+// out-of-process manner. In normal usage, objects are in-process and are thus
+// instantiated with the `LocalAddressSpaceView` type. This type is used to
+// load any pointers in instance methods. This implementation is effectively
+// a no-op. When an object is to be used in an out-of-process manner it is
+// instansiated with the `RemoteAddressSpaceView` type.
+//
+// By making `AddressSpaceView` a template parameter of an object, it can
+// change its implementation at compile time which has no run time overhead.
+// This also allows unifying in-process and out-of-process code which avoids
+// code duplication.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_LOCAL_ADDRES_SPACE_VIEW_H
+#define SANITIZER_LOCAL_ADDRES_SPACE_VIEW_H
+
+namespace __sanitizer {
+struct LocalAddressSpaceView {
+  // Load memory `sizeof(T) * num_elements` bytes of memory
+  // from the target process (always local for this implementation)
+  // starting at address `target_address`. The local copy of
+  // this memory is returned as a pointer. It is guaranteed that
+  //
+  // * That the function will always return the same value
+  //   for a given set of arguments.
+  // * That the memory returned is writable and that writes will persist.
+  //
+  // The lifetime of loaded memory is implementation defined.
+  template <typename T>
+  static T *Load(T *target_address, uptr num_elements = 1) {
+    // The target address space is the local address space so
+    // nothing needs to be copied. Just return the pointer.
+    return target_address;
+  }
+};
+}  // namespace __sanitizer
+
+#endif
diff --git a/lib/sanitizer_common/sanitizer_malloc_mac.inc b/lib/sanitizer_common/sanitizer_malloc_mac.inc
index f9f40f8..44c914c 100644
--- a/lib/sanitizer_common/sanitizer_malloc_mac.inc
+++ b/lib/sanitizer_common/sanitizer_malloc_mac.inc
@@ -30,9 +30,27 @@
 // https://github.com/gperftools/gperftools.
 
 namespace __sanitizer {
+
 extern malloc_zone_t sanitizer_zone;
+
+struct sanitizer_malloc_introspection_t : public malloc_introspection_t {
+  // IMPORTANT: Do not change the order, alignment, or types of these fields to
+  // maintain binary compatibility. You should only add fields to this struct.
+
+  // Used to track changes to the allocator that will affect
+  // zone enumeration.
+  u64 allocator_enumeration_version;
+};
+
+u64 GetMallocZoneAllocatorEnumerationVersion() {
+  // This represents the current allocator ABI version.
+  // This field should be incremented every time the Allocator
+  // ABI changes in a way that breaks allocator enumeration.
+  return 0;
 }
 
+}  // namespace __sanitizer
+
 INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
                              vm_size_t start_size, unsigned zone_flags) {
   COMMON_MALLOC_ENTER();
@@ -247,6 +265,13 @@
   return p;
 }
 
+// This public API exists purely for testing purposes.
+extern "C"
+SANITIZER_INTERFACE_ATTRIBUTE
+malloc_zone_t* __sanitizer_mz_default_zone() {
+  return &sanitizer_zone;
+}
+
 // This function is currently unused, and we build with -Werror.
 #if 0
 void __sanitizer_mz_free_definite_size(
@@ -303,7 +328,7 @@
 namespace COMMON_MALLOC_NAMESPACE {
 
 void InitMallocZoneFields() {
-  static malloc_introspection_t sanitizer_zone_introspection;
+  static sanitizer_malloc_introspection_t sanitizer_zone_introspection;
   // Ok to use internal_memset, these places are not performance-critical.
   internal_memset(&sanitizer_zone_introspection, 0,
                   sizeof(sanitizer_zone_introspection));
@@ -318,6 +343,10 @@
   sanitizer_zone_introspection.statistics = &mi_statistics;
   sanitizer_zone_introspection.zone_locked = &mi_zone_locked;
 
+  // Set current allocator enumeration version.
+  sanitizer_zone_introspection.allocator_enumeration_version =
+      GetMallocZoneAllocatorEnumerationVersion();
+
   internal_memset(&sanitizer_zone, 0, sizeof(malloc_zone_t));
 
   // Use version 6 for OSX >= 10.6.
diff --git a/lib/sanitizer_common/sanitizer_netbsd.cc b/lib/sanitizer_common/sanitizer_netbsd.cc
index 83beb00..cdf552c 100644
--- a/lib/sanitizer_common/sanitizer_netbsd.cc
+++ b/lib/sanitizer_common/sanitizer_netbsd.cc
@@ -202,7 +202,7 @@
 
 unsigned int internal_sleep(unsigned int seconds) {
   struct timespec ts;
-  ts.tv_sec = 1;
+  ts.tv_sec = seconds;
   ts.tv_nsec = 0;
   CHECK(&_sys___nanosleep50);
   int res = _sys___nanosleep50(&ts, &ts);
diff --git a/lib/sanitizer_common/sanitizer_platform.h b/lib/sanitizer_common/sanitizer_platform.h
index 106a147..fd7228c 100644
--- a/lib/sanitizer_common/sanitizer_platform.h
+++ b/lib/sanitizer_common/sanitizer_platform.h
@@ -342,4 +342,13 @@
 #define SANITIZER_SYMBOLIZER_MARKUP 0
 #endif
 
+// Enable ability to support sanitizer initialization that is
+// compatible with the sanitizer library being loaded via
+// `dlopen()`.
+#if SANITIZER_MAC
+#define SANITIZER_SUPPORTS_INIT_FOR_DLOPEN 1
+#else
+#define SANITIZER_SUPPORTS_INIT_FOR_DLOPEN 0
+#endif
+
 #endif // SANITIZER_PLATFORM_H
diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h
index 851e812..8d77109 100644
--- a/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -33,8 +33,9 @@
 #endif
 
 #if SI_POSIX
+# include "sanitizer_platform_limits_freebsd.h"
 # include "sanitizer_platform_limits_netbsd.h"
-#include "sanitizer_platform_limits_openbsd.h"
+# include "sanitizer_platform_limits_openbsd.h"
 # include "sanitizer_platform_limits_posix.h"
 # include "sanitizer_platform_limits_solaris.h"
 #endif
@@ -386,7 +387,7 @@
 #define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \
   (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
 #define SANITIZER_INTERCEPT_PTHREAD_GETNAME_NP \
-  (SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
+  (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
 
 #define SANITIZER_INTERCEPT_TLS_GET_ADDR \
   (SI_FREEBSD || SI_NETBSD || SI_OPENBSD || SI_LINUX_NOT_ANDROID || SI_SOLARIS)
@@ -516,5 +517,32 @@
 #define SANITIZER_INTERCEPT_TTYENT SI_NETBSD
 #define SANITIZER_INTERCEPT_PROTOENT SI_NETBSD
 #define SANITIZER_INTERCEPT_NETENT SI_NETBSD
+#define SANITIZER_INTERCEPT_SETVBUF (SI_NETBSD || SI_FREEBSD || \
+  SI_LINUX || SI_MAC)
+#define SANITIZER_INTERCEPT_GETMNTINFO (SI_NETBSD || SI_FREEBSD || SI_MAC)
+#define SANITIZER_INTERCEPT_MI_VECTOR_HASH SI_NETBSD
+#define SANITIZER_INTERCEPT_GETVFSSTAT SI_NETBSD
+#define SANITIZER_INTERCEPT_REGEX SI_NETBSD
+#define SANITIZER_INTERCEPT_FTS SI_NETBSD
+#define SANITIZER_INTERCEPT_SYSCTL (SI_NETBSD || SI_FREEBSD || SI_MAC)
+#define SANITIZER_INTERCEPT_ASYSCTL SI_NETBSD
+#define SANITIZER_INTERCEPT_SYSCTLGETMIBINFO SI_NETBSD
+#define SANITIZER_INTERCEPT_NL_LANGINFO (SI_NETBSD || SI_FREEBSD || SI_MAC)
+#define SANITIZER_INTERCEPT_MODCTL SI_NETBSD
+#define SANITIZER_INTERCEPT_CAPSICUM SI_FREEBSD
+#define SANITIZER_INTERCEPT_STRTONUM SI_NETBSD
+#define SANITIZER_INTERCEPT_FPARSELN SI_NETBSD
+#define SANITIZER_INTERCEPT_STATVFS1 SI_NETBSD
+#define SANITIZER_INTERCEPT_STRTOI SI_NETBSD
+#define SANITIZER_INTERCEPT_CAPSICUM SI_FREEBSD
+#define SANITIZER_INTERCEPT_SHA1 SI_NETBSD
+#define SANITIZER_INTERCEPT_MD4 SI_NETBSD
+#define SANITIZER_INTERCEPT_RMD160 SI_NETBSD
+#define SANITIZER_INTERCEPT_MD5 SI_NETBSD
+#define SANITIZER_INTERCEPT_FSEEK (SI_NETBSD || SI_FREEBSD)
+#define SANITIZER_INTERCEPT_MD2 SI_NETBSD
+#define SANITIZER_INTERCEPT_SHA2 SI_NETBSD
+#define SANITIZER_INTERCEPT_CDB SI_NETBSD
+#define SANITIZER_INTERCEPT_VIS SI_NETBSD
 
 #endif  // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cc b/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cc
new file mode 100644
index 0000000..cebb216
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_platform_limits_freebsd.cc
@@ -0,0 +1,513 @@
+//===-- sanitizer_platform_limits_freebsd.cc ------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer common code.
+//
+// Sizes and layouts of platform-specific FreeBSD data structures.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#if SANITIZER_FREEBSD
+
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <grp.h>
+#include <limits.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <poll.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stddef.h>
+#include <sys/mman.h>
+#include <sys/capsicum.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <termios.h>
+#include <time.h>
+
+#include <net/route.h>
+#include <sys/mount.h>
+#include <sys/sockio.h>
+#include <sys/socket.h>
+#include <sys/filio.h>
+#include <sys/signal.h>
+#include <sys/timespec.h>
+#include <sys/timeb.h>
+#include <sys/mqueue.h>
+#include <sys/msg.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/statvfs.h>
+#include <sys/soundcard.h>
+#include <sys/mtio.h>
+#include <sys/consio.h>
+#include <sys/kbio.h>
+#include <sys/link_elf.h>
+#include <netinet/ip_mroute.h>
+#include <netinet/in.h>
+#include <net/ethernet.h>
+#include <net/ppp_defs.h>
+#include <glob.h>
+#include <stdio.h>
+#include <term.h>
+#include <utmpx.h>
+#include <wchar.h>
+
+#define _KERNEL  // to declare 'shminfo' structure
+# include <sys/shm.h>
+#undef _KERNEL
+
+#undef INLINE  // to avoid clashes with sanitizers' definitions
+
+#undef IOC_DIRMASK
+
+# include <utime.h>
+# include <sys/ptrace.h>
+# include <semaphore.h>
+
+#include <ifaddrs.h>
+#include <sys/ucontext.h>
+#include <wordexp.h>
+
+// Include these after system headers to avoid name clashes and ambiguities.
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform_limits_freebsd.h"
+
+namespace __sanitizer {
+  unsigned struct_cap_rights_sz = sizeof(cap_rights_t);
+  unsigned struct_utsname_sz = sizeof(struct utsname);
+  unsigned struct_stat_sz = sizeof(struct stat);
+  unsigned struct_rusage_sz = sizeof(struct rusage);
+  unsigned struct_tm_sz = sizeof(struct tm);
+  unsigned struct_passwd_sz = sizeof(struct passwd);
+  unsigned struct_group_sz = sizeof(struct group);
+  unsigned siginfo_t_sz = sizeof(siginfo_t);
+  unsigned struct_sigaction_sz = sizeof(struct sigaction);
+  unsigned struct_itimerval_sz = sizeof(struct itimerval);
+  unsigned pthread_t_sz = sizeof(pthread_t);
+  unsigned pthread_mutex_t_sz = sizeof(pthread_mutex_t);
+  unsigned pthread_cond_t_sz = sizeof(pthread_cond_t);
+  unsigned pid_t_sz = sizeof(pid_t);
+  unsigned timeval_sz = sizeof(timeval);
+  unsigned uid_t_sz = sizeof(uid_t);
+  unsigned gid_t_sz = sizeof(gid_t);
+  unsigned fpos_t_sz = sizeof(fpos_t);
+  unsigned mbstate_t_sz = sizeof(mbstate_t);
+  unsigned sigset_t_sz = sizeof(sigset_t);
+  unsigned struct_timezone_sz = sizeof(struct timezone);
+  unsigned struct_tms_sz = sizeof(struct tms);
+  unsigned struct_sigevent_sz = sizeof(struct sigevent);
+  unsigned struct_sched_param_sz = sizeof(struct sched_param);
+  unsigned struct_statfs_sz = sizeof(struct statfs);
+  unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
+  unsigned ucontext_t_sz = sizeof(ucontext_t);
+  unsigned struct_rlimit_sz = sizeof(struct rlimit);
+  unsigned struct_timespec_sz = sizeof(struct timespec);
+  unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
+  unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
+  unsigned struct_timeb_sz = sizeof(struct timeb);
+  unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
+  unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
+  unsigned struct_statvfs_sz = sizeof(struct statvfs);
+  unsigned struct_shminfo_sz = sizeof(struct shminfo);
+  unsigned struct_shm_info_sz = sizeof(struct shm_info);
+
+  const uptr sig_ign = (uptr)SIG_IGN;
+  const uptr sig_dfl = (uptr)SIG_DFL;
+  const uptr sig_err = (uptr)SIG_ERR;
+  const uptr sa_siginfo = (uptr)SA_SIGINFO;
+
+  int shmctl_ipc_stat = (int)IPC_STAT;
+  int shmctl_ipc_info = (int)IPC_INFO;
+  int shmctl_shm_info = (int)SHM_INFO;
+  int shmctl_shm_stat = (int)SHM_STAT;
+  unsigned struct_utmpx_sz = sizeof(struct utmpx);
+
+  int map_fixed = MAP_FIXED;
+
+  int af_inet = (int)AF_INET;
+  int af_inet6 = (int)AF_INET6;
+
+  uptr __sanitizer_in_addr_sz(int af) {
+    if (af == AF_INET)
+      return sizeof(struct in_addr);
+    else if (af == AF_INET6)
+      return sizeof(struct in6_addr);
+    else
+      return 0;
+  }
+
+  unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
+  int glob_nomatch = GLOB_NOMATCH;
+  int glob_altdirfunc = GLOB_ALTDIRFUNC;
+
+  unsigned path_max = PATH_MAX;
+
+  // ioctl arguments
+  unsigned struct_ifreq_sz = sizeof(struct ifreq);
+  unsigned struct_termios_sz = sizeof(struct termios);
+  unsigned struct_winsize_sz = sizeof(struct winsize);
+#if SOUND_VERSION >= 0x040000
+  unsigned struct_copr_buffer_sz = 0;
+  unsigned struct_copr_debug_buf_sz = 0;
+  unsigned struct_copr_msg_sz = 0;
+#else
+  unsigned struct_copr_buffer_sz = sizeof(struct copr_buffer);
+  unsigned struct_copr_debug_buf_sz = sizeof(struct copr_debug_buf);
+  unsigned struct_copr_msg_sz = sizeof(struct copr_msg);
+#endif
+  unsigned struct_midi_info_sz = sizeof(struct midi_info);
+  unsigned struct_mtget_sz = sizeof(struct mtget);
+  unsigned struct_mtop_sz = sizeof(struct mtop);
+  unsigned struct_sbi_instrument_sz = sizeof(struct sbi_instrument);
+  unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec);
+  unsigned struct_synth_info_sz = sizeof(struct synth_info);
+  unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
+  unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
+  unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
+  unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
+  const unsigned long __sanitizer_bufsiz = BUFSIZ;
+
+  const unsigned IOCTL_NOT_PRESENT = 0;
+
+  unsigned IOCTL_FIOASYNC = FIOASYNC;
+  unsigned IOCTL_FIOCLEX = FIOCLEX;
+  unsigned IOCTL_FIOGETOWN = FIOGETOWN;
+  unsigned IOCTL_FIONBIO = FIONBIO;
+  unsigned IOCTL_FIONCLEX = FIONCLEX;
+  unsigned IOCTL_FIOSETOWN = FIOSETOWN;
+  unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI;
+  unsigned IOCTL_SIOCATMARK = SIOCATMARK;
+  unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI;
+  unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR;
+  unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR;
+  unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF;
+  unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR;
+  unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS;
+  unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC;
+  unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU;
+  unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK;
+  unsigned IOCTL_SIOCGPGRP = SIOCGPGRP;
+  unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR;
+  unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR;
+  unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR;
+  unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS;
+  unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC;
+  unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU;
+  unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK;
+  unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;
+  unsigned IOCTL_TIOCCONS = TIOCCONS;
+  unsigned IOCTL_TIOCEXCL = TIOCEXCL;
+  unsigned IOCTL_TIOCGETD = TIOCGETD;
+  unsigned IOCTL_TIOCGPGRP = TIOCGPGRP;
+  unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ;
+  unsigned IOCTL_TIOCMBIC = TIOCMBIC;
+  unsigned IOCTL_TIOCMBIS = TIOCMBIS;
+  unsigned IOCTL_TIOCMGET = TIOCMGET;
+  unsigned IOCTL_TIOCMSET = TIOCMSET;
+  unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;
+  unsigned IOCTL_TIOCNXCL = TIOCNXCL;
+  unsigned IOCTL_TIOCOUTQ = TIOCOUTQ;
+  unsigned IOCTL_TIOCPKT = TIOCPKT;
+  unsigned IOCTL_TIOCSCTTY = TIOCSCTTY;
+  unsigned IOCTL_TIOCSETD = TIOCSETD;
+  unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
+  unsigned IOCTL_TIOCSTI = TIOCSTI;
+  unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
+  unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
+  unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
+  unsigned IOCTL_MTIOCGET = MTIOCGET;
+  unsigned IOCTL_MTIOCTOP = MTIOCTOP;
+  unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
+  unsigned IOCTL_SNDCTL_DSP_GETFMTS = SNDCTL_DSP_GETFMTS;
+  unsigned IOCTL_SNDCTL_DSP_NONBLOCK = SNDCTL_DSP_NONBLOCK;
+  unsigned IOCTL_SNDCTL_DSP_POST = SNDCTL_DSP_POST;
+  unsigned IOCTL_SNDCTL_DSP_RESET = SNDCTL_DSP_RESET;
+  unsigned IOCTL_SNDCTL_DSP_SETFMT = SNDCTL_DSP_SETFMT;
+  unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT = SNDCTL_DSP_SETFRAGMENT;
+  unsigned IOCTL_SNDCTL_DSP_SPEED = SNDCTL_DSP_SPEED;
+  unsigned IOCTL_SNDCTL_DSP_STEREO = SNDCTL_DSP_STEREO;
+  unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE = SNDCTL_DSP_SUBDIVIDE;
+  unsigned IOCTL_SNDCTL_DSP_SYNC = SNDCTL_DSP_SYNC;
+  unsigned IOCTL_SNDCTL_FM_4OP_ENABLE = SNDCTL_FM_4OP_ENABLE;
+  unsigned IOCTL_SNDCTL_FM_LOAD_INSTR = SNDCTL_FM_LOAD_INSTR;
+  unsigned IOCTL_SNDCTL_MIDI_INFO = SNDCTL_MIDI_INFO;
+  unsigned IOCTL_SNDCTL_MIDI_PRETIME = SNDCTL_MIDI_PRETIME;
+  unsigned IOCTL_SNDCTL_SEQ_CTRLRATE = SNDCTL_SEQ_CTRLRATE;
+  unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT = SNDCTL_SEQ_GETINCOUNT;
+  unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT = SNDCTL_SEQ_GETOUTCOUNT;
+  unsigned IOCTL_SNDCTL_SEQ_NRMIDIS = SNDCTL_SEQ_NRMIDIS;
+  unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS = SNDCTL_SEQ_NRSYNTHS;
+  unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND = SNDCTL_SEQ_OUTOFBAND;
+  unsigned IOCTL_SNDCTL_SEQ_PANIC = SNDCTL_SEQ_PANIC;
+  unsigned IOCTL_SNDCTL_SEQ_PERCMODE = SNDCTL_SEQ_PERCMODE;
+  unsigned IOCTL_SNDCTL_SEQ_RESET = SNDCTL_SEQ_RESET;
+  unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES = SNDCTL_SEQ_RESETSAMPLES;
+  unsigned IOCTL_SNDCTL_SEQ_SYNC = SNDCTL_SEQ_SYNC;
+  unsigned IOCTL_SNDCTL_SEQ_TESTMIDI = SNDCTL_SEQ_TESTMIDI;
+  unsigned IOCTL_SNDCTL_SEQ_THRESHOLD = SNDCTL_SEQ_THRESHOLD;
+  unsigned IOCTL_SNDCTL_SYNTH_INFO = SNDCTL_SYNTH_INFO;
+  unsigned IOCTL_SNDCTL_SYNTH_MEMAVL = SNDCTL_SYNTH_MEMAVL;
+  unsigned IOCTL_SNDCTL_TMR_CONTINUE = SNDCTL_TMR_CONTINUE;
+  unsigned IOCTL_SNDCTL_TMR_METRONOME = SNDCTL_TMR_METRONOME;
+  unsigned IOCTL_SNDCTL_TMR_SELECT = SNDCTL_TMR_SELECT;
+  unsigned IOCTL_SNDCTL_TMR_SOURCE = SNDCTL_TMR_SOURCE;
+  unsigned IOCTL_SNDCTL_TMR_START = SNDCTL_TMR_START;
+  unsigned IOCTL_SNDCTL_TMR_STOP = SNDCTL_TMR_STOP;
+  unsigned IOCTL_SNDCTL_TMR_TEMPO = SNDCTL_TMR_TEMPO;
+  unsigned IOCTL_SNDCTL_TMR_TIMEBASE = SNDCTL_TMR_TIMEBASE;
+  unsigned IOCTL_SOUND_MIXER_READ_ALTPCM = SOUND_MIXER_READ_ALTPCM;
+  unsigned IOCTL_SOUND_MIXER_READ_BASS = SOUND_MIXER_READ_BASS;
+  unsigned IOCTL_SOUND_MIXER_READ_CAPS = SOUND_MIXER_READ_CAPS;
+  unsigned IOCTL_SOUND_MIXER_READ_CD = SOUND_MIXER_READ_CD;
+  unsigned IOCTL_SOUND_MIXER_READ_DEVMASK = SOUND_MIXER_READ_DEVMASK;
+  unsigned IOCTL_SOUND_MIXER_READ_ENHANCE = SOUND_MIXER_READ_ENHANCE;
+  unsigned IOCTL_SOUND_MIXER_READ_IGAIN = SOUND_MIXER_READ_IGAIN;
+  unsigned IOCTL_SOUND_MIXER_READ_IMIX = SOUND_MIXER_READ_IMIX;
+  unsigned IOCTL_SOUND_MIXER_READ_LINE = SOUND_MIXER_READ_LINE;
+  unsigned IOCTL_SOUND_MIXER_READ_LINE1 = SOUND_MIXER_READ_LINE1;
+  unsigned IOCTL_SOUND_MIXER_READ_LINE2 = SOUND_MIXER_READ_LINE2;
+  unsigned IOCTL_SOUND_MIXER_READ_LINE3 = SOUND_MIXER_READ_LINE3;
+  unsigned IOCTL_SOUND_MIXER_READ_LOUD = SOUND_MIXER_READ_LOUD;
+  unsigned IOCTL_SOUND_MIXER_READ_MIC = SOUND_MIXER_READ_MIC;
+  unsigned IOCTL_SOUND_MIXER_READ_MUTE = SOUND_MIXER_READ_MUTE;
+  unsigned IOCTL_SOUND_MIXER_READ_OGAIN = SOUND_MIXER_READ_OGAIN;
+  unsigned IOCTL_SOUND_MIXER_READ_PCM = SOUND_MIXER_READ_PCM;
+  unsigned IOCTL_SOUND_MIXER_READ_RECLEV = SOUND_MIXER_READ_RECLEV;
+  unsigned IOCTL_SOUND_MIXER_READ_RECMASK = SOUND_MIXER_READ_RECMASK;
+  unsigned IOCTL_SOUND_MIXER_READ_RECSRC = SOUND_MIXER_READ_RECSRC;
+  unsigned IOCTL_SOUND_MIXER_READ_SPEAKER = SOUND_MIXER_READ_SPEAKER;
+  unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS = SOUND_MIXER_READ_STEREODEVS;
+  unsigned IOCTL_SOUND_MIXER_READ_SYNTH = SOUND_MIXER_READ_SYNTH;
+  unsigned IOCTL_SOUND_MIXER_READ_TREBLE = SOUND_MIXER_READ_TREBLE;
+  unsigned IOCTL_SOUND_MIXER_READ_VOLUME = SOUND_MIXER_READ_VOLUME;
+  unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM = SOUND_MIXER_WRITE_ALTPCM;
+  unsigned IOCTL_SOUND_MIXER_WRITE_BASS = SOUND_MIXER_WRITE_BASS;
+  unsigned IOCTL_SOUND_MIXER_WRITE_CD = SOUND_MIXER_WRITE_CD;
+  unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE = SOUND_MIXER_WRITE_ENHANCE;
+  unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN = SOUND_MIXER_WRITE_IGAIN;
+  unsigned IOCTL_SOUND_MIXER_WRITE_IMIX = SOUND_MIXER_WRITE_IMIX;
+  unsigned IOCTL_SOUND_MIXER_WRITE_LINE = SOUND_MIXER_WRITE_LINE;
+  unsigned IOCTL_SOUND_MIXER_WRITE_LINE1 = SOUND_MIXER_WRITE_LINE1;
+  unsigned IOCTL_SOUND_MIXER_WRITE_LINE2 = SOUND_MIXER_WRITE_LINE2;
+  unsigned IOCTL_SOUND_MIXER_WRITE_LINE3 = SOUND_MIXER_WRITE_LINE3;
+  unsigned IOCTL_SOUND_MIXER_WRITE_LOUD = SOUND_MIXER_WRITE_LOUD;
+  unsigned IOCTL_SOUND_MIXER_WRITE_MIC = SOUND_MIXER_WRITE_MIC;
+  unsigned IOCTL_SOUND_MIXER_WRITE_MUTE = SOUND_MIXER_WRITE_MUTE;
+  unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN = SOUND_MIXER_WRITE_OGAIN;
+  unsigned IOCTL_SOUND_MIXER_WRITE_PCM = SOUND_MIXER_WRITE_PCM;
+  unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV = SOUND_MIXER_WRITE_RECLEV;
+  unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC = SOUND_MIXER_WRITE_RECSRC;
+  unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER = SOUND_MIXER_WRITE_SPEAKER;
+  unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH = SOUND_MIXER_WRITE_SYNTH;
+  unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE = SOUND_MIXER_WRITE_TREBLE;
+  unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME = SOUND_MIXER_WRITE_VOLUME;
+  unsigned IOCTL_VT_ACTIVATE = VT_ACTIVATE;
+  unsigned IOCTL_VT_GETMODE = VT_GETMODE;
+  unsigned IOCTL_VT_OPENQRY = VT_OPENQRY;
+  unsigned IOCTL_VT_RELDISP = VT_RELDISP;
+  unsigned IOCTL_VT_SETMODE = VT_SETMODE;
+  unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
+  unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
+  unsigned IOCTL_KDDISABIO = KDDISABIO;
+  unsigned IOCTL_KDENABIO = KDENABIO;
+  unsigned IOCTL_KDGETLED = KDGETLED;
+  unsigned IOCTL_KDGETMODE = KDGETMODE;
+  unsigned IOCTL_KDGKBMODE = KDGKBMODE;
+  unsigned IOCTL_KDGKBTYPE = KDGKBTYPE;
+  unsigned IOCTL_KDMKTONE = KDMKTONE;
+  unsigned IOCTL_KDSETLED = KDSETLED;
+  unsigned IOCTL_KDSETMODE = KDSETMODE;
+  unsigned IOCTL_KDSKBMODE = KDSKBMODE;
+  unsigned IOCTL_KIOCSOUND = KIOCSOUND;
+  unsigned IOCTL_PIO_SCRNMAP = PIO_SCRNMAP;
+  unsigned IOCTL_SNDCTL_DSP_GETISPACE = SNDCTL_DSP_GETISPACE;
+
+  const int si_SEGV_MAPERR = SEGV_MAPERR;
+  const int si_SEGV_ACCERR = SEGV_ACCERR;
+} // namespace __sanitizer
+
+using namespace __sanitizer;
+
+COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t));
+
+COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned));
+CHECK_TYPE_SIZE(pthread_key_t);
+
+// There are more undocumented fields in dl_phdr_info that we are not interested
+// in.
+COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info));
+CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr);
+CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name);
+CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr);
+CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum);
+
+CHECK_TYPE_SIZE(glob_t);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_offs);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_flags);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_stat);
+
+CHECK_TYPE_SIZE(addrinfo);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_family);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr);
+
+CHECK_TYPE_SIZE(hostent);
+CHECK_SIZE_AND_OFFSET(hostent, h_name);
+CHECK_SIZE_AND_OFFSET(hostent, h_aliases);
+CHECK_SIZE_AND_OFFSET(hostent, h_addrtype);
+CHECK_SIZE_AND_OFFSET(hostent, h_length);
+CHECK_SIZE_AND_OFFSET(hostent, h_addr_list);
+
+CHECK_TYPE_SIZE(iovec);
+CHECK_SIZE_AND_OFFSET(iovec, iov_base);
+CHECK_SIZE_AND_OFFSET(iovec, iov_len);
+
+CHECK_TYPE_SIZE(msghdr);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_name);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_iov);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_control);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_flags);
+
+CHECK_TYPE_SIZE(cmsghdr);
+CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len);
+CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level);
+CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type);
+
+COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent));
+CHECK_SIZE_AND_OFFSET(dirent, d_ino);
+CHECK_SIZE_AND_OFFSET(dirent, d_reclen);
+
+CHECK_TYPE_SIZE(ifconf);
+CHECK_SIZE_AND_OFFSET(ifconf, ifc_len);
+CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu);
+
+CHECK_TYPE_SIZE(pollfd);
+CHECK_SIZE_AND_OFFSET(pollfd, fd);
+CHECK_SIZE_AND_OFFSET(pollfd, events);
+CHECK_SIZE_AND_OFFSET(pollfd, revents);
+
+CHECK_TYPE_SIZE(nfds_t);
+
+CHECK_TYPE_SIZE(sigset_t);
+
+COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction));
+// Can't write checks for sa_handler and sa_sigaction due to them being
+// preprocessor macros.
+CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask);
+
+CHECK_TYPE_SIZE(wordexp_t);
+CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc);
+CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv);
+CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs);
+
+CHECK_TYPE_SIZE(tm);
+CHECK_SIZE_AND_OFFSET(tm, tm_sec);
+CHECK_SIZE_AND_OFFSET(tm, tm_min);
+CHECK_SIZE_AND_OFFSET(tm, tm_hour);
+CHECK_SIZE_AND_OFFSET(tm, tm_mday);
+CHECK_SIZE_AND_OFFSET(tm, tm_mon);
+CHECK_SIZE_AND_OFFSET(tm, tm_year);
+CHECK_SIZE_AND_OFFSET(tm, tm_wday);
+CHECK_SIZE_AND_OFFSET(tm, tm_yday);
+CHECK_SIZE_AND_OFFSET(tm, tm_isdst);
+CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff);
+CHECK_SIZE_AND_OFFSET(tm, tm_zone);
+
+CHECK_TYPE_SIZE(ether_addr);
+
+CHECK_TYPE_SIZE(ipc_perm);
+CHECK_SIZE_AND_OFFSET(ipc_perm, key);
+CHECK_SIZE_AND_OFFSET(ipc_perm, seq);
+CHECK_SIZE_AND_OFFSET(ipc_perm, uid);
+CHECK_SIZE_AND_OFFSET(ipc_perm, gid);
+CHECK_SIZE_AND_OFFSET(ipc_perm, cuid);
+CHECK_SIZE_AND_OFFSET(ipc_perm, cgid);
+
+CHECK_TYPE_SIZE(shmid_ds);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch);
+
+CHECK_TYPE_SIZE(clock_t);
+
+CHECK_TYPE_SIZE(ifaddrs);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask);
+#undef ifa_dstaddr
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data);
+
+CHECK_TYPE_SIZE(timeb);
+CHECK_SIZE_AND_OFFSET(timeb, time);
+CHECK_SIZE_AND_OFFSET(timeb, millitm);
+CHECK_SIZE_AND_OFFSET(timeb, timezone);
+CHECK_SIZE_AND_OFFSET(timeb, dstflag);
+
+CHECK_TYPE_SIZE(passwd);
+CHECK_SIZE_AND_OFFSET(passwd, pw_name);
+CHECK_SIZE_AND_OFFSET(passwd, pw_passwd);
+CHECK_SIZE_AND_OFFSET(passwd, pw_uid);
+CHECK_SIZE_AND_OFFSET(passwd, pw_gid);
+CHECK_SIZE_AND_OFFSET(passwd, pw_dir);
+CHECK_SIZE_AND_OFFSET(passwd, pw_shell);
+
+CHECK_SIZE_AND_OFFSET(passwd, pw_gecos);
+
+CHECK_TYPE_SIZE(group);
+CHECK_SIZE_AND_OFFSET(group, gr_name);
+CHECK_SIZE_AND_OFFSET(group, gr_passwd);
+CHECK_SIZE_AND_OFFSET(group, gr_gid);
+CHECK_SIZE_AND_OFFSET(group, gr_mem);
+
+#if HAVE_RPC_XDR_H || HAVE_TIRPC_RPC_XDR_H
+CHECK_TYPE_SIZE(XDR);
+CHECK_SIZE_AND_OFFSET(XDR, x_op);
+CHECK_SIZE_AND_OFFSET(XDR, x_ops);
+CHECK_SIZE_AND_OFFSET(XDR, x_public);
+CHECK_SIZE_AND_OFFSET(XDR, x_private);
+CHECK_SIZE_AND_OFFSET(XDR, x_base);
+CHECK_SIZE_AND_OFFSET(XDR, x_handy);
+COMPILER_CHECK(__sanitizer_XDR_ENCODE == XDR_ENCODE);
+COMPILER_CHECK(__sanitizer_XDR_DECODE == XDR_DECODE);
+COMPILER_CHECK(__sanitizer_XDR_FREE == XDR_FREE);
+#endif
+
+CHECK_TYPE_SIZE(sem_t);
+
+COMPILER_CHECK(sizeof(__sanitizer_cap_rights_t) >= sizeof(cap_rights_t));
+#endif  // SANITIZER_FREEBSD
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h b/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h
new file mode 100644
index 0000000..90329ac
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_platform_limits_freebsd.h
@@ -0,0 +1,648 @@
+//===-- sanitizer_platform_limits_freebsd.h -------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer common code.
+//
+// Sizes and layouts of platform-specific FreeBSD data structures.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_PLATFORM_LIMITS_FREEBSD_H
+#define SANITIZER_PLATFORM_LIMITS_FREEBSD_H
+
+#if SANITIZER_FREEBSD
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform.h"
+
+#include "sanitizer_platform_limits_posix.h"
+
+// FreeBSD's dlopen() returns a pointer to an Obj_Entry structure that
+// incorporates the map structure.
+# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
+    ((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 560)))
+// Get sys/_types.h, because that tells us whether 64-bit inodes are
+// used in struct dirent below.
+#include <sys/_types.h>
+
+namespace __sanitizer {
+  extern unsigned struct_utsname_sz;
+  extern unsigned struct_stat_sz;
+#if defined(__powerpc64__)
+  const unsigned struct___old_kernel_stat_sz = 0;
+#else
+  const unsigned struct___old_kernel_stat_sz = 32;
+#endif
+  extern unsigned struct_rusage_sz;
+  extern unsigned siginfo_t_sz;
+  extern unsigned struct_itimerval_sz;
+  extern unsigned pthread_t_sz;
+  extern unsigned pthread_mutex_t_sz;
+  extern unsigned pthread_cond_t_sz;
+  extern unsigned pid_t_sz;
+  extern unsigned timeval_sz;
+  extern unsigned uid_t_sz;
+  extern unsigned gid_t_sz;
+  extern unsigned fpos_t_sz;
+  extern unsigned mbstate_t_sz;
+  extern unsigned struct_timezone_sz;
+  extern unsigned struct_tms_sz;
+  extern unsigned struct_itimerspec_sz;
+  extern unsigned struct_sigevent_sz;
+  extern unsigned struct_sched_param_sz;
+  extern unsigned struct_statfs64_sz;
+  extern unsigned struct_statfs_sz;
+  extern unsigned struct_sockaddr_sz;
+  extern unsigned ucontext_t_sz;
+  extern unsigned struct_rlimit_sz;
+  extern unsigned struct_utimbuf_sz;
+  extern unsigned struct_timespec_sz;
+
+  struct __sanitizer_iocb {
+    u64   aio_data;
+    u32   aio_key_or_aio_reserved1; // Simply crazy.
+    u32   aio_reserved1_or_aio_key; // Luckily, we don't need these.
+    u16   aio_lio_opcode;
+    s16   aio_reqprio;
+    u32   aio_fildes;
+    u64   aio_buf;
+    u64   aio_nbytes;
+    s64   aio_offset;
+    u64   aio_reserved2;
+    u64   aio_reserved3;
+  };
+
+  struct __sanitizer_io_event {
+    u64 data;
+    u64 obj;
+    u64 res;
+    u64 res2;
+  };
+
+  const unsigned iocb_cmd_pread = 0;
+  const unsigned iocb_cmd_pwrite = 1;
+  const unsigned iocb_cmd_preadv = 7;
+  const unsigned iocb_cmd_pwritev = 8;
+
+  struct __sanitizer___sysctl_args {
+    int *name;
+    int nlen;
+    void *oldval;
+    uptr *oldlenp;
+    void *newval;
+    uptr newlen;
+    unsigned long ___unused[4];
+  };
+
+  struct __sanitizer_ipc_perm {
+    unsigned int cuid;
+    unsigned int cgid;
+    unsigned int uid;
+    unsigned int gid;
+    unsigned short mode;
+    unsigned short seq;
+    long key;
+  };
+
+  struct __sanitizer_shmid_ds {
+    __sanitizer_ipc_perm shm_perm;
+    unsigned long shm_segsz;
+    unsigned int shm_lpid;
+    unsigned int shm_cpid;
+    int shm_nattch;
+    unsigned long shm_atime;
+    unsigned long shm_dtime;
+    unsigned long shm_ctime;
+  };
+
+  extern unsigned struct_msqid_ds_sz;
+  extern unsigned struct_mq_attr_sz;
+  extern unsigned struct_timeb_sz;
+  extern unsigned struct_statvfs_sz;
+
+  struct __sanitizer_iovec {
+    void *iov_base;
+    uptr iov_len;
+  };
+
+  struct __sanitizer_ifaddrs {
+    struct __sanitizer_ifaddrs *ifa_next;
+    char *ifa_name;
+    unsigned int ifa_flags;
+    void *ifa_addr;    // (struct sockaddr *)
+    void *ifa_netmask; // (struct sockaddr *)
+# undef ifa_dstaddr
+    void *ifa_dstaddr; // (struct sockaddr *)
+    void *ifa_data;
+  };
+
+  typedef unsigned __sanitizer_pthread_key_t;
+
+  struct __sanitizer_passwd {
+    char *pw_name;
+    char *pw_passwd;
+    int pw_uid;
+    int pw_gid;
+    long pw_change;
+    char *pw_class;
+    char *pw_gecos;
+    char *pw_dir;
+    char *pw_shell;
+    long pw_expire;
+    int pw_fields;
+  };
+
+  struct __sanitizer_group {
+    char *gr_name;
+    char *gr_passwd;
+    int gr_gid;
+    char **gr_mem;
+  };
+
+#if defined(__LP64___)
+  typedef long long __sanitizer_time_t;
+#else
+  typedef long __sanitizer_time_t;
+#endif
+
+  typedef long __sanitizer_suseconds_t;
+
+  struct __sanitizer_timeval {
+    __sanitizer_time_t tv_sec;
+    __sanitizer_suseconds_t tv_usec;
+  };
+
+  struct __sanitizer_itimerval {
+    struct __sanitizer_timeval it_interval;
+    struct __sanitizer_timeval it_value;
+  };
+
+  struct __sanitizer_timeb {
+    __sanitizer_time_t time;
+    unsigned short millitm;
+    short timezone;
+    short dstflag;
+  };
+
+  struct __sanitizer_ether_addr {
+    u8 octet[6];
+  };
+
+  struct __sanitizer_tm {
+    int tm_sec;
+    int tm_min;
+    int tm_hour;
+    int tm_mday;
+    int tm_mon;
+    int tm_year;
+    int tm_wday;
+    int tm_yday;
+    int tm_isdst;
+    long int tm_gmtoff;
+    const char *tm_zone;
+  };
+
+  struct __sanitizer_msghdr {
+    void *msg_name;
+    unsigned msg_namelen;
+    struct __sanitizer_iovec *msg_iov;
+    unsigned msg_iovlen;
+    void *msg_control;
+    unsigned msg_controllen;
+    int msg_flags;
+  };
+
+  struct __sanitizer_cmsghdr {
+    unsigned cmsg_len;
+    int cmsg_level;
+    int cmsg_type;
+  };
+
+  struct __sanitizer_dirent {
+#if defined(__INO64)
+    unsigned long long d_fileno;
+    unsigned long long d_off;
+#else
+    unsigned int d_fileno;
+#endif
+    unsigned short d_reclen;
+    // more fields that we don't care about
+  };
+
+// 'clock_t' is 32 bits wide on x64 FreeBSD
+  typedef int __sanitizer_clock_t;
+  typedef int __sanitizer_clockid_t;
+
+#if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__)\
+                   || defined(__mips__)
+  typedef unsigned __sanitizer___kernel_uid_t;
+  typedef unsigned __sanitizer___kernel_gid_t;
+#else
+  typedef unsigned short __sanitizer___kernel_uid_t;
+  typedef unsigned short __sanitizer___kernel_gid_t;
+#endif
+  typedef long long __sanitizer___kernel_off_t;
+
+#if defined(__powerpc__) || defined(__mips__)
+  typedef unsigned int __sanitizer___kernel_old_uid_t;
+  typedef unsigned int __sanitizer___kernel_old_gid_t;
+#else
+  typedef unsigned short __sanitizer___kernel_old_uid_t;
+  typedef unsigned short __sanitizer___kernel_old_gid_t;
+#endif
+
+  typedef long long __sanitizer___kernel_loff_t;
+  typedef struct {
+    unsigned long fds_bits[1024 / (8 * sizeof(long))];
+  } __sanitizer___kernel_fd_set;
+
+  // This thing depends on the platform. We are only interested in the upper
+  // limit. Verified with a compiler assert in .cc.
+  const int pthread_attr_t_max_sz = 128;
+  union __sanitizer_pthread_attr_t {
+    char size[pthread_attr_t_max_sz]; // NOLINT
+    void *align;
+  };
+
+  const unsigned old_sigset_t_sz = sizeof(unsigned long);
+
+  struct __sanitizer_sigset_t {
+     // uint32_t * 4
+     unsigned int __bits[4];
+  };
+
+  typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t;
+
+  struct __sanitizer_siginfo {
+    // The size is determined by looking at sizeof of real siginfo_t on linux.
+    u64 opaque[128 / sizeof(u64)];
+  };
+
+  using __sanitizer_sighandler_ptr = void (*)(int sig);
+  using __sanitizer_sigactionhandler_ptr =
+      void (*)(int sig, __sanitizer_siginfo *siginfo, void *uctx);
+
+  struct __sanitizer_sigaction {
+    union {
+      __sanitizer_sigactionhandler_ptr sigaction;
+      __sanitizer_sighandler_ptr handler;
+    };
+    int sa_flags;
+    __sanitizer_sigset_t sa_mask;
+  };
+
+  struct __sanitizer_sem_t {
+    u32 data[4];
+  };
+
+  extern const uptr sig_ign;
+  extern const uptr sig_dfl;
+  extern const uptr sig_err;
+  extern const uptr sa_siginfo;
+
+  extern int af_inet;
+  extern int af_inet6;
+  uptr __sanitizer_in_addr_sz(int af);
+
+  struct __sanitizer_dl_phdr_info {
+    uptr dlpi_addr;
+    const char *dlpi_name;
+    const void *dlpi_phdr;
+    short dlpi_phnum;
+  };
+
+  extern unsigned struct_ElfW_Phdr_sz;
+
+  struct __sanitizer_addrinfo {
+    int ai_flags;
+    int ai_family;
+    int ai_socktype;
+    int ai_protocol;
+    unsigned ai_addrlen;
+    char *ai_canonname;
+    void *ai_addr;
+    struct __sanitizer_addrinfo *ai_next;
+  };
+
+  struct __sanitizer_hostent {
+    char *h_name;
+    char **h_aliases;
+    int h_addrtype;
+    int h_length;
+    char **h_addr_list;
+  };
+
+  struct __sanitizer_pollfd {
+    int fd;
+    short events;
+    short revents;
+  };
+
+  typedef unsigned __sanitizer_nfds_t;
+
+  struct __sanitizer_glob_t {
+    uptr gl_pathc;
+    uptr gl_matchc;
+    uptr gl_offs;
+    int gl_flags;
+    char **gl_pathv;
+    int (*gl_errfunc)(const char*, int);
+    void (*gl_closedir)(void *dirp);
+    struct dirent *(*gl_readdir)(void *dirp);
+    void *(*gl_opendir)(const char*);
+    int (*gl_lstat)(const char*, void* /* struct stat* */);
+    int (*gl_stat)(const char*, void* /* struct stat* */);
+  };
+
+  extern int glob_nomatch;
+  extern int glob_altdirfunc;
+
+  extern unsigned path_max;
+
+  struct __sanitizer_wordexp_t {
+    uptr we_wordc;
+    char **we_wordv;
+    uptr we_offs;
+    char *we_strings;
+    uptr we_nbytes;
+  };
+
+  typedef void __sanitizer_FILE;
+
+  extern unsigned struct_shminfo_sz;
+  extern unsigned struct_shm_info_sz;
+  extern int shmctl_ipc_stat;
+  extern int shmctl_ipc_info;
+  extern int shmctl_shm_info;
+  extern int shmctl_shm_stat;
+
+  extern unsigned struct_utmpx_sz;
+
+  extern int map_fixed;
+
+  // ioctl arguments
+  struct __sanitizer_ifconf {
+    int ifc_len;
+    union {
+      void *ifcu_req;
+    } ifc_ifcu;
+  };
+
+#define IOC_NRBITS 8
+#define IOC_TYPEBITS 8
+#if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__)
+#define IOC_SIZEBITS 13
+#define IOC_DIRBITS 3
+#define IOC_NONE 1U
+#define IOC_WRITE 4U
+#define IOC_READ 2U
+#else
+#define IOC_SIZEBITS 14
+#define IOC_DIRBITS 2
+#define IOC_NONE 0U
+#define IOC_WRITE 1U
+#define IOC_READ 2U
+#endif
+#define IOC_NRMASK ((1 << IOC_NRBITS) - 1)
+#define IOC_TYPEMASK ((1 << IOC_TYPEBITS) - 1)
+#define IOC_SIZEMASK ((1 << IOC_SIZEBITS) - 1)
+#if defined(IOC_DIRMASK)
+#undef IOC_DIRMASK
+#endif
+#define IOC_DIRMASK ((1 << IOC_DIRBITS) - 1)
+#define IOC_NRSHIFT 0
+#define IOC_TYPESHIFT (IOC_NRSHIFT + IOC_NRBITS)
+#define IOC_SIZESHIFT (IOC_TYPESHIFT + IOC_TYPEBITS)
+#define IOC_DIRSHIFT (IOC_SIZESHIFT + IOC_SIZEBITS)
+#define EVIOC_EV_MAX 0x1f
+#define EVIOC_ABS_MAX 0x3f
+
+#define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK)
+#define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK)
+#define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK)
+#define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK)
+
+  extern unsigned struct_ifreq_sz;
+  extern unsigned struct_termios_sz;
+  extern unsigned struct_winsize_sz;
+
+  extern unsigned struct_copr_buffer_sz;
+  extern unsigned struct_copr_debug_buf_sz;
+  extern unsigned struct_copr_msg_sz;
+  extern unsigned struct_midi_info_sz;
+  extern unsigned struct_mtget_sz;
+  extern unsigned struct_mtop_sz;
+  extern unsigned struct_rtentry_sz;
+  extern unsigned struct_sbi_instrument_sz;
+  extern unsigned struct_seq_event_rec_sz;
+  extern unsigned struct_synth_info_sz;
+  extern unsigned struct_vt_mode_sz;
+
+  extern const unsigned long __sanitizer_bufsiz;
+  extern unsigned struct_audio_buf_info_sz;
+  extern unsigned struct_ppp_stats_sz;
+  extern unsigned struct_sioc_sg_req_sz;
+  extern unsigned struct_sioc_vif_req_sz;
+
+  // ioctl request identifiers
+
+  // A special value to mark ioctls that are not present on the target platform,
+  // when it can not be determined without including any system headers.
+  extern const unsigned IOCTL_NOT_PRESENT;
+
+  extern unsigned IOCTL_FIOASYNC;
+  extern unsigned IOCTL_FIOCLEX;
+  extern unsigned IOCTL_FIOGETOWN;
+  extern unsigned IOCTL_FIONBIO;
+  extern unsigned IOCTL_FIONCLEX;
+  extern unsigned IOCTL_FIOSETOWN;
+  extern unsigned IOCTL_SIOCADDMULTI;
+  extern unsigned IOCTL_SIOCATMARK;
+  extern unsigned IOCTL_SIOCDELMULTI;
+  extern unsigned IOCTL_SIOCGIFADDR;
+  extern unsigned IOCTL_SIOCGIFBRDADDR;
+  extern unsigned IOCTL_SIOCGIFCONF;
+  extern unsigned IOCTL_SIOCGIFDSTADDR;
+  extern unsigned IOCTL_SIOCGIFFLAGS;
+  extern unsigned IOCTL_SIOCGIFMETRIC;
+  extern unsigned IOCTL_SIOCGIFMTU;
+  extern unsigned IOCTL_SIOCGIFNETMASK;
+  extern unsigned IOCTL_SIOCGPGRP;
+  extern unsigned IOCTL_SIOCSIFADDR;
+  extern unsigned IOCTL_SIOCSIFBRDADDR;
+  extern unsigned IOCTL_SIOCSIFDSTADDR;
+  extern unsigned IOCTL_SIOCSIFFLAGS;
+  extern unsigned IOCTL_SIOCSIFMETRIC;
+  extern unsigned IOCTL_SIOCSIFMTU;
+  extern unsigned IOCTL_SIOCSIFNETMASK;
+  extern unsigned IOCTL_SIOCSPGRP;
+  extern unsigned IOCTL_TIOCCONS;
+  extern unsigned IOCTL_TIOCEXCL;
+  extern unsigned IOCTL_TIOCGETD;
+  extern unsigned IOCTL_TIOCGPGRP;
+  extern unsigned IOCTL_TIOCGWINSZ;
+  extern unsigned IOCTL_TIOCMBIC;
+  extern unsigned IOCTL_TIOCMBIS;
+  extern unsigned IOCTL_TIOCMGET;
+  extern unsigned IOCTL_TIOCMSET;
+  extern unsigned IOCTL_TIOCNOTTY;
+  extern unsigned IOCTL_TIOCNXCL;
+  extern unsigned IOCTL_TIOCOUTQ;
+  extern unsigned IOCTL_TIOCPKT;
+  extern unsigned IOCTL_TIOCSCTTY;
+  extern unsigned IOCTL_TIOCSETD;
+  extern unsigned IOCTL_TIOCSPGRP;
+  extern unsigned IOCTL_TIOCSTI;
+  extern unsigned IOCTL_TIOCSWINSZ;
+  extern unsigned IOCTL_SIOCGETSGCNT;
+  extern unsigned IOCTL_SIOCGETVIFCNT;
+  extern unsigned IOCTL_MTIOCGET;
+  extern unsigned IOCTL_MTIOCTOP;
+  extern unsigned IOCTL_SIOCADDRT;
+  extern unsigned IOCTL_SIOCDELRT;
+  extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE;
+  extern unsigned IOCTL_SNDCTL_DSP_GETFMTS;
+  extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK;
+  extern unsigned IOCTL_SNDCTL_DSP_POST;
+  extern unsigned IOCTL_SNDCTL_DSP_RESET;
+  extern unsigned IOCTL_SNDCTL_DSP_SETFMT;
+  extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT;
+  extern unsigned IOCTL_SNDCTL_DSP_SPEED;
+  extern unsigned IOCTL_SNDCTL_DSP_STEREO;
+  extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE;
+  extern unsigned IOCTL_SNDCTL_DSP_SYNC;
+  extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE;
+  extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR;
+  extern unsigned IOCTL_SNDCTL_MIDI_INFO;
+  extern unsigned IOCTL_SNDCTL_MIDI_PRETIME;
+  extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE;
+  extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT;
+  extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT;
+  extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS;
+  extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS;
+  extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND;
+  extern unsigned IOCTL_SNDCTL_SEQ_PANIC;
+  extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE;
+  extern unsigned IOCTL_SNDCTL_SEQ_RESET;
+  extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES;
+  extern unsigned IOCTL_SNDCTL_SEQ_SYNC;
+  extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI;
+  extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD;
+  extern unsigned IOCTL_SNDCTL_SYNTH_INFO;
+  extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL;
+  extern unsigned IOCTL_SNDCTL_TMR_CONTINUE;
+  extern unsigned IOCTL_SNDCTL_TMR_METRONOME;
+  extern unsigned IOCTL_SNDCTL_TMR_SELECT;
+  extern unsigned IOCTL_SNDCTL_TMR_SOURCE;
+  extern unsigned IOCTL_SNDCTL_TMR_START;
+  extern unsigned IOCTL_SNDCTL_TMR_STOP;
+  extern unsigned IOCTL_SNDCTL_TMR_TEMPO;
+  extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE;
+  extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM;
+  extern unsigned IOCTL_SOUND_MIXER_READ_BASS;
+  extern unsigned IOCTL_SOUND_MIXER_READ_CAPS;
+  extern unsigned IOCTL_SOUND_MIXER_READ_CD;
+  extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK;
+  extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE;
+  extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN;
+  extern unsigned IOCTL_SOUND_MIXER_READ_IMIX;
+  extern unsigned IOCTL_SOUND_MIXER_READ_LINE1;
+  extern unsigned IOCTL_SOUND_MIXER_READ_LINE2;
+  extern unsigned IOCTL_SOUND_MIXER_READ_LINE3;
+  extern unsigned IOCTL_SOUND_MIXER_READ_LINE;
+  extern unsigned IOCTL_SOUND_MIXER_READ_LOUD;
+  extern unsigned IOCTL_SOUND_MIXER_READ_MIC;
+  extern unsigned IOCTL_SOUND_MIXER_READ_MUTE;
+  extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN;
+  extern unsigned IOCTL_SOUND_MIXER_READ_PCM;
+  extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV;
+  extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK;
+  extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC;
+  extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER;
+  extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS;
+  extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH;
+  extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE;
+  extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_CD;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE;
+  extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME;
+  extern unsigned IOCTL_SOUND_PCM_READ_BITS;
+  extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS;
+  extern unsigned IOCTL_SOUND_PCM_READ_FILTER;
+  extern unsigned IOCTL_SOUND_PCM_READ_RATE;
+  extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS;
+  extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER;
+  extern unsigned IOCTL_VT_ACTIVATE;
+  extern unsigned IOCTL_VT_GETMODE;
+  extern unsigned IOCTL_VT_OPENQRY;
+  extern unsigned IOCTL_VT_RELDISP;
+  extern unsigned IOCTL_VT_SETMODE;
+  extern unsigned IOCTL_VT_WAITACTIVE;
+  extern unsigned IOCTL_GIO_SCRNMAP;
+  extern unsigned IOCTL_KDDISABIO;
+  extern unsigned IOCTL_KDENABIO;
+  extern unsigned IOCTL_KDGETLED;
+  extern unsigned IOCTL_KDGETMODE;
+  extern unsigned IOCTL_KDGKBMODE;
+  extern unsigned IOCTL_KDGKBTYPE;
+  extern unsigned IOCTL_KDMKTONE;
+  extern unsigned IOCTL_KDSETLED;
+  extern unsigned IOCTL_KDSETMODE;
+  extern unsigned IOCTL_KDSKBMODE;
+
+  extern const int si_SEGV_MAPERR;
+  extern const int si_SEGV_ACCERR;
+
+  struct __sanitizer_cap_rights {
+    u64 cr_rights[2];
+  };
+
+  typedef struct __sanitizer_cap_rights __sanitizer_cap_rights_t;
+  extern unsigned struct_cap_rights_sz;
+} // namespace __sanitizer
+
+#define CHECK_TYPE_SIZE(TYPE) \
+  COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE))
+
+#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER)                       \
+  COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *) NULL)->MEMBER) == \
+                 sizeof(((CLASS *) NULL)->MEMBER));                \
+  COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) ==          \
+                 offsetof(CLASS, MEMBER))
+
+// For sigaction, which is a function and struct at the same time,
+// and thus requires explicit "struct" in sizeof() expression.
+#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER)                       \
+  COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *) NULL)->MEMBER) == \
+                 sizeof(((struct CLASS *) NULL)->MEMBER));                \
+  COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) ==          \
+                 offsetof(struct CLASS, MEMBER))
+
+#define SIGACTION_SYMNAME sigaction
+
+#endif
+
+#endif // SANITIZER_FREEBSD
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc
index 0f60e73..6633a36 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc
+++ b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc
@@ -253,6 +253,10 @@
 unsigned struct_timespec_sz = sizeof(struct timespec);
 unsigned struct_sembuf_sz = sizeof(struct sembuf);
 unsigned struct_kevent_sz = sizeof(struct kevent);
+unsigned struct_FTS_sz = sizeof(FTS);
+unsigned struct_FTSENT_sz = sizeof(FTSENT);
+unsigned struct_regex_sz = sizeof(regex_t);
+unsigned struct_regmatch_sz = sizeof(regmatch_t);
 unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
 unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
 unsigned struct_timex_sz = sizeof(struct timex);
@@ -266,6 +270,8 @@
 const uptr sig_err = (uptr)SIG_ERR;
 const uptr sa_siginfo = (uptr)SA_SIGINFO;
 
+const unsigned long __sanitizer_bufsiz = BUFSIZ;
+
 int ptrace_pt_io = PT_IO;
 int ptrace_pt_lwpinfo = PT_LWPINFO;
 int ptrace_pt_set_event_mask = PT_SET_EVENT_MASK;
@@ -2090,6 +2096,44 @@
 
 const int si_SEGV_MAPERR = SEGV_MAPERR;
 const int si_SEGV_ACCERR = SEGV_ACCERR;
+
+const int modctl_load = MODCTL_LOAD;
+const int modctl_unload = MODCTL_UNLOAD;
+const int modctl_stat = MODCTL_STAT;
+const int modctl_exists = MODCTL_EXISTS;
+
+const unsigned SHA1_CTX_sz = sizeof(SHA1_CTX);
+const unsigned SHA1_return_length = SHA1_DIGEST_STRING_LENGTH;
+
+const unsigned MD4_CTX_sz = sizeof(MD4_CTX);
+const unsigned MD4_return_length = MD4_DIGEST_STRING_LENGTH;
+
+const unsigned RMD160_CTX_sz = sizeof(RMD160_CTX);
+const unsigned RMD160_return_length = RMD160_DIGEST_STRING_LENGTH;
+
+const unsigned MD5_CTX_sz = sizeof(MD5_CTX);
+const unsigned MD5_return_length = MD5_DIGEST_STRING_LENGTH;
+
+const unsigned fpos_t_sz = sizeof(fpos_t);
+
+const unsigned MD2_CTX_sz = sizeof(MD2_CTX);
+const unsigned MD2_return_length = MD2_DIGEST_STRING_LENGTH;
+
+#define SHA2_CONST(LEN)                                                      \
+  const unsigned SHA##LEN##_CTX_sz = sizeof(SHA##LEN##_CTX);                 \
+  const unsigned SHA##LEN##_return_length = SHA##LEN##_DIGEST_STRING_LENGTH; \
+  const unsigned SHA##LEN##_block_length = SHA##LEN##_BLOCK_LENGTH;          \
+  const unsigned SHA##LEN##_digest_length = SHA##LEN##_DIGEST_LENGTH
+
+SHA2_CONST(224);
+SHA2_CONST(256);
+SHA2_CONST(384);
+SHA2_CONST(512);
+
+#undef SHA2_CONST
+
+const int unvis_valid = UNVIS_VALID;
+const int unvis_validpush = UNVIS_VALIDPUSH;
 }  // namespace __sanitizer
 
 using namespace __sanitizer;
@@ -2251,4 +2295,10 @@
 CHECK_SIZE_AND_OFFSET(group, gr_gid);
 CHECK_SIZE_AND_OFFSET(group, gr_mem);
 
+CHECK_TYPE_SIZE(modctl_load_t);
+CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_filename);
+CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_flags);
+CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_props);
+CHECK_SIZE_AND_OFFSET(modctl_load_t, ml_propslen);
+
 #endif  // SANITIZER_NETBSD
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h
index f6429cd..3958136 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h
+++ b/lib/sanitizer_common/sanitizer_platform_limits_netbsd.h
@@ -25,10 +25,10 @@
 
 #if defined(__x86_64__)
 #define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
-  _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 312)
+  _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 264)
 #elif defined(__i386__)
 #define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
-  _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 164)
+  _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 136)
 #endif
 
 namespace __sanitizer {
@@ -60,6 +60,27 @@
 extern unsigned struct_sembuf_sz;
 
 extern unsigned struct_kevent_sz;
+extern unsigned struct_FTS_sz;
+extern unsigned struct_FTSENT_sz;
+
+extern unsigned struct_regex_sz;
+extern unsigned struct_regmatch_sz;
+
+struct __sanitizer_regmatch {
+  OFF_T rm_so;
+  OFF_T rm_eo;
+};
+
+typedef struct __sanitizer_modctl_load {
+  const char *ml_filename;
+  int ml_flags;
+  const char *ml_props;
+  uptr ml_propslen;
+} __sanitizer_modctl_load_t;
+extern const int modctl_load;
+extern const int modctl_unload;
+extern const int modctl_stat;
+extern const int modctl_exists;
 
 union __sanitizer_sigval {
   int sival_int;
@@ -460,6 +481,8 @@
   char *ty_class;
 };
 
+extern const unsigned long __sanitizer_bufsiz;
+
 #define IOC_NRBITS 8
 #define IOC_TYPEBITS 8
 #define IOC_SIZEBITS 14
@@ -2200,6 +2223,74 @@
 
 extern const int si_SEGV_MAPERR;
 extern const int si_SEGV_ACCERR;
+
+extern const unsigned SHA1_CTX_sz;
+extern const unsigned SHA1_return_length;
+
+extern const unsigned MD4_CTX_sz;
+extern const unsigned MD4_return_length;
+
+extern const unsigned RMD160_CTX_sz;
+extern const unsigned RMD160_return_length;
+
+extern const unsigned MD5_CTX_sz;
+extern const unsigned MD5_return_length;
+
+extern const unsigned fpos_t_sz;
+
+extern const unsigned MD2_CTX_sz;
+extern const unsigned MD2_return_length;
+
+#define SHA2_EXTERN(LEN)                          \
+  extern const unsigned SHA##LEN##_CTX_sz;        \
+  extern const unsigned SHA##LEN##_return_length; \
+  extern const unsigned SHA##LEN##_block_length;  \
+  extern const unsigned SHA##LEN##_digest_length
+
+SHA2_EXTERN(224);
+SHA2_EXTERN(256);
+SHA2_EXTERN(384);
+SHA2_EXTERN(512);
+
+#undef SHA2_EXTERN
+
+extern const int unvis_valid;
+extern const int unvis_validpush;
+
+struct __sanitizer_cdbr {
+  void (*unmap)(void *, void *, uptr);
+  void *cookie;
+  u8 *mmap_base;
+  uptr mmap_size;
+
+  u8 *hash_base;
+  u8 *offset_base;
+  u8 *data_base;
+
+  u32 data_size;
+  u32 entries;
+  u32 entries_index;
+  u32 seed;
+
+  u8 offset_size;
+  u8 index_size;
+
+  u32 entries_m;
+  u32 entries_index_m;
+  u8 entries_s1, entries_s2;
+  u8 entries_index_s1, entries_index_s2;
+};
+
+struct __sanitizer_cdbw {
+  uptr data_counter;
+  uptr data_allocated;
+  uptr data_size;
+  uptr *data_len;
+  void **data_ptr;
+  uptr hash_size;
+  void *hash;
+  uptr key_counter;
+};
 }  // namespace __sanitizer
 
 #define CHECK_TYPE_SIZE(TYPE) \
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
index cd1b73d..a383ebf 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -14,7 +14,7 @@
 
 #include "sanitizer_platform.h"
 
-#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_MAC
+#if SANITIZER_LINUX || SANITIZER_MAC
 // Tests in this file assume that off_t-dependent data structures match the
 // libc ABI. For example, struct dirent here is what readdir() function (as
 // exported from libc) returns, and not the user-facing "dirent", which
@@ -45,7 +45,7 @@
 #include <termios.h>
 #include <time.h>
 #include <wchar.h>
-#if !SANITIZER_MAC && !SANITIZER_FREEBSD
+#if !SANITIZER_MAC
 #include <utmp.h>
 #endif
 
@@ -78,43 +78,11 @@
 #include <net/if_arp.h>
 #endif
 
-#if SANITIZER_FREEBSD
-# include <sys/mount.h>
-# include <sys/sockio.h>
-# include <sys/socket.h>
-# include <sys/filio.h>
-# include <sys/signal.h>
-# include <sys/timespec.h>
-# include <sys/timex.h>
-# include <sys/mqueue.h>
-# include <sys/msg.h>
-# include <sys/ipc.h>
-# include <sys/msg.h>
-# include <sys/statvfs.h>
-# include <sys/soundcard.h>
-# include <sys/mtio.h>
-# include <sys/consio.h>
-# include <sys/kbio.h>
-# include <sys/link_elf.h>
-# include <netinet/ip_mroute.h>
-# include <netinet/in.h>
-# include <net/ethernet.h>
-# include <net/ppp_defs.h>
-# include <glob.h>
-# include <term.h>
-
-#define _KERNEL  // to declare 'shminfo' structure
-# include <sys/shm.h>
-#undef _KERNEL
-
-#undef INLINE  // to avoid clashes with sanitizers' definitions
-#endif
-
-#if SANITIZER_FREEBSD || SANITIZER_IOS
+#if SANITIZER_IOS
 #undef IOC_DIRMASK
 #endif
 
-#if SANITIZER_LINUX || SANITIZER_FREEBSD
+#if SANITIZER_LINUX
 # include <utime.h>
 # include <sys/ptrace.h>
 # if defined(__mips64) || defined(__aarch64__) || defined(__arm__)
@@ -198,9 +166,9 @@
 namespace __sanitizer {
   unsigned struct_utsname_sz = sizeof(struct utsname);
   unsigned struct_stat_sz = sizeof(struct stat);
-#if !SANITIZER_IOS && !SANITIZER_FREEBSD
+#if !SANITIZER_IOS
   unsigned struct_stat64_sz = sizeof(struct stat64);
-#endif // !SANITIZER_IOS && !SANITIZER_FREEBSD
+#endif // !SANITIZER_IOS
   unsigned struct_rusage_sz = sizeof(struct rusage);
   unsigned struct_tm_sz = sizeof(struct tm);
   unsigned struct_passwd_sz = sizeof(struct passwd);
@@ -244,12 +212,12 @@
   unsigned struct_oldold_utsname_sz = sizeof(struct oldold_utsname);
 #endif // SANITIZER_LINUX
 
-#if SANITIZER_LINUX || SANITIZER_FREEBSD
+#if SANITIZER_LINUX
   unsigned struct_rlimit_sz = sizeof(struct rlimit);
   unsigned struct_timespec_sz = sizeof(struct timespec);
   unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
   unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
-#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+#endif // SANITIZER_LINUX
 
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
   // Use pre-computed size of struct ustat to avoid <sys/ustat.h> which
@@ -269,12 +237,12 @@
   unsigned struct_statvfs64_sz = sizeof(struct statvfs64);
 #endif // SANITIZER_LINUX && !SANITIZER_ANDROID
 
-#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
   unsigned struct_timex_sz = sizeof(struct timex);
   unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
   unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
   unsigned struct_statvfs_sz = sizeof(struct statvfs);
-#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
 
   const uptr sig_ign = (uptr)SIG_IGN;
   const uptr sig_dfl = (uptr)SIG_DFL;
@@ -286,7 +254,7 @@
 #endif
 
 
-#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
   unsigned struct_shminfo_sz = sizeof(struct shminfo);
   unsigned struct_shm_info_sz = sizeof(struct shm_info);
   int shmctl_ipc_stat = (int)IPC_STAT;
@@ -322,7 +290,7 @@
 unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
 #endif
 
-#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
   int glob_nomatch = GLOB_NOMATCH;
   int glob_altdirfunc = GLOB_ALTDIRFUNC;
 #endif
@@ -447,7 +415,7 @@
   unsigned struct_vt_stat_sz = sizeof(struct vt_stat);
 #endif // SANITIZER_LINUX
 
-#if SANITIZER_LINUX || SANITIZER_FREEBSD
+#if SANITIZER_LINUX
 #if SOUND_VERSION >= 0x040000
   unsigned struct_copr_buffer_sz = 0;
   unsigned struct_copr_debug_buf_sz = 0;
@@ -464,7 +432,7 @@
   unsigned struct_seq_event_rec_sz = sizeof(struct seq_event_rec);
   unsigned struct_synth_info_sz = sizeof(struct synth_info);
   unsigned struct_vt_mode_sz = sizeof(struct vt_mode);
-#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+#endif // SANITIZER_LINUX
 
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
   unsigned struct_ax25_parms_struct_sz = sizeof(struct ax25_parms_struct);
@@ -491,7 +459,7 @@
   unsigned struct_unimapinit_sz = sizeof(struct unimapinit);
 #endif // SANITIZER_LINUX && !SANITIZER_ANDROID
 
-#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
   unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
   unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
 #endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
@@ -501,6 +469,8 @@
   unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
 #endif
 
+  const unsigned long __sanitizer_bufsiz = BUFSIZ;
+
   const unsigned IOCTL_NOT_PRESENT = 0;
 
   unsigned IOCTL_FIOASYNC = FIOASYNC;
@@ -547,7 +517,7 @@
   unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
   unsigned IOCTL_TIOCSTI = TIOCSTI;
   unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
-#if ((SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID)
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
   unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
   unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
 #endif
@@ -737,9 +707,6 @@
   unsigned IOCTL_VT_RESIZE = VT_RESIZE;
   unsigned IOCTL_VT_RESIZEX = VT_RESIZEX;
   unsigned IOCTL_VT_SENDSIG = VT_SENDSIG;
-#endif // SANITIZER_LINUX
-
-#if SANITIZER_LINUX || SANITIZER_FREEBSD
   unsigned IOCTL_MTIOCGET = MTIOCGET;
   unsigned IOCTL_MTIOCTOP = MTIOCTOP;
   unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE = SNDCTL_DSP_GETBLKSIZE;
@@ -832,7 +799,7 @@
   unsigned IOCTL_VT_RELDISP = VT_RELDISP;
   unsigned IOCTL_VT_SETMODE = VT_SETMODE;
   unsigned IOCTL_VT_WAITACTIVE = VT_WAITACTIVE;
-#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+#endif // SANITIZER_LINUX
 
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
   unsigned IOCTL_CYGETDEFTHRESH = CYGETDEFTHRESH;
@@ -925,7 +892,7 @@
   unsigned IOCTL_TIOCSSERIAL = TIOCSSERIAL;
 #endif // SANITIZER_LINUX && !SANITIZER_ANDROID
 
-#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
   unsigned IOCTL_GIO_SCRNMAP = GIO_SCRNMAP;
   unsigned IOCTL_KDDISABIO = KDDISABIO;
   unsigned IOCTL_KDENABIO = KDENABIO;
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
index 3f67916..f51644e 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -15,22 +15,12 @@
 #ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H
 #define SANITIZER_PLATFORM_LIMITS_POSIX_H
 
-#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC
+#if SANITIZER_LINUX || SANITIZER_MAC
 
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_platform.h"
 
-#if SANITIZER_FREEBSD
-// FreeBSD's dlopen() returns a pointer to an Obj_Entry structure that
-// incorporates the map structure.
-# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
-    ((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 560)))
-// Get sys/_types.h, because that tells us whether 64-bit inodes are
-// used in struct dirent below.
-#include <sys/_types.h>
-#else
 # define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) ((link_map*)(handle))
-#endif  // !SANITIZER_FREEBSD
 
 #ifndef __GLIBC_PREREQ
 #define __GLIBC_PREREQ(x, y) 0
@@ -39,7 +29,7 @@
 namespace __sanitizer {
   extern unsigned struct_utsname_sz;
   extern unsigned struct_stat_sz;
-#if !SANITIZER_FREEBSD && !SANITIZER_IOS
+#if !SANITIZER_IOS
   extern unsigned struct_stat64_sz;
 #endif
   extern unsigned struct_rusage_sz;
@@ -123,7 +113,7 @@
   const unsigned struct_kexec_segment_sz = 4 * sizeof(unsigned long);
 #endif  // SANITIZER_LINUX
 
-#if SANITIZER_LINUX || SANITIZER_FREEBSD
+#if SANITIZER_LINUX
 
 #if defined(__powerpc64__) || defined(__s390__)
   const unsigned struct___old_kernel_stat_sz = 0;
@@ -180,11 +170,9 @@
     int data;
 #elif SANITIZER_LINUX
     uptr data[4];
-#elif SANITIZER_FREEBSD
-    u32 data[4];
 #endif
   };
-#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+#endif // SANITIZER_LINUX
 
 #if SANITIZER_ANDROID
   struct __sanitizer_struct_mallinfo {
@@ -306,35 +294,14 @@
   #endif
 #endif
   };
-#elif SANITIZER_FREEBSD
-  struct __sanitizer_ipc_perm {
-    unsigned int cuid;
-    unsigned int cgid;
-    unsigned int uid;
-    unsigned int gid;
-    unsigned short mode;
-    unsigned short seq;
-    long key;
-  };
-
-  struct __sanitizer_shmid_ds {
-    __sanitizer_ipc_perm shm_perm;
-    unsigned long shm_segsz;
-    unsigned int shm_lpid;
-    unsigned int shm_cpid;
-    int shm_nattch;
-    unsigned long shm_atime;
-    unsigned long shm_dtime;
-    unsigned long shm_ctime;
-  };
 #endif
 
-#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
   extern unsigned struct_msqid_ds_sz;
   extern unsigned struct_mq_attr_sz;
   extern unsigned struct_timex_sz;
   extern unsigned struct_statvfs_sz;
-#endif  // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#endif  // SANITIZER_LINUX && !SANITIZER_ANDROID
 
   struct __sanitizer_iovec {
     void *iov_base;
@@ -384,7 +351,7 @@
     char *pw_passwd;
     int pw_uid;
     int pw_gid;
-#if SANITIZER_MAC || SANITIZER_FREEBSD
+#if SANITIZER_MAC
     long pw_change;
     char *pw_class;
 #endif
@@ -393,12 +360,9 @@
 #endif
     char *pw_dir;
     char *pw_shell;
-#if SANITIZER_MAC || SANITIZER_FREEBSD
+#if SANITIZER_MAC
     long pw_expire;
 #endif
-#if SANITIZER_FREEBSD
-    int pw_fields;
-#endif
   };
 
   struct __sanitizer_group {
@@ -468,7 +432,7 @@
   };
 #endif
 
-#if SANITIZER_MAC || SANITIZER_FREEBSD
+#if SANITIZER_MAC
   struct __sanitizer_msghdr {
     void *msg_name;
     unsigned msg_namelen;
@@ -514,17 +478,6 @@
     unsigned short d_reclen;
     // more fields that we don't care about
   };
-#elif SANITIZER_FREEBSD
-  struct __sanitizer_dirent {
-#if defined(__INO64)
-    unsigned long long d_fileno;
-    unsigned long long d_off;
-#else
-    unsigned int d_fileno;
-#endif
-    unsigned short d_reclen;
-    // more fields that we don't care about
-  };
 #elif SANITIZER_ANDROID || defined(__x86_64__)
   struct __sanitizer_dirent {
     unsigned long long d_ino;
@@ -550,20 +503,17 @@
   };
 #endif
 
-// 'clock_t' is 32 bits wide on x64 FreeBSD
-#if SANITIZER_FREEBSD
-  typedef int __sanitizer_clock_t;
-#elif defined(__x86_64__) && !defined(_LP64)
+#if defined(__x86_64__) && !defined(_LP64)
   typedef long long __sanitizer_clock_t;
 #else
   typedef long __sanitizer_clock_t;
 #endif
 
-#if SANITIZER_LINUX || SANITIZER_FREEBSD
+#if SANITIZER_LINUX
   typedef int __sanitizer_clockid_t;
 #endif
 
-#if SANITIZER_LINUX || SANITIZER_FREEBSD
+#if SANITIZER_LINUX
 #if defined(_LP64) || defined(__x86_64__) || defined(__powerpc__)\
                    || defined(__mips__)
   typedef unsigned __sanitizer___kernel_uid_t;
@@ -613,11 +563,6 @@
     // The size is determined by looking at sizeof of real sigset_t on linux.
     uptr val[128 / sizeof(uptr)];
   };
-#elif SANITIZER_FREEBSD
-  struct __sanitizer_sigset_t {
-     // uint32_t * 4
-     unsigned int __bits[4];
-  };
 #endif
 
   struct __sanitizer_siginfo {
@@ -707,9 +652,7 @@
   };
 #endif // !SANITIZER_ANDROID
 
-#if SANITIZER_FREEBSD
-  typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t;
-#elif defined(__mips__)
+#if defined(__mips__)
   struct __sanitizer_kernel_sigset_t {
     uptr sig[2];
   };
@@ -755,7 +698,7 @@
   extern int af_inet6;
   uptr __sanitizer_in_addr_sz(int af);
 
-#if SANITIZER_LINUX || SANITIZER_FREEBSD
+#if SANITIZER_LINUX
   struct __sanitizer_dl_phdr_info {
     uptr dlpi_addr;
     const char *dlpi_name;
@@ -771,7 +714,7 @@
     int ai_family;
     int ai_socktype;
     int ai_protocol;
-#if SANITIZER_ANDROID || SANITIZER_MAC || SANITIZER_FREEBSD
+#if SANITIZER_ANDROID || SANITIZER_MAC
     unsigned ai_addrlen;
     char *ai_canonname;
     void *ai_addr;
@@ -797,7 +740,7 @@
     short revents;
   };
 
-#if SANITIZER_ANDROID || SANITIZER_MAC || SANITIZER_FREEBSD
+#if SANITIZER_ANDROID || SANITIZER_MAC
   typedef unsigned __sanitizer_nfds_t;
 #else
   typedef unsigned long __sanitizer_nfds_t;
@@ -817,23 +760,9 @@
     int (*gl_lstat)(const char *, void *);
     int (*gl_stat)(const char *, void *);
   };
-# elif SANITIZER_FREEBSD
-  struct __sanitizer_glob_t {
-    uptr gl_pathc;
-    uptr gl_matchc;
-    uptr gl_offs;
-    int gl_flags;
-    char **gl_pathv;
-    int (*gl_errfunc)(const char*, int);
-    void (*gl_closedir)(void *dirp);
-    struct dirent *(*gl_readdir)(void *dirp);
-    void *(*gl_opendir)(const char*);
-    int (*gl_lstat)(const char*, void* /* struct stat* */);
-    int (*gl_stat)(const char*, void* /* struct stat* */);
-  };
-# endif  // SANITIZER_FREEBSD
+# endif  // SANITIZER_LINUX
 
-# if SANITIZER_LINUX || SANITIZER_FREEBSD
+# if SANITIZER_LINUX
   extern int glob_nomatch;
   extern int glob_altdirfunc;
 # endif
@@ -845,10 +774,6 @@
     uptr we_wordc;
     char **we_wordv;
     uptr we_offs;
-#if SANITIZER_FREEBSD
-    char *we_strings;
-    uptr we_nbytes;
-#endif
   };
 
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
@@ -902,7 +827,7 @@
   extern int ptrace_geteventmsg;
 #endif
 
-#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#if SANITIZER_LINUX  && !SANITIZER_ANDROID
   extern unsigned struct_shminfo_sz;
   extern unsigned struct_shm_info_sz;
   extern int shmctl_ipc_stat;
@@ -1039,7 +964,7 @@
   extern unsigned struct_vt_stat_sz;
 #endif  // SANITIZER_LINUX
 
-#if SANITIZER_LINUX || SANITIZER_FREEBSD
+#if SANITIZER_LINUX
   extern unsigned struct_copr_buffer_sz;
   extern unsigned struct_copr_debug_buf_sz;
   extern unsigned struct_copr_msg_sz;
@@ -1051,7 +976,7 @@
   extern unsigned struct_seq_event_rec_sz;
   extern unsigned struct_synth_info_sz;
   extern unsigned struct_vt_mode_sz;
-#endif // SANITIZER_LINUX || SANITIZER_FREEBSD
+#endif // SANITIZER_LINUX
 
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
   extern unsigned struct_ax25_parms_struct_sz;
@@ -1073,7 +998,9 @@
   extern unsigned struct_unimapinit_sz;
 #endif  // SANITIZER_LINUX && !SANITIZER_ANDROID
 
-#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+  extern const unsigned long __sanitizer_bufsiz;
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
   extern unsigned struct_audio_buf_info_sz;
   extern unsigned struct_ppp_stats_sz;
 #endif  // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
@@ -1133,7 +1060,7 @@
   extern unsigned IOCTL_TIOCSPGRP;
   extern unsigned IOCTL_TIOCSTI;
   extern unsigned IOCTL_TIOCSWINSZ;
-#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
   extern unsigned IOCTL_SIOCGETSGCNT;
   extern unsigned IOCTL_SIOCGETVIFCNT;
 #endif
@@ -1295,8 +1222,6 @@
   extern unsigned IOCTL_VT_RESIZE;
   extern unsigned IOCTL_VT_RESIZEX;
   extern unsigned IOCTL_VT_SENDSIG;
-#endif  // SANITIZER_LINUX
-#if SANITIZER_LINUX || SANITIZER_FREEBSD
   extern unsigned IOCTL_MTIOCGET;
   extern unsigned IOCTL_MTIOCTOP;
   extern unsigned IOCTL_SIOCADDRT;
@@ -1397,7 +1322,7 @@
   extern unsigned IOCTL_VT_RELDISP;
   extern unsigned IOCTL_VT_SETMODE;
   extern unsigned IOCTL_VT_WAITACTIVE;
-#endif  // SANITIZER_LINUX || SANITIZER_FREEBSD
+#endif  // SANITIZER_LINUX
 
 #if SANITIZER_LINUX && !SANITIZER_ANDROID
   extern unsigned IOCTL_CYGETDEFTHRESH;
@@ -1484,9 +1409,6 @@
   extern unsigned IOCTL_TIOCSERGETMULTI;
   extern unsigned IOCTL_TIOCSERSETMULTI;
   extern unsigned IOCTL_TIOCSSERIAL;
-#endif  // SANITIZER_LINUX && !SANITIZER_ANDROID
-
-#if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
   extern unsigned IOCTL_GIO_SCRNMAP;
   extern unsigned IOCTL_KDDISABIO;
   extern unsigned IOCTL_KDENABIO;
@@ -1525,6 +1447,6 @@
 
 #define SIGACTION_SYMNAME sigaction
 
-#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC
+#endif  // SANITIZER_LINUX || SANITIZER_MAC
 
 #endif
diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc
index f7dfc86..116270f 100644
--- a/lib/sanitizer_common/sanitizer_posix.cc
+++ b/lib/sanitizer_common/sanitizer_posix.cc
@@ -193,11 +193,6 @@
   return true;
 }
 
-bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) {
-  uptr res = internal_rename(oldpath, newpath);
-  return !internal_iserror(res, error_p);
-}
-
 void *MapFileToMemory(const char *file_name, uptr *buff_size) {
   fd_t fd = OpenFile(file_name, RdOnly);
   CHECK(fd != kInvalidFd);
diff --git a/lib/sanitizer_common/sanitizer_posix.h b/lib/sanitizer_common/sanitizer_posix.h
index 3075a13..2ebfae8 100644
--- a/lib/sanitizer_common/sanitizer_posix.h
+++ b/lib/sanitizer_common/sanitizer_posix.h
@@ -16,6 +16,7 @@
 // ----------- ATTENTION -------------
 // This header should NOT include any other headers from sanitizer runtime.
 #include "sanitizer_internal_defs.h"
+#include "sanitizer_platform_limits_freebsd.h"
 #include "sanitizer_platform_limits_netbsd.h"
 #include "sanitizer_platform_limits_openbsd.h"
 #include "sanitizer_platform_limits_posix.h"
diff --git a/lib/sanitizer_common/sanitizer_rtems.cc b/lib/sanitizer_common/sanitizer_rtems.cc
index 27078ef..678906a 100644
--- a/lib/sanitizer_common/sanitizer_rtems.cc
+++ b/lib/sanitizer_common/sanitizer_rtems.cc
@@ -227,11 +227,6 @@
   return true;
 }
 
-bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) {
-  uptr res = rename(oldpath, newpath);
-  return !internal_iserror(res, error_p);
-}
-
 void ReleaseMemoryPagesToOS(uptr beg, uptr end) {}
 void DumpProcessMap() {}
 
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.h b/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.h
index 3c1c864..b241b9d 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.h
+++ b/lib/sanitizer_common/sanitizer_symbolizer_fuchsia.h
@@ -35,6 +35,9 @@
 // One frame in a backtrace (printed on a line by itself).
 constexpr const char *kFormatFrame = "{{{bt:%u:%p}}}";
 
+// Dump trigger element.
+#define FORMAT_DUMPFILE "{{{dumpfile:%s:%s}}}"
+
 }  // namespace __sanitizer
 
 #endif  // SANITIZER_SYMBOLIZER_FUCHSIA_H
diff --git a/lib/sanitizer_common/sanitizer_thread_registry.cc b/lib/sanitizer_common/sanitizer_thread_registry.cc
index d9fd654..eb35cb6 100644
--- a/lib/sanitizer_common/sanitizer_thread_registry.cc
+++ b/lib/sanitizer_common/sanitizer_thread_registry.cc
@@ -338,4 +338,15 @@
   return tctx;
 }
 
+void ThreadRegistry::SetThreadUserId(u32 tid, uptr user_id) {
+  BlockingMutexLock l(&mtx_);
+  CHECK_LT(tid, n_contexts_);
+  ThreadContextBase *tctx = threads_[tid];
+  CHECK_NE(tctx, 0);
+  CHECK_NE(tctx->status, ThreadStatusInvalid);
+  CHECK_NE(tctx->status, ThreadStatusDead);
+  CHECK_EQ(tctx->user_id, 0);
+  tctx->user_id = user_id;
+}
+
 }  // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_thread_registry.h b/lib/sanitizer_common/sanitizer_thread_registry.h
index b203be2..30dc603 100644
--- a/lib/sanitizer_common/sanitizer_thread_registry.h
+++ b/lib/sanitizer_common/sanitizer_thread_registry.h
@@ -122,6 +122,7 @@
   void JoinThread(u32 tid, void *arg);
   void FinishThread(u32 tid);
   void StartThread(u32 tid, tid_t os_id, bool workerthread, void *arg);
+  void SetThreadUserId(u32 tid, uptr user_id);
 
  private:
   const ThreadContextFactory context_factory_;
diff --git a/lib/sanitizer_common/sanitizer_type_traits.h b/lib/sanitizer_common/sanitizer_type_traits.h
new file mode 100644
index 0000000..572eaa5
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_type_traits.h
@@ -0,0 +1,44 @@
+//===-- sanitizer_type_traits.h ---------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements a subset of C++ type traits. This is so we can avoid depending
+// on system C++ headers.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_TYPE_TRAITS_H
+#define SANITIZER_TYPE_TRAITS_H
+
+namespace __sanitizer {
+
+struct true_type {
+  static const bool value = true;
+};
+
+struct false_type {
+  static const bool value = false;
+};
+
+// is_same<T, U>
+//
+// Type trait to compare if types are the same.
+// E.g.
+//
+// ```
+// is_same<int,int>::value - True
+// is_same<int,char>::value - False
+// ```
+template <typename T, typename U>
+struct is_same : public false_type {};
+
+template <typename T>
+struct is_same<T, T> : public true_type {};
+
+};  // namespace __sanitizer
+
+#endif
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index 7623d42..d3b7df6 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -737,10 +737,6 @@
   }
 }
 
-bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) {
-  UNIMPLEMENTED();
-}
-
 uptr internal_sched_yield() {
   Sleep(0);
   return 0;
diff --git a/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt b/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt
index f77648d..beee0ac 100644
--- a/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt
+++ b/lib/sanitizer_common/symbolizer/scripts/global_symbols.txt
@@ -49,6 +49,7 @@
 dup2 U
 environ U
 execv U
+execve U
 exit U
 fclose U
 fflush U
@@ -65,6 +66,7 @@
 getenv U
 getpagesize U
 getpid U
+getrlimit U
 gettimeofday U
 ioctl U
 isalpha U
@@ -101,6 +103,7 @@
 readlink U
 realloc U
 remove U
+setrlimit U
 setvbuf U
 sigfillset U
 sigprocmask U
diff --git a/lib/sanitizer_common/tests/CMakeLists.txt b/lib/sanitizer_common/tests/CMakeLists.txt
index 75998c8..21ffe25 100644
--- a/lib/sanitizer_common/tests/CMakeLists.txt
+++ b/lib/sanitizer_common/tests/CMakeLists.txt
@@ -5,7 +5,7 @@
 # FIXME: use SANITIZER_COMMON_SUPPORTED_ARCH here
 filter_available_targets(SANITIZER_UNITTEST_SUPPORTED_ARCH x86_64 i386 mips64 mips64el)
 if(APPLE)
-  darwin_filter_host_archs(SANITIZER_UNITTEST_SUPPORTED_ARCH SANITIZER_COMMON_SUPPORTED_ARCH)
+  darwin_filter_host_archs(SANITIZER_UNITTEST_SUPPORTED_ARCH SANITIZER_UNITTEST_SUPPORTED_ARCH)
 endif()
 
 set(SANITIZER_UNITTESTS
@@ -36,6 +36,7 @@
   sanitizer_symbolizer_test.cc
   sanitizer_test_main.cc
   sanitizer_thread_registry_test.cc
+  sanitizer_type_traits_test.cc
   sanitizer_vector_test.cc)
 
 set(SANITIZER_TEST_HEADERS
diff --git a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
index 05fef25..f12b70e 100644
--- a/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
@@ -118,17 +118,22 @@
 static const uptr kRegionSizeLog = FIRST_32_SECOND_64(20, 24);
 static const uptr kFlatByteMapSize = kAddressSpaceSize >> kRegionSizeLog;
 
+template <typename AddressSpaceViewTy>
 struct AP32Compact {
   static const uptr kSpaceBeg = 0;
   static const u64 kSpaceSize = kAddressSpaceSize;
   static const uptr kMetadataSize = 16;
   typedef CompactSizeClassMap SizeClassMap;
   static const uptr kRegionSizeLog = ::kRegionSizeLog;
-  typedef FlatByteMap<kFlatByteMapSize> ByteMap;
+  using AddressSpaceView = AddressSpaceViewTy;
+  using ByteMap = FlatByteMap<kFlatByteMapSize, AddressSpaceView>;
   typedef NoOpMapUnmapCallback MapUnmapCallback;
   static const uptr kFlags = 0;
 };
-typedef SizeClassAllocator32<AP32Compact> Allocator32Compact;
+template <typename AddressSpaceView>
+using Allocator32CompactASVT =
+    SizeClassAllocator32<AP32Compact<AddressSpaceView>>;
+using Allocator32Compact = Allocator32CompactASVT<LocalAddressSpaceView>;
 
 template <class SizeClassMap>
 void TestSizeClassMap() {
@@ -259,18 +264,24 @@
   TestSizeClassAllocator<Allocator32Compact>();
 }
 
+template <typename AddressSpaceViewTy>
 struct AP32SeparateBatches {
   static const uptr kSpaceBeg = 0;
   static const u64 kSpaceSize = kAddressSpaceSize;
   static const uptr kMetadataSize = 16;
   typedef DefaultSizeClassMap SizeClassMap;
   static const uptr kRegionSizeLog = ::kRegionSizeLog;
-  typedef FlatByteMap<kFlatByteMapSize> ByteMap;
+  using AddressSpaceView = AddressSpaceViewTy;
+  using ByteMap = FlatByteMap<kFlatByteMapSize, AddressSpaceView>;
   typedef NoOpMapUnmapCallback MapUnmapCallback;
   static const uptr kFlags =
       SizeClassAllocator32FlagMasks::kUseSeparateSizeClassForBatch;
 };
-typedef SizeClassAllocator32<AP32SeparateBatches> Allocator32SeparateBatches;
+template <typename AddressSpaceView>
+using Allocator32SeparateBatchesASVT =
+    SizeClassAllocator32<AP32SeparateBatches<AddressSpaceView>>;
+using Allocator32SeparateBatches =
+    Allocator32SeparateBatchesASVT<LocalAddressSpaceView>;
 
 TEST(SanitizerCommon, SizeClassAllocator32SeparateBatches) {
   TestSizeClassAllocator<Allocator32SeparateBatches>();
@@ -426,13 +437,15 @@
 #endif
 #endif
 
+template <typename AddressSpaceViewTy = LocalAddressSpaceView>
 struct AP32WithCallback {
   static const uptr kSpaceBeg = 0;
   static const u64 kSpaceSize = kAddressSpaceSize;
   static const uptr kMetadataSize = 16;
   typedef CompactSizeClassMap SizeClassMap;
   static const uptr kRegionSizeLog = ::kRegionSizeLog;
-  typedef FlatByteMap<kFlatByteMapSize> ByteMap;
+  using AddressSpaceView = AddressSpaceViewTy;
+  using ByteMap = FlatByteMap<kFlatByteMapSize, AddressSpaceView>;
   typedef TestMapUnmapCallback MapUnmapCallback;
   static const uptr kFlags = 0;
 };
@@ -440,7 +453,7 @@
 TEST(SanitizerCommon, SizeClassAllocator32MapUnmapCallback) {
   TestMapUnmapCallback::map_count = 0;
   TestMapUnmapCallback::unmap_count = 0;
-  typedef SizeClassAllocator32<AP32WithCallback> Allocator32WithCallBack;
+  typedef SizeClassAllocator32<AP32WithCallback<>> Allocator32WithCallBack;
   Allocator32WithCallBack *a = new Allocator32WithCallBack;
   a->Init(kReleaseToOSIntervalNever);
   EXPECT_EQ(TestMapUnmapCallback::map_count, 0);
@@ -615,6 +628,22 @@
 
     std::shuffle(allocated.begin(), allocated.end(), r);
 
+    // Test ForEachChunk(...)
+    {
+      std::set<void *> reported_chunks;
+      auto cb = [](uptr chunk, void *arg) {
+        auto reported_chunks_ptr = reinterpret_cast<std::set<void *> *>(arg);
+        auto pair =
+            reported_chunks_ptr->insert(reinterpret_cast<void *>(chunk));
+        // Check chunk is never reported more than once.
+        ASSERT_TRUE(pair.second);
+      };
+      a->ForEachChunk(cb, reinterpret_cast<void *>(&reported_chunks));
+      for (const auto &allocated_ptr : allocated) {
+        ASSERT_NE(reported_chunks.find(allocated_ptr), reported_chunks.end());
+      }
+    }
+
     for (uptr i = 0; i < kNumAllocs; i++) {
       void *x = allocated[i];
       uptr *meta = reinterpret_cast<uptr*>(a->GetMetaData(x));
@@ -1321,8 +1350,10 @@
   m.TestOnlyUnmap();
 }
 
-
-typedef TwoLevelByteMap<1 << 12, 1 << 13, TestMapUnmapCallback> TestByteMap;
+template <typename AddressSpaceView>
+using TestByteMapASVT =
+    TwoLevelByteMap<1 << 12, 1 << 13, AddressSpaceView, TestMapUnmapCallback>;
+using TestByteMap = TestByteMapASVT<LocalAddressSpaceView>;
 
 struct TestByteMapParam {
   TestByteMap *m;
diff --git a/lib/sanitizer_common/tests/sanitizer_type_traits_test.cc b/lib/sanitizer_common/tests/sanitizer_type_traits_test.cc
new file mode 100644
index 0000000..0dce02f
--- /dev/null
+++ b/lib/sanitizer_common/tests/sanitizer_type_traits_test.cc
@@ -0,0 +1,28 @@
+//===-- sanitizer_type_traits_test.cc -------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
+//
+//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_type_traits.h"
+#include "gtest/gtest.h"
+#include "sanitizer_common/sanitizer_internal_defs.h"
+
+using namespace __sanitizer;
+
+TEST(SanitizerCommon, IsSame) {
+  ASSERT_TRUE((is_same<unsigned, unsigned>::value));
+  ASSERT_TRUE((is_same<uptr, uptr>::value));
+  ASSERT_TRUE((is_same<sptr, sptr>::value));
+  ASSERT_TRUE((is_same<const uptr, const uptr>::value));
+
+  ASSERT_FALSE((is_same<unsigned, signed>::value));
+  ASSERT_FALSE((is_same<uptr, sptr>::value));
+  ASSERT_FALSE((is_same<uptr, const uptr>::value));
+}
diff --git a/lib/scudo/scudo_allocator.h b/lib/scudo/scudo_allocator.h
index 0002b4a..869e74a 100644
--- a/lib/scudo/scudo_allocator.h
+++ b/lib/scudo/scudo_allocator.h
@@ -96,7 +96,8 @@
   static const uptr kMetadataSize = 0;
   typedef __scudo::SizeClassMap SizeClassMap;
   static const uptr kRegionSizeLog = RegionSizeLog;
-  typedef __scudo::ByteMap ByteMap;
+  using AddressSpaceView = LocalAddressSpaceView;
+  using ByteMap = __scudo::ByteMap;
   typedef NoOpMapUnmapCallback MapUnmapCallback;
   static const uptr kFlags =
       SizeClassAllocator32FlagMasks::kRandomShuffleChunks |
diff --git a/lib/tsan/CMakeLists.txt b/lib/tsan/CMakeLists.txt
index d501d0c..e1da319 100644
--- a/lib/tsan/CMakeLists.txt
+++ b/lib/tsan/CMakeLists.txt
@@ -220,11 +220,12 @@
 endif()
 
 # Make sure that non-platform-specific files don't include any system headers.
-# FreeBSD does not install a number of Clang-provided headers for the compiler
-# in the base system due to incompatibilities between FreeBSD's and Clang's
-# versions. As a workaround do not use --sysroot=. on FreeBSD until this is
-# addressed.
-if(COMPILER_RT_HAS_SYSROOT_FLAG AND NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+# FreeBSD/NetBSD do not install a number of Clang-provided headers for the
+# compiler in the base system due to incompatibilities between FreeBSD/NetBSD's
+# and Clang's versions. As a workaround do not use --sysroot=. on FreeBSD/NetBSD
+# until this is addressed.
+if(COMPILER_RT_HAS_SYSROOT_FLAG AND NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD"
+   AND NOT CMAKE_SYSTEM_NAME MATCHES "NetBSD")
   file(GLOB _tsan_generic_sources rtl/tsan*)
   file(GLOB _tsan_platform_sources rtl/tsan*posix* rtl/tsan*mac*
                                    rtl/tsan*linux*)
diff --git a/lib/tsan/check_analyze.sh b/lib/tsan/check_analyze.sh
index b2beb85..65c34d4 100755
--- a/lib/tsan/check_analyze.sh
+++ b/lib/tsan/check_analyze.sh
@@ -8,7 +8,7 @@
 # performance has not regressed by running the following benchmarks before and
 # after the breaking change to verify that the values in this file are safe to
 # update:
-# ./projects/compiler-rt/lib/tsan/tests/rtl/TsanRtlTest
+# ./projects/compiler-rt/lib/tsan/tests/rtl/TsanRtlTest-x86_64-Test
 #   --gtest_also_run_disabled_tests --gtest_filter=DISABLED_BENCH.Mop*
 
 set -u
@@ -34,13 +34,13 @@
   fi
 }
 
-for f in write1 write2 write4 write8 read2 read4 read8; do
+for f in write1 write2 write4 write8 read2 read4; do
   check $f rsp 1
   check $f push 1
   check $f pop 6
 done
 
-for f in read1; do
+for f in read1 read8; do
   check $f rsp 1
   check $f push 2
   check $f pop 12
diff --git a/lib/tsan/rtl/tsan_flags.cc b/lib/tsan/rtl/tsan_flags.cc
index 89e22a1..877fc8b 100644
--- a/lib/tsan/rtl/tsan_flags.cc
+++ b/lib/tsan/rtl/tsan_flags.cc
@@ -61,8 +61,7 @@
       // Does not work as expected for Go: runtime handles SIGABRT and crashes.
       cf.abort_on_error = false;
       // Go does not have mutexes.
-    } else {
-      cf.detect_deadlocks = true;
+      cf.detect_deadlocks = false;
     }
     cf.print_suppressions = false;
     cf.stack_trace_format = "    #%n %f %S %M";
diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc
index a8d2fea..cc6dab8 100644
--- a/lib/tsan/rtl/tsan_interceptors.cc
+++ b/lib/tsan/rtl/tsan_interceptors.cc
@@ -228,6 +228,16 @@
   libignore()->OnLibraryLoaded(0);
 }
 
+// The following two hooks can be used by for cooperative scheduling when
+// locking.
+#ifdef TSAN_EXTERNAL_HOOKS
+void OnPotentiallyBlockingRegionBegin();
+void OnPotentiallyBlockingRegionEnd();
+#else
+SANITIZER_WEAK_CXX_DEFAULT_IMPL void OnPotentiallyBlockingRegionBegin() {}
+SANITIZER_WEAK_CXX_DEFAULT_IMPL void OnPotentiallyBlockingRegionEnd() {}
+#endif
+
 }  // namespace __tsan
 
 static ThreadSignalContext *SigCtx(ThreadState *thr) {
@@ -866,6 +876,8 @@
 // Used in thread-safe function static initialization.
 STDCXX_INTERCEPTOR(int, __cxa_guard_acquire, atomic_uint32_t *g) {
   SCOPED_INTERCEPTOR_RAW(__cxa_guard_acquire, g);
+  OnPotentiallyBlockingRegionBegin();
+  auto on_exit = at_scope_exit(&OnPotentiallyBlockingRegionEnd);
   for (;;) {
     u32 cmp = atomic_load(g, memory_order_acquire);
     if (cmp == 0) {
@@ -1044,6 +1056,35 @@
   return res;
 }
 
+#if SANITIZER_LINUX
+TSAN_INTERCEPTOR(int, pthread_tryjoin_np, void *th, void **ret) {
+  SCOPED_TSAN_INTERCEPTOR(pthread_tryjoin_np, th, ret);
+  int tid = ThreadTid(thr, pc, (uptr)th);
+  ThreadIgnoreBegin(thr, pc);
+  int res = REAL(pthread_tryjoin_np)(th, ret);
+  ThreadIgnoreEnd(thr, pc);
+  if (res == 0)
+    ThreadJoin(thr, pc, tid);
+  else
+    ThreadNotJoined(thr, pc, tid, (uptr)th);
+  return res;
+}
+
+TSAN_INTERCEPTOR(int, pthread_timedjoin_np, void *th, void **ret,
+                 const struct timespec *abstime) {
+  SCOPED_TSAN_INTERCEPTOR(pthread_timedjoin_np, th, ret, abstime);
+  int tid = ThreadTid(thr, pc, (uptr)th);
+  ThreadIgnoreBegin(thr, pc);
+  int res = BLOCK_REAL(pthread_timedjoin_np)(th, ret, abstime);
+  ThreadIgnoreEnd(thr, pc);
+  if (res == 0)
+    ThreadJoin(thr, pc, tid);
+  else
+    ThreadNotJoined(thr, pc, tid, (uptr)th);
+  return res;
+}
+#endif
+
 // Problem:
 // NPTL implementation of pthread_cond has 2 versions (2.2.5 and 2.3.2).
 // pthread_cond_t has different size in the different versions.
@@ -2640,6 +2681,10 @@
   TSAN_INTERCEPT(pthread_create);
   TSAN_INTERCEPT(pthread_join);
   TSAN_INTERCEPT(pthread_detach);
+  #if SANITIZER_LINUX
+  TSAN_INTERCEPT(pthread_tryjoin_np);
+  TSAN_INTERCEPT(pthread_timedjoin_np);
+  #endif
 
   TSAN_INTERCEPT_VER(pthread_cond_init, PTHREAD_ABI_BASE);
   TSAN_INTERCEPT_VER(pthread_cond_signal, PTHREAD_ABI_BASE);
diff --git a/lib/tsan/rtl/tsan_interceptors_mac.cc b/lib/tsan/rtl/tsan_interceptors_mac.cc
index b58e6b7..5e8b58f 100644
--- a/lib/tsan/rtl/tsan_interceptors_mac.cc
+++ b/lib/tsan/rtl/tsan_interceptors_mac.cc
@@ -326,7 +326,7 @@
 }
 
 TSAN_INTERCEPTOR(int, objc_sync_exit, void *obj) {
-  SCOPED_TSAN_INTERCEPTOR(objc_sync_enter, obj);
+  SCOPED_TSAN_INTERCEPTOR(objc_sync_exit, obj);
   if (obj) Release(thr, pc, SyncAddressForObjCObject(obj));
   return REAL(objc_sync_exit)(obj);
 }
diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h
index 523b69a..60e6f82 100644
--- a/lib/tsan/rtl/tsan_rtl.h
+++ b/lib/tsan/rtl/tsan_rtl.h
@@ -59,15 +59,16 @@
 static const uptr kAllocatorRegionSizeLog = 20;
 static const uptr kAllocatorNumRegions =
     SANITIZER_MMAP_RANGE_SIZE >> kAllocatorRegionSizeLog;
-typedef TwoLevelByteMap<(kAllocatorNumRegions >> 12), 1 << 12,
-    MapUnmapCallback> ByteMap;
+using ByteMap = TwoLevelByteMap<(kAllocatorNumRegions >> 12), 1 << 12,
+                                LocalAddressSpaceView, MapUnmapCallback>;
 struct AP32 {
   static const uptr kSpaceBeg = 0;
   static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
   static const uptr kMetadataSize = 0;
   typedef __sanitizer::CompactSizeClassMap SizeClassMap;
   static const uptr kRegionSizeLog = kAllocatorRegionSizeLog;
-  typedef __tsan::ByteMap ByteMap;
+  using AddressSpaceView = LocalAddressSpaceView;
+  using ByteMap = __tsan::ByteMap;
   typedef __tsan::MapUnmapCallback MapUnmapCallback;
   static const uptr kFlags = 0;
 };
@@ -772,6 +773,7 @@
 void ThreadSetName(ThreadState *thr, const char *name);
 int ThreadCount(ThreadState *thr);
 void ProcessPendingSignals(ThreadState *thr);
+void ThreadNotJoined(ThreadState *thr, uptr pc, int tid, uptr uid);
 
 Processor *ProcCreate();
 void ProcDestroy(Processor *proc);
diff --git a/lib/tsan/rtl/tsan_rtl_thread.cc b/lib/tsan/rtl/tsan_rtl_thread.cc
index e4d65b9..766a0f5 100644
--- a/lib/tsan/rtl/tsan_rtl_thread.cc
+++ b/lib/tsan/rtl/tsan_rtl_thread.cc
@@ -312,6 +312,12 @@
   ctx->thread_registry->DetachThread(tid, thr);
 }
 
+void ThreadNotJoined(ThreadState *thr, uptr pc, int tid, uptr uid) {
+  CHECK_GT(tid, 0);
+  CHECK_LT(tid, kMaxTid);
+  ctx->thread_registry->SetThreadUserId(tid, uid);
+}
+
 void ThreadSetName(ThreadState *thr, const char *name) {
   ctx->thread_registry->SetThreadName(thr->tid, name);
 }
diff --git a/lib/ubsan/ubsan_flags.inc b/lib/ubsan/ubsan_flags.inc
index 1638a05..e75a4c4 100644
--- a/lib/ubsan/ubsan_flags.inc
+++ b/lib/ubsan/ubsan_flags.inc
@@ -25,5 +25,5 @@
 UBSAN_FLAG(bool, report_error_type, false,
         "Print specific error type instead of 'undefined-behavior' in summary.")
 UBSAN_FLAG(bool, silence_unsigned_overflow, false,
-	"Do not print error reports for unsigned integer overflow. "
-	"Used to provide fuzzing signal without blowing up logs.")
+        "Do not print non-fatal error reports for unsigned integer overflow. "
+        "Used to provide fuzzing signal without blowing up logs.")
diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc
index bfcd16c..53430a6 100644
--- a/lib/ubsan/ubsan_handlers.cc
+++ b/lib/ubsan/ubsan_handlers.cc
@@ -119,7 +119,9 @@
   if (ignoreReport(Loc, Opts, ET))
     return;
 
-  if (!IsSigned && flags()->silence_unsigned_overflow)
+  // If this is an unsigned overflow in non-fatal mode, potentially ignore it.
+  if (!IsSigned && !Opts.FromUnrecoverableHandler &&
+      flags()->silence_unsigned_overflow)
     return;
 
   ScopedReport R(Opts, Loc, ET);
diff --git a/lib/xray/CMakeLists.txt b/lib/xray/CMakeLists.txt
index 541e181..0a86c52 100644
--- a/lib/xray/CMakeLists.txt
+++ b/lib/xray/CMakeLists.txt
@@ -2,6 +2,7 @@
 
 # XRay runtime library implementation files.
 set(XRAY_SOURCES
+    xray_buffer_queue.cc
     xray_init.cc
     xray_flags.cc
     xray_interface.cc
@@ -11,7 +12,6 @@
 # Implementation files for all XRay modes.
 set(XRAY_FDR_MODE_SOURCES
     xray_fdr_flags.cc
-    xray_buffer_queue.cc
     xray_fdr_logging.cc)
 
 set(XRAY_BASIC_MODE_SOURCES
diff --git a/lib/xray/tests/unit/allocator_test.cc b/lib/xray/tests/unit/allocator_test.cc
index be40416..1170741 100644
--- a/lib/xray/tests/unit/allocator_test.cc
+++ b/lib/xray/tests/unit/allocator_test.cc
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "xray_allocator.h"
+#include "xray_buffer_queue.h"
 #include "gtest/gtest.h"
 
 namespace __xray {
@@ -33,10 +34,49 @@
 TEST(AllocatorTest, OverAllocate) {
   Allocator<sizeof(TestData)> A(sizeof(TestData));
   auto B1 = A.Allocate();
-  (void)B1;
+  ASSERT_NE(B1.Data, nullptr);
   auto B2 = A.Allocate();
   ASSERT_EQ(B2.Data, nullptr);
 }
 
+struct OddSizedData {
+  s64 A;
+  s32 B;
+};
+
+TEST(AllocatorTest, AllocateBoundaries) {
+  Allocator<sizeof(OddSizedData)> A(GetPageSizeCached());
+
+  // Keep allocating until we hit a nullptr block.
+  unsigned C = 0;
+  auto Expected =
+      GetPageSizeCached() / RoundUpTo(sizeof(OddSizedData), kCacheLineSize);
+  for (auto B = A.Allocate(); B.Data != nullptr; B = A.Allocate(), ++C)
+    ;
+
+  ASSERT_EQ(C, Expected);
+}
+
+TEST(AllocatorTest, AllocateFromNonOwned) {
+  bool Success = false;
+  BufferQueue BQ(GetPageSizeCached(), 10, Success);
+  ASSERT_TRUE(Success);
+  BufferQueue::Buffer B;
+  ASSERT_EQ(BQ.getBuffer(B), BufferQueue::ErrorCode::Ok);
+  {
+    Allocator<sizeof(OddSizedData)> A(B.Data, B.Size);
+
+    // Keep allocating until we hit a nullptr block.
+    unsigned C = 0;
+    auto Expected =
+        GetPageSizeCached() / RoundUpTo(sizeof(OddSizedData), kCacheLineSize);
+    for (auto B = A.Allocate(); B.Data != nullptr; B = A.Allocate(), ++C)
+      ;
+
+    ASSERT_EQ(C, Expected);
+  }
+  ASSERT_EQ(BQ.releaseBuffer(B), BufferQueue::ErrorCode::Ok);
+}
+
 } // namespace
 } // namespace __xray
diff --git a/lib/xray/tests/unit/fdr_controller_test.cc b/lib/xray/tests/unit/fdr_controller_test.cc
index 2a1df67..8967c49 100644
--- a/lib/xray/tests/unit/fdr_controller_test.cc
+++ b/lib/xray/tests/unit/fdr_controller_test.cc
@@ -77,6 +77,32 @@
           AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::EXIT)))));
 }
 
+TEST_F(FunctionSequenceTest, BoundaryFuncIdEncoding) {
+  // We ensure that we can write function id's that are at the boundary of the
+  // acceptable function ids.
+  int32_t FId = (1 << 28) - 1;
+  uint64_t TSC = 2;
+  uint16_t CPU = 1;
+  ASSERT_TRUE(C->functionEnter(FId, TSC++, CPU));
+  ASSERT_TRUE(C->functionExit(FId, TSC++, CPU));
+  ASSERT_TRUE(C->functionEnterArg(FId, TSC++, CPU, 1));
+  ASSERT_TRUE(C->functionTailExit(FId, TSC++, CPU));
+  ASSERT_TRUE(C->flush());
+  ASSERT_EQ(BQ->finalize(), BufferQueue::ErrorCode::Ok);
+
+  // Serialize the buffers then test to see we find the expected records.
+  std::string Serialized = serialize(*BQ, 3);
+  llvm::DataExtractor DE(Serialized, true, 8);
+  auto TraceOrErr = llvm::xray::loadTrace(DE);
+  EXPECT_THAT_EXPECTED(
+      TraceOrErr,
+      HasValue(ElementsAre(
+          AllOf(FuncId(FId), RecordType(llvm::xray::RecordTypes::ENTER)),
+          AllOf(FuncId(FId), RecordType(llvm::xray::RecordTypes::EXIT)),
+          AllOf(FuncId(FId), RecordType(llvm::xray::RecordTypes::ENTER_ARG)),
+          AllOf(FuncId(FId), RecordType(llvm::xray::RecordTypes::TAIL_EXIT)))));
+}
+
 TEST_F(FunctionSequenceTest, ThresholdsAreEnforced) {
   C = llvm::make_unique<FDRController<>>(BQ.get(), B, *W, clock_gettime, 1000);
   ASSERT_TRUE(C->functionEnter(1, 2, 3));
@@ -222,6 +248,50 @@
   EXPECT_THAT_EXPECTED(TraceOrErr, HasValue(IsEmpty()));
 }
 
+TEST_F(FunctionSequenceTest, RewindingAfterMigration) {
+  C = llvm::make_unique<FDRController<>>(BQ.get(), B, *W, clock_gettime, 1000);
+
+  // First we construct an arbitrarily deep function enter/call stack.
+  // We also ensure that we are in the same CPU.
+  uint64_t TSC = 1;
+  uint16_t CPU = 1;
+  ASSERT_TRUE(C->functionEnter(1, TSC++, CPU));
+  ASSERT_TRUE(C->functionEnter(2, TSC++, CPU));
+  ASSERT_TRUE(C->functionEnter(3, TSC++, CPU));
+
+  // Next we tail-exit into a new function multiple times.
+  ASSERT_TRUE(C->functionTailExit(3, TSC++, CPU));
+  ASSERT_TRUE(C->functionEnter(4, TSC++, CPU));
+  ASSERT_TRUE(C->functionTailExit(4, TSC++, CPU));
+
+  // But before we enter the next function, we migrate to a different CPU.
+  CPU = 2;
+  ASSERT_TRUE(C->functionEnter(5, TSC++, CPU));
+  ASSERT_TRUE(C->functionTailExit(5, TSC++, CPU));
+  ASSERT_TRUE(C->functionEnter(6, TSC++, CPU));
+
+  // Then we exit them one at a time, in reverse order of entry.
+  ASSERT_TRUE(C->functionExit(6, TSC++, CPU));
+  ASSERT_TRUE(C->functionExit(2, TSC++, CPU));
+  ASSERT_TRUE(C->functionExit(1, TSC++, CPU));
+
+  ASSERT_TRUE(C->flush());
+  ASSERT_EQ(BQ->finalize(), BufferQueue::ErrorCode::Ok);
+
+  // Serialize buffers then test that we can find all the events that span the
+  // CPU migration.
+  std::string Serialized = serialize(*BQ, 3);
+  llvm::DataExtractor DE(Serialized, true, 8);
+  auto TraceOrErr = llvm::xray::loadTrace(DE);
+  EXPECT_THAT_EXPECTED(
+      TraceOrErr,
+      HasValue(ElementsAre(
+          AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::ENTER)),
+          AllOf(FuncId(2), RecordType(llvm::xray::RecordTypes::ENTER)),
+          AllOf(FuncId(2), RecordType(llvm::xray::RecordTypes::EXIT)),
+          AllOf(FuncId(1), RecordType(llvm::xray::RecordTypes::EXIT)))));
+}
+
 class BufferManagementTest : public ::testing::Test {
 protected:
   BufferQueue::Buffer B{};
@@ -262,6 +332,23 @@
   EXPECT_THAT_EXPECTED(TraceOrErr, HasValue(SizeIs(kBuffers * 2)));
 }
 
+TEST_F(BufferManagementTest, HandlesOverflowWithArgs) {
+  uint64_t TSC = 1;
+  uint16_t CPU = 1;
+  uint64_t ARG = 1;
+  for (size_t I = 0; I < kBuffers + 1; ++I) {
+    ASSERT_TRUE(C->functionEnterArg(1, TSC++, CPU, ARG++));
+    ASSERT_TRUE(C->functionExit(1, TSC++, CPU));
+  }
+  ASSERT_TRUE(C->flush());
+  ASSERT_THAT(BQ->finalize(), Eq(BufferQueue::ErrorCode::Ok));
+
+  std::string Serialized = serialize(*BQ, 3);
+  llvm::DataExtractor DE(Serialized, true, 8);
+  auto TraceOrErr = llvm::xray::loadTrace(DE);
+  EXPECT_THAT_EXPECTED(TraceOrErr, HasValue(SizeIs(kBuffers)));
+}
+
 TEST_F(BufferManagementTest, HandlesOverflowWithCustomEvents) {
   uint64_t TSC = 1;
   uint16_t CPU = 1;
diff --git a/lib/xray/tests/unit/function_call_trie_test.cc b/lib/xray/tests/unit/function_call_trie_test.cc
index 9b0f210..01be691 100644
--- a/lib/xray/tests/unit/function_call_trie_test.cc
+++ b/lib/xray/tests/unit/function_call_trie_test.cc
@@ -309,6 +309,36 @@
   EXPECT_EQ(F2.Callees.size(), 0u);
 }
 
+TEST(FunctionCallTrieTest, PlacementNewOnAlignedStorage) {
+  profilingFlags()->setDefaults();
+  typename std::aligned_storage<sizeof(FunctionCallTrie::Allocators),
+                                alignof(FunctionCallTrie::Allocators)>::type
+      AllocatorsStorage;
+  new (&AllocatorsStorage)
+      FunctionCallTrie::Allocators(FunctionCallTrie::InitAllocators());
+  auto *A =
+      reinterpret_cast<FunctionCallTrie::Allocators *>(&AllocatorsStorage);
+
+  typename std::aligned_storage<sizeof(FunctionCallTrie),
+                                alignof(FunctionCallTrie)>::type FCTStorage;
+  new (&FCTStorage) FunctionCallTrie(*A);
+  auto *T = reinterpret_cast<FunctionCallTrie *>(&FCTStorage);
+
+  // Put some data into it.
+  T->enterFunction(1, 0, 0);
+  T->exitFunction(1, 1, 0);
+
+  // Re-initialize the objects in storage.
+  T->~FunctionCallTrie();
+  A->~Allocators();
+  new (A) FunctionCallTrie::Allocators(FunctionCallTrie::InitAllocators());
+  new (T) FunctionCallTrie(*A);
+
+  // Then put some data into it again.
+  T->enterFunction(1, 0, 0);
+  T->exitFunction(1, 1, 0);
+}
+
 } // namespace
 
 } // namespace __xray
diff --git a/lib/xray/tests/unit/profile_collector_test.cc b/lib/xray/tests/unit/profile_collector_test.cc
index f06b702..df786d4 100644
--- a/lib/xray/tests/unit/profile_collector_test.cc
+++ b/lib/xray/tests/unit/profile_collector_test.cc
@@ -110,24 +110,31 @@
 
 TEST(profileCollectorServiceTest, PostSerializeCollect) {
   profilingFlags()->setDefaults();
-  // The most basic use-case (the one we actually only care about) is the one
-  // where we ensure that we can post FunctionCallTrie instances, which are then
-  // destroyed but serialized properly.
-  //
-  // First, we initialise a set of allocators in the local scope. This ensures
-  // that we're able to copy the contents of the FunctionCallTrie that uses
-  // the local allocators.
-  auto Allocators = FunctionCallTrie::InitAllocators();
+  bool Success = false;
+  BufferQueue BQ(profilingFlags()->per_thread_allocator_max,
+                 profilingFlags()->buffers_max, Success);
+  ASSERT_EQ(Success, true);
+  FunctionCallTrie::Allocators::Buffers Buffers;
+  ASSERT_EQ(BQ.getBuffer(Buffers.NodeBuffer), BufferQueue::ErrorCode::Ok);
+  ASSERT_EQ(BQ.getBuffer(Buffers.RootsBuffer), BufferQueue::ErrorCode::Ok);
+  ASSERT_EQ(BQ.getBuffer(Buffers.ShadowStackBuffer),
+            BufferQueue::ErrorCode::Ok);
+  ASSERT_EQ(BQ.getBuffer(Buffers.NodeIdPairBuffer), BufferQueue::ErrorCode::Ok);
+  auto Allocators = FunctionCallTrie::InitAllocatorsFromBuffers(Buffers);
   FunctionCallTrie T(Allocators);
 
-  // Then, we populate the trie with some data.
+  // Populate the trie with some data.
   T.enterFunction(1, 1, 0);
   T.enterFunction(2, 2, 0);
   T.exitFunction(2, 3, 0);
   T.exitFunction(1, 4, 0);
 
+  // Reset the collector data structures.
+  profileCollectorService::reset();
+
   // Then we post the data to the global profile collector service.
-  profileCollectorService::post(T, 1);
+  profileCollectorService::post(&BQ, std::move(T), std::move(Allocators),
+                                std::move(Buffers), 1);
 
   // Then we serialize the data.
   profileCollectorService::serialize();
@@ -174,7 +181,21 @@
 // profileCollectorService. This simulates what the threads being profiled would
 // be doing anyway, but through the XRay logging implementation.
 void threadProcessing() {
-  thread_local auto Allocators = FunctionCallTrie::InitAllocators();
+  static bool Success = false;
+  static BufferQueue BQ(profilingFlags()->per_thread_allocator_max,
+                        profilingFlags()->buffers_max, Success);
+  thread_local FunctionCallTrie::Allocators::Buffers Buffers = [] {
+    FunctionCallTrie::Allocators::Buffers B;
+    BQ.getBuffer(B.NodeBuffer);
+    BQ.getBuffer(B.RootsBuffer);
+    BQ.getBuffer(B.ShadowStackBuffer);
+    BQ.getBuffer(B.NodeIdPairBuffer);
+    return B;
+  }();
+
+  thread_local auto Allocators =
+      FunctionCallTrie::InitAllocatorsFromBuffers(Buffers);
+
   FunctionCallTrie T(Allocators);
 
   T.enterFunction(1, 1, 0);
@@ -182,11 +203,15 @@
   T.exitFunction(2, 3, 0);
   T.exitFunction(1, 4, 0);
 
-  profileCollectorService::post(T, GetTid());
+  profileCollectorService::post(&BQ, std::move(T), std::move(Allocators),
+                                std::move(Buffers), GetTid());
 }
 
 TEST(profileCollectorServiceTest, PostSerializeCollectMultipleThread) {
   profilingFlags()->setDefaults();
+
+  profileCollectorService::reset();
+
   std::thread t1(threadProcessing);
   std::thread t2(threadProcessing);
 
diff --git a/lib/xray/tests/unit/segmented_array_test.cc b/lib/xray/tests/unit/segmented_array_test.cc
index 80991b1..46aeb88 100644
--- a/lib/xray/tests/unit/segmented_array_test.cc
+++ b/lib/xray/tests/unit/segmented_array_test.cc
@@ -2,6 +2,9 @@
 #include "xray_segmented_array.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include <algorithm>
+#include <numeric>
+#include <vector>
 
 namespace __xray {
 namespace {
@@ -221,5 +224,126 @@
   }
 }
 
+TEST(SegmentedArrayTest, PlacementNewOnAlignedStorage) {
+  using AllocatorType = typename Array<ShadowStackEntry>::AllocatorType;
+  typename std::aligned_storage<sizeof(AllocatorType),
+                                alignof(AllocatorType)>::type AllocatorStorage;
+  new (&AllocatorStorage) AllocatorType(1 << 10);
+  auto *A = reinterpret_cast<AllocatorType *>(&AllocatorStorage);
+  typename std::aligned_storage<sizeof(Array<ShadowStackEntry>),
+                                alignof(Array<ShadowStackEntry>)>::type
+      ArrayStorage;
+  new (&ArrayStorage) Array<ShadowStackEntry>(*A);
+  auto *Data = reinterpret_cast<Array<ShadowStackEntry> *>(&ArrayStorage);
+
+  static uint64_t Dummy = 0;
+  constexpr uint64_t Max = 9;
+
+  for (uint64_t i = 0; i < Max; ++i) {
+    auto P = Data->Append({i, &Dummy});
+    ASSERT_NE(P, nullptr);
+    ASSERT_EQ(P->NodePtr, &Dummy);
+    auto &Back = Data->back();
+    ASSERT_EQ(Back.NodePtr, &Dummy);
+    ASSERT_EQ(Back.EntryTSC, i);
+  }
+
+  // Simulate a stack by checking the data from the end as we're trimming.
+  auto Counter = Max;
+  ASSERT_EQ(Data->size(), size_t(Max));
+  while (!Data->empty()) {
+    const auto &Top = Data->back();
+    uint64_t *TopNode = Top.NodePtr;
+    EXPECT_EQ(TopNode, &Dummy) << "Counter = " << Counter;
+    Data->trim(1);
+    --Counter;
+    ASSERT_EQ(Data->size(), size_t(Counter));
+  }
+
+  // Once the stack is exhausted, we re-use the storage.
+  for (uint64_t i = 0; i < Max; ++i) {
+    auto P = Data->Append({i, &Dummy});
+    ASSERT_NE(P, nullptr);
+    ASSERT_EQ(P->NodePtr, &Dummy);
+    auto &Back = Data->back();
+    ASSERT_EQ(Back.NodePtr, &Dummy);
+    ASSERT_EQ(Back.EntryTSC, i);
+  }
+
+  // We re-initialize the storage, by calling the destructor and
+  // placement-new'ing again.
+  Data->~Array();
+  A->~AllocatorType();
+  new (A) AllocatorType(1 << 10);
+  new (Data) Array<ShadowStackEntry>(*A);
+
+  // Then re-do the test.
+  for (uint64_t i = 0; i < Max; ++i) {
+    auto P = Data->Append({i, &Dummy});
+    ASSERT_NE(P, nullptr);
+    ASSERT_EQ(P->NodePtr, &Dummy);
+    auto &Back = Data->back();
+    ASSERT_EQ(Back.NodePtr, &Dummy);
+    ASSERT_EQ(Back.EntryTSC, i);
+  }
+
+  // Simulate a stack by checking the data from the end as we're trimming.
+  Counter = Max;
+  ASSERT_EQ(Data->size(), size_t(Max));
+  while (!Data->empty()) {
+    const auto &Top = Data->back();
+    uint64_t *TopNode = Top.NodePtr;
+    EXPECT_EQ(TopNode, &Dummy) << "Counter = " << Counter;
+    Data->trim(1);
+    --Counter;
+    ASSERT_EQ(Data->size(), size_t(Counter));
+  }
+
+  // Once the stack is exhausted, we re-use the storage.
+  for (uint64_t i = 0; i < Max; ++i) {
+    auto P = Data->Append({i, &Dummy});
+    ASSERT_NE(P, nullptr);
+    ASSERT_EQ(P->NodePtr, &Dummy);
+    auto &Back = Data->back();
+    ASSERT_EQ(Back.NodePtr, &Dummy);
+    ASSERT_EQ(Back.EntryTSC, i);
+  }
+}
+
+TEST(SegmentedArrayTest, ArrayOfPointersIteratorAccess) {
+  using PtrArray = Array<int *>;
+  PtrArray::AllocatorType Alloc(16384);
+  Array<int *> A(Alloc);
+  static constexpr size_t Count = 100;
+  std::vector<int> Integers(Count);
+  std::iota(Integers.begin(), Integers.end(), 0);
+  for (auto &I : Integers)
+    ASSERT_NE(A.Append(&I), nullptr);
+  int V = 0;
+  ASSERT_EQ(A.size(), Count);
+  for (auto P : A) {
+    ASSERT_NE(P, nullptr);
+    ASSERT_EQ(*P, V++);
+  }
+}
+
+TEST(SegmentedArrayTest, ArrayOfPointersIteratorAccessExhaustion) {
+  using PtrArray = Array<int *>;
+  PtrArray::AllocatorType Alloc(4096);
+  Array<int *> A(Alloc);
+  static constexpr size_t Count = 1000;
+  std::vector<int> Integers(Count);
+  std::iota(Integers.begin(), Integers.end(), 0);
+  for (auto &I : Integers)
+    if (A.Append(&I) == nullptr)
+      break;
+  int V = 0;
+  ASSERT_LT(A.size(), Count);
+  for (auto P : A) {
+    ASSERT_NE(P, nullptr);
+    ASSERT_EQ(*P, V++);
+  }
+}
+
 } // namespace
 } // namespace __xray
diff --git a/lib/xray/tests/unit/test_helpers.cc b/lib/xray/tests/unit/test_helpers.cc
index 771a96e..284492d 100644
--- a/lib/xray/tests/unit/test_helpers.cc
+++ b/lib/xray/tests/unit/test_helpers.cc
@@ -82,7 +82,7 @@
   Serialized.append(reinterpret_cast<const char *>(&HeaderStorage),
                     sizeof(XRayFileHeader));
   Buffers.apply([&](const BufferQueue::Buffer &B) {
-    auto Size = atomic_load_relaxed(&B.Extents);
+    auto Size = atomic_load_relaxed(B.Extents);
     auto Extents =
         createMetadataRecord<MetadataRecord::RecordKinds::BufferExtents>(Size);
     Serialized.append(reinterpret_cast<const char *>(&Extents),
diff --git a/lib/xray/xray_allocator.h b/lib/xray/xray_allocator.h
index f77bccb..907c545 100644
--- a/lib/xray/xray_allocator.h
+++ b/lib/xray/xray_allocator.h
@@ -19,7 +19,13 @@
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "sanitizer_common/sanitizer_mutex.h"
+#if SANITIZER_FUCHSIA
+#include <zircon/process.h>
+#include <zircon/status.h>
+#include <zircon/syscalls.h>
+#else
 #include "sanitizer_common/sanitizer_posix.h"
+#endif
 #include "xray_defs.h"
 #include "xray_utils.h"
 #include <cstddef>
@@ -33,9 +39,31 @@
 // mmap'ed memory to back the allocators.
 template <class T> T *allocate() XRAY_NEVER_INSTRUMENT {
   uptr RoundedSize = RoundUpTo(sizeof(T), GetPageSizeCached());
+#if SANITIZER_FUCHSIA
+  zx_handle_t Vmo;
+  zx_status_t Status = _zx_vmo_create(RoundedSize, 0, &Vmo);
+  if (Status != ZX_OK) {
+    if (Verbosity())
+      Report("XRay Profiling: Failed to create VMO of size %zu: %s\n",
+             sizeof(T), _zx_status_get_string(Status));
+    return nullptr;
+  }
+  uintptr_t B;
+  Status =
+      _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0,
+                   Vmo, 0, sizeof(T), &B);
+  _zx_handle_close(Vmo);
+  if (Status != ZX_OK) {
+    if (Verbosity())
+      Report("XRay Profiling: Failed to map VMAR of size %zu: %s\n", sizeof(T),
+             _zx_status_get_string(Status));
+    return nullptr;
+  }
+  return reinterpret_cast<T *>(B);
+#else
   uptr B = internal_mmap(NULL, RoundedSize, PROT_READ | PROT_WRITE,
                          MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-  int ErrNo;
+  int ErrNo = 0;
   if (UNLIKELY(internal_iserror(B, &ErrNo))) {
     if (Verbosity())
       Report(
@@ -43,6 +71,7 @@
           RoundedSize, B);
     return nullptr;
   }
+#endif
   return reinterpret_cast<T *>(B);
 }
 
@@ -50,14 +79,40 @@
   if (B == nullptr)
     return;
   uptr RoundedSize = RoundUpTo(sizeof(T), GetPageSizeCached());
+#if SANITIZER_FUCHSIA
+  _zx_vmar_unmap(_zx_vmar_root_self(), reinterpret_cast<uintptr_t>(B),
+                 RoundedSize);
+#else
   internal_munmap(B, RoundedSize);
+#endif
 }
 
-template <class T = uint8_t> T *allocateBuffer(size_t S) XRAY_NEVER_INSTRUMENT {
+template <class T = unsigned char>
+T *allocateBuffer(size_t S) XRAY_NEVER_INSTRUMENT {
   uptr RoundedSize = RoundUpTo(S * sizeof(T), GetPageSizeCached());
+#if SANITIZER_FUCHSIA
+  zx_handle_t Vmo;
+  zx_status_t Status = _zx_vmo_create(RoundedSize, 0, &Vmo);
+  if (Status != ZX_OK) {
+    if (Verbosity())
+      Report("XRay Profiling: Failed to create VMO of size %zu: %s\n", S,
+             _zx_status_get_string(Status));
+    return nullptr;
+  }
+  uintptr_t B;
+  Status = _zx_vmar_map(_zx_vmar_root_self(),
+                        ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0, Vmo, 0, S, &B);
+  _zx_handle_close(Vmo);
+  if (Status != ZX_OK) {
+    if (Verbosity())
+      Report("XRay Profiling: Failed to map VMAR of size %zu: %s\n", S,
+             _zx_status_get_string(Status));
+    return nullptr;
+  }
+#else
   uptr B = internal_mmap(NULL, RoundedSize, PROT_READ | PROT_WRITE,
                          MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-  int ErrNo;
+  int ErrNo = 0;
   if (UNLIKELY(internal_iserror(B, &ErrNo))) {
     if (Verbosity())
       Report(
@@ -65,6 +120,7 @@
           RoundedSize, B);
     return nullptr;
   }
+#endif
   return reinterpret_cast<T *>(B);
 }
 
@@ -72,7 +128,12 @@
   if (B == nullptr)
     return;
   uptr RoundedSize = RoundUpTo(S * sizeof(T), GetPageSizeCached());
+#if SANITIZER_FUCHSIA
+  _zx_vmar_unmap(_zx_vmar_root_self(), reinterpret_cast<uintptr_t>(B),
+                 RoundedSize);
+#else
   internal_munmap(B, RoundedSize);
+#endif
 }
 
 template <class T, class... U>
@@ -110,10 +171,11 @@
   };
 
 private:
-  const size_t MaxMemory{0};
-  uint8_t *BackingStore = nullptr;
-  uint8_t *AlignedNextBlock = nullptr;
+  size_t MaxMemory{0};
+  unsigned char *BackingStore = nullptr;
+  unsigned char *AlignedNextBlock = nullptr;
   size_t AllocatedBlocks = 0;
+  bool Owned;
   SpinMutex Mutex{};
 
   void *Alloc() XRAY_NEVER_INSTRUMENT {
@@ -141,33 +203,82 @@
         return nullptr;
       }
 
-      AlignedNextBlock = reinterpret_cast<uint8_t *>(AlignedNextBlockNum);
+      AlignedNextBlock = reinterpret_cast<unsigned char *>(AlignedNextBlockNum);
 
       // Assert that AlignedNextBlock is cache-line aligned.
       DCHECK_EQ(reinterpret_cast<uintptr_t>(AlignedNextBlock) % kCacheLineSize,
                 0);
     }
 
-    if ((AllocatedBlocks * Block::Size) >= MaxMemory)
+    if (((AllocatedBlocks + 1) * Block::Size) > MaxMemory)
       return nullptr;
 
     // Align the pointer we'd like to return to an appropriate alignment, then
     // advance the pointer from where to start allocations.
     void *Result = AlignedNextBlock;
-    AlignedNextBlock = reinterpret_cast<uint8_t *>(
-        reinterpret_cast<uint8_t *>(AlignedNextBlock) + N);
+    AlignedNextBlock =
+        reinterpret_cast<unsigned char *>(AlignedNextBlock) + Block::Size;
     ++AllocatedBlocks;
     return Result;
   }
 
 public:
   explicit Allocator(size_t M) XRAY_NEVER_INSTRUMENT
-      : MaxMemory(nearest_boundary(M, kCacheLineSize)) {}
+      : MaxMemory(RoundUpTo(M, kCacheLineSize)),
+        BackingStore(nullptr),
+        AlignedNextBlock(nullptr),
+        AllocatedBlocks(0),
+        Owned(true),
+        Mutex() {}
+
+  explicit Allocator(void *P, size_t M) XRAY_NEVER_INSTRUMENT
+      : MaxMemory(M),
+        BackingStore(reinterpret_cast<unsigned char *>(P)),
+        AlignedNextBlock(reinterpret_cast<unsigned char *>(P)),
+        AllocatedBlocks(0),
+        Owned(false),
+        Mutex() {}
+
+  Allocator(const Allocator &) = delete;
+  Allocator &operator=(const Allocator &) = delete;
+
+  Allocator(Allocator &&O) XRAY_NEVER_INSTRUMENT {
+    SpinMutexLock L0(&Mutex);
+    SpinMutexLock L1(&O.Mutex);
+    MaxMemory = O.MaxMemory;
+    O.MaxMemory = 0;
+    BackingStore = O.BackingStore;
+    O.BackingStore = nullptr;
+    AlignedNextBlock = O.AlignedNextBlock;
+    O.AlignedNextBlock = nullptr;
+    AllocatedBlocks = O.AllocatedBlocks;
+    O.AllocatedBlocks = 0;
+    Owned = O.Owned;
+    O.Owned = false;
+  }
+
+  Allocator &operator=(Allocator &&O) XRAY_NEVER_INSTRUMENT {
+    SpinMutexLock L0(&Mutex);
+    SpinMutexLock L1(&O.Mutex);
+    MaxMemory = O.MaxMemory;
+    O.MaxMemory = 0;
+    if (BackingStore != nullptr)
+      deallocateBuffer(BackingStore, MaxMemory);
+    BackingStore = O.BackingStore;
+    O.BackingStore = nullptr;
+    AlignedNextBlock = O.AlignedNextBlock;
+    O.AlignedNextBlock = nullptr;
+    AllocatedBlocks = O.AllocatedBlocks;
+    O.AllocatedBlocks = 0;
+    Owned = O.Owned;
+    O.Owned = false;
+    return *this;
+  }
 
   Block Allocate() XRAY_NEVER_INSTRUMENT { return {Alloc()}; }
 
   ~Allocator() NOEXCEPT XRAY_NEVER_INSTRUMENT {
-    if (BackingStore != nullptr) {
+    if (Owned && BackingStore != nullptr) {
       deallocateBuffer(BackingStore, MaxMemory);
     }
   }
diff --git a/lib/xray/xray_basic_logging.cc b/lib/xray/xray_basic_logging.cc
index cd8ee8f..b65c0e4 100644
--- a/lib/xray/xray_basic_logging.cc
+++ b/lib/xray/xray_basic_logging.cc
@@ -19,7 +19,9 @@
 #include <fcntl.h>
 #include <pthread.h>
 #include <sys/stat.h>
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD || SANITIZER_MAC
 #include <sys/syscall.h>
+#endif
 #include <sys/types.h>
 #include <time.h>
 #include <unistd.h>
diff --git a/lib/xray/xray_buffer_queue.cc b/lib/xray/xray_buffer_queue.cc
index 3cfe0bc..7d0e5a1 100644
--- a/lib/xray/xray_buffer_queue.cc
+++ b/lib/xray/xray_buffer_queue.cc
@@ -16,14 +16,15 @@
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_libc.h"
+#if !SANITIZER_FUCHSIA
 #include "sanitizer_common/sanitizer_posix.h"
+#endif
 #include "xray_allocator.h"
 #include "xray_defs.h"
 #include <memory>
 #include <sys/mman.h>
 
 using namespace __xray;
-using namespace __sanitizer;
 
 namespace {
 
@@ -53,6 +54,18 @@
   atomic_fetch_add(&C->RefCount, 1, memory_order_acq_rel);
 }
 
+// We use a struct to ensure that we are allocating one atomic_uint64_t per
+// cache line. This allows us to not worry about false-sharing among atomic
+// objects being updated (constantly) by different threads.
+struct ExtentsPadded {
+  union {
+    atomic_uint64_t Extents;
+    unsigned char Storage[kCacheLineSize];
+  };
+};
+
+constexpr size_t kExtentsSize = sizeof(ExtentsPadded);
+
 } // namespace
 
 BufferQueue::ErrorCode BufferQueue::init(size_t BS, size_t BC) {
@@ -71,13 +84,25 @@
   if (BackingStore == nullptr)
     return BufferQueue::ErrorCode::NotEnoughMemory;
 
-  auto CleanupBackingStore = __sanitizer::at_scope_exit([&, this] {
+  auto CleanupBackingStore = at_scope_exit([&, this] {
     if (Success)
       return;
     deallocControlBlock(BackingStore, BufferSize, BufferCount);
     BackingStore = nullptr;
   });
 
+  // Initialize enough atomic_uint64_t instances, each
+  ExtentsBackingStore = allocControlBlock(kExtentsSize, BufferCount);
+  if (ExtentsBackingStore == nullptr)
+    return BufferQueue::ErrorCode::NotEnoughMemory;
+
+  auto CleanupExtentsBackingStore = at_scope_exit([&, this] {
+    if (Success)
+      return;
+    deallocControlBlock(ExtentsBackingStore, kExtentsSize, BufferCount);
+    ExtentsBackingStore = nullptr;
+  });
+
   Buffers = initArray<BufferRep>(BufferCount);
   if (Buffers == nullptr)
     return BufferQueue::ErrorCode::NotEnoughMemory;
@@ -89,6 +114,7 @@
   // First, we initialize the refcount in the ControlBlock, which we treat as
   // being at the start of the BackingStore pointer.
   atomic_store(&BackingStore->RefCount, 1, memory_order_release);
+  atomic_store(&ExtentsBackingStore->RefCount, 1, memory_order_release);
 
   // Then we initialise the individual buffers that sub-divide the whole backing
   // store. Each buffer will start at the `Data` member of the ControlBlock, and
@@ -96,11 +122,15 @@
   for (size_t i = 0; i < BufferCount; ++i) {
     auto &T = Buffers[i];
     auto &Buf = T.Buff;
-    atomic_store(&Buf.Extents, 0, memory_order_release);
+    auto *E = reinterpret_cast<ExtentsPadded *>(&ExtentsBackingStore->Data +
+                                                (kExtentsSize * i));
+    Buf.Extents = &E->Extents;
+    atomic_store(Buf.Extents, 0, memory_order_release);
     Buf.Generation = generation();
     Buf.Data = &BackingStore->Data + (BufferSize * i);
     Buf.Size = BufferSize;
     Buf.BackingStore = BackingStore;
+    Buf.ExtentsBackingStore = ExtentsBackingStore;
     Buf.Count = BufferCount;
     T.Used = false;
   }
@@ -120,6 +150,7 @@
       Mutex(),
       Finalizing{1},
       BackingStore(nullptr),
+      ExtentsBackingStore(nullptr),
       Buffers(nullptr),
       Next(Buffers),
       First(Buffers),
@@ -144,6 +175,7 @@
   }
 
   incRefCount(BackingStore);
+  incRefCount(ExtentsBackingStore);
   Buf = B->Buff;
   Buf.Generation = generation();
   B->Used = true;
@@ -159,6 +191,7 @@
     if (Buf.Generation != generation() || LiveBuffers == 0) {
       Buf = {};
       decRefCount(Buf.BackingStore, Buf.Size, Buf.Count);
+      decRefCount(Buf.ExtentsBackingStore, kExtentsSize, Buf.Count);
       return BufferQueue::ErrorCode::Ok;
     }
 
@@ -176,8 +209,8 @@
   B->Buff = Buf;
   B->Used = true;
   decRefCount(Buf.BackingStore, Buf.Size, Buf.Count);
-  atomic_store(&B->Buff.Extents,
-               atomic_load(&Buf.Extents, memory_order_acquire),
+  decRefCount(Buf.ExtentsBackingStore, kExtentsSize, Buf.Count);
+  atomic_store(B->Buff.Extents, atomic_load(Buf.Extents, memory_order_acquire),
                memory_order_release);
   Buf = {};
   return ErrorCode::Ok;
@@ -194,7 +227,9 @@
     B->~BufferRep();
   deallocateBuffer(Buffers, BufferCount);
   decRefCount(BackingStore, BufferSize, BufferCount);
+  decRefCount(ExtentsBackingStore, kExtentsSize, BufferCount);
   BackingStore = nullptr;
+  ExtentsBackingStore = nullptr;
   Buffers = nullptr;
   BufferCount = 0;
   BufferSize = 0;
diff --git a/lib/xray/xray_buffer_queue.h b/lib/xray/xray_buffer_queue.h
index a60f7c1..ef2b433 100644
--- a/lib/xray/xray_buffer_queue.h
+++ b/lib/xray/xray_buffer_queue.h
@@ -32,10 +32,11 @@
 class BufferQueue {
 public:
   /// ControlBlock represents the memory layout of how we interpret the backing
-  /// store for all buffers managed by a BufferQueue instance. The ControlBlock
-  /// has the reference count as the first member, sized according to
-  /// platform-specific cache-line size. We never use the Buffer member of the
-  /// union, which is only there for compiler-supported alignment and sizing.
+  /// store for all buffers and extents managed by a BufferQueue instance. The
+  /// ControlBlock has the reference count as the first member, sized according
+  /// to platform-specific cache-line size. We never use the Buffer member of
+  /// the union, which is only there for compiler-supported alignment and
+  /// sizing.
   ///
   /// This ensures that the `Data` member will be placed at least kCacheLineSize
   /// bytes from the beginning of the structure.
@@ -52,7 +53,7 @@
   };
 
   struct Buffer {
-    atomic_uint64_t Extents{0};
+    atomic_uint64_t *Extents = nullptr;
     uint64_t Generation{0};
     void *Data = nullptr;
     size_t Size = 0;
@@ -60,6 +61,7 @@
   private:
     friend class BufferQueue;
     ControlBlock *BackingStore = nullptr;
+    ControlBlock *ExtentsBackingStore = nullptr;
     size_t Count = 0;
   };
 
@@ -142,6 +144,9 @@
   // The collocated ControlBlock and buffer storage.
   ControlBlock *BackingStore;
 
+  // The collocated ControlBlock and extents storage.
+  ControlBlock *ExtentsBackingStore;
+
   // A dynamically allocated array of BufferRep instances.
   BufferRep *Buffers;
 
diff --git a/lib/xray/xray_fdr_controller.h b/lib/xray/xray_fdr_controller.h
index 5c04cbf..d44d030 100644
--- a/lib/xray/xray_fdr_controller.h
+++ b/lib/xray/xray_fdr_controller.h
@@ -64,7 +64,7 @@
     First = true;
     UndoableFunctionEnters = 0;
     UndoableTailExits = 0;
-    atomic_store(&B.Extents, 0, memory_order_release);
+    atomic_store(B.Extents, 0, memory_order_release);
     return true;
   }
 
@@ -123,7 +123,7 @@
     if (First) {
       First = false;
       W.resetRecord();
-      atomic_store(&B.Extents, 0, memory_order_release);
+      atomic_store(B.Extents, 0, memory_order_release);
       return setupNewBuffer();
     }
 
@@ -252,9 +252,13 @@
     if (PreambleStatus == PreambleResult::InvalidBuffer)
       return returnBuffer();
 
-    UndoableFunctionEnters = (PreambleStatus == PreambleResult::WroteMetadata)
-                                 ? 1
-                                 : UndoableFunctionEnters + 1;
+    if (PreambleStatus == PreambleResult::WroteMetadata) {
+      UndoableFunctionEnters = 1;
+      UndoableTailExits = 0;
+    } else {
+      ++UndoableFunctionEnters;
+    }
+
     auto Delta = TSC - LatestTSC;
     LastFunctionEntryTSC = TSC;
     LatestTSC = TSC;
@@ -300,9 +304,8 @@
     UndoableFunctionEnters = 0;
     UndoableTailExits = 0;
 
-    W.writeFunction(FDRLogWriter::FunctionRecordKind::EnterArg, mask(FuncId),
-                    Delta);
-    return W.writeMetadata<MetadataRecord::RecordKinds::CallArgument>(Arg);
+    return W.writeFunctionWithArg(FDRLogWriter::FunctionRecordKind::EnterArg,
+                                  mask(FuncId), Delta, Arg);
   }
 
   bool functionExit(int32_t FuncId, uint64_t TSC,
diff --git a/lib/xray/xray_fdr_log_writer.h b/lib/xray/xray_fdr_log_writer.h
index 5f94969..7712e13 100644
--- a/lib/xray/xray_fdr_log_writer.h
+++ b/lib/xray/xray_fdr_log_writer.h
@@ -41,13 +41,32 @@
                 Index >= std::tuple_size<typename std::remove_reference<
                              Tuple>::type>::value,
                 int>::type = 0>
-  static void serializeTo(char *, Tuple &&){};
+  static void serializeTo(char *, Tuple &&) {}
 };
 
 using Serializer = SerializerImpl<0>;
 
+template <class Tuple, size_t Index> struct AggregateSizesImpl {
+  static constexpr size_t value =
+      sizeof(typename std::tuple_element<Index, Tuple>::type) +
+      AggregateSizesImpl<Tuple, Index - 1>::value;
+};
+
+template <class Tuple> struct AggregateSizesImpl<Tuple, 0> {
+  static constexpr size_t value =
+      sizeof(typename std::tuple_element<0, Tuple>::type);
+};
+
+template <class Tuple> struct AggregateSizes {
+  static constexpr size_t value =
+      AggregateSizesImpl<Tuple, std::tuple_size<Tuple>::value - 1>::value;
+};
+
 template <MetadataRecord::RecordKinds Kind, class... DataTypes>
 MetadataRecord createMetadataRecord(DataTypes &&... Ds) {
+  static_assert(AggregateSizes<std::tuple<DataTypes...>>::value <=
+                    sizeof(MetadataRecord) - 1,
+                "Metadata payload longer than metadata buffer!");
   MetadataRecord R;
   R.Type = 1;
   R.RecordKind = static_cast<uint8_t>(Kind);
@@ -63,7 +82,11 @@
   template <class T> void writeRecord(const T &R) {
     internal_memcpy(NextRecord, reinterpret_cast<const char *>(&R), sizeof(T));
     NextRecord += sizeof(T);
-    atomic_fetch_add(&Buffer.Extents, sizeof(T), memory_order_acq_rel);
+    // We need this atomic fence here to ensure that other threads attempting to
+    // read the bytes in the buffer will see the writes committed before the
+    // extents are updated.
+    atomic_thread_fence(memory_order_release);
+    atomic_fetch_add(Buffer.Extents, sizeof(T), memory_order_acq_rel);
   }
 
 public:
@@ -89,7 +112,11 @@
     constexpr auto Size = sizeof(MetadataRecord) * N;
     internal_memcpy(NextRecord, reinterpret_cast<const char *>(Recs), Size);
     NextRecord += Size;
-    atomic_fetch_add(&Buffer.Extents, Size, memory_order_acq_rel);
+    // We need this atomic fence here to ensure that other threads attempting to
+    // read the bytes in the buffer will see the writes committed before the
+    // extents are updated.
+    atomic_thread_fence(memory_order_release);
+    atomic_fetch_add(Buffer.Extents, Size, memory_order_acq_rel);
     return Size;
   }
 
@@ -110,6 +137,34 @@
     return true;
   }
 
+  bool writeFunctionWithArg(FunctionRecordKind Kind, int32_t FuncId,
+                            int32_t Delta, uint64_t Arg) {
+    // We need to write the function with arg into the buffer, and then
+    // atomically update the buffer extents. This ensures that any reads
+    // synchronised on the buffer extents record will always see the writes
+    // that happen before the atomic update.
+    FunctionRecord R;
+    R.Type = 0;
+    R.RecordKind = uint8_t(Kind);
+    R.FuncId = FuncId;
+    R.TSCDelta = Delta;
+    MetadataRecord A =
+        createMetadataRecord<MetadataRecord::RecordKinds::CallArgument>(Arg);
+    NextRecord = reinterpret_cast<char *>(internal_memcpy(
+                     NextRecord, reinterpret_cast<char *>(&R), sizeof(R))) +
+                 sizeof(R);
+    NextRecord = reinterpret_cast<char *>(internal_memcpy(
+                     NextRecord, reinterpret_cast<char *>(&A), sizeof(A))) +
+                 sizeof(A);
+    // We need this atomic fence here to ensure that other threads attempting to
+    // read the bytes in the buffer will see the writes committed before the
+    // extents are updated.
+    atomic_thread_fence(memory_order_release);
+    atomic_fetch_add(Buffer.Extents, sizeof(R) + sizeof(A),
+                     memory_order_acq_rel);
+    return true;
+  }
+
   bool writeCustomEvent(int32_t Delta, const void *Event, int32_t EventSize) {
     // We write the metadata record and the custom event data into the buffer
     // first, before we atomically update the extents for the buffer. This
@@ -125,7 +180,12 @@
     NextRecord = reinterpret_cast<char *>(
                      internal_memcpy(NextRecord, Event, EventSize)) +
                  EventSize;
-    atomic_fetch_add(&Buffer.Extents, sizeof(R) + EventSize,
+
+    // We need this atomic fence here to ensure that other threads attempting to
+    // read the bytes in the buffer will see the writes committed before the
+    // extents are updated.
+    atomic_thread_fence(memory_order_release);
+    atomic_fetch_add(Buffer.Extents, sizeof(R) + EventSize,
                      memory_order_acq_rel);
     return true;
   }
@@ -143,7 +203,12 @@
     NextRecord = reinterpret_cast<char *>(
                      internal_memcpy(NextRecord, Event, EventSize)) +
                  EventSize;
-    atomic_fetch_add(&Buffer.Extents, EventSize, memory_order_acq_rel);
+
+    // We need this atomic fence here to ensure that other threads attempting to
+    // read the bytes in the buffer will see the writes committed before the
+    // extents are updated.
+    atomic_thread_fence(memory_order_release);
+    atomic_fetch_add(Buffer.Extents, EventSize, memory_order_acq_rel);
     return true;
   }
 
@@ -151,13 +216,13 @@
 
   void resetRecord() {
     NextRecord = reinterpret_cast<char *>(Buffer.Data);
-    atomic_store(&Buffer.Extents, 0, memory_order_release);
+    atomic_store(Buffer.Extents, 0, memory_order_release);
   }
 
   void undoWrites(size_t B) {
     DCHECK_GE(NextRecord - B, reinterpret_cast<char *>(Buffer.Data));
     NextRecord -= B;
-    atomic_fetch_sub(&Buffer.Extents, B, memory_order_acq_rel);
+    atomic_fetch_sub(Buffer.Extents, B, memory_order_acq_rel);
   }
 
 }; // namespace __xray
diff --git a/lib/xray/xray_fdr_logging.cc b/lib/xray/xray_fdr_logging.cc
index 83f4f97..3893b7a 100644
--- a/lib/xray/xray_fdr_logging.cc
+++ b/lib/xray/xray_fdr_logging.cc
@@ -20,7 +20,6 @@
 #include <limits>
 #include <memory>
 #include <pthread.h>
-#include <sys/syscall.h>
 #include <sys/time.h>
 #include <time.h>
 #include <unistd.h>
@@ -243,7 +242,14 @@
   // out to disk. The difference here would be that we still write "empty"
   // buffers, or at least go through the iterators faithfully to let the
   // handlers see the empty buffers in the queue.
-  auto BufferSize = atomic_load(&It->Extents, memory_order_acquire);
+  //
+  // We need this atomic fence here to ensure that writes happening to the
+  // buffer have been committed before we load the extents atomically. Because
+  // the buffer is not explicitly synchronised across threads, we rely on the
+  // fence ordering to ensure that writes we expect to have been completed
+  // before the fence are fully committed before we read the extents.
+  atomic_thread_fence(memory_order_acquire);
+  auto BufferSize = atomic_load(It->Extents, memory_order_acquire);
   SerializedBufferSize = BufferSize + sizeof(MetadataRecord);
   CurrentBuffer = allocateBuffer(SerializedBufferSize);
   if (CurrentBuffer == nullptr)
@@ -357,7 +363,7 @@
     // still use a Metadata record, but fill in the extents instead for the
     // data.
     MetadataRecord ExtentsRecord;
-    auto BufferExtents = atomic_load(&B.Extents, memory_order_acquire);
+    auto BufferExtents = atomic_load(B.Extents, memory_order_acquire);
     DCHECK(BufferExtents <= B.Size);
     ExtentsRecord.Type = uint8_t(RecordType::Metadata);
     ExtentsRecord.RecordKind =
diff --git a/lib/xray/xray_function_call_trie.h b/lib/xray/xray_function_call_trie.h
index 4a6a94c..d01ad20 100644
--- a/lib/xray/xray_function_call_trie.h
+++ b/lib/xray/xray_function_call_trie.h
@@ -15,6 +15,7 @@
 #ifndef XRAY_FUNCTION_CALL_TRIE_H
 #define XRAY_FUNCTION_CALL_TRIE_H
 
+#include "xray_buffer_queue.h"
 #include "xray_defs.h"
 #include "xray_profiling_flags.h"
 #include "xray_segmented_array.h"
@@ -98,9 +99,6 @@
   struct NodeIdPair {
     Node *NodePtr;
     int32_t FId;
-
-    // Constructor for inplace-construction.
-    NodeIdPair(Node *N, int32_t F) : NodePtr(N), FId(F) {}
   };
 
   using NodeIdPairArray = Array<NodeIdPair>;
@@ -118,15 +116,6 @@
     uint64_t CumulativeLocalTime; // Typically in TSC deltas, not wall-time.
     int32_t FId;
 
-    // We add a constructor here to allow us to inplace-construct through
-    // Array<...>'s AppendEmplace.
-    Node(Node *P, NodeIdPairAllocatorType &A, uint64_t CC, uint64_t CLT,
-         int32_t F) XRAY_NEVER_INSTRUMENT : Parent(P),
-                                            Callees(A),
-                                            CallCount(CC),
-                                            CumulativeLocalTime(CLT),
-                                            FId(F) {}
-
     // TODO: Include the compact histogram.
   };
 
@@ -135,13 +124,6 @@
     uint64_t EntryTSC;
     Node *NodePtr;
     uint16_t EntryCPU;
-
-    // We add a constructor here to allow us to inplace-construct through
-    // Array<...>'s AppendEmplace.
-    ShadowStackEntry(uint64_t T, Node *N, uint16_t C) XRAY_NEVER_INSTRUMENT
-        : EntryTSC{T},
-          NodePtr{N},
-          EntryCPU{C} {}
   };
 
   using NodeArray = Array<Node>;
@@ -156,20 +138,100 @@
     using RootAllocatorType = RootArray::AllocatorType;
     using ShadowStackAllocatorType = ShadowStackArray::AllocatorType;
 
+    // Use hosted aligned storage members to allow for trivial move and init.
+    // This also allows us to sidestep the potential-failing allocation issue.
+    typename std::aligned_storage<sizeof(NodeAllocatorType),
+                                  alignof(NodeAllocatorType)>::type
+        NodeAllocatorStorage;
+    typename std::aligned_storage<sizeof(RootAllocatorType),
+                                  alignof(RootAllocatorType)>::type
+        RootAllocatorStorage;
+    typename std::aligned_storage<sizeof(ShadowStackAllocatorType),
+                                  alignof(ShadowStackAllocatorType)>::type
+        ShadowStackAllocatorStorage;
+    typename std::aligned_storage<sizeof(NodeIdPairAllocatorType),
+                                  alignof(NodeIdPairAllocatorType)>::type
+        NodeIdPairAllocatorStorage;
+
     NodeAllocatorType *NodeAllocator = nullptr;
     RootAllocatorType *RootAllocator = nullptr;
     ShadowStackAllocatorType *ShadowStackAllocator = nullptr;
     NodeIdPairAllocatorType *NodeIdPairAllocator = nullptr;
 
-    Allocators() {}
+    Allocators() = default;
     Allocators(const Allocators &) = delete;
     Allocators &operator=(const Allocators &) = delete;
 
-    Allocators(Allocators &&O) XRAY_NEVER_INSTRUMENT
-        : NodeAllocator(O.NodeAllocator),
-          RootAllocator(O.RootAllocator),
-          ShadowStackAllocator(O.ShadowStackAllocator),
-          NodeIdPairAllocator(O.NodeIdPairAllocator) {
+    struct Buffers {
+      BufferQueue::Buffer NodeBuffer;
+      BufferQueue::Buffer RootsBuffer;
+      BufferQueue::Buffer ShadowStackBuffer;
+      BufferQueue::Buffer NodeIdPairBuffer;
+    };
+
+    explicit Allocators(Buffers &B) XRAY_NEVER_INSTRUMENT {
+      new (&NodeAllocatorStorage)
+          NodeAllocatorType(B.NodeBuffer.Data, B.NodeBuffer.Size);
+      NodeAllocator =
+          reinterpret_cast<NodeAllocatorType *>(&NodeAllocatorStorage);
+
+      new (&RootAllocatorStorage)
+          RootAllocatorType(B.RootsBuffer.Data, B.RootsBuffer.Size);
+      RootAllocator =
+          reinterpret_cast<RootAllocatorType *>(&RootAllocatorStorage);
+
+      new (&ShadowStackAllocatorStorage) ShadowStackAllocatorType(
+          B.ShadowStackBuffer.Data, B.ShadowStackBuffer.Size);
+      ShadowStackAllocator = reinterpret_cast<ShadowStackAllocatorType *>(
+          &ShadowStackAllocatorStorage);
+
+      new (&NodeIdPairAllocatorStorage) NodeIdPairAllocatorType(
+          B.NodeIdPairBuffer.Data, B.NodeIdPairBuffer.Size);
+      NodeIdPairAllocator = reinterpret_cast<NodeIdPairAllocatorType *>(
+          &NodeIdPairAllocatorStorage);
+    }
+
+    explicit Allocators(uptr Max) XRAY_NEVER_INSTRUMENT {
+      new (&NodeAllocatorStorage) NodeAllocatorType(Max);
+      NodeAllocator =
+          reinterpret_cast<NodeAllocatorType *>(&NodeAllocatorStorage);
+
+      new (&RootAllocatorStorage) RootAllocatorType(Max);
+      RootAllocator =
+          reinterpret_cast<RootAllocatorType *>(&RootAllocatorStorage);
+
+      new (&ShadowStackAllocatorStorage) ShadowStackAllocatorType(Max);
+      ShadowStackAllocator = reinterpret_cast<ShadowStackAllocatorType *>(
+          &ShadowStackAllocatorStorage);
+
+      new (&NodeIdPairAllocatorStorage) NodeIdPairAllocatorType(Max);
+      NodeIdPairAllocator = reinterpret_cast<NodeIdPairAllocatorType *>(
+          &NodeIdPairAllocatorStorage);
+    }
+
+    Allocators(Allocators &&O) XRAY_NEVER_INSTRUMENT {
+      // Here we rely on the safety of memcpy'ing contents of the storage
+      // members, and then pointing the source pointers to nullptr.
+      internal_memcpy(&NodeAllocatorStorage, &O.NodeAllocatorStorage,
+                      sizeof(NodeAllocatorType));
+      internal_memcpy(&RootAllocatorStorage, &O.RootAllocatorStorage,
+                      sizeof(RootAllocatorType));
+      internal_memcpy(&ShadowStackAllocatorStorage,
+                      &O.ShadowStackAllocatorStorage,
+                      sizeof(ShadowStackAllocatorType));
+      internal_memcpy(&NodeIdPairAllocatorStorage,
+                      &O.NodeIdPairAllocatorStorage,
+                      sizeof(NodeIdPairAllocatorType));
+
+      NodeAllocator =
+          reinterpret_cast<NodeAllocatorType *>(&NodeAllocatorStorage);
+      RootAllocator =
+          reinterpret_cast<RootAllocatorType *>(&RootAllocatorStorage);
+      ShadowStackAllocator = reinterpret_cast<ShadowStackAllocatorType *>(
+          &ShadowStackAllocatorStorage);
+      NodeIdPairAllocator = reinterpret_cast<NodeIdPairAllocatorType *>(
+          &NodeIdPairAllocatorStorage);
+
       O.NodeAllocator = nullptr;
       O.RootAllocator = nullptr;
       O.ShadowStackAllocator = nullptr;
@@ -177,79 +239,83 @@
     }
 
     Allocators &operator=(Allocators &&O) XRAY_NEVER_INSTRUMENT {
-      {
-        auto Tmp = O.NodeAllocator;
-        O.NodeAllocator = this->NodeAllocator;
-        this->NodeAllocator = Tmp;
+      // When moving into an existing instance, we ensure that we clean up the
+      // current allocators.
+      if (NodeAllocator)
+        NodeAllocator->~NodeAllocatorType();
+      if (O.NodeAllocator) {
+        new (&NodeAllocatorStorage)
+            NodeAllocatorType(std::move(*O.NodeAllocator));
+        NodeAllocator =
+            reinterpret_cast<NodeAllocatorType *>(&NodeAllocatorStorage);
+        O.NodeAllocator = nullptr;
+      } else {
+        NodeAllocator = nullptr;
       }
-      {
-        auto Tmp = O.RootAllocator;
-        O.RootAllocator = this->RootAllocator;
-        this->RootAllocator = Tmp;
+
+      if (RootAllocator)
+        RootAllocator->~RootAllocatorType();
+      if (O.RootAllocator) {
+        new (&RootAllocatorStorage)
+            RootAllocatorType(std::move(*O.RootAllocator));
+        RootAllocator =
+            reinterpret_cast<RootAllocatorType *>(&RootAllocatorStorage);
+        O.RootAllocator = nullptr;
+      } else {
+        RootAllocator = nullptr;
       }
-      {
-        auto Tmp = O.ShadowStackAllocator;
-        O.ShadowStackAllocator = this->ShadowStackAllocator;
-        this->ShadowStackAllocator = Tmp;
+
+      if (ShadowStackAllocator)
+        ShadowStackAllocator->~ShadowStackAllocatorType();
+      if (O.ShadowStackAllocator) {
+        new (&ShadowStackAllocatorStorage)
+            ShadowStackAllocatorType(std::move(*O.ShadowStackAllocator));
+        ShadowStackAllocator = reinterpret_cast<ShadowStackAllocatorType *>(
+            &ShadowStackAllocatorStorage);
+        O.ShadowStackAllocator = nullptr;
+      } else {
+        ShadowStackAllocator = nullptr;
       }
-      {
-        auto Tmp = O.NodeIdPairAllocator;
-        O.NodeIdPairAllocator = this->NodeIdPairAllocator;
-        this->NodeIdPairAllocator = Tmp;
+
+      if (NodeIdPairAllocator)
+        NodeIdPairAllocator->~NodeIdPairAllocatorType();
+      if (O.NodeIdPairAllocator) {
+        new (&NodeIdPairAllocatorStorage)
+            NodeIdPairAllocatorType(std::move(*O.NodeIdPairAllocator));
+        NodeIdPairAllocator = reinterpret_cast<NodeIdPairAllocatorType *>(
+            &NodeIdPairAllocatorStorage);
+        O.NodeIdPairAllocator = nullptr;
+      } else {
+        NodeIdPairAllocator = nullptr;
       }
+
       return *this;
     }
 
     ~Allocators() XRAY_NEVER_INSTRUMENT {
-      // Note that we cannot use delete on these pointers, as they need to be
-      // returned to the sanitizer_common library's internal memory tracking
-      // system.
-      if (NodeAllocator != nullptr) {
+      if (NodeAllocator != nullptr)
         NodeAllocator->~NodeAllocatorType();
-        deallocate(NodeAllocator);
-        NodeAllocator = nullptr;
-      }
-      if (RootAllocator != nullptr) {
+      if (RootAllocator != nullptr)
         RootAllocator->~RootAllocatorType();
-        deallocate(RootAllocator);
-        RootAllocator = nullptr;
-      }
-      if (ShadowStackAllocator != nullptr) {
+      if (ShadowStackAllocator != nullptr)
         ShadowStackAllocator->~ShadowStackAllocatorType();
-        deallocate(ShadowStackAllocator);
-        ShadowStackAllocator = nullptr;
-      }
-      if (NodeIdPairAllocator != nullptr) {
+      if (NodeIdPairAllocator != nullptr)
         NodeIdPairAllocator->~NodeIdPairAllocatorType();
-        deallocate(NodeIdPairAllocator);
-        NodeIdPairAllocator = nullptr;
-      }
     }
   };
 
-  // TODO: Support configuration of options through the arguments.
   static Allocators InitAllocators() XRAY_NEVER_INSTRUMENT {
     return InitAllocatorsCustom(profilingFlags()->per_thread_allocator_max);
   }
 
   static Allocators InitAllocatorsCustom(uptr Max) XRAY_NEVER_INSTRUMENT {
-    Allocators A;
-    auto NodeAllocator = allocate<Allocators::NodeAllocatorType>();
-    new (NodeAllocator) Allocators::NodeAllocatorType(Max);
-    A.NodeAllocator = NodeAllocator;
+    Allocators A(Max);
+    return A;
+  }
 
-    auto RootAllocator = allocate<Allocators::RootAllocatorType>();
-    new (RootAllocator) Allocators::RootAllocatorType(Max);
-    A.RootAllocator = RootAllocator;
-
-    auto ShadowStackAllocator =
-        allocate<Allocators::ShadowStackAllocatorType>();
-    new (ShadowStackAllocator) Allocators::ShadowStackAllocatorType(Max);
-    A.ShadowStackAllocator = ShadowStackAllocator;
-
-    auto NodeIdPairAllocator = allocate<NodeIdPairAllocatorType>();
-    new (NodeIdPairAllocator) NodeIdPairAllocatorType(Max);
-    A.NodeIdPairAllocator = NodeIdPairAllocator;
+  static Allocators
+  InitAllocatorsFromBuffers(Allocators::Buffers &Bufs) XRAY_NEVER_INSTRUMENT {
+    Allocators A(Bufs);
     return A;
   }
 
@@ -257,63 +323,113 @@
   NodeArray Nodes;
   RootArray Roots;
   ShadowStackArray ShadowStack;
-  NodeIdPairAllocatorType *NodeIdPairAllocator = nullptr;
+  NodeIdPairAllocatorType *NodeIdPairAllocator;
+  uint32_t OverflowedFunctions;
 
 public:
   explicit FunctionCallTrie(const Allocators &A) XRAY_NEVER_INSTRUMENT
       : Nodes(*A.NodeAllocator),
         Roots(*A.RootAllocator),
         ShadowStack(*A.ShadowStackAllocator),
-        NodeIdPairAllocator(A.NodeIdPairAllocator) {}
+        NodeIdPairAllocator(A.NodeIdPairAllocator),
+        OverflowedFunctions(0) {}
+
+  FunctionCallTrie() = delete;
+  FunctionCallTrie(const FunctionCallTrie &) = delete;
+  FunctionCallTrie &operator=(const FunctionCallTrie &) = delete;
+
+  FunctionCallTrie(FunctionCallTrie &&O) XRAY_NEVER_INSTRUMENT
+      : Nodes(std::move(O.Nodes)),
+        Roots(std::move(O.Roots)),
+        ShadowStack(std::move(O.ShadowStack)),
+        NodeIdPairAllocator(O.NodeIdPairAllocator),
+        OverflowedFunctions(O.OverflowedFunctions) {}
+
+  FunctionCallTrie &operator=(FunctionCallTrie &&O) XRAY_NEVER_INSTRUMENT {
+    Nodes = std::move(O.Nodes);
+    Roots = std::move(O.Roots);
+    ShadowStack = std::move(O.ShadowStack);
+    NodeIdPairAllocator = O.NodeIdPairAllocator;
+    OverflowedFunctions = O.OverflowedFunctions;
+    return *this;
+  }
+
+  ~FunctionCallTrie() XRAY_NEVER_INSTRUMENT {}
 
   void enterFunction(const int32_t FId, uint64_t TSC,
                      uint16_t CPU) XRAY_NEVER_INSTRUMENT {
     DCHECK_NE(FId, 0);
-    // This function primarily deals with ensuring that the ShadowStack is
-    // consistent and ready for when an exit event is encountered.
-    if (UNLIKELY(ShadowStack.empty())) {
-      auto NewRoot =
-          Nodes.AppendEmplace(nullptr, *NodeIdPairAllocator, 0u, 0u, FId);
-      if (UNLIKELY(NewRoot == nullptr))
-        return;
-      Roots.Append(NewRoot);
-      ShadowStack.AppendEmplace(TSC, NewRoot, CPU);
+
+    // If we're already overflowed the function call stack, do not bother
+    // attempting to record any more function entries.
+    if (UNLIKELY(OverflowedFunctions)) {
+      ++OverflowedFunctions;
       return;
     }
 
-    auto &Top = ShadowStack.back();
-    auto TopNode = Top.NodePtr;
+    // If this is the first function we've encountered, we want to set up the
+    // node(s) and treat it as a root.
+    if (UNLIKELY(ShadowStack.empty())) {
+      auto *NewRoot = Nodes.AppendEmplace(
+          nullptr, NodeIdPairArray(*NodeIdPairAllocator), 0u, 0u, FId);
+      if (UNLIKELY(NewRoot == nullptr))
+        return;
+      if (Roots.AppendEmplace(NewRoot) == nullptr) {
+        Nodes.trim(1);
+        return;
+      }
+      if (ShadowStack.AppendEmplace(TSC, NewRoot, CPU) == nullptr) {
+        Nodes.trim(1);
+        Roots.trim(1);
+        ++OverflowedFunctions;
+        return;
+      }
+      return;
+    }
+
+    // From this point on, we require that the stack is not empty.
+    DCHECK(!ShadowStack.empty());
+    auto TopNode = ShadowStack.back().NodePtr;
     DCHECK_NE(TopNode, nullptr);
 
-    // If we've seen this callee before, then we just access that node and place
-    // that on the top of the stack.
-    auto Callee = TopNode->Callees.find_element(
+    // If we've seen this callee before, then we access that node and place that
+    // on the top of the stack.
+    auto* Callee = TopNode->Callees.find_element(
         [FId](const NodeIdPair &NR) { return NR.FId == FId; });
     if (Callee != nullptr) {
       CHECK_NE(Callee->NodePtr, nullptr);
-      ShadowStack.AppendEmplace(TSC, Callee->NodePtr, CPU);
+      if (ShadowStack.AppendEmplace(TSC, Callee->NodePtr, CPU) == nullptr)
+        ++OverflowedFunctions;
       return;
     }
 
     // This means we've never seen this stack before, create a new node here.
-    auto NewNode =
-        Nodes.AppendEmplace(TopNode, *NodeIdPairAllocator, 0u, 0u, FId);
+    auto* NewNode = Nodes.AppendEmplace(
+        TopNode, NodeIdPairArray(*NodeIdPairAllocator), 0u, 0u, FId);
     if (UNLIKELY(NewNode == nullptr))
       return;
     DCHECK_NE(NewNode, nullptr);
     TopNode->Callees.AppendEmplace(NewNode, FId);
-    ShadowStack.AppendEmplace(TSC, NewNode, CPU);
-    DCHECK_NE(ShadowStack.back().NodePtr, nullptr);
+    if (ShadowStack.AppendEmplace(TSC, NewNode, CPU) == nullptr)
+      ++OverflowedFunctions;
     return;
   }
 
   void exitFunction(int32_t FId, uint64_t TSC,
                     uint16_t CPU) XRAY_NEVER_INSTRUMENT {
+    // If we're exiting functions that have "overflowed" or don't fit into the
+    // stack due to allocator constraints, we then decrement that count first.
+    if (OverflowedFunctions) {
+      --OverflowedFunctions;
+      return;
+    }
+
     // When we exit a function, we look up the ShadowStack to see whether we've
     // entered this function before. We do as little processing here as we can,
     // since most of the hard work would have already been done at function
     // entry.
     uint64_t CumulativeTreeTime = 0;
+
     while (!ShadowStack.empty()) {
       const auto &Top = ShadowStack.back();
       auto TopNode = Top.NodePtr;
@@ -380,18 +496,20 @@
     for (const auto Root : getRoots()) {
       // Add a node in O for this root.
       auto NewRoot = O.Nodes.AppendEmplace(
-          nullptr, *O.NodeIdPairAllocator, Root->CallCount,
+          nullptr, NodeIdPairArray(*O.NodeIdPairAllocator), Root->CallCount,
           Root->CumulativeLocalTime, Root->FId);
 
       // Because we cannot allocate more memory we should bail out right away.
       if (UNLIKELY(NewRoot == nullptr))
         return;
 
-      O.Roots.Append(NewRoot);
+      if (UNLIKELY(O.Roots.Append(NewRoot) == nullptr))
+        return;
 
       // TODO: Figure out what to do if we fail to allocate any more stack
       // space. Maybe warn or report once?
-      DFSStack.AppendEmplace(Root, NewRoot);
+      if (DFSStack.AppendEmplace(Root, NewRoot) == nullptr)
+        return;
       while (!DFSStack.empty()) {
         NodeAndParent NP = DFSStack.back();
         DCHECK_NE(NP.Node, nullptr);
@@ -399,12 +517,17 @@
         DFSStack.trim(1);
         for (const auto Callee : NP.Node->Callees) {
           auto NewNode = O.Nodes.AppendEmplace(
-              NP.NewNode, *O.NodeIdPairAllocator, Callee.NodePtr->CallCount,
-              Callee.NodePtr->CumulativeLocalTime, Callee.FId);
+              NP.NewNode, NodeIdPairArray(*O.NodeIdPairAllocator),
+              Callee.NodePtr->CallCount, Callee.NodePtr->CumulativeLocalTime,
+              Callee.FId);
           if (UNLIKELY(NewNode == nullptr))
             return;
-          NP.NewNode->Callees.AppendEmplace(NewNode, Callee.FId);
-          DFSStack.AppendEmplace(Callee.NodePtr, NewNode);
+          if (UNLIKELY(NP.NewNode->Callees.AppendEmplace(NewNode, Callee.FId) ==
+                       nullptr))
+            return;
+          if (UNLIKELY(DFSStack.AppendEmplace(Callee.NodePtr, NewNode) ==
+                       nullptr))
+            return;
         }
       }
     }
@@ -433,8 +556,9 @@
       auto R = O.Roots.find_element(
           [&](const Node *Node) { return Node->FId == Root->FId; });
       if (R == nullptr) {
-        TargetRoot = O.Nodes.AppendEmplace(nullptr, *O.NodeIdPairAllocator, 0u,
-                                           0u, Root->FId);
+        TargetRoot = O.Nodes.AppendEmplace(
+            nullptr, NodeIdPairArray(*O.NodeIdPairAllocator), 0u, 0u,
+            Root->FId);
         if (UNLIKELY(TargetRoot == nullptr))
           return;
 
@@ -443,7 +567,7 @@
         TargetRoot = *R;
       }
 
-      DFSStack.Append(NodeAndTarget{Root, TargetRoot});
+      DFSStack.AppendEmplace(Root, TargetRoot);
       while (!DFSStack.empty()) {
         NodeAndTarget NT = DFSStack.back();
         DCHECK_NE(NT.OrigNode, nullptr);
@@ -459,7 +583,8 @@
               });
           if (TargetCallee == nullptr) {
             auto NewTargetNode = O.Nodes.AppendEmplace(
-                NT.TargetNode, *O.NodeIdPairAllocator, 0u, 0u, Callee.FId);
+                NT.TargetNode, NodeIdPairArray(*O.NodeIdPairAllocator), 0u, 0u,
+                Callee.FId);
 
             if (UNLIKELY(NewTargetNode == nullptr))
               return;
diff --git a/lib/xray/xray_interface.cc b/lib/xray/xray_interface.cc
index 01bf6dd..6f7b661 100644
--- a/lib/xray/xray_interface.cc
+++ b/lib/xray/xray_interface.cc
@@ -22,6 +22,13 @@
 #include <string.h>
 #include <sys/mman.h>
 
+#if SANITIZER_FUCHSIA
+#include <zircon/process.h>
+#include <zircon/sanitizer.h>
+#include <zircon/status.h>
+#include <zircon/syscalls.h>
+#endif
+
 #include "sanitizer_common/sanitizer_addrhashmap.h"
 #include "sanitizer_common/sanitizer_common.h"
 
@@ -92,22 +99,48 @@
 
 public:
   explicit MProtectHelper(void *PageAlignedAddr,
-                          std::size_t MProtectLen) XRAY_NEVER_INSTRUMENT
+                          std::size_t MProtectLen,
+                          std::size_t PageSize) XRAY_NEVER_INSTRUMENT
       : PageAlignedAddr(PageAlignedAddr),
         MProtectLen(MProtectLen),
-        MustCleanup(false) {}
+        MustCleanup(false) {
+#if SANITIZER_FUCHSIA
+    MProtectLen = RoundUpTo(MProtectLen, PageSize);
+#endif
+  }
 
   int MakeWriteable() XRAY_NEVER_INSTRUMENT {
+#if SANITIZER_FUCHSIA
+    auto R = __sanitizer_change_code_protection(
+        reinterpret_cast<uintptr_t>(PageAlignedAddr), MProtectLen, true);
+    if (R != ZX_OK) {
+      Report("XRay: cannot change code protection: %s\n",
+             _zx_status_get_string(R));
+      return -1;
+    }
+    MustCleanup = true;
+    return 0;
+#else
     auto R = mprotect(PageAlignedAddr, MProtectLen,
                       PROT_READ | PROT_WRITE | PROT_EXEC);
     if (R != -1)
       MustCleanup = true;
     return R;
+#endif
   }
 
   ~MProtectHelper() XRAY_NEVER_INSTRUMENT {
     if (MustCleanup) {
+#if SANITIZER_FUCHSIA
+      auto R = __sanitizer_change_code_protection(
+          reinterpret_cast<uintptr_t>(PageAlignedAddr), MProtectLen, false);
+      if (R != ZX_OK) {
+        Report("XRay: cannot change code protection: %s\n",
+               _zx_status_get_string(R));
+      }
+#else
       mprotect(PageAlignedAddr, MProtectLen, PROT_READ | PROT_EXEC);
+#endif
     }
   }
 };
@@ -254,7 +287,7 @@
       reinterpret_cast<void *>(MinSled.Address & ~(PageSize - 1));
   size_t MProtectLen =
       (MaxSled.Address - reinterpret_cast<uptr>(PageAlignedAddr)) + cSledLength;
-  MProtectHelper Protector(PageAlignedAddr, MProtectLen);
+  MProtectHelper Protector(PageAlignedAddr, MProtectLen, PageSize);
   if (Protector.MakeWriteable() == -1) {
     Report("Failed mprotect: %d\n", errno);
     return XRayPatchingStatus::FAILED;
@@ -319,7 +352,7 @@
       reinterpret_cast<void *>(MinSled.Address & ~(PageSize - 1));
   size_t MProtectLen =
       (MaxSled.Address - reinterpret_cast<uptr>(PageAlignedAddr)) + cSledLength;
-  MProtectHelper Protector(PageAlignedAddr, MProtectLen);
+  MProtectHelper Protector(PageAlignedAddr, MProtectLen, PageSize);
   if (Protector.MakeWriteable() == -1) {
     Report("Failed mprotect: %d\n", errno);
     return XRayPatchingStatus::FAILED;
diff --git a/lib/xray/xray_profile_collector.cc b/lib/xray/xray_profile_collector.cc
index a2a8f1f..dc3a820 100644
--- a/lib/xray/xray_profile_collector.cc
+++ b/lib/xray/xray_profile_collector.cc
@@ -57,51 +57,91 @@
   u64 ThreadId;
 };
 
-using ThreadTriesArray = Array<ThreadTrie>;
+struct ThreadData {
+  BufferQueue *BQ;
+  FunctionCallTrie::Allocators::Buffers Buffers;
+  FunctionCallTrie::Allocators Allocators;
+  FunctionCallTrie FCT;
+  tid_t TId;
+};
+
+using ThreadDataArray = Array<ThreadData>;
+using ThreadDataAllocator = ThreadDataArray::AllocatorType;
+
+// We use a separate buffer queue for the backing store for the allocator used
+// by the ThreadData array. This lets us host the buffers, allocators, and tries
+// associated with a thread by moving the data into the array instead of
+// attempting to copy the data to a separately backed set of tries.
+static typename std::aligned_storage<
+    sizeof(BufferQueue), alignof(BufferQueue)>::type BufferQueueStorage;
+static BufferQueue *BQ = nullptr;
+static BufferQueue::Buffer Buffer;
+static typename std::aligned_storage<sizeof(ThreadDataAllocator),
+                                     alignof(ThreadDataAllocator)>::type
+    ThreadDataAllocatorStorage;
+static typename std::aligned_storage<sizeof(ThreadDataArray),
+                                     alignof(ThreadDataArray)>::type
+    ThreadDataArrayStorage;
+
+static ThreadDataAllocator *TDAllocator = nullptr;
+static ThreadDataArray *TDArray = nullptr;
+
 using ProfileBufferArray = Array<ProfileBuffer>;
-using ThreadTriesArrayAllocator = typename ThreadTriesArray::AllocatorType;
 using ProfileBufferArrayAllocator = typename ProfileBufferArray::AllocatorType;
 
 // These need to be global aligned storage to avoid dynamic initialization. We
 // need these to be aligned to allow us to placement new objects into the
 // storage, and have pointers to those objects be appropriately aligned.
-static typename std::aligned_storage<sizeof(FunctionCallTrie::Allocators)>::type
-    AllocatorStorage;
-static typename std::aligned_storage<sizeof(ThreadTriesArray)>::type
-    ThreadTriesStorage;
 static typename std::aligned_storage<sizeof(ProfileBufferArray)>::type
     ProfileBuffersStorage;
-static typename std::aligned_storage<sizeof(ThreadTriesArrayAllocator)>::type
-    ThreadTriesArrayAllocatorStorage;
 static typename std::aligned_storage<sizeof(ProfileBufferArrayAllocator)>::type
     ProfileBufferArrayAllocatorStorage;
 
-static ThreadTriesArray *ThreadTries = nullptr;
-static ThreadTriesArrayAllocator *ThreadTriesAllocator = nullptr;
-static ProfileBufferArray *ProfileBuffers = nullptr;
 static ProfileBufferArrayAllocator *ProfileBuffersAllocator = nullptr;
-static FunctionCallTrie::Allocators *GlobalAllocators = nullptr;
+static ProfileBufferArray *ProfileBuffers = nullptr;
+
+// Use a global flag to determine whether the collector implementation has been
+// initialized.
+static atomic_uint8_t CollectorInitialized{0};
 
 } // namespace
 
-void post(const FunctionCallTrie &T, tid_t TId) XRAY_NEVER_INSTRUMENT {
-  static pthread_once_t Once = PTHREAD_ONCE_INIT;
-  pthread_once(&Once, +[] { reset(); });
+void post(BufferQueue *Q, FunctionCallTrie &&T,
+          FunctionCallTrie::Allocators &&A,
+          FunctionCallTrie::Allocators::Buffers &&B,
+          tid_t TId) XRAY_NEVER_INSTRUMENT {
+  DCHECK_NE(Q, nullptr);
 
-  ThreadTrie *Item = nullptr;
-  {
-    SpinMutexLock Lock(&GlobalMutex);
-    if (GlobalAllocators == nullptr || ThreadTries == nullptr)
-      return;
-
-    Item = ThreadTries->Append({});
-    Item->TId = TId;
-    auto Trie = reinterpret_cast<FunctionCallTrie *>(&Item->TrieStorage);
-    new (Trie) FunctionCallTrie(*GlobalAllocators);
+  // Bail out early if the collector has not been initialized.
+  if (!atomic_load(&CollectorInitialized, memory_order_acquire)) {
+    T.~FunctionCallTrie();
+    A.~Allocators();
+    Q->releaseBuffer(B.NodeBuffer);
+    Q->releaseBuffer(B.RootsBuffer);
+    Q->releaseBuffer(B.ShadowStackBuffer);
+    Q->releaseBuffer(B.NodeIdPairBuffer);
+    B.~Buffers();
+    return;
   }
 
-  auto Trie = reinterpret_cast<FunctionCallTrie *>(&Item->TrieStorage);
-  T.deepCopyInto(*Trie);
+  {
+    SpinMutexLock Lock(&GlobalMutex);
+    DCHECK_NE(TDAllocator, nullptr);
+    DCHECK_NE(TDArray, nullptr);
+
+    if (TDArray->AppendEmplace(Q, std::move(B), std::move(A), std::move(T),
+                               TId) == nullptr) {
+      // If we fail to add the data to the array, we should destroy the objects
+      // handed us.
+      T.~FunctionCallTrie();
+      A.~Allocators();
+      Q->releaseBuffer(B.NodeBuffer);
+      Q->releaseBuffer(B.RootsBuffer);
+      Q->releaseBuffer(B.ShadowStackBuffer);
+      Q->releaseBuffer(B.NodeIdPairBuffer);
+      B.~Buffers();
+    }
+  }
 }
 
 // A PathArray represents the function id's representing a stack trace. In this
@@ -115,13 +155,7 @@
   // The Path in this record is the function id's from the leaf to the root of
   // the function call stack as represented from a FunctionCallTrie.
   PathArray Path;
-  const FunctionCallTrie::Node *Node = nullptr;
-
-  // Constructor for in-place construction.
-  ProfileRecord(PathAllocator &A,
-                const FunctionCallTrie::Node *N) XRAY_NEVER_INSTRUMENT
-      : Path(A),
-        Node(N) {}
+  const FunctionCallTrie::Node *Node;
 };
 
 namespace {
@@ -137,12 +171,14 @@
   using StackAllocator = typename StackArray::AllocatorType;
   StackAllocator StackAlloc(profilingFlags()->stack_allocator_max);
   StackArray DFSStack(StackAlloc);
-  for (const auto R : Trie.getRoots()) {
+  for (const auto *R : Trie.getRoots()) {
     DFSStack.Append(R);
     while (!DFSStack.empty()) {
-      auto Node = DFSStack.back();
+      auto *Node = DFSStack.back();
       DFSStack.trim(1);
-      auto Record = PRs.AppendEmplace(PA, Node);
+      if (Node == nullptr)
+        continue;
+      auto Record = PRs.AppendEmplace(PathArray{PA}, Node);
       if (Record == nullptr)
         return;
       DCHECK_NE(Record, nullptr);
@@ -195,40 +231,54 @@
 } // namespace
 
 void serialize() XRAY_NEVER_INSTRUMENT {
-  SpinMutexLock Lock(&GlobalMutex);
-
-  if (GlobalAllocators == nullptr || ThreadTries == nullptr ||
-      ProfileBuffers == nullptr)
+  if (!atomic_load(&CollectorInitialized, memory_order_acquire))
     return;
 
+  SpinMutexLock Lock(&GlobalMutex);
+
   // Clear out the global ProfileBuffers, if it's not empty.
   for (auto &B : *ProfileBuffers)
-    deallocateBuffer(reinterpret_cast<uint8_t *>(B.Data), B.Size);
+    deallocateBuffer(reinterpret_cast<unsigned char *>(B.Data), B.Size);
   ProfileBuffers->trim(ProfileBuffers->size());
 
-  if (ThreadTries->empty())
+  DCHECK_NE(TDArray, nullptr);
+  if (TDArray->empty())
     return;
 
   // Then repopulate the global ProfileBuffers.
   u32 I = 0;
-  for (const auto &ThreadTrie : *ThreadTries) {
+  auto MaxSize = profilingFlags()->global_allocator_max;
+  auto ProfileArena = allocateBuffer(MaxSize);
+  if (ProfileArena == nullptr)
+    return;
+
+  auto ProfileArenaCleanup = at_scope_exit(
+      [&]() XRAY_NEVER_INSTRUMENT { deallocateBuffer(ProfileArena, MaxSize); });
+
+  auto PathArena = allocateBuffer(profilingFlags()->global_allocator_max);
+  if (PathArena == nullptr)
+    return;
+
+  auto PathArenaCleanup = at_scope_exit(
+      [&]() XRAY_NEVER_INSTRUMENT { deallocateBuffer(PathArena, MaxSize); });
+
+  for (const auto &ThreadTrie : *TDArray) {
     using ProfileRecordAllocator = typename ProfileRecordArray::AllocatorType;
-    ProfileRecordAllocator PRAlloc(profilingFlags()->global_allocator_max);
+    ProfileRecordAllocator PRAlloc(ProfileArena,
+                                   profilingFlags()->global_allocator_max);
     ProfileRecord::PathAllocator PathAlloc(
-        profilingFlags()->global_allocator_max);
+        PathArena, profilingFlags()->global_allocator_max);
     ProfileRecordArray ProfileRecords(PRAlloc);
 
     // First, we want to compute the amount of space we're going to need. We'll
     // use a local allocator and an __xray::Array<...> to store the intermediary
     // data, then compute the size as we're going along. Then we'll allocate the
     // contiguous space to contain the thread buffer data.
-    const auto &Trie =
-        *reinterpret_cast<const FunctionCallTrie *>(&(ThreadTrie.TrieStorage));
-    if (Trie.getRoots().empty())
+    if (ThreadTrie.FCT.getRoots().empty())
       continue;
 
-    populateRecords(ProfileRecords, PathAlloc, Trie);
-    DCHECK(!Trie.getRoots().empty());
+    populateRecords(ProfileRecords, PathAlloc, ThreadTrie.FCT);
+    DCHECK(!ThreadTrie.FCT.getRoots().empty());
     DCHECK(!ProfileRecords.empty());
 
     // Go through each record, to compute the sizes.
@@ -245,15 +295,16 @@
       CumulativeSizes += 20 + (4 * Record.Path.size());
 
     BlockHeader Header{16 + CumulativeSizes, I++, ThreadTrie.TId};
-    auto Buffer = ProfileBuffers->Append({});
-    Buffer->Size = sizeof(Header) + CumulativeSizes;
-    Buffer->Data = allocateBuffer(Buffer->Size);
-    DCHECK_NE(Buffer->Data, nullptr);
-    serializeRecords(Buffer, Header, ProfileRecords);
+    auto B = ProfileBuffers->Append({});
+    B->Size = sizeof(Header) + CumulativeSizes;
+    B->Data = allocateBuffer(B->Size);
+    DCHECK_NE(B->Data, nullptr);
+    serializeRecords(B, Header, ProfileRecords);
   }
 }
 
 void reset() XRAY_NEVER_INSTRUMENT {
+  atomic_store(&CollectorInitialized, 0, memory_order_release);
   SpinMutexLock Lock(&GlobalMutex);
 
   if (ProfileBuffers != nullptr) {
@@ -261,46 +312,68 @@
     for (auto &B : *ProfileBuffers)
       deallocateBuffer(reinterpret_cast<uint8_t *>(B.Data), B.Size);
     ProfileBuffers->trim(ProfileBuffers->size());
+    ProfileBuffers = nullptr;
   }
 
-  if (ThreadTries != nullptr) {
-    // Clear out the function call tries per thread.
-    for (auto &T : *ThreadTries) {
-      auto Trie = reinterpret_cast<FunctionCallTrie *>(&T.TrieStorage);
-      Trie->~FunctionCallTrie();
+  if (TDArray != nullptr) {
+    // Release the resources as required.
+    for (auto &TD : *TDArray) {
+      TD.BQ->releaseBuffer(TD.Buffers.NodeBuffer);
+      TD.BQ->releaseBuffer(TD.Buffers.RootsBuffer);
+      TD.BQ->releaseBuffer(TD.Buffers.ShadowStackBuffer);
+      TD.BQ->releaseBuffer(TD.Buffers.NodeIdPairBuffer);
     }
-    ThreadTries->trim(ThreadTries->size());
+    // We don't bother destroying the array here because we've already
+    // potentially freed the backing store for the array. Instead we're going to
+    // reset the pointer to nullptr, and re-use the storage later instead
+    // (placement-new'ing into the storage as-is).
+    TDArray = nullptr;
   }
 
-  // Reset the global allocators.
-  if (GlobalAllocators != nullptr)
-    GlobalAllocators->~Allocators();
+  if (TDAllocator != nullptr) {
+    TDAllocator->~Allocator();
+    TDAllocator = nullptr;
+  }
 
-  GlobalAllocators =
-      reinterpret_cast<FunctionCallTrie::Allocators *>(&AllocatorStorage);
-  new (GlobalAllocators) FunctionCallTrie::Allocators();
-  *GlobalAllocators = FunctionCallTrie::InitAllocators();
+  if (Buffer.Data != nullptr) {
+    BQ->releaseBuffer(Buffer);
+  }
 
-  if (ThreadTriesAllocator != nullptr)
-    ThreadTriesAllocator->~ThreadTriesArrayAllocator();
+  if (BQ == nullptr) {
+    bool Success = false;
+    new (&BufferQueueStorage)
+        BufferQueue(profilingFlags()->global_allocator_max, 1, Success);
+    if (!Success)
+      return;
+    BQ = reinterpret_cast<BufferQueue *>(&BufferQueueStorage);
+  } else {
+    BQ->finalize();
 
-  ThreadTriesAllocator = reinterpret_cast<ThreadTriesArrayAllocator *>(
-      &ThreadTriesArrayAllocatorStorage);
-  new (ThreadTriesAllocator)
-      ThreadTriesArrayAllocator(profilingFlags()->global_allocator_max);
-  ThreadTries = reinterpret_cast<ThreadTriesArray *>(&ThreadTriesStorage);
-  new (ThreadTries) ThreadTriesArray(*ThreadTriesAllocator);
+    if (BQ->init(profilingFlags()->global_allocator_max, 1) !=
+        BufferQueue::ErrorCode::Ok)
+      return;
+  }
 
-  if (ProfileBuffersAllocator != nullptr)
-    ProfileBuffersAllocator->~ProfileBufferArrayAllocator();
+  if (BQ->getBuffer(Buffer) != BufferQueue::ErrorCode::Ok)
+    return;
 
+  new (&ProfileBufferArrayAllocatorStorage)
+      ProfileBufferArrayAllocator(profilingFlags()->global_allocator_max);
   ProfileBuffersAllocator = reinterpret_cast<ProfileBufferArrayAllocator *>(
       &ProfileBufferArrayAllocatorStorage);
-  new (ProfileBuffersAllocator)
-      ProfileBufferArrayAllocator(profilingFlags()->global_allocator_max);
+
+  new (&ProfileBuffersStorage) ProfileBufferArray(*ProfileBuffersAllocator);
   ProfileBuffers =
       reinterpret_cast<ProfileBufferArray *>(&ProfileBuffersStorage);
-  new (ProfileBuffers) ProfileBufferArray(*ProfileBuffersAllocator);
+
+  new (&ThreadDataAllocatorStorage)
+      ThreadDataAllocator(Buffer.Data, Buffer.Size);
+  TDAllocator =
+      reinterpret_cast<ThreadDataAllocator *>(&ThreadDataAllocatorStorage);
+  new (&ThreadDataArrayStorage) ThreadDataArray(*TDAllocator);
+  TDArray = reinterpret_cast<ThreadDataArray *>(&ThreadDataArrayStorage);
+
+  atomic_store(&CollectorInitialized, 1, memory_order_release);
 }
 
 XRayBuffer nextBuffer(XRayBuffer B) XRAY_NEVER_INSTRUMENT {
@@ -312,8 +385,10 @@
   static pthread_once_t Once = PTHREAD_ONCE_INIT;
   static typename std::aligned_storage<sizeof(XRayProfilingFileHeader)>::type
       FileHeaderStorage;
-  pthread_once(&Once,
-               +[] { new (&FileHeaderStorage) XRayProfilingFileHeader{}; });
+  pthread_once(
+      &Once, +[]() XRAY_NEVER_INSTRUMENT {
+        new (&FileHeaderStorage) XRayProfilingFileHeader{};
+      });
 
   if (UNLIKELY(B.Data == nullptr)) {
     // The first buffer should always contain the file header information.
diff --git a/lib/xray/xray_profile_collector.h b/lib/xray/xray_profile_collector.h
index 335043d..86c4ce8 100644
--- a/lib/xray/xray_profile_collector.h
+++ b/lib/xray/xray_profile_collector.h
@@ -33,27 +33,13 @@
 /// Posts the FunctionCallTrie associated with a specific Thread ID. This
 /// will:
 ///
-///   - Make a copy of the FunctionCallTrie and store that against the Thread
-///     ID. This will use the global allocator for the service-managed
-///     FunctionCallTrie instances.
-///   - Queue up a pointer to the FunctionCallTrie.
-///   - If the queue is long enough (longer than some arbitrary threshold) we
-///     then pre-calculate a single FunctionCallTrie for the whole process.
+/// Moves the collection of FunctionCallTrie, Allocators, and Buffers associated
+/// with a thread's data to the queue. This takes ownership of the memory
+/// associated with a thread, and manages those exclusively.
 ///
-///
-/// We are making a copy of the FunctionCallTrie because the intent is to have
-/// this function be called at thread exit, or soon after the profiling
-/// handler is finalized through the XRay APIs. By letting threads each
-/// process their own thread-local FunctionCallTrie instances, we're removing
-/// the need for synchronisation across threads while we're profiling.
-/// However, once we're done profiling, we can then collect copies of these
-/// FunctionCallTrie instances and pay the cost of the copy.
-///
-/// NOTE: In the future, if this turns out to be more costly than "moving" the
-/// FunctionCallTrie instances from the owning thread to the collector
-/// service, then we can change the implementation to do it this way (moving)
-/// instead.
-void post(const FunctionCallTrie &T, tid_t TId);
+void post(BufferQueue *Q, FunctionCallTrie &&T,
+          FunctionCallTrie::Allocators &&A,
+          FunctionCallTrie::Allocators::Buffers &&B, tid_t TId);
 
 /// The serialize will process all FunctionCallTrie instances in memory, and
 /// turn those into specifically formatted blocks, each describing the
diff --git a/lib/xray/xray_profiling.cc b/lib/xray/xray_profiling.cc
index 4b9222a..4323170 100644
--- a/lib/xray/xray_profiling.cc
+++ b/lib/xray/xray_profiling.cc
@@ -19,6 +19,7 @@
 #include "sanitizer_common/sanitizer_flags.h"
 #include "xray/xray_interface.h"
 #include "xray/xray_log_interface.h"
+#include "xray_buffer_queue.h"
 #include "xray_flags.h"
 #include "xray_profile_collector.h"
 #include "xray_profiling_flags.h"
@@ -31,67 +32,167 @@
 
 namespace {
 
-atomic_sint32_t ProfilerLogFlushStatus = {
+static atomic_sint32_t ProfilerLogFlushStatus = {
     XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING};
 
-atomic_sint32_t ProfilerLogStatus = {XRayLogInitStatus::XRAY_LOG_UNINITIALIZED};
+static atomic_sint32_t ProfilerLogStatus = {
+    XRayLogInitStatus::XRAY_LOG_UNINITIALIZED};
 
-SpinMutex ProfilerOptionsMutex;
+static SpinMutex ProfilerOptionsMutex;
 
-struct alignas(64) ProfilingData {
-  FunctionCallTrie::Allocators *Allocators;
-  FunctionCallTrie *FCT;
+struct ProfilingData {
+  atomic_uintptr_t Allocators;
+  atomic_uintptr_t FCT;
 };
 
 static pthread_key_t ProfilingKey;
 
-thread_local std::aligned_storage<sizeof(FunctionCallTrie::Allocators)>::type
-    AllocatorsStorage;
-thread_local std::aligned_storage<sizeof(FunctionCallTrie)>::type
-    FunctionCallTrieStorage;
-thread_local std::aligned_storage<sizeof(ProfilingData)>::type ThreadStorage{};
+// We use a global buffer queue, which gets initialized once at initialisation
+// time, and gets reset when profiling is "done".
+static std::aligned_storage<sizeof(BufferQueue), alignof(BufferQueue)>::type
+    BufferQueueStorage;
+static BufferQueue *BQ = nullptr;
 
-static ProfilingData &getThreadLocalData() XRAY_NEVER_INSTRUMENT {
-  thread_local auto ThreadOnce = [] {
-    new (&ThreadStorage) ProfilingData{};
-    auto *Allocators =
-        reinterpret_cast<FunctionCallTrie::Allocators *>(&AllocatorsStorage);
-    new (Allocators) FunctionCallTrie::Allocators();
-    *Allocators = FunctionCallTrie::InitAllocators();
-    auto *FCT = reinterpret_cast<FunctionCallTrie *>(&FunctionCallTrieStorage);
-    new (FCT) FunctionCallTrie(*Allocators);
-    auto &TLD = *reinterpret_cast<ProfilingData *>(&ThreadStorage);
-    TLD.Allocators = Allocators;
-    TLD.FCT = FCT;
-    pthread_setspecific(ProfilingKey, &ThreadStorage);
+thread_local FunctionCallTrie::Allocators::Buffers ThreadBuffers;
+thread_local std::aligned_storage<sizeof(FunctionCallTrie::Allocators),
+                                  alignof(FunctionCallTrie::Allocators)>::type
+    AllocatorsStorage;
+thread_local std::aligned_storage<sizeof(FunctionCallTrie),
+                                  alignof(FunctionCallTrie)>::type
+    FunctionCallTrieStorage;
+thread_local ProfilingData TLD{{0}, {0}};
+thread_local atomic_uint8_t ReentranceGuard{0};
+
+// We use a separate guard for ensuring that for this thread, if we're already
+// cleaning up, that any signal handlers don't attempt to cleanup nor
+// initialise.
+thread_local atomic_uint8_t TLDInitGuard{0};
+
+// We also use a separate latch to signal that the thread is exiting, and
+// non-essential work should be ignored (things like recording events, etc.).
+thread_local atomic_uint8_t ThreadExitingLatch{0};
+
+static ProfilingData *getThreadLocalData() XRAY_NEVER_INSTRUMENT {
+  thread_local auto ThreadOnce = []() XRAY_NEVER_INSTRUMENT {
+    pthread_setspecific(ProfilingKey, &TLD);
     return false;
   }();
   (void)ThreadOnce;
 
-  auto &TLD = *reinterpret_cast<ProfilingData *>(&ThreadStorage);
+  RecursionGuard TLDInit(TLDInitGuard);
+  if (!TLDInit)
+    return nullptr;
 
-  if (UNLIKELY(TLD.Allocators == nullptr || TLD.FCT == nullptr)) {
-    auto *Allocators =
-        reinterpret_cast<FunctionCallTrie::Allocators *>(&AllocatorsStorage);
-    new (Allocators) FunctionCallTrie::Allocators();
-    *Allocators = FunctionCallTrie::InitAllocators();
-    auto *FCT = reinterpret_cast<FunctionCallTrie *>(&FunctionCallTrieStorage);
-    new (FCT) FunctionCallTrie(*Allocators);
-    TLD.Allocators = Allocators;
-    TLD.FCT = FCT;
+  if (atomic_load_relaxed(&ThreadExitingLatch))
+    return nullptr;
+
+  uptr Allocators = 0;
+  if (atomic_compare_exchange_strong(&TLD.Allocators, &Allocators, 1,
+                                     memory_order_acq_rel)) {
+    bool Success = false;
+    auto AllocatorsUndo = at_scope_exit([&]() XRAY_NEVER_INSTRUMENT {
+      if (!Success)
+        atomic_store(&TLD.Allocators, 0, memory_order_release);
+    });
+
+    // Acquire a set of buffers for this thread.
+    if (BQ == nullptr)
+      return nullptr;
+
+    if (BQ->getBuffer(ThreadBuffers.NodeBuffer) != BufferQueue::ErrorCode::Ok)
+      return nullptr;
+    auto NodeBufferUndo = at_scope_exit([&]() XRAY_NEVER_INSTRUMENT {
+      if (!Success)
+        BQ->releaseBuffer(ThreadBuffers.NodeBuffer);
+    });
+
+    if (BQ->getBuffer(ThreadBuffers.RootsBuffer) != BufferQueue::ErrorCode::Ok)
+      return nullptr;
+    auto RootsBufferUndo = at_scope_exit([&]() XRAY_NEVER_INSTRUMENT {
+      if (!Success)
+        BQ->releaseBuffer(ThreadBuffers.RootsBuffer);
+    });
+
+    if (BQ->getBuffer(ThreadBuffers.ShadowStackBuffer) !=
+        BufferQueue::ErrorCode::Ok)
+      return nullptr;
+    auto ShadowStackBufferUndo = at_scope_exit([&]() XRAY_NEVER_INSTRUMENT {
+      if (!Success)
+        BQ->releaseBuffer(ThreadBuffers.ShadowStackBuffer);
+    });
+
+    if (BQ->getBuffer(ThreadBuffers.NodeIdPairBuffer) !=
+        BufferQueue::ErrorCode::Ok)
+      return nullptr;
+
+    Success = true;
+    new (&AllocatorsStorage) FunctionCallTrie::Allocators(
+        FunctionCallTrie::InitAllocatorsFromBuffers(ThreadBuffers));
+    Allocators = reinterpret_cast<uptr>(
+        reinterpret_cast<FunctionCallTrie::Allocators *>(&AllocatorsStorage));
+    atomic_store(&TLD.Allocators, Allocators, memory_order_release);
   }
 
-  return *reinterpret_cast<ProfilingData *>(&ThreadStorage);
+  if (Allocators == 1)
+    return nullptr;
+
+  uptr FCT = 0;
+  if (atomic_compare_exchange_strong(&TLD.FCT, &FCT, 1, memory_order_acq_rel)) {
+    new (&FunctionCallTrieStorage)
+        FunctionCallTrie(*reinterpret_cast<FunctionCallTrie::Allocators *>(
+            atomic_load_relaxed(&TLD.Allocators)));
+    FCT = reinterpret_cast<uptr>(
+        reinterpret_cast<FunctionCallTrie *>(&FunctionCallTrieStorage));
+    atomic_store(&TLD.FCT, FCT, memory_order_release);
+  }
+
+  if (FCT == 1)
+    return nullptr;
+
+  return &TLD;
 }
 
 static void cleanupTLD() XRAY_NEVER_INSTRUMENT {
-  auto &TLD = *reinterpret_cast<ProfilingData *>(&ThreadStorage);
-  if (TLD.Allocators != nullptr && TLD.FCT != nullptr) {
-    TLD.FCT->~FunctionCallTrie();
-    TLD.Allocators->~Allocators();
-    TLD.FCT = nullptr;
-    TLD.Allocators = nullptr;
-  }
+  auto FCT = atomic_exchange(&TLD.FCT, 0, memory_order_acq_rel);
+  if (FCT == reinterpret_cast<uptr>(reinterpret_cast<FunctionCallTrie *>(
+                 &FunctionCallTrieStorage)))
+    reinterpret_cast<FunctionCallTrie *>(FCT)->~FunctionCallTrie();
+
+  auto Allocators = atomic_exchange(&TLD.Allocators, 0, memory_order_acq_rel);
+  if (Allocators ==
+      reinterpret_cast<uptr>(
+          reinterpret_cast<FunctionCallTrie::Allocators *>(&AllocatorsStorage)))
+    reinterpret_cast<FunctionCallTrie::Allocators *>(Allocators)->~Allocators();
+}
+
+static void postCurrentThreadFCT(ProfilingData &T) XRAY_NEVER_INSTRUMENT {
+  RecursionGuard TLDInit(TLDInitGuard);
+  if (!TLDInit)
+    return;
+
+  uptr P = atomic_exchange(&T.FCT, 0, memory_order_acq_rel);
+  if (P != reinterpret_cast<uptr>(
+               reinterpret_cast<FunctionCallTrie *>(&FunctionCallTrieStorage)))
+    return;
+
+  auto FCT = reinterpret_cast<FunctionCallTrie *>(P);
+  DCHECK_NE(FCT, nullptr);
+
+  uptr A = atomic_exchange(&T.Allocators, 0, memory_order_acq_rel);
+  if (A !=
+      reinterpret_cast<uptr>(
+          reinterpret_cast<FunctionCallTrie::Allocators *>(&AllocatorsStorage)))
+    return;
+
+  auto Allocators = reinterpret_cast<FunctionCallTrie::Allocators *>(A);
+  DCHECK_NE(Allocators, nullptr);
+
+  // Always move the data into the profile collector.
+  profileCollectorService::post(BQ, std::move(*FCT), std::move(*Allocators),
+                                std::move(ThreadBuffers), GetTid());
+
+  // Re-initialize the ThreadBuffers object to a known "default" state.
+  ThreadBuffers = FunctionCallTrie::Allocators::Buffers{};
 }
 
 } // namespace
@@ -104,9 +205,6 @@
 #endif
 }
 
-atomic_sint32_t ProfileFlushStatus = {
-    XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING};
-
 XRayLogFlushStatus profilingFlush() XRAY_NEVER_INSTRUMENT {
   if (atomic_load(&ProfilerLogStatus, memory_order_acquire) !=
       XRayLogInitStatus::XRAY_LOG_FINALIZED) {
@@ -115,12 +213,23 @@
     return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING;
   }
 
-  s32 Result = XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING;
-  if (!atomic_compare_exchange_strong(&ProfilerLogFlushStatus, &Result,
-                                      XRayLogFlushStatus::XRAY_LOG_FLUSHING,
-                                      memory_order_acq_rel)) {
+  RecursionGuard SignalGuard(ReentranceGuard);
+  if (!SignalGuard) {
     if (Verbosity())
-      Report("Not flushing profiles, implementation still finalizing.\n");
+      Report("Cannot finalize properly inside a signal handler!\n");
+    atomic_store(&ProfilerLogFlushStatus,
+                 XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING,
+                 memory_order_release);
+    return XRayLogFlushStatus::XRAY_LOG_NOT_FLUSHING;
+  }
+
+  s32 Previous = atomic_exchange(&ProfilerLogFlushStatus,
+                                 XRayLogFlushStatus::XRAY_LOG_FLUSHING,
+                                 memory_order_acq_rel);
+  if (Previous == XRayLogFlushStatus::XRAY_LOG_FLUSHING) {
+    if (Verbosity())
+      Report("Not flushing profiles, implementation still flushing.\n");
+    return XRayLogFlushStatus::XRAY_LOG_FLUSHING;
   }
 
   // At this point, we'll create the file that will contain the profile, but
@@ -152,31 +261,14 @@
 
   profileCollectorService::reset();
 
-  // Flush the current thread's local data structures as well.
-  cleanupTLD();
-
-  atomic_store(&ProfilerLogStatus, XRayLogFlushStatus::XRAY_LOG_FLUSHED,
+  atomic_store(&ProfilerLogFlushStatus, XRayLogFlushStatus::XRAY_LOG_FLUSHED,
+               memory_order_release);
+  atomic_store(&ProfilerLogStatus, XRayLogInitStatus::XRAY_LOG_UNINITIALIZED,
                memory_order_release);
 
   return XRayLogFlushStatus::XRAY_LOG_FLUSHED;
 }
 
-namespace {
-
-thread_local atomic_uint8_t ReentranceGuard{0};
-
-static void postCurrentThreadFCT(ProfilingData &TLD) XRAY_NEVER_INSTRUMENT {
-  if (TLD.Allocators == nullptr || TLD.FCT == nullptr)
-    return;
-
-  if (!TLD.FCT->getRoots().empty())
-    profileCollectorService::post(*TLD.FCT, GetTid());
-
-  cleanupTLD();
-}
-
-} // namespace
-
 void profilingHandleArg0(int32_t FuncId,
                          XRayEntryType Entry) XRAY_NEVER_INSTRUMENT {
   unsigned char CPU;
@@ -186,22 +278,29 @@
     return;
 
   auto Status = atomic_load(&ProfilerLogStatus, memory_order_acquire);
+  if (UNLIKELY(Status == XRayLogInitStatus::XRAY_LOG_UNINITIALIZED ||
+               Status == XRayLogInitStatus::XRAY_LOG_INITIALIZING))
+    return;
+
   if (UNLIKELY(Status == XRayLogInitStatus::XRAY_LOG_FINALIZED ||
                Status == XRayLogInitStatus::XRAY_LOG_FINALIZING)) {
-    auto &TLD = getThreadLocalData();
     postCurrentThreadFCT(TLD);
     return;
   }
 
-  auto &TLD = getThreadLocalData();
+  auto T = getThreadLocalData();
+  if (T == nullptr)
+    return;
+
+  auto FCT = reinterpret_cast<FunctionCallTrie *>(atomic_load_relaxed(&T->FCT));
   switch (Entry) {
   case XRayEntryType::ENTRY:
   case XRayEntryType::LOG_ARGS_ENTRY:
-    TLD.FCT->enterFunction(FuncId, TSC, CPU);
+    FCT->enterFunction(FuncId, TSC, CPU);
     break;
   case XRayEntryType::EXIT:
   case XRayEntryType::TAIL:
-    TLD.FCT->exitFunction(FuncId, TSC, CPU);
+    FCT->exitFunction(FuncId, TSC, CPU);
     break;
   default:
     // FIXME: Handle bugs.
@@ -224,18 +323,23 @@
     return static_cast<XRayLogInitStatus>(CurrentStatus);
   }
 
+  // Mark then finalize the current generation of buffers. This allows us to let
+  // the threads currently holding onto new buffers still use them, but let the
+  // last reference do the memory cleanup.
+  DCHECK_NE(BQ, nullptr);
+  BQ->finalize();
+
   // Wait a grace period to allow threads to see that we're finalizing.
   SleepForMillis(profilingFlags()->grace_period_ms);
 
-  // We also want to make sure that the current thread's data is cleaned up, if
-  // we have any. We need to ensure that the call to postCurrentThreadFCT() is
-  // guarded by our recursion guard.
-  auto &TLD = getThreadLocalData();
-  {
-    RecursionGuard G(ReentranceGuard);
-    if (G)
-      postCurrentThreadFCT(TLD);
-  }
+  // If we for some reason are entering this function from an instrumented
+  // handler, we bail out.
+  RecursionGuard G(ReentranceGuard);
+  if (!G)
+    return static_cast<XRayLogInitStatus>(CurrentStatus);
+
+  // Post the current thread's data if we have any.
+  postCurrentThreadFCT(TLD);
 
   // Then we force serialize the log data.
   profileCollectorService::serialize();
@@ -246,12 +350,16 @@
 }
 
 XRayLogInitStatus
-profilingLoggingInit(UNUSED size_t BufferSize, UNUSED size_t BufferMax,
-                     void *Options, size_t OptionsSize) XRAY_NEVER_INSTRUMENT {
+profilingLoggingInit(size_t, size_t, void *Options,
+                     size_t OptionsSize) XRAY_NEVER_INSTRUMENT {
+  RecursionGuard G(ReentranceGuard);
+  if (!G)
+    return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
+
   s32 CurrentStatus = XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
   if (!atomic_compare_exchange_strong(&ProfilerLogStatus, &CurrentStatus,
                                       XRayLogInitStatus::XRAY_LOG_INITIALIZING,
-                                      memory_order_release)) {
+                                      memory_order_acq_rel)) {
     if (Verbosity())
       Report("Cannot initialize already initialised profiling "
              "implementation.\n");
@@ -280,41 +388,88 @@
   // We need to reset the profile data collection implementation now.
   profileCollectorService::reset();
 
+  // Then also reset the buffer queue implementation.
+  if (BQ == nullptr) {
+    bool Success = false;
+    new (&BufferQueueStorage)
+        BufferQueue(profilingFlags()->per_thread_allocator_max,
+                    profilingFlags()->buffers_max, Success);
+    if (!Success) {
+      if (Verbosity())
+        Report("Failed to initialize preallocated memory buffers!");
+      atomic_store(&ProfilerLogStatus,
+                   XRayLogInitStatus::XRAY_LOG_UNINITIALIZED,
+                   memory_order_release);
+      return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
+    }
+
+    // If we've succeded, set the global pointer to the initialised storage.
+    BQ = reinterpret_cast<BufferQueue *>(&BufferQueueStorage);
+  } else {
+    BQ->finalize();
+    auto InitStatus = BQ->init(profilingFlags()->per_thread_allocator_max,
+                               profilingFlags()->buffers_max);
+
+    if (InitStatus != BufferQueue::ErrorCode::Ok) {
+      if (Verbosity())
+        Report("Failed to initialize preallocated memory buffers; error: %s",
+               BufferQueue::getErrorString(InitStatus));
+      atomic_store(&ProfilerLogStatus,
+                   XRayLogInitStatus::XRAY_LOG_UNINITIALIZED,
+                   memory_order_release);
+      return XRayLogInitStatus::XRAY_LOG_UNINITIALIZED;
+    }
+
+    DCHECK(!BQ->finalizing());
+  }
+
   // We need to set up the exit handlers.
   static pthread_once_t Once = PTHREAD_ONCE_INIT;
-  pthread_once(&Once, +[] {
-    pthread_key_create(&ProfilingKey, +[](void *P) {
-      // This is the thread-exit handler.
-      auto &TLD = *reinterpret_cast<ProfilingData *>(P);
-      if (TLD.Allocators == nullptr && TLD.FCT == nullptr)
-        return;
+  pthread_once(
+      &Once, +[] {
+        pthread_key_create(
+            &ProfilingKey, +[](void *P) XRAY_NEVER_INSTRUMENT {
+              if (atomic_exchange(&ThreadExitingLatch, 1, memory_order_acq_rel))
+                return;
 
-      {
-        // If we're somehow executing this while inside a non-reentrant-friendly
-        // context, we skip attempting to post the current thread's data.
-        RecursionGuard G(ReentranceGuard);
-        if (G)
-          postCurrentThreadFCT(TLD);
-      }
-    });
+              if (P == nullptr)
+                return;
 
-    // We also need to set up an exit handler, so that we can get the profile
-    // information at exit time. We use the C API to do this, to not rely on C++
-    // ABI functions for registering exit handlers.
-    Atexit(+[] {
-      // Finalize and flush.
-      if (profilingFinalize() != XRAY_LOG_FINALIZED) {
-        cleanupTLD();
-        return;
-      }
-      if (profilingFlush() != XRAY_LOG_FLUSHED) {
-        cleanupTLD();
-        return;
-      }
-      if (Verbosity())
-        Report("XRay Profile flushed at exit.");
-    });
-  });
+              auto T = reinterpret_cast<ProfilingData *>(P);
+              if (atomic_load_relaxed(&T->Allocators) == 0)
+                return;
+
+              {
+                // If we're somehow executing this while inside a
+                // non-reentrant-friendly context, we skip attempting to post
+                // the current thread's data.
+                RecursionGuard G(ReentranceGuard);
+                if (!G)
+                  return;
+
+                postCurrentThreadFCT(*T);
+              }
+            });
+
+        // We also need to set up an exit handler, so that we can get the
+        // profile information at exit time. We use the C API to do this, to not
+        // rely on C++ ABI functions for registering exit handlers.
+        Atexit(+[]() XRAY_NEVER_INSTRUMENT {
+          if (atomic_exchange(&ThreadExitingLatch, 1, memory_order_acq_rel))
+            return;
+
+          auto Cleanup =
+              at_scope_exit([]() XRAY_NEVER_INSTRUMENT { cleanupTLD(); });
+
+          // Finalize and flush.
+          if (profilingFinalize() != XRAY_LOG_FINALIZED ||
+              profilingFlush() != XRAY_LOG_FLUSHED)
+            return;
+
+          if (Verbosity())
+            Report("XRay Profile flushed at exit.");
+        });
+      });
 
   __xray_log_set_buffer_iterator(profileCollectorService::nextBuffer);
   __xray_set_handler(profilingHandleArg0);
diff --git a/lib/xray/xray_profiling_flags.inc b/lib/xray/xray_profiling_flags.inc
index e9230ae..ccd7086 100644
--- a/lib/xray/xray_profiling_flags.inc
+++ b/lib/xray/xray_profiling_flags.inc
@@ -14,7 +14,7 @@
 #error "Define XRAY_FLAG prior to including this file!"
 #endif
 
-XRAY_FLAG(uptr, per_thread_allocator_max, 2 << 20,
+XRAY_FLAG(uptr, per_thread_allocator_max, 16384,
           "Maximum size of any single per-thread allocator.")
 XRAY_FLAG(uptr, global_allocator_max, 2 << 24,
           "Maximum size of the global allocator for profile storage.")
@@ -27,3 +27,6 @@
 XRAY_FLAG(bool, no_flush, false,
           "Set to true if we want the profiling implementation to not write "
           "out files.")
+XRAY_FLAG(int, buffers_max, 128,
+          "The number of buffers to pre-allocate used by the profiling "
+          "implementation.")
diff --git a/lib/xray/xray_segmented_array.h b/lib/xray/xray_segmented_array.h
index 42f53be..bc7e937 100644
--- a/lib/xray/xray_segmented_array.h
+++ b/lib/xray/xray_segmented_array.h
@@ -32,14 +32,9 @@
 /// is destroyed. When an Array is destroyed, it will destroy elements in the
 /// backing store but will not free the memory.
 template <class T> class Array {
-  struct SegmentBase {
-    SegmentBase *Prev;
-    SegmentBase *Next;
-  };
-
-  // We want each segment of the array to be cache-line aligned, and elements of
-  // the array be offset from the beginning of the segment.
-  struct Segment : SegmentBase {
+  struct Segment {
+    Segment *Prev;
+    Segment *Next;
     char Data[1];
   };
 
@@ -62,91 +57,35 @@
   //     kCacheLineSize-multiple segments, minus the size of two pointers.
   //
   //   - Request cacheline-multiple sized elements from the allocator.
-  static constexpr size_t AlignedElementStorageSize =
+  static constexpr uint64_t AlignedElementStorageSize =
       sizeof(typename std::aligned_storage<sizeof(T), alignof(T)>::type);
 
-  static constexpr size_t SegmentSize =
-      nearest_boundary(sizeof(Segment) + next_pow2(sizeof(T)), kCacheLineSize);
+  static constexpr uint64_t SegmentControlBlockSize = sizeof(Segment *) * 2;
+
+  static constexpr uint64_t SegmentSize = nearest_boundary(
+      SegmentControlBlockSize + next_pow2(sizeof(T)), kCacheLineSize);
 
   using AllocatorType = Allocator<SegmentSize>;
 
-  static constexpr size_t ElementsPerSegment =
-      (SegmentSize - sizeof(Segment)) / next_pow2(sizeof(T));
+  static constexpr uint64_t ElementsPerSegment =
+      (SegmentSize - SegmentControlBlockSize) / next_pow2(sizeof(T));
 
   static_assert(ElementsPerSegment > 0,
                 "Must have at least 1 element per segment.");
 
-  static SegmentBase SentinelSegment;
+  static Segment SentinelSegment;
 
-  using size_type = size_t;
+  using size_type = uint64_t;
 
 private:
-  AllocatorType *Alloc;
-  SegmentBase *Head = &SentinelSegment;
-  SegmentBase *Tail = &SentinelSegment;
-  size_t Size = 0;
-
-  // Here we keep track of segments in the freelist, to allow us to re-use
-  // segments when elements are trimmed off the end.
-  SegmentBase *Freelist = &SentinelSegment;
-
-  Segment *NewSegment() XRAY_NEVER_INSTRUMENT {
-    // We need to handle the case in which enough elements have been trimmed to
-    // allow us to re-use segments we've allocated before. For this we look into
-    // the Freelist, to see whether we need to actually allocate new blocks or
-    // just re-use blocks we've already seen before.
-    if (Freelist != &SentinelSegment) {
-      auto *FreeSegment = Freelist;
-      Freelist = FreeSegment->Next;
-      FreeSegment->Next = &SentinelSegment;
-      Freelist->Prev = &SentinelSegment;
-      return static_cast<Segment *>(FreeSegment);
-    }
-
-    auto SegmentBlock = Alloc->Allocate();
-    if (SegmentBlock.Data == nullptr)
-      return nullptr;
-
-    // Placement-new the Segment element at the beginning of the SegmentBlock.
-    auto S = reinterpret_cast<Segment *>(SegmentBlock.Data);
-    new (S) SegmentBase{&SentinelSegment, &SentinelSegment};
-    return S;
-  }
-
-  Segment *InitHeadAndTail() XRAY_NEVER_INSTRUMENT {
-    DCHECK_EQ(Head, &SentinelSegment);
-    DCHECK_EQ(Tail, &SentinelSegment);
-    auto Segment = NewSegment();
-    if (Segment == nullptr)
-      return nullptr;
-    DCHECK_EQ(Segment->Next, &SentinelSegment);
-    DCHECK_EQ(Segment->Prev, &SentinelSegment);
-    Head = Tail = static_cast<SegmentBase *>(Segment);
-    return Segment;
-  }
-
-  Segment *AppendNewSegment() XRAY_NEVER_INSTRUMENT {
-    auto S = NewSegment();
-    if (S == nullptr)
-      return nullptr;
-    DCHECK_NE(Tail, &SentinelSegment);
-    DCHECK_EQ(Tail->Next, &SentinelSegment);
-    DCHECK_EQ(S->Prev, &SentinelSegment);
-    DCHECK_EQ(S->Next, &SentinelSegment);
-    Tail->Next = S;
-    S->Prev = Tail;
-    Tail = S;
-    return static_cast<Segment *>(Tail);
-  }
-
   // This Iterator models a BidirectionalIterator.
   template <class U> class Iterator {
-    SegmentBase *S = &SentinelSegment;
-    size_t Offset = 0;
-    size_t Size = 0;
+    Segment *S = &SentinelSegment;
+    uint64_t Offset = 0;
+    uint64_t Size = 0;
 
   public:
-    Iterator(SegmentBase *IS, size_t Off, size_t S) XRAY_NEVER_INSTRUMENT
+    Iterator(Segment *IS, uint64_t Off, uint64_t S) XRAY_NEVER_INSTRUMENT
         : S(IS),
           Offset(Off),
           Size(S) {}
@@ -215,7 +154,7 @@
 
       // We need to compute the character-aligned pointer, offset from the
       // segment's Data location to get the element in the position of Offset.
-      auto Base = static_cast<Segment *>(S)->Data;
+      auto Base = &S->Data;
       auto AlignedOffset = Base + (RelOff * AlignedElementStorageSize);
       return *reinterpret_cast<U *>(AlignedOffset);
     }
@@ -223,17 +162,183 @@
     U *operator->() const XRAY_NEVER_INSTRUMENT { return &(**this); }
   };
 
+  AllocatorType *Alloc;
+  Segment *Head;
+  Segment *Tail;
+
+  // Here we keep track of segments in the freelist, to allow us to re-use
+  // segments when elements are trimmed off the end.
+  Segment *Freelist;
+  uint64_t Size;
+
+  // ===============================
+  // In the following implementation, we work through the algorithms and the
+  // list operations using the following notation:
+  //
+  //   - pred(s) is the predecessor (previous node accessor) and succ(s) is
+  //     the successor (next node accessor).
+  //
+  //   - S is a sentinel segment, which has the following property:
+  //
+  //         pred(S) == succ(S) == S
+  //
+  //   - @ is a loop operator, which can imply pred(s) == s if it appears on
+  //     the left of s, or succ(s) == S if it appears on the right of s.
+  //
+  //   - sL <-> sR : means a bidirectional relation between sL and sR, which
+  //     means:
+  //
+  //         succ(sL) == sR && pred(SR) == sL
+  //
+  //   - sL -> sR : implies a unidirectional relation between sL and SR,
+  //     with the following properties:
+  //
+  //         succ(sL) == sR
+  //
+  //     sL <- sR : implies a unidirectional relation between sR and sL,
+  //     with the following properties:
+  //
+  //         pred(sR) == sL
+  //
+  // ===============================
+
+  Segment *NewSegment() XRAY_NEVER_INSTRUMENT {
+    // We need to handle the case in which enough elements have been trimmed to
+    // allow us to re-use segments we've allocated before. For this we look into
+    // the Freelist, to see whether we need to actually allocate new blocks or
+    // just re-use blocks we've already seen before.
+    if (Freelist != &SentinelSegment) {
+      // The current state of lists resemble something like this at this point:
+      //
+      //   Freelist: @S@<-f0->...<->fN->@S@
+      //                  ^ Freelist
+      //
+      // We want to perform a splice of `f0` from Freelist to a temporary list,
+      // which looks like:
+      //
+      //   Templist: @S@<-f0->@S@
+      //                  ^ FreeSegment
+      //
+      // Our algorithm preconditions are:
+      DCHECK_EQ(Freelist->Prev, &SentinelSegment);
+
+      // Then the algorithm we implement is:
+      //
+      //   SFS = Freelist
+      //   Freelist = succ(Freelist)
+      //   if (Freelist != S)
+      //     pred(Freelist) = S
+      //   succ(SFS) = S
+      //   pred(SFS) = S
+      //
+      auto *FreeSegment = Freelist;
+      Freelist = Freelist->Next;
+
+      // Note that we need to handle the case where Freelist is now pointing to
+      // S, which we don't want to be overwriting.
+      // TODO: Determine whether the cost of the branch is higher than the cost
+      // of the blind assignment.
+      if (Freelist != &SentinelSegment)
+        Freelist->Prev = &SentinelSegment;
+
+      FreeSegment->Next = &SentinelSegment;
+      FreeSegment->Prev = &SentinelSegment;
+
+      // Our postconditions are:
+      DCHECK_EQ(Freelist->Prev, &SentinelSegment);
+      DCHECK_NE(FreeSegment, &SentinelSegment);
+      return FreeSegment;
+    }
+
+    auto SegmentBlock = Alloc->Allocate();
+    if (SegmentBlock.Data == nullptr)
+      return nullptr;
+
+    // Placement-new the Segment element at the beginning of the SegmentBlock.
+    new (SegmentBlock.Data) Segment{&SentinelSegment, &SentinelSegment, {0}};
+    auto SB = reinterpret_cast<Segment *>(SegmentBlock.Data);
+    return SB;
+  }
+
+  Segment *InitHeadAndTail() XRAY_NEVER_INSTRUMENT {
+    DCHECK_EQ(Head, &SentinelSegment);
+    DCHECK_EQ(Tail, &SentinelSegment);
+    auto S = NewSegment();
+    if (S == nullptr)
+      return nullptr;
+    DCHECK_EQ(S->Next, &SentinelSegment);
+    DCHECK_EQ(S->Prev, &SentinelSegment);
+    DCHECK_NE(S, &SentinelSegment);
+    Head = S;
+    Tail = S;
+    DCHECK_EQ(Head, Tail);
+    DCHECK_EQ(Tail->Next, &SentinelSegment);
+    DCHECK_EQ(Tail->Prev, &SentinelSegment);
+    return S;
+  }
+
+  Segment *AppendNewSegment() XRAY_NEVER_INSTRUMENT {
+    auto S = NewSegment();
+    if (S == nullptr)
+      return nullptr;
+    DCHECK_NE(Tail, &SentinelSegment);
+    DCHECK_EQ(Tail->Next, &SentinelSegment);
+    DCHECK_EQ(S->Prev, &SentinelSegment);
+    DCHECK_EQ(S->Next, &SentinelSegment);
+    S->Prev = Tail;
+    Tail->Next = S;
+    Tail = S;
+    DCHECK_EQ(S, S->Prev->Next);
+    DCHECK_EQ(Tail->Next, &SentinelSegment);
+    return S;
+  }
+
 public:
-  explicit Array(AllocatorType &A) XRAY_NEVER_INSTRUMENT : Alloc(&A) {}
+  explicit Array(AllocatorType &A) XRAY_NEVER_INSTRUMENT
+      : Alloc(&A),
+        Head(&SentinelSegment),
+        Tail(&SentinelSegment),
+        Freelist(&SentinelSegment),
+        Size(0) {}
+
+  Array() XRAY_NEVER_INSTRUMENT : Alloc(nullptr),
+                                  Head(&SentinelSegment),
+                                  Tail(&SentinelSegment),
+                                  Freelist(&SentinelSegment),
+                                  Size(0) {}
 
   Array(const Array &) = delete;
-  Array(Array &&O) NOEXCEPT : Alloc(O.Alloc),
-                              Head(O.Head),
-                              Tail(O.Tail),
-                              Size(O.Size) {
+  Array &operator=(const Array &) = delete;
+
+  Array(Array &&O) XRAY_NEVER_INSTRUMENT : Alloc(O.Alloc),
+                                           Head(O.Head),
+                                           Tail(O.Tail),
+                                           Freelist(O.Freelist),
+                                           Size(O.Size) {
+    O.Alloc = nullptr;
     O.Head = &SentinelSegment;
     O.Tail = &SentinelSegment;
     O.Size = 0;
+    O.Freelist = &SentinelSegment;
+  }
+
+  Array &operator=(Array &&O) XRAY_NEVER_INSTRUMENT {
+    Alloc = O.Alloc;
+    O.Alloc = nullptr;
+    Head = O.Head;
+    O.Head = &SentinelSegment;
+    Tail = O.Tail;
+    O.Tail = &SentinelSegment;
+    Freelist = O.Freelist;
+    O.Freelist = &SentinelSegment;
+    Size = O.Size;
+    O.Size = 0;
+    return *this;
+  }
+
+  ~Array() XRAY_NEVER_INSTRUMENT {
+    for (auto &E : *this)
+      (&E)->~T();
   }
 
   bool empty() const XRAY_NEVER_INSTRUMENT { return Size == 0; }
@@ -243,52 +348,71 @@
     return *Alloc;
   }
 
-  size_t size() const XRAY_NEVER_INSTRUMENT { return Size; }
+  uint64_t size() const XRAY_NEVER_INSTRUMENT { return Size; }
 
-  T *Append(const T &E) XRAY_NEVER_INSTRUMENT {
-    if (UNLIKELY(Head == &SentinelSegment))
-      if (InitHeadAndTail() == nullptr)
+  template <class... Args>
+  T *AppendEmplace(Args &&... args) XRAY_NEVER_INSTRUMENT {
+    DCHECK((Size == 0 && Head == &SentinelSegment && Head == Tail) ||
+           (Size != 0 && Head != &SentinelSegment && Tail != &SentinelSegment));
+    if (UNLIKELY(Head == &SentinelSegment)) {
+      auto R = InitHeadAndTail();
+      if (R == nullptr)
         return nullptr;
+    }
+
+    DCHECK_NE(Head, &SentinelSegment);
+    DCHECK_NE(Tail, &SentinelSegment);
 
     auto Offset = Size % ElementsPerSegment;
     if (UNLIKELY(Size != 0 && Offset == 0))
       if (AppendNewSegment() == nullptr)
         return nullptr;
 
-    auto Base = static_cast<Segment *>(Tail)->Data;
+    DCHECK_NE(Tail, &SentinelSegment);
+    auto Base = &Tail->Data;
     auto AlignedOffset = Base + (Offset * AlignedElementStorageSize);
-    auto Position = reinterpret_cast<T *>(AlignedOffset);
-    *Position = E;
+    DCHECK_LE(AlignedOffset + sizeof(T),
+              reinterpret_cast<unsigned char *>(Base) + SegmentSize);
+
+    // In-place construct at Position.
+    new (AlignedOffset) T{std::forward<Args>(args)...};
     ++Size;
-    return Position;
+    return reinterpret_cast<T *>(AlignedOffset);
   }
 
-  template <class... Args>
-  T *AppendEmplace(Args &&... args) XRAY_NEVER_INSTRUMENT {
-    if (UNLIKELY(Head == &SentinelSegment))
-      if (InitHeadAndTail() == nullptr)
-        return nullptr;
-
-    auto Offset = Size % ElementsPerSegment;
-    auto *LatestSegment = Tail;
-    if (UNLIKELY(Size != 0 && Offset == 0)) {
-      LatestSegment = AppendNewSegment();
-      if (LatestSegment == nullptr)
+  T *Append(const T &E) XRAY_NEVER_INSTRUMENT {
+    // FIXME: This is a duplication of AppenEmplace with the copy semantics
+    // explicitly used, as a work-around to GCC 4.8 not invoking the copy
+    // constructor with the placement new with braced-init syntax.
+    DCHECK((Size == 0 && Head == &SentinelSegment && Head == Tail) ||
+           (Size != 0 && Head != &SentinelSegment && Tail != &SentinelSegment));
+    if (UNLIKELY(Head == &SentinelSegment)) {
+      auto R = InitHeadAndTail();
+      if (R == nullptr)
         return nullptr;
     }
 
+    DCHECK_NE(Head, &SentinelSegment);
     DCHECK_NE(Tail, &SentinelSegment);
-    auto Base = static_cast<Segment *>(LatestSegment)->Data;
+
+    auto Offset = Size % ElementsPerSegment;
+    if (UNLIKELY(Size != 0 && Offset == 0))
+      if (AppendNewSegment() == nullptr)
+        return nullptr;
+
+    DCHECK_NE(Tail, &SentinelSegment);
+    auto Base = &Tail->Data;
     auto AlignedOffset = Base + (Offset * AlignedElementStorageSize);
-    auto Position = reinterpret_cast<T *>(AlignedOffset);
+    DCHECK_LE(AlignedOffset + sizeof(T),
+              reinterpret_cast<unsigned char *>(Tail) + SegmentSize);
 
     // In-place construct at Position.
-    new (Position) T{std::forward<Args>(args)...};
+    new (AlignedOffset) T(E);
     ++Size;
-    return reinterpret_cast<T *>(Position);
+    return reinterpret_cast<T *>(AlignedOffset);
   }
 
-  T &operator[](size_t Offset) const XRAY_NEVER_INSTRUMENT {
+  T &operator[](uint64_t Offset) const XRAY_NEVER_INSTRUMENT {
     DCHECK_LE(Offset, Size);
     // We need to traverse the array enough times to find the element at Offset.
     auto S = Head;
@@ -297,7 +421,7 @@
       Offset -= ElementsPerSegment;
       DCHECK_NE(S, &SentinelSegment);
     }
-    auto Base = static_cast<Segment *>(S)->Data;
+    auto Base = &S->Data;
     auto AlignedOffset = Base + (Offset * AlignedElementStorageSize);
     auto Position = reinterpret_cast<T *>(AlignedOffset);
     return *reinterpret_cast<T *>(Position);
@@ -332,41 +456,172 @@
 
   /// Remove N Elements from the end. This leaves the blocks behind, and not
   /// require allocation of new blocks for new elements added after trimming.
-  void trim(size_t Elements) XRAY_NEVER_INSTRUMENT {
-    if (Elements == 0)
-      return;
-
+  void trim(uint64_t Elements) XRAY_NEVER_INSTRUMENT {
     auto OldSize = Size;
-    Elements = Elements >= Size ? Size : Elements;
+    Elements = Elements > Size ? Size : Elements;
     Size -= Elements;
 
-    DCHECK_NE(Head, &SentinelSegment);
-    DCHECK_NE(Tail, &SentinelSegment);
-
-    for (auto SegmentsToTrim = (nearest_boundary(OldSize, ElementsPerSegment) -
-                                nearest_boundary(Size, ElementsPerSegment)) /
-                               ElementsPerSegment;
-         SegmentsToTrim > 0; --SegmentsToTrim) {
-
-      // We want to short-circuit if the trace is already empty.
-      if (Head == &SentinelSegment && Head == Tail)
-        return;
-
-      // Put the tail into the Freelist.
-      auto *FreeSegment = Tail;
-      Tail = Tail->Prev;
-      if (Tail == &SentinelSegment)
-        Head = Tail;
-      else
-        Tail->Next = &SentinelSegment;
-
+    // We compute the number of segments we're going to return from the tail by
+    // counting how many elements have been trimmed. Given the following:
+    //
+    // - Each segment has N valid positions, where N > 0
+    // - The previous size > current size
+    //
+    // To compute the number of segments to return, we need to perform the
+    // following calculations for the number of segments required given 'x'
+    // elements:
+    //
+    //   f(x) = {
+    //            x == 0          : 0
+    //          , 0 < x <= N      : 1
+    //          , N < x <= max    : x / N + (x % N ? 1 : 0)
+    //          }
+    //
+    // We can simplify this down to:
+    //
+    //   f(x) = {
+    //            x == 0          : 0,
+    //          , 0 < x <= max    : x / N + (x < N || x % N ? 1 : 0)
+    //          }
+    //
+    // And further down to:
+    //
+    //   f(x) = x ? x / N + (x < N || x % N ? 1 : 0) : 0
+    //
+    // We can then perform the following calculation `s` which counts the number
+    // of segments we need to remove from the end of the data structure:
+    //
+    //   s(p, c) = f(p) - f(c)
+    //
+    // If we treat p = previous size, and c = current size, and given the
+    // properties above, the possible range for s(...) is [0..max(typeof(p))/N]
+    // given that typeof(p) == typeof(c).
+    auto F = [](uint64_t X) {
+      return X ? (X / ElementsPerSegment) +
+                     (X < ElementsPerSegment || X % ElementsPerSegment ? 1 : 0)
+               : 0;
+    };
+    auto PS = F(OldSize);
+    auto CS = F(Size);
+    DCHECK_GE(PS, CS);
+    auto SegmentsToTrim = PS - CS;
+    for (auto I = 0uL; I < SegmentsToTrim; ++I) {
+      // Here we place the current tail segment to the freelist. To do this
+      // appropriately, we need to perform a splice operation on two
+      // bidirectional linked-lists. In particular, we have the current state of
+      // the doubly-linked list of segments:
+      //
+      //   @S@ <- s0 <-> s1 <-> ... <-> sT -> @S@
+      //
+      DCHECK_NE(Head, &SentinelSegment);
+      DCHECK_NE(Tail, &SentinelSegment);
       DCHECK_EQ(Tail->Next, &SentinelSegment);
-      FreeSegment->Next = Freelist;
-      FreeSegment->Prev = &SentinelSegment;
-      if (Freelist != &SentinelSegment)
-        Freelist->Prev = FreeSegment;
-      Freelist = FreeSegment;
+
+      if (Freelist == &SentinelSegment) {
+        // Our two lists at this point are in this configuration:
+        //
+        //   Freelist: (potentially) @S@
+        //   Mainlist: @S@<-s0<->s1<->...<->sPT<->sT->@S@
+        //                  ^ Head                ^ Tail
+        //
+        // The end state for us will be this configuration:
+        //
+        //   Freelist: @S@<-sT->@S@
+        //   Mainlist: @S@<-s0<->s1<->...<->sPT->@S@
+        //                  ^ Head          ^ Tail
+        //
+        // The first step for us is to hold a reference to the tail of Mainlist,
+        // which in our notation is represented by sT. We call this our "free
+        // segment" which is the segment we are placing on the Freelist.
+        //
+        //   sF = sT
+        //
+        // Then, we also hold a reference to the "pre-tail" element, which we
+        // call sPT:
+        //
+        //   sPT = pred(sT)
+        //
+        // We want to splice sT into the beginning of the Freelist, which in
+        // an empty Freelist means placing a segment whose predecessor and
+        // successor is the sentinel segment.
+        //
+        // The splice operation then can be performed in the following
+        // algorithm:
+        //
+        //   succ(sPT) = S
+        //   pred(sT) = S
+        //   succ(sT) = Freelist
+        //   Freelist = sT
+        //   Tail = sPT
+        //
+        auto SPT = Tail->Prev;
+        SPT->Next = &SentinelSegment;
+        Tail->Prev = &SentinelSegment;
+        Tail->Next = Freelist;
+        Freelist = Tail;
+        Tail = SPT;
+
+        // Our post-conditions here are:
+        DCHECK_EQ(Tail->Next, &SentinelSegment);
+        DCHECK_EQ(Freelist->Prev, &SentinelSegment);
+      } else {
+        // In the other case, where the Freelist is not empty, we perform the
+        // following transformation instead:
+        //
+        // This transforms the current state:
+        //
+        //   Freelist: @S@<-f0->@S@
+        //                  ^ Freelist
+        //   Mainlist: @S@<-s0<->s1<->...<->sPT<->sT->@S@
+        //                  ^ Head                ^ Tail
+        //
+        // Into the following:
+        //
+        //   Freelist: @S@<-sT<->f0->@S@
+        //                  ^ Freelist
+        //   Mainlist: @S@<-s0<->s1<->...<->sPT->@S@
+        //                  ^ Head          ^ Tail
+        //
+        // The algorithm is:
+        //
+        //   sFH = Freelist
+        //   sPT = pred(sT)
+        //   pred(SFH) = sT
+        //   succ(sT) = Freelist
+        //   pred(sT) = S
+        //   succ(sPT) = S
+        //   Tail = sPT
+        //   Freelist = sT
+        //
+        auto SFH = Freelist;
+        auto SPT = Tail->Prev;
+        auto ST = Tail;
+        SFH->Prev = ST;
+        ST->Next = Freelist;
+        ST->Prev = &SentinelSegment;
+        SPT->Next = &SentinelSegment;
+        Tail = SPT;
+        Freelist = ST;
+
+        // Our post-conditions here are:
+        DCHECK_EQ(Tail->Next, &SentinelSegment);
+        DCHECK_EQ(Freelist->Prev, &SentinelSegment);
+        DCHECK_EQ(Freelist->Next->Prev, Freelist);
+      }
     }
+
+    // Now in case we've spliced all the segments in the end, we ensure that the
+    // main list is "empty", or both the head and tail pointing to the sentinel
+    // segment.
+    if (Tail == &SentinelSegment)
+      Head = Tail;
+
+    DCHECK(
+        (Size == 0 && Head == &SentinelSegment && Tail == &SentinelSegment) ||
+        (Size != 0 && Head != &SentinelSegment && Tail != &SentinelSegment));
+    DCHECK(
+        (Freelist != &SentinelSegment && Freelist->Prev == &SentinelSegment) ||
+        (Freelist == &SentinelSegment && Tail->Next == &SentinelSegment));
   }
 
   // Provide iterators.
@@ -388,8 +643,8 @@
 // ensure that storage for the SentinelSegment is defined and has a single
 // address.
 template <class T>
-typename Array<T>::SegmentBase Array<T>::SentinelSegment{
-    &Array<T>::SentinelSegment, &Array<T>::SentinelSegment};
+typename Array<T>::Segment Array<T>::SentinelSegment{
+    &Array<T>::SentinelSegment, &Array<T>::SentinelSegment, {'\0'}};
 
 } // namespace __xray
 
diff --git a/lib/xray/xray_tsc.h b/lib/xray/xray_tsc.h
index 4507564..180d6df 100644
--- a/lib/xray/xray_tsc.h
+++ b/lib/xray/xray_tsc.h
@@ -13,10 +13,32 @@
 #ifndef XRAY_EMULATE_TSC_H
 #define XRAY_EMULATE_TSC_H
 
+#include "sanitizer_common/sanitizer_common.h"
+
 namespace __xray {
 static constexpr uint64_t NanosecondsPerSecond = 1000ULL * 1000 * 1000;
 }
 
+#if SANITIZER_FUCHSIA
+#include <zircon/syscalls.h>
+
+namespace __xray {
+
+inline bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT { return true; }
+
+ALWAYS_INLINE uint64_t readTSC(uint8_t &CPU) XRAY_NEVER_INSTRUMENT {
+  CPU = 0;
+  return _zx_ticks_get();
+}
+
+inline uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT {
+  return _zx_ticks_per_second();
+}
+
+} // namespace __xray
+
+#else // SANITIZER_FUCHSIA
+
 #if defined(__x86_64__)
 #include "xray_x86_64.inc"
 #elif defined(__powerpc64__)
@@ -64,5 +86,6 @@
 #else
 #error Target architecture is not supported.
 #endif // CPU architecture
+#endif // SANITIZER_FUCHSIA
 
 #endif // XRAY_EMULATE_TSC_H
diff --git a/lib/xray/xray_utils.cc b/lib/xray/xray_utils.cc
index 22c0dfa..59ba6c3 100644
--- a/lib/xray/xray_utils.cc
+++ b/lib/xray/xray_utils.cc
@@ -27,12 +27,108 @@
 #include <unistd.h>
 #include <utility>
 
+#if SANITIZER_FUCHSIA
+#include "sanitizer_common/sanitizer_symbolizer_fuchsia.h"
+
+#include <inttypes.h>
+#include <zircon/process.h>
+#include <zircon/sanitizer.h>
+#include <zircon/status.h>
+#include <zircon/syscalls.h>
+#endif
+
 namespace __xray {
 
-void printToStdErr(const char *Buffer) XRAY_NEVER_INSTRUMENT {
-  fprintf(stderr, "%s", Buffer);
+#if SANITIZER_FUCHSIA
+constexpr const char* ProfileSinkName = "llvm-xray";
+
+LogWriter::~LogWriter() {
+  _zx_handle_close(Vmo);
 }
 
+void LogWriter::WriteAll(const char *Begin, const char *End) XRAY_NEVER_INSTRUMENT {
+  if (Begin == End)
+    return;
+  auto TotalBytes = std::distance(Begin, End);
+
+  const size_t PageSize = flags()->xray_page_size_override > 0
+                              ? flags()->xray_page_size_override
+                              : GetPageSizeCached();
+  if (RoundUpTo(Offset, PageSize) != RoundUpTo(Offset + TotalBytes, PageSize)) {
+    // Resize the VMO to ensure there's sufficient space for the data.
+    zx_status_t Status = _zx_vmo_set_size(Vmo, Offset + TotalBytes);
+    if (Status != ZX_OK) {
+      Report("Failed to resize VMO: %s\n", _zx_status_get_string(Status));
+      return;
+    }
+  }
+
+  // Write the data into VMO.
+  zx_status_t Status = _zx_vmo_write(Vmo, Begin, Offset, TotalBytes);
+  if (Status != ZX_OK) {
+    Report("Failed to write: %s\n", _zx_status_get_string(Status));
+    return;
+  }
+  Offset += TotalBytes;
+}
+
+void LogWriter::Flush() XRAY_NEVER_INSTRUMENT {
+  // Nothing to do here since WriteAll writes directly into the VMO.
+}
+
+LogWriter *LogWriter::Open() XRAY_NEVER_INSTRUMENT {
+  // Create VMO to hold the profile data.
+  zx_handle_t Vmo;
+  zx_status_t Status = _zx_vmo_create(0, 0, &Vmo);
+  if (Status != ZX_OK) {
+    Report("XRay: cannot create VMO: %s\n", _zx_status_get_string(Status));
+    return nullptr;
+  }
+
+  // Get the KOID of the current process to use in the VMO name.
+  zx_info_handle_basic_t Info;
+  Status = _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &Info,
+                               sizeof(Info), NULL, NULL);
+  if (Status != ZX_OK) {
+    Report("XRay: cannot get basic info about current process handle: %s\n",
+           _zx_status_get_string(Status));
+    return nullptr;
+  }
+
+  // Give the VMO a name including our process KOID so it's easy to spot.
+  char VmoName[ZX_MAX_NAME_LEN];
+  internal_snprintf(VmoName, sizeof(VmoName), "%s.%zu", ProfileSinkName,
+                    Info.koid);
+  _zx_object_set_property(Vmo, ZX_PROP_NAME, VmoName, strlen(VmoName));
+
+  // Duplicate the handle since __sanitizer_publish_data consumes it and
+  // LogWriter needs to hold onto it.
+  zx_handle_t Handle;
+  Status =_zx_handle_duplicate(Vmo, ZX_RIGHT_SAME_RIGHTS, &Handle);
+  if (Status != ZX_OK) {
+    Report("XRay: cannot duplicate VMO handle: %s\n",
+           _zx_status_get_string(Status));
+    return nullptr;
+  }
+
+  // Publish the VMO that receives the logging. Note the VMO's contents can
+  // grow and change after publication. The contents won't be read out until
+  // after the process exits.
+  __sanitizer_publish_data(ProfileSinkName, Handle);
+
+  // Use the dumpfile symbolizer markup element to write the name of the VMO.
+  Report("XRay: " FORMAT_DUMPFILE "\n", ProfileSinkName, VmoName);
+
+  LogWriter *LW = reinterpret_cast<LogWriter *>(InternalAlloc(sizeof(LogWriter)));
+  new (LW) LogWriter(Vmo);
+  return LW;
+}
+
+void LogWriter::Close(LogWriter *LW) {
+  LW->~LogWriter();
+  InternalFree(LW);
+}
+#else // SANITIZER_FUCHSIA
 LogWriter::~LogWriter() {
   internal_close(Fd);
 }
@@ -95,5 +191,6 @@
   LW->~LogWriter();
   deallocate(LW);
 }
+#endif // SANITIZER_FUCHSIA
 
 } // namespace __xray
diff --git a/lib/xray/xray_utils.h b/lib/xray/xray_utils.h
index 3e0d282..6043897 100644
--- a/lib/xray/xray_utils.h
+++ b/lib/xray/xray_utils.h
@@ -20,30 +20,41 @@
 #include <sys/types.h>
 #include <utility>
 
+#include "sanitizer_common/sanitizer_common.h"
+#if SANITIZER_FUCHSIA
+#include <zircon/types.h>
+#endif
+
 namespace __xray {
 
 class LogWriter {
 public:
+#if SANITIZER_FUCHSIA
+ LogWriter(zx_handle_t Vmo) : Vmo(Vmo) {}
+#else
   explicit LogWriter(int Fd) : Fd(Fd) {}
-  ~LogWriter();
+#endif
+ ~LogWriter();
 
-  // Write a character range into a log.
-  void WriteAll(const char *Begin, const char *End);
+ // Write a character range into a log.
+ void WriteAll(const char *Begin, const char *End);
 
-  void Flush();
+ void Flush();
 
-  // Returns a new log instance initialized using the flag-provided values.
-  static LogWriter *Open();
-  // Closes and deallocates the log instance.
-  static void Close(LogWriter *LogWriter);
+ // Returns a new log instance initialized using the flag-provided values.
+ static LogWriter *Open();
+ // Closes and deallocates the log instance.
+ static void Close(LogWriter *LogWriter);
 
 private:
-  int Fd = -1;
+#if SANITIZER_FUCHSIA
+ zx_handle_t Vmo = ZX_HANDLE_INVALID;
+ uint64_t Offset = 0;
+#else
+ int Fd = -1;
+#endif
 };
 
-// Default implementation of the reporting interface for sanitizer errors.
-void printToStdErr(const char *Buffer);
-
 constexpr size_t gcd(size_t a, size_t b) {
   return (b == 0) ? a : gcd(b, a % b);
 }
diff --git a/lib/xray/xray_x86_64.cc b/lib/xray/xray_x86_64.cc
index d0411d0..e63ee1b 100644
--- a/lib/xray/xray_x86_64.cc
+++ b/lib/xray/xray_x86_64.cc
@@ -1,6 +1,8 @@
 #include "cpuid.h"
 #include "sanitizer_common/sanitizer_common.h"
+#if !SANITIZER_FUCHSIA
 #include "sanitizer_common/sanitizer_posix.h"
+#endif
 #include "xray_defs.h"
 #include "xray_interface_internal.h"
 
@@ -11,6 +13,8 @@
 #include <machine/cpu.h>
 #endif
 #include <sys/sysctl.h>
+#elif SANITIZER_FUCHSIA
+#include <zircon/syscalls.h>
 #endif
 
 #include <atomic>
@@ -104,7 +108,7 @@
 
     return 0;
 }
-#else
+#elif !SANITIZER_FUCHSIA
 uint64_t getTSCFrequency() XRAY_NEVER_INSTRUMENT {
     /* Not supported */
     return 0;
@@ -321,6 +325,7 @@
   return false;
 }
 
+#if !SANITIZER_FUCHSIA
 // We determine whether the CPU we're running on has the correct features we
 // need. In x86_64 this will be rdtscp support.
 bool probeRequiredCPUFeatures() XRAY_NEVER_INSTRUMENT {
@@ -343,5 +348,6 @@
   }
   return true;
 }
+#endif
 
 } // namespace __xray
diff --git a/test/.clang-format b/test/.clang-format
new file mode 100644
index 0000000..4799b66
--- /dev/null
+++ b/test/.clang-format
@@ -0,0 +1,2 @@
+BasedOnStyle: LLVM
+ColumnLimit: 0
diff --git a/test/asan/TestCases/Darwin/init_for_dlopen.cc b/test/asan/TestCases/Darwin/init_for_dlopen.cc
new file mode 100644
index 0000000..8a0fbf9
--- /dev/null
+++ b/test/asan/TestCases/Darwin/init_for_dlopen.cc
@@ -0,0 +1,46 @@
+// RUN: %clangxx -g -O0 %s -o %t
+
+// Check that trying to dlopen() the ASan dylib fails.
+// We explictly set `abort_on_error=0` because
+// - By default the lit config sets this but we don't want this
+//   test to implicitly depend on this.
+// - It avoids requiring `--crash` to be passed to `not`.
+// RUN: APPLE_ASAN_INIT_FOR_DLOPEN=0 %env_asan_opts=abort_on_error=0 not \
+// RUN:   %run %t %shared_libasan 2>&1 | \
+// RUN:   FileCheck -check-prefix=CHECK-DL-OPEN-FAIL %s
+// RUN: env -u APPLE_ASAN_INIT_FOR_DLOPEN %env_asan_opts=abort_on_error=0 not \
+// RUN:   %run %t %shared_libasan 2>&1 | \
+// RUN:   FileCheck -check-prefix=CHECK-DL-OPEN-FAIL %s
+
+// Check that we can successfully dlopen the ASan dylib when we set the right
+// environment variable.
+// RUN: env APPLE_ASAN_INIT_FOR_DLOPEN=1 %run %t %shared_libasan 2>&1 | \
+// RUN:   FileCheck -check-prefix=CHECK-DL-OPEN-SUCCESS %s
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+// CHECK-DL-OPEN-FAIL: ERROR: Interceptors are not working
+
+int main(int argc, char **argv) {
+  if (argc != 2) {
+    fprintf(stderr, "Usage: %s <dylib_path>\n", argv[0]);
+    return 1;
+  }
+  const char *dylib_path = argv[1];
+  void *handle = dlopen(dylib_path, RTLD_LAZY);
+  if (!handle) {
+    fprintf(stderr, "Failed to dlopen: %s\n", dlerror());
+    return 1;
+  }
+  // Make sure we can find a function we expect to be in the dylib.
+  void *fn = dlsym(handle, "__sanitizer_mz_size");
+  if (!fn) {
+    fprintf(stderr, "Failed to get symbol: %s\n", dlerror());
+    return 1;
+  }
+  // TODO(dliew): Actually call a function from the dylib that is safe to call.
+  // CHECK-DL-OPEN-SUCCESS: DONE
+  printf("DONE\n");
+  return 0;
+}
diff --git a/test/asan/TestCases/Darwin/odr-lto.cc b/test/asan/TestCases/Darwin/odr-lto.cc
index 56dd89b..e1e454b 100644
--- a/test/asan/TestCases/Darwin/odr-lto.cc
+++ b/test/asan/TestCases/Darwin/odr-lto.cc
@@ -1,4 +1,4 @@
-// Check that -asan-use-private-alias and use_odr_indicator=1 silence the false
+// Check that -asan-use-private-alias silence the false
 // positive ODR violation on Darwin with LTO.
 
 // REQUIRES: lto
@@ -6,7 +6,7 @@
 // RUN: %clangxx_asan -DPART=0 -c %s -o %t-1.o -flto -mllvm -asan-use-private-alias
 // RUN: %clangxx_asan -DPART=1 -c %s -o %t-2.o -flto -mllvm -asan-use-private-alias
 // RUN: %clangxx_asan %t-1.o %t-2.o -o %t -flto
-// RUN: %env_asan_opts=use_odr_indicator=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #include <stdio.h>
 #include <stdlib.h>
diff --git a/test/asan/TestCases/Linux/local_alias.cc b/test/asan/TestCases/Linux/local_alias.cc
index 266d3fe..635e30b 100644
--- a/test/asan/TestCases/Linux/local_alias.cc
+++ b/test/asan/TestCases/Linux/local_alias.cc
@@ -11,7 +11,7 @@
 // RUN: %clangxx -DBUILD_UNINSTRUMENTED_DSO=1 -fPIC -shared %s -o %t-UNINSTRUMENTED-SO.so
 // RUN: %clangxx %s -c -mllvm -asan-use-private-alias -o %t.o
 // RUN: %clangxx_asan %t.o %t-UNINSTRUMENTED-SO.so %t-INSTRUMENTED-SO.so -o %t-EXE
-// RUN: %env_asan_opts=use_odr_indicator=true %run %t-EXE
+// RUN: %run %t-EXE
 
 #if defined (BUILD_INSTRUMENTED_DSO)
 long h = 15;
diff --git a/test/asan/TestCases/Linux/odr-violation.cc b/test/asan/TestCases/Linux/odr-violation.cc
index 70437a8..05ee1e5 100644
--- a/test/asan/TestCases/Linux/odr-violation.cc
+++ b/test/asan/TestCases/Linux/odr-violation.cc
@@ -23,12 +23,20 @@
 // RUN: %env_asan_opts=fast_unwind_on_malloc=0:detect_odr_violation=2:suppressions=%t.supp      %run %t-ODR-EXE 2>&1 | FileCheck %s --check-prefix=DISABLED
 // RUN: rm -f %t.supp
 //
-// Use private aliases for global variables: use indicator symbol to detect ODR violation.
+// Use private aliases for global variables without indicator symbol.
 // RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared -mllvm -asan-use-private-alias %s -o %t-ODR-SO.so -DSZ=100
 // RUN: %clangxx_asan -mllvm -asan-use-private-alias %s %t-ODR-SO.so -Wl,-R. -o %t-ODR-EXE
-// RUN: %env_asan_opts=fast_unwind_on_malloc=0                              %run %t-ODR-EXE 2>&1 | FileCheck %s --check-prefix=DISABLED
-// RUN: %env_asan_opts=fast_unwind_on_malloc=0:use_odr_indicator=false      %run %t-ODR-EXE 2>&1 | FileCheck %s --check-prefix=DISABLED
-// RUN: %env_asan_opts=fast_unwind_on_malloc=0:use_odr_indicator=true   not %run %t-ODR-EXE 2>&1 | FileCheck %s
+// RUN: %env_asan_opts=fast_unwind_on_malloc=0 %run %t-ODR-EXE 2>&1 | FileCheck %s --check-prefix=DISABLED
+
+// Use private aliases for global variables: use indicator symbol to detect ODR violation.
+// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared -mllvm -asan-use-private-alias -mllvm -asan-use-odr-indicator  %s -o %t-ODR-SO.so -DSZ=100
+// RUN: %clangxx_asan -mllvm -asan-use-private-alias -mllvm -asan-use-odr-indicator %s %t-ODR-SO.so -Wl,-R. -o %t-ODR-EXE
+// RUN: %env_asan_opts=fast_unwind_on_malloc=0 not %run %t-ODR-EXE 2>&1 | FileCheck %s
+
+// Same as above but with clang switches.
+// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared -fsanitize-address-use-odr-indicator %s -o %t-ODR-SO.so -DSZ=100
+// RUN: %clangxx_asan -fsanitize-address-use-odr-indicator %s %t-ODR-SO.so -Wl,-R. -o %t-ODR-EXE
+// RUN: %env_asan_opts=fast_unwind_on_malloc=0 not %run %t-ODR-EXE 2>&1 | FileCheck %s
 
 // GNU driver doesn't handle .so files properly.
 // REQUIRES: Clang
diff --git a/test/asan/TestCases/Linux/odr-vtable.cc b/test/asan/TestCases/Linux/odr-vtable.cc
new file mode 100644
index 0000000..283295d
--- /dev/null
+++ b/test/asan/TestCases/Linux/odr-vtable.cc
@@ -0,0 +1,29 @@
+// FIXME: Same as test/asan/TestCases/Linux/odr-violation.cc ?
+// XFAIL: android
+
+// RUN: %clangxx_asan -fno-rtti -DBUILD_SO1 -fPIC -shared %s -o %t1.so
+// RUN: %clangxx_asan -fno-rtti -DBUILD_SO2 -fPIC -shared %s -o %t2.so
+// RUN: %clangxx_asan -fno-rtti %t1.so %t2.so %s -Wl,-R. -o %t
+// RUN: %env_asan_opts=fast_unwind_on_malloc=0:detect_odr_violation=2 not %run %t 2>&1 | FileCheck %s
+
+struct XYZ {
+  virtual void foo();
+};
+
+#if defined(BUILD_SO1)
+
+void XYZ::foo() {}
+
+#elif defined(BUILD_SO2)
+
+void XYZ::foo() {}
+
+#else
+
+int main() {}
+
+#endif
+
+// CHECK: AddressSanitizer: odr-violation
+// CHECK-NEXT: 'vtable for XYZ'
+// CHECK-NEXT: 'vtable for XYZ'
diff --git a/test/asan/TestCases/Linux/odr_indicators.cc b/test/asan/TestCases/Linux/odr_indicators.cc
new file mode 100644
index 0000000..36176b5
--- /dev/null
+++ b/test/asan/TestCases/Linux/odr_indicators.cc
@@ -0,0 +1,26 @@
+// RUN: %clangxx_asan -fPIC %s -o %t
+// RUN: %env_asan_opts=report_globals=2 %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,INDICATOR0
+
+// RUN: %clangxx_asan -fsanitize-address-use-odr-indicator -fPIC %s -o %t
+// RUN: %env_asan_opts=report_globals=2 %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK,INDICATOR1
+
+#include <stdio.h>
+
+int test_global_1;
+// INDICATOR0-DAG: Added Global{{.*}} name=test_global_1{{.*}} odr_indicator={{0x0+$}}
+// INDICATOR1-DAG: Added Global{{.*}} name=test_global_1{{.*}} odr_indicator={{0x0*[^0]+.*$}}
+
+static int test_global_2;
+// CHECK-DAG: Added Global{{.*}} name=test_global_2{{.*}} odr_indicator={{0xf+$}}
+
+namespace {
+static int test_global_3;
+// CHECK-DAG: Added Global{{.*}} name={{.*}}::test_global_3{{.*}} odr_indicator={{0xf+$}}
+} // namespace
+
+int main() {
+  const char f[] = "%d %d %d\n";
+  // CHECK-DAG: Added Global{{.*}} name=__const.main.f{{.*}} odr_indicator={{0xf+$}}
+  printf(f, test_global_1, test_global_2, test_global_3);
+  return 0;
+}
diff --git a/test/asan/TestCases/Linux/preinstalled_signal.cc b/test/asan/TestCases/Linux/preinstalled_signal.cc
index ac4ea93..2b50944 100644
--- a/test/asan/TestCases/Linux/preinstalled_signal.cc
+++ b/test/asan/TestCases/Linux/preinstalled_signal.cc
@@ -1,4 +1,3 @@
-// clang-format off
 // RUN: %clangxx -std=c++11 %s -o %t
 // RUN: env LD_PRELOAD=%shared_libasan %env_asan_opts=handle_segv=1 not %run %t 2>&1 | FileCheck %s
 // RUN: env LD_PRELOAD=%shared_libasan %env_asan_opts=handle_segv=2 not %run %t 2>&1 | FileCheck %s
@@ -17,7 +16,6 @@
 
 // This way of setting LD_PRELOAD does not work with Android test runner.
 // REQUIRES: !android
-// clang-format on
 
 #include <assert.h>
 #include <signal.h>
diff --git a/test/asan/TestCases/interception_failure_test.cc b/test/asan/TestCases/interception_failure_test.cc
index b4e6c58..4f6698e 100644
--- a/test/asan/TestCases/interception_failure_test.cc
+++ b/test/asan/TestCases/interception_failure_test.cc
@@ -5,12 +5,16 @@
 // RUN: %clangxx_asan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
 // RUN: %clangxx_asan -O2 %s -o %t && %run %t 2>&1 | FileCheck %s
 // RUN: %clangxx_asan -O3 %s -o %t && %run %t 2>&1 | FileCheck %s
-// XFAIL: freebsd, netbsd
+// XFAIL: freebsd
 
 // On Windows, defining strtoll in a static build results in linker errors, but
 // it works with the dynamic runtime.
 // XFAIL: win32-static-asan
 
+// On NetBSD, defining strtol in a static build results in linker errors, but
+// it works with the dynamic runtime.
+// XFAIL: netbsd && !asan-dynamic-runtime
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg
index a5e3f7b..3deb4cc 100644
--- a/test/asan/lit.cfg
+++ b/test/asan/lit.cfg
@@ -102,7 +102,7 @@
 config.substitutions.append( ("%clang_asan ", build_invocation(clang_asan_cflags)) )
 config.substitutions.append( ("%clangxx_asan ", build_invocation(clang_asan_cxxflags)) )
 if config.asan_dynamic:
-  if config.host_os == 'Linux':
+  if config.host_os in ['Linux', 'NetBSD']:
     shared_libasan_path = os.path.join(config.compiler_rt_libdir, "libclang_rt.asan{}.so".format(config.target_suffix))
   elif config.host_os == 'Darwin':
     shared_libasan_path = os.path.join(config.compiler_rt_libdir, 'libclang_rt.asan_{}_dynamic.dylib'.format(config.apple_platform))
diff --git a/test/hwasan/TestCases/abort-message-android.cc b/test/hwasan/TestCases/abort-message-android.cc
new file mode 100644
index 0000000..f89b929
--- /dev/null
+++ b/test/hwasan/TestCases/abort-message-android.cc
@@ -0,0 +1,28 @@
+// RUN: %clangxx_hwasan -DERR=1 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_hwasan -DERR=2 %s -o %t && not %run %t 2>&1 | FileCheck %s
+// REQUIRES: android
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <sanitizer/hwasan_interface.h>
+
+__attribute__((no_sanitize("hwaddress")))
+extern "C" void android_set_abort_message(const char *msg) {
+  fprintf(stderr, "== abort message start\n%s\n== abort message end\n", msg);
+}
+
+int main() {
+  __hwasan_enable_allocator_tagging();
+  char *volatile p = (char *)malloc(16);
+  if (ERR==1) {
+    p[16] = 1;
+  } else {
+    free(p);
+    free(p);
+  }
+  // CHECK: ERROR: HWAddressSanitizer:
+  // CHECK: == abort message start
+  // CHECK: ERROR: HWAddressSanitizer:
+  // CHECK: == abort message end
+}
diff --git a/test/hwasan/TestCases/cfi.cc b/test/hwasan/TestCases/cfi.cc
new file mode 100644
index 0000000..457e296
--- /dev/null
+++ b/test/hwasan/TestCases/cfi.cc
@@ -0,0 +1,18 @@
+// RUN: %clang_hwasan -fsanitize=cfi -fno-sanitize-trap=cfi -flto -fvisibility=hidden -fuse-ld=lld %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+
+// REQUIRES: android
+
+// Smoke test for CFI + HWASAN.
+
+struct A {
+  virtual void f();
+};
+
+void A::f() {}
+
+int main() {
+  // CHECK: control flow integrity check for type {{.*}} failed during cast to unrelated type
+  A *a = reinterpret_cast<A *>(reinterpret_cast<void *>(&main));
+  (void)a;
+}
diff --git a/test/hwasan/TestCases/deep-recursion.c b/test/hwasan/TestCases/deep-recursion.c
index 1ac0f5b..2fe77a7 100644
--- a/test/hwasan/TestCases/deep-recursion.c
+++ b/test/hwasan/TestCases/deep-recursion.c
@@ -30,25 +30,25 @@
 
 int main() { FUNC10(); }
 
-// D1: Previosly allocated frames
+// D1: Previously allocated frames
 // D1: in OOB
 // D1-NOT: in FUNC
 // D1: Memory tags around the buggy address
 
-// D2: Previosly allocated frames
+// D2: Previously allocated frames
 // D2: in OOB
 // D2: in FUNC1
 // D2-NOT: in FUNC
 // D2: Memory tags around the buggy address
 
-// D3: Previosly allocated frames
+// D3: Previously allocated frames
 // D3: in OOB
 // D3: in FUNC1
 // D3: in FUNC2
 // D3-NOT: in FUNC
 // D3: Memory tags around the buggy address
 
-// D5: Previosly allocated frames
+// D5: Previously allocated frames
 // D5: in OOB
 // D5: in FUNC1
 // D5: in FUNC2
@@ -57,7 +57,7 @@
 // D5-NOT: in FUNC
 // D5: Memory tags around the buggy address
 
-// DEFAULT: Previosly allocated frames
+// DEFAULT: Previously allocated frames
 // DEFAULT: in OOB
 // DEFAULT: in FUNC1
 // DEFAULT: in FUNC2
diff --git a/test/hwasan/TestCases/heap-buffer-overflow.c b/test/hwasan/TestCases/heap-buffer-overflow.c
index cd35d28..bff39d2 100644
--- a/test/hwasan/TestCases/heap-buffer-overflow.c
+++ b/test/hwasan/TestCases/heap-buffer-overflow.c
@@ -1,27 +1,47 @@
 // RUN: %clang_hwasan  %s -o %t
-// RUN: not %run %t 40 2>&1 | FileCheck %s --check-prefix=CHECK40
-// RUN: not %run %t 80 2>&1 | FileCheck %s --check-prefix=CHECK80
+// RUN:                                       not %run %t 40 2>&1 | FileCheck %s --check-prefix=CHECK40-LEFT
+// RUN: %env_hwasan_opts=malloc_align_right=2 not %run %t 40 2>&1 | FileCheck %s --check-prefix=CHECK40-RIGHT
+// RUN:                                       not %run %t 80 2>&1 | FileCheck %s --check-prefix=CHECK80-LEFT
+// RUN: %env_hwasan_opts=malloc_align_right=2 not %run %t 80 2>&1 | FileCheck %s --check-prefix=CHECK80-RIGHT
 // RUN: not %run %t -30 2>&1 | FileCheck %s --check-prefix=CHECKm30
 // RUN: not %run %t -30 1000000 2>&1 | FileCheck %s --check-prefix=CHECKMm30
 // RUN: not %run %t 1000000 1000000 2>&1 | FileCheck %s --check-prefix=CHECKM
 
+// Test OOB within the granule.
+// Misses the bug when malloc is left-aligned, catches it otherwise.
+// RUN:                                           %run %t 31
+// RUN: %env_hwasan_opts=malloc_align_right=2 not %run %t 31 2>&1 | FileCheck %s --check-prefix=CHECK31
+
+// RUN:                                           %run %t 30 20
+// RUN: %env_hwasan_opts=malloc_align_right=9 not %run %t 30 20 2>&1 | FileCheck %s --check-prefix=CHECK20-RIGHT8
+
+// RUN: %env_hwasan_opts=malloc_align_right=42 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-WRONG-FLAG
+
 // REQUIRES: stable-runtime
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <sanitizer/hwasan_interface.h>
 
+static volatile char sink;
+
 int main(int argc, char **argv) {
   __hwasan_enable_allocator_tagging();
   int offset = argc < 2 ? 40 : atoi(argv[1]);
   int size = argc < 3 ? 30 : atoi(argv[2]);
   char * volatile x = (char*)malloc(size);
-  x[offset] = 42;
-// CHECK40: allocated heap chunk; size: 32 offset: 8
-// CHECK40: is located 10 bytes to the right of 30-byte region
+  fprintf(stderr, "base: %p access: %p\n", x, &x[offset]);
+  sink = x[offset];
+
+// CHECK40-LEFT: allocated heap chunk; size: 32 offset: 8
+// CHECK40-LEFT: is located 10 bytes to the right of 30-byte region
+// CHECK40-RIGHT: allocated heap chunk; size: 32 offset:
+// CHECK40-RIGHT: is located 10 bytes to the right of 30-byte region
 //
-// CHECK80: allocated heap chunk; size: 32 offset: 16
-// CHECK80: is located 50 bytes to the right of 30-byte region
+// CHECK80-LEFT: allocated heap chunk; size: 32 offset: 16
+// CHECK80-LEFT: is located 50 bytes to the right of 30-byte region
+// CHECK80-RIGHT: allocated heap chunk; size: 32 offset:
+// CHECK80-RIGHT: is located 50 bytes to the right of 30-byte region
 //
 // CHECKm30: allocated heap chunk; size: 32 offset: 2
 // CHECKm30: is located 30 bytes to the left of 30-byte region
@@ -31,5 +51,11 @@
 //
 // CHECKM: is a large allocated heap chunk; size: 1003520 offset: 1000000
 // CHECKM: is located 0 bytes to the right of 1000000-byte region
+//
+// CHECK31: is located 1 bytes to the right of 30-byte region
+//
+// CHECK20-RIGHT8: is located 10 bytes to the right of 20-byte region [0x{{.*}}8,0x{{.*}}c)
+//
+// CHECK-WRONG-FLAG: ERROR: unsupported value of malloc_align_right flag: 42
   free(x);
 }
diff --git a/test/hwasan/TestCases/random-align-right.c b/test/hwasan/TestCases/random-align-right.c
new file mode 100644
index 0000000..8c524ef
--- /dev/null
+++ b/test/hwasan/TestCases/random-align-right.c
@@ -0,0 +1,35 @@
+// Tests malloc_align_right=1 and 8 (randomly aligning right).
+// RUN: %clang_hwasan  %s -o %t
+//
+// RUN: %run %t
+// RUN: %env_hwasan_opts=malloc_align_right=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1
+// RUN: %env_hwasan_opts=malloc_align_right=8 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK8
+
+// REQUIRES: stable-runtime
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sanitizer/hwasan_interface.h>
+
+static volatile void *sink;
+
+int main(int argc, char **argv) {
+  __hwasan_enable_allocator_tagging();
+
+  // Perform 1000 buffer overflows within the 16-byte granule,
+  // so that random right-alignment has a very high chance of
+  // catching at least one of them.
+  for (int i = 0; i < 1000; i++) {
+    char *p = (char*)malloc(20);
+    sink = p;
+    fprintf(stderr, "[%d] p: %p; accessing p[20]:\n", i, p);
+    p[20 * argc] = 0;  // requires malloc_align_right=1 to catch
+    fprintf(stderr, "[%d] p: %p; accessing p[30]:\n", i, p);
+    p[30 * argc] = 0;  // requires malloc_align_right={1,8} to catch
+// CHECK1: accessing p[20]
+// CHECK1-NEXT: HWAddressSanitizer: tag-mismatch
+// CHECK8: accessing p[30]:
+// CHECK8-NEXT: HWAddressSanitizer: tag-mismatch
+  }
+}
+
diff --git a/test/hwasan/TestCases/stack-history-length.c b/test/hwasan/TestCases/stack-history-length.c
index c8583c6..0aefd40 100644
--- a/test/hwasan/TestCases/stack-history-length.c
+++ b/test/hwasan/TestCases/stack-history-length.c
@@ -25,12 +25,12 @@
   OOB();
 }
 
-// YES: Previosly allocated frames
+// YES: Previously allocated frames
 // YES: OOB
 // YES: FUNC
 // YES: FUNC0
 
-// NO: Previosly allocated frames
+// NO: Previously allocated frames
 // NO: OOB
 // NO: FUNC
 // NO-NOT: FUNC0
diff --git a/test/hwasan/TestCases/stack-uar.c b/test/hwasan/TestCases/stack-uar.c
index 0b1faf8..863a840 100644
--- a/test/hwasan/TestCases/stack-uar.c
+++ b/test/hwasan/TestCases/stack-uar.c
@@ -27,7 +27,7 @@
   // CHECK: READ of size 1 at
   // CHECK: #0 {{.*}} in main{{.*}}stack-uar.c:[[@LINE-2]]
   // CHECK: is located in stack of thread
-  // CHECK: Previosly allocated frames:
+  // CHECK: Previously allocated frames:
   // CHECK: Unrelated3
   // CHECK: 16 CCC
   // CHECK: Unrelated2
diff --git a/test/hwasan/TestCases/tail-magic.c b/test/hwasan/TestCases/tail-magic.c
new file mode 100644
index 0000000..95c5ada
--- /dev/null
+++ b/test/hwasan/TestCases/tail-magic.c
@@ -0,0 +1,28 @@
+// Tests free_checks_tail_magic=1.
+// RUN: %clang_hwasan  %s -o %t
+// RUN: %env_hwasan_opts=free_checks_tail_magic=0     %run %t
+// RUN: %env_hwasan_opts=free_checks_tail_magic=1 not %run %t 2>&1 | FileCheck %s
+// RUN:                                           not %run %t 2>&1 | FileCheck %s
+
+// REQUIRES: stable-runtime
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sanitizer/hwasan_interface.h>
+
+static volatile void *sink;
+
+int main(int argc, char **argv) {
+  __hwasan_enable_allocator_tagging();
+
+  char *p = (char*)malloc(20);
+  sink = p;
+  p[20] = 0x42;
+  p[24] = 0x66;
+  free(p);
+// CHECK: ERROR: HWAddressSanitizer: alocation-tail-overwritten; heap object [{{.*}}) of size 20
+// CHECK: in main {{.*}}tail-magic.c:[[@LINE-2]]
+// CHECK: allocated here:
+// CHECK: in main {{.*}}tail-magic.c:[[@LINE-8]]
+// CHECK: Tail contains: .. .. .. .. 42 {{.. .. ..}} 66
+}
diff --git a/test/hwasan/TestCases/use-after-free.c b/test/hwasan/TestCases/use-after-free.c
index bc2c8d4..fcdd077 100644
--- a/test/hwasan/TestCases/use-after-free.c
+++ b/test/hwasan/TestCases/use-after-free.c
@@ -22,8 +22,8 @@
   if (ISREAD) r = x[5]; else x[5] = 42;  // should be on the same line.
   // CHECK: [[TYPE]] of size 1 at {{.*}} tags: [[PTR_TAG:[0-9a-f][0-9a-f]]]/[[MEM_TAG:[0-9a-f][0-9a-f]]] (ptr/mem)
   // CHECK: #0 {{.*}} in main {{.*}}use-after-free.c:[[@LINE-2]]
-
-  // CHECK: is a small unallocated heap chunk; size: 16 offset: 5
+  // Offset is 5 or 11 depending on left/right alignment.
+  // CHECK: is a small unallocated heap chunk; size: 16 offset: {{5|11}}
   // CHECK: is located 5 bytes inside of 10-byte region
   //
   // CHECK: freed by thread {{.*}} here:
diff --git a/test/msan/pthread_getname_np.cc b/test/msan/pthread_getname_np.cc
index e19b652..4827b3a 100644
--- a/test/msan/pthread_getname_np.cc
+++ b/test/msan/pthread_getname_np.cc
@@ -1,7 +1,7 @@
 // RUN: %clangxx_msan -std=c++11 -O0 %s -o %t && %run %t
 // The main goal is getting the pthread name back and
 // FreeBSD based do not support this feature
-// UNSUPPORTED: android, netbsd, freebsd
+// UNSUPPORTED: android, freebsd
 
 // Regression test for a deadlock in pthread_getattr_np
 
@@ -32,7 +32,11 @@
   assert(!res);
 
   const char *kMyThreadName = "my-thread-name";
+#if defined(__NetBSD__)
+  res = pthread_setname_np(t, "%s", (void *)kMyThreadName);
+#else
   res = pthread_setname_np(t, kMyThreadName);
+#endif
   assert(!res);
 
   char buf[100];
diff --git a/test/profile/Posix/instrprof-gcov-fork.test b/test/profile/Posix/instrprof-gcov-fork.test
index 4725048..5a406fd 100644
--- a/test/profile/Posix/instrprof-gcov-fork.test
+++ b/test/profile/Posix/instrprof-gcov-fork.test
@@ -1,4 +1,4 @@
-XFAIL: arm
+UNSUPPORTED: linux
 
 RUN: mkdir -p %t.d
 RUN: cd %t.d
diff --git a/test/profile/instrprof-darwin-exports.c b/test/profile/instrprof-darwin-exports.c
index 146ad5e..1ef36ae 100644
--- a/test/profile/instrprof-darwin-exports.c
+++ b/test/profile/instrprof-darwin-exports.c
@@ -8,6 +8,9 @@
 // RUN: %clang_profgen -Werror -fcoverage-mapping -Wl,-exported_symbols_list,%t.exports -o %t %s 2>&1 | tee -a %t.log
 // RUN: cat %t.log | count 0
 
+// RUN: %clang -Werror -Wl,-exported_symbols_list,%t.exports --coverage -o %t.gcov %s | tee -a %t.gcov.log
+// RUN: cat %t.gcov.log | count 0
+
 // The default set of weak external symbols should match the set of symbols
 // exported by clang. See Darwin::addProfileRTLibs.
 
@@ -16,4 +19,9 @@
 // RUN: nm -jUg %t > %t.clang.exports
 // RUN: diff %t.default.exports %t.clang.exports
 
+// RUN: %clang -Werror --coverage -o %t.gcov.default %s
+// RUN: nm -jUg %t.gcov | grep -v __mh_execute_header > %t.gcov.exports
+// RUN: nm -jUg %t.gcov.default | grep -v __mh_execute_header > %t.gcov.default.exports
+// RUN: diff %t.gcov.default.exports %t.gcov.exports
+
 int main() {}
diff --git a/test/sanitizer_common/TestCases/FreeBSD/capsicum.cc b/test/sanitizer_common/TestCases/FreeBSD/capsicum.cc
new file mode 100644
index 0000000..1bfb6f8
--- /dev/null
+++ b/test/sanitizer_common/TestCases/FreeBSD/capsicum.cc
@@ -0,0 +1,68 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <sys/capsicum.h>
+#include <sys/ioctl.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+void test_cap_ioctls() {
+  cap_rights_t rights;
+  unsigned long ncmds[] = {TIOCGETA, TIOCGWINSZ, FIODTYPE};
+  unsigned long rcmds = 0;
+  cap_rights_t *rptr = cap_rights_init(&rights, CAP_IOCTL, CAP_READ);
+  assert(rptr);
+
+  int rv = cap_rights_limit(STDIN_FILENO, &rights);
+  assert(rv == 0);
+  rv = cap_ioctls_limit(STDIN_FILENO, ncmds, 3);
+  assert(rv == 0);
+  ssize_t rz = cap_ioctls_get(STDIN_FILENO, &rcmds, 3);
+  assert(rz == 3);
+  printf("ioctls test: %ld commands authorized\n", rz);
+}
+
+void test_cap_rights() {
+  cap_rights_t rights, little, remove, grights;
+  cap_rights_t *rptr = cap_rights_init(&rights, CAP_IOCTL, CAP_READ);
+  assert(rptr);
+  cap_rights_t *gptr = cap_rights_init(&remove, CAP_IOCTL);
+  assert(gptr);
+  cap_rights_t *sptr = cap_rights_init(&little, CAP_READ);
+  assert(sptr);
+  bool hasit = cap_rights_contains(rptr, sptr);
+  assert(hasit == true);
+  cap_rights_t *pptr = cap_rights_remove(&rights, gptr);
+  hasit = cap_rights_contains(pptr, sptr);
+  assert(hasit == true);
+  cap_rights_t *aptr = cap_rights_merge(&rights, gptr);
+  assert(aptr);
+  bool correct = cap_rights_is_valid(&rights);
+  assert(correct == true);
+
+  int rv = cap_rights_limit(STDIN_FILENO, &rights);
+  assert(rv == 0);
+  rv = cap_rights_get(STDIN_FILENO, &grights);
+  assert(rv == 0);
+  assert(memcmp(&grights, &rights, sizeof(grights)) == 0);
+  cap_rights_t *iptr = cap_rights_set(&rights, CAP_IOCTL);
+  assert(iptr);
+  cap_rights_t *eptr = cap_rights_clear(&rights, CAP_READ);
+  assert(eptr);
+  hasit = cap_rights_is_set(&rights, CAP_IOCTL);
+  assert(hasit == true);
+  printf("rights test: %d\n", rv);
+}
+
+int main(void) {
+  test_cap_ioctls();
+
+  test_cap_rights();
+
+  // CHECK: ioctls test: {{.*}} commands authorized
+  // CHECK: rights test: {{.*}}
+}
diff --git a/test/sanitizer_common/TestCases/FreeBSD/lit.local.cfg b/test/sanitizer_common/TestCases/FreeBSD/lit.local.cfg
new file mode 100644
index 0000000..6f2f428
--- /dev/null
+++ b/test/sanitizer_common/TestCases/FreeBSD/lit.local.cfg
@@ -0,0 +1,9 @@
+def getRoot(config):
+  if not config.parent:
+    return config
+  return getRoot(config.parent)
+
+root = getRoot(config)
+
+if root.host_os not in ['FreeBSD']:
+  config.unsupported = True
diff --git a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc
index e17de18..bd58f4b 100644
--- a/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc
+++ b/test/sanitizer_common/TestCases/Linux/allow_user_segv.cc
@@ -1,7 +1,6 @@
 // Regression test for
 // https://code.google.com/p/address-sanitizer/issues/detail?id=180
 
-// clang-format off
 // RUN: %clangxx -O0 %s -o %t
 
 // RUN: %env_tool_opts=handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0
@@ -15,7 +14,6 @@
 // RUN: %env_tool_opts=handle_segv=0:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0
 // RUN: %env_tool_opts=handle_segv=1:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1
 // RUN: %env_tool_opts=handle_segv=2:allow_user_segv_handler=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2
-// clang-format on
 
 // Flaky errors in debuggerd with "waitpid returned unexpected pid (0)" in logcat.
 // UNSUPPORTED: android && i386-target-arch
diff --git a/test/sanitizer_common/TestCases/Linux/assert.cc b/test/sanitizer_common/TestCases/Linux/assert.cc
index 9c5263f..2a73c50 100644
--- a/test/sanitizer_common/TestCases/Linux/assert.cc
+++ b/test/sanitizer_common/TestCases/Linux/assert.cc
@@ -1,11 +1,9 @@
 // Test the handle_abort option.
 
-// clang-format off
 // RUN: %clangxx %s -o %t
 // RUN:                              not --crash %run %t 2>&1 | FileCheck --check-prefix=CHECK0 %s
 // RUN: %env_tool_opts=handle_abort=0 not --crash %run %t 2>&1 | FileCheck --check-prefix=CHECK0 %s
 // RUN: %env_tool_opts=handle_abort=1 not         %run %t 2>&1 | FileCheck --check-prefix=CHECK1 %s
-// clang-format on
 
 #include <assert.h>
 #include <stdio.h>
diff --git a/test/sanitizer_common/TestCases/Linux/ill.cc b/test/sanitizer_common/TestCases/Linux/ill.cc
index 43f7a78..bbde13b 100644
--- a/test/sanitizer_common/TestCases/Linux/ill.cc
+++ b/test/sanitizer_common/TestCases/Linux/ill.cc
@@ -1,11 +1,9 @@
 // Test the handle_sigill option.
 
-// clang-format off
 // RUN: %clangxx %s -o %t -O1
 // RUN:                                not --crash %run %t 2>&1 | FileCheck --check-prefix=CHECK0 %s
 // RUN: %env_tool_opts=handle_sigill=0 not --crash %run %t 2>&1 | FileCheck --check-prefix=CHECK0 %s
 // RUN: %env_tool_opts=handle_sigill=1 not         %run %t 2>&1 | FileCheck --check-prefix=CHECK1 %s
-// clang-format on
 
 // FIXME: seems to fail on ARM
 // REQUIRES: x86_64-target-arch
diff --git a/test/sanitizer_common/TestCases/Linux/signal_segv_handler.cc b/test/sanitizer_common/TestCases/Linux/signal_segv_handler.cc
index d6c3ecb..9802617 100644
--- a/test/sanitizer_common/TestCases/Linux/signal_segv_handler.cc
+++ b/test/sanitizer_common/TestCases/Linux/signal_segv_handler.cc
@@ -1,6 +1,4 @@
-// clang-format off
 // RUN: %clangxx -O1 %s -o %t && TSAN_OPTIONS="flush_memory_ms=1 memory_limit_mb=1" %run %t 2>&1 | FileCheck %s
-// clang-format on
 
 // JVM uses SEGV to preempt threads. All threads do a load from a known address
 // periodically. When runtime needs to preempt threads, it unmaps the page.
diff --git a/test/sanitizer_common/TestCases/NetBSD/asysctl.cc b/test/sanitizer_common/TestCases/NetBSD/asysctl.cc
new file mode 100644
index 0000000..acdfb17
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/asysctl.cc
@@ -0,0 +1,44 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <sys/sysctl.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void test_asysctl() {
+  int mib[] = {CTL_KERN, KERN_OSTYPE};
+  size_t len;
+  char *buf = (char *)asysctl(mib, __arraycount(mib), &len);
+  assert(buf);
+
+  printf("asysctl: '%s' size: '%zu'\n", buf, len);
+
+  free(buf);
+}
+
+void test_asysctlbyname() {
+  size_t len;
+  char *buf = (char *)asysctlbyname("kern.ostype", &len);
+  assert(buf);
+
+  printf("asysctlbyname: '%s' size: '%zu'\n", buf, len);
+
+  free(buf);
+}
+
+int main(void) {
+  printf("asysctl\n");
+
+  test_asysctl();
+  test_asysctlbyname();
+
+  return 0;
+
+  // CHECK: asysctl
+  // CHECK: asysctl: '{{.*}}' size: '{{.*}}'
+  // CHECK: asysctlbyname: '{{.*}}' size: '{{.*}}'
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/cdb.cc b/test/sanitizer_common/TestCases/NetBSD/cdb.cc
new file mode 100644
index 0000000..065623b
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/cdb.cc
@@ -0,0 +1,134 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <sys/param.h>
+
+#include <sys/types.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <cdbr.h>
+#include <cdbw.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static char *name;
+
+const char data1[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
+const char data2[] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17};
+const char key1[] = {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27};
+const char key2[] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37};
+
+void test_cdbw() {
+  uint32_t idx;
+
+  struct cdbw *cdbw = cdbw_open();
+  assert(cdbw);
+
+  int rv = cdbw_put_data(cdbw, data1, __arraycount(data1), &idx);
+  assert(!rv);
+
+  rv = cdbw_put_key(cdbw, key1, __arraycount(key1), idx);
+  assert(!rv);
+
+  rv = cdbw_put(cdbw, key2, __arraycount(key2), data2, __arraycount(data2));
+  assert(!rv);
+
+  name = strdup("/tmp/temp.XXXXXX");
+  assert(name);
+
+  name = mktemp(name);
+  assert(name);
+
+  int fd = open(name, O_RDWR | O_CREAT, 0644);
+  assert(fd != -1);
+
+  cdbw_output(cdbw, fd, "TEST1", cdbw_stable_seeder);
+
+  cdbw_close(cdbw);
+
+  rv = close(fd);
+  assert(rv != -1);
+}
+
+void test_cdbr1() {
+  struct cdbr *cdbr = cdbr_open(name, CDBR_DEFAULT);
+  assert(cdbr);
+
+  uint32_t idx = cdbr_entries(cdbr);
+  assert(idx > 0);
+  printf("entries: %" PRIu32 "\n", idx);
+
+  const void *data;
+  size_t data_len;
+  int rv = cdbr_get(cdbr, idx - 1, &data, &data_len);
+  assert(rv == 0);
+
+  printf("data: ");
+  for (size_t i = 0; i < data_len; i++)
+    printf("%02" PRIx8, ((uint8_t *)data)[i]);
+  printf("\n");
+
+  rv = cdbr_find(cdbr, key1, __arraycount(key1), &data, &data_len);
+
+  printf("data: ");
+  for (size_t i = 0; i < data_len; i++)
+    printf("%02" PRIx8, ((uint8_t *)data)[i]);
+  printf("\n");
+
+  cdbr_close(cdbr);
+}
+
+#define COOKIE ((void *)1)
+
+static void cdbr_unmap(void *cookie, void *base, size_t sz) {
+  assert(cookie == COOKIE);
+  int rv = munmap(base, sz);
+  assert(rv != -1);
+}
+
+void test_cdbr2() {
+  struct stat sb;
+
+  int fd = open(name, O_RDONLY);
+  assert(fd != -1);
+
+  int rv = fstat(fd, &sb);
+  assert(rv != -1);
+
+  size_t sz = sb.st_size;
+  assert(sz < SSIZE_MAX);
+
+  void *base = mmap(NULL, sz, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0);
+  assert(base != MAP_FAILED);
+
+  rv = close(fd);
+  assert(rv != -1);
+
+  struct cdbr *cdbr = cdbr_open_mem(base, sz, CDBR_DEFAULT, cdbr_unmap, COOKIE);
+  assert(cdbr);
+
+  printf("entries: %" PRIu32 "\n", cdbr_entries(cdbr));
+
+  cdbr_close(cdbr);
+}
+
+int main(void) {
+  printf("cdb\n");
+
+  test_cdbw();
+  test_cdbr1();
+  test_cdbr2();
+
+  // CHECK: cdb
+  // CHECK: entries: 2
+  // CHECK: data: 1011121314151617
+  // CHECK: data: 0001020304050607
+  // CHECK: entries: 2
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/fparseln.cc b/test/sanitizer_common/TestCases/NetBSD/fparseln.cc
new file mode 100644
index 0000000..8a71d5f
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/fparseln.cc
@@ -0,0 +1,25 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(void) {
+  printf("fparseln\n");
+
+  FILE *fp = fopen("/etc/fstab", "r");
+  assert(fp);
+
+  int flags = FPARSELN_UNESCALL;
+  const char *delim = "\\\\#";
+  size_t lineno = 0, len;
+  char *line;
+  while ((line = fparseln(fp, &len, &lineno, delim, flags))) {
+    printf("lineno: %zu, length: %zu, line: %s\n", lineno, len, line);
+    free(line);
+  }
+
+  // CHECK: fparseln
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/fts.cc b/test/sanitizer_common/TestCases/NetBSD/fts.cc
new file mode 100644
index 0000000..1461005
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/fts.cc
@@ -0,0 +1,40 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+  char *const paths[] = {(char *)"/etc", 0};
+  FTS *ftsp = fts_open(paths, FTS_LOGICAL, NULL);
+  assert(ftsp);
+
+  FTSENT *chp = fts_children(ftsp, 0);
+  assert(chp);
+
+  size_t n = 0;
+  for (FTSENT *p = fts_read(ftsp); p; p = fts_read(ftsp)) {
+    /* Skip recursively subdirectories */
+    if (p->fts_info == FTS_D && p->fts_level != FTS_ROOTLEVEL) /* pre-order */
+      fts_set(ftsp, p, FTS_SKIP);
+    else if (p->fts_info == FTS_DP) /* post-order */
+      continue;
+    else if (p->fts_info == FTS_F) /* regular file */
+      n++;
+  }
+
+  int rv = fts_close(ftsp);
+  assert(!rv);
+
+  printf("Number of files in /etc: '%zu'\n", n);
+
+  return EXIT_SUCCESS;
+
+  // CHECK: Number of files in /etc: '{{.*}}'
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/getvfsstat.cc b/test/sanitizer_common/TestCases/NetBSD/getvfsstat.cc
new file mode 100644
index 0000000..ea72e41
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/getvfsstat.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <sys/types.h>
+
+#include <sys/statvfs.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(void) {
+  printf("getvfsstat\n");
+
+  int rv = getvfsstat(NULL, 0, ST_WAIT);
+  assert(rv != -1);
+
+  size_t sz = rv * sizeof(struct statvfs);
+  struct statvfs *buf = (struct statvfs *)malloc(sz);
+  assert(buf);
+
+  rv = getvfsstat(buf, sz, ST_WAIT);
+  assert(rv != -1);
+
+  for (int i = 0; i < rv; i++) {
+    printf("Filesystem %d\n", i);
+    printf("\tfstypename=%s\n", buf[i].f_fstypename);
+    printf("\tmntonname=%s\n", buf[i].f_mntonname);
+    printf("\tmntfromname=%s\n", buf[i].f_mntfromname);
+  }
+
+  free(buf);
+
+  // CHECK: getvfsstat
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/md2.cc b/test/sanitizer_common/TestCases/NetBSD/md2.cc
new file mode 100644
index 0000000..f76a35a
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/md2.cc
@@ -0,0 +1,114 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <endian.h>
+#include <md2.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1() {
+  MD2_CTX ctx;
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+  uint8_t digest[MD2_DIGEST_LENGTH];
+
+  MD2Init(&ctx);
+  MD2Update(&ctx, entropy, __arraycount(entropy));
+  MD2Final(digest, &ctx);
+
+  printf("test1: '");
+  for (size_t i = 0; i < __arraycount(digest); i++)
+    printf("%02x", digest[i]);
+  printf("'\n");
+}
+
+void test2() {
+  MD2_CTX ctx;
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+  char digest[MD2_DIGEST_STRING_LENGTH];
+
+  MD2Init(&ctx);
+  MD2Update(&ctx, entropy, __arraycount(entropy));
+  char *p = MD2End(&ctx, digest);
+  assert(p == digest);
+
+  printf("test2: '%s'\n", digest);
+}
+
+void test3() {
+  MD2_CTX ctx;
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+
+  MD2Init(&ctx);
+  MD2Update(&ctx, entropy, __arraycount(entropy));
+  char *p = MD2End(&ctx, NULL);
+  assert(strlen(p) == MD2_DIGEST_STRING_LENGTH - 1);
+
+  printf("test3: '%s'\n", p);
+
+  free(p);
+}
+
+void test4() {
+  char digest[MD2_DIGEST_STRING_LENGTH];
+
+  char *p = MD2File("/etc/fstab", digest);
+  assert(p == digest);
+
+  printf("test4: '%s'\n", p);
+}
+
+void test5() {
+  char *p = MD2File("/etc/fstab", NULL);
+  assert(strlen(p) == MD2_DIGEST_STRING_LENGTH - 1);
+
+  printf("test5: '%s'\n", p);
+
+  free(p);
+}
+
+void test6() {
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+  char digest[MD2_DIGEST_STRING_LENGTH];
+
+  char *p = MD2Data(entropy, __arraycount(entropy), digest);
+  assert(p == digest);
+
+  printf("test6: '%s'\n", p);
+}
+
+void test7() {
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+
+  char *p = MD2Data(entropy, __arraycount(entropy), NULL);
+  assert(strlen(p) == MD2_DIGEST_STRING_LENGTH - 1);
+
+  printf("test7: '%s'\n", p);
+
+  free(p);
+}
+
+int main(void) {
+  printf("MD2\n");
+
+  test1();
+  test2();
+  test3();
+  test4();
+  test5();
+  test6();
+  test7();
+
+  // CHECK: MD2
+  // CHECK: test1: 'e303e49b34f981c2740cdf809200d51b'
+  // CHECK: test2: 'e303e49b34f981c2740cdf809200d51b'
+  // CHECK: test3: 'e303e49b34f981c2740cdf809200d51b'
+  // CHECK: test4: 'a409cff8627afa00f3b563cf5f09af05'
+  // CHECK: test5: 'a409cff8627afa00f3b563cf5f09af05'
+  // CHECK: test6: '{{.*}}'
+  // CHECK: test7: '{{.*}}'
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/md4.cc b/test/sanitizer_common/TestCases/NetBSD/md4.cc
new file mode 100644
index 0000000..8318326
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/md4.cc
@@ -0,0 +1,114 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <endian.h>
+#include <md4.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1() {
+  MD4_CTX ctx;
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+  uint8_t digest[MD4_DIGEST_LENGTH];
+
+  MD4Init(&ctx);
+  MD4Update(&ctx, entropy, __arraycount(entropy));
+  MD4Final(digest, &ctx);
+
+  printf("test1: '");
+  for (size_t i = 0; i < __arraycount(digest); i++)
+    printf("%02x", digest[i]);
+  printf("'\n");
+}
+
+void test2() {
+  MD4_CTX ctx;
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+  char digest[MD4_DIGEST_STRING_LENGTH];
+
+  MD4Init(&ctx);
+  MD4Update(&ctx, entropy, __arraycount(entropy));
+  char *p = MD4End(&ctx, digest);
+  assert(p == digest);
+
+  printf("test2: '%s'\n", digest);
+}
+
+void test3() {
+  MD4_CTX ctx;
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+
+  MD4Init(&ctx);
+  MD4Update(&ctx, entropy, __arraycount(entropy));
+  char *p = MD4End(&ctx, NULL);
+  assert(strlen(p) == MD4_DIGEST_STRING_LENGTH - 1);
+
+  printf("test3: '%s'\n", p);
+
+  free(p);
+}
+
+void test4() {
+  char digest[MD4_DIGEST_STRING_LENGTH];
+
+  char *p = MD4File("/etc/fstab", digest);
+  assert(p == digest);
+
+  printf("test4: '%s'\n", p);
+}
+
+void test5() {
+  char *p = MD4File("/etc/fstab", NULL);
+  assert(strlen(p) == MD4_DIGEST_STRING_LENGTH - 1);
+
+  printf("test5: '%s'\n", p);
+
+  free(p);
+}
+
+void test6() {
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+  char digest[MD4_DIGEST_STRING_LENGTH];
+
+  char *p = MD4Data(entropy, __arraycount(entropy), digest);
+  assert(p == digest);
+
+  printf("test6: '%s'\n", p);
+}
+
+void test7() {
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+
+  char *p = MD4Data(entropy, __arraycount(entropy), NULL);
+  assert(strlen(p) == MD4_DIGEST_STRING_LENGTH - 1);
+
+  printf("test7: '%s'\n", p);
+
+  free(p);
+}
+
+int main(void) {
+  printf("MD4\n");
+
+  test1();
+  test2();
+  test3();
+  test4();
+  test5();
+  test6();
+  test7();
+
+  // CHECK: MD4
+  // CHECK: test1: 'bf78fda2ca35eb7a026bfcdd3d17283d'
+  // CHECK: test2: 'bf78fda2ca35eb7a026bfcdd3d17283d'
+  // CHECK: test3: 'bf78fda2ca35eb7a026bfcdd3d17283d'
+  // CHECK: test4: '85b3d78ce68be51f710272728fe606af'
+  // CHECK: test5: '85b3d78ce68be51f710272728fe606af'
+  // CHECK: test6: '{{.*}}'
+  // CHECK: test7: '{{.*}}'
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/md5.cc b/test/sanitizer_common/TestCases/NetBSD/md5.cc
new file mode 100644
index 0000000..e279979
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/md5.cc
@@ -0,0 +1,114 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <endian.h>
+#include <md5.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1() {
+  MD5_CTX ctx;
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+  uint8_t digest[MD5_DIGEST_LENGTH];
+
+  MD5Init(&ctx);
+  MD5Update(&ctx, entropy, __arraycount(entropy));
+  MD5Final(digest, &ctx);
+
+  printf("test1: '");
+  for (size_t i = 0; i < __arraycount(digest); i++)
+    printf("%02x", digest[i]);
+  printf("'\n");
+}
+
+void test2() {
+  MD5_CTX ctx;
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+  char digest[MD5_DIGEST_STRING_LENGTH];
+
+  MD5Init(&ctx);
+  MD5Update(&ctx, entropy, __arraycount(entropy));
+  char *p = MD5End(&ctx, digest);
+  assert(p);
+
+  printf("test2: '%s'\n", digest);
+}
+
+void test3() {
+  MD5_CTX ctx;
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+
+  MD5Init(&ctx);
+  MD5Update(&ctx, entropy, __arraycount(entropy));
+  char *p = MD5End(&ctx, NULL);
+  assert(strlen(p) == MD5_DIGEST_STRING_LENGTH - 1);
+
+  printf("test3: '%s'\n", p);
+
+  free(p);
+}
+
+void test4() {
+  char digest[MD5_DIGEST_STRING_LENGTH];
+
+  char *p = MD5File("/etc/fstab", digest);
+  assert(p == digest);
+
+  printf("test4: '%s'\n", p);
+}
+
+void test5() {
+  char *p = MD5File("/etc/fstab", NULL);
+  assert(strlen(p) == MD5_DIGEST_STRING_LENGTH - 1);
+
+  printf("test5: '%s'\n", p);
+
+  free(p);
+}
+
+void test6() {
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+  char digest[MD5_DIGEST_STRING_LENGTH];
+
+  char *p = MD5Data(entropy, __arraycount(entropy), digest);
+  assert(p == digest);
+
+  printf("test6: '%s'\n", p);
+}
+
+void test7() {
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+
+  char *p = MD5Data(entropy, __arraycount(entropy), NULL);
+  assert(strlen(p) == MD5_DIGEST_STRING_LENGTH - 1);
+
+  printf("test7: '%s'\n", p);
+
+  free(p);
+}
+
+int main(void) {
+  printf("MD5\n");
+
+  test1();
+  test2();
+  test3();
+  test4();
+  test5();
+  test6();
+  test7();
+
+  // CHECK: MD5
+  // CHECK: test1: '86e65b1ef4a830af347ac05ab4f0e999'
+  // CHECK: test2: '86e65b1ef4a830af347ac05ab4f0e999'
+  // CHECK: test3: '86e65b1ef4a830af347ac05ab4f0e999'
+  // CHECK: test4: 'd6798ca88175b5feece4dda691a5b9b5'
+  // CHECK: test5: 'd6798ca88175b5feece4dda691a5b9b5'
+  // CHECK: test6: '86e65b1ef4a830af347ac05ab4f0e999'
+  // CHECK: test7: '86e65b1ef4a830af347ac05ab4f0e999'
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/mi_vector_hash.cc b/test/sanitizer_common/TestCases/NetBSD/mi_vector_hash.cc
new file mode 100644
index 0000000..1f6c148
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/mi_vector_hash.cc
@@ -0,0 +1,19 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(void) {
+  unsigned char key[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99};
+  uint32_t hashes[3];
+  mi_vector_hash(key, __arraycount(key), 0, hashes);
+  for (size_t i = 0; i < __arraycount(hashes); i++)
+    printf("hashes[%zu]='%" PRIx32 "'\n", i, hashes[i]);
+
+  // CHECK: hashes[0]='{{.*}}'
+  // CHECK: hashes[1]='{{.*}}'
+  // CHECK: hashes[2]='{{.*}}'
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/regex.cc b/test/sanitizer_common/TestCases/NetBSD/regex.cc
new file mode 100644
index 0000000..8a4fb38
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/regex.cc
@@ -0,0 +1,101 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void test_matched(const regex_t *preg, const char *string) {
+  int rv = regexec(preg, string, 0, NULL, 0);
+  if (!rv)
+    printf("%s: matched\n", string);
+  else if (rv == REG_NOMATCH)
+    printf("%s: not-matched\n", string);
+  else
+    abort();
+}
+
+void test_print_matches(const regex_t *preg, const char *string) {
+  regmatch_t rm[10];
+  int rv = regexec(preg, string, __arraycount(rm), rm, 0);
+  if (!rv) {
+    for (size_t i = 0; i < __arraycount(rm); i++) {
+      // This condition shall be simplified, but verify that the data fields
+      // are accessible.
+      if (rm[i].rm_so == -1 && rm[i].rm_eo == -1)
+        continue;
+      printf("matched[%zu]='%.*s'\n", i, (int)(rm[i].rm_eo - rm[i].rm_so),
+             string + rm[i].rm_so);
+    }
+  } else if (rv == REG_NOMATCH)
+    printf("%s: not-matched\n", string);
+  else
+    abort();
+}
+
+void test_nsub(const regex_t *preg, const char *string) {
+  regmatch_t rm[10];
+  int rv = regexec(preg, string, __arraycount(rm), rm, 0);
+  if (!rv) {
+    char buf[1024];
+    ssize_t ss = regnsub(buf, __arraycount(buf), "\\1xyz", rm, string);
+    assert(ss != -1);
+
+    printf("'%s' -> '%s'\n", string, buf);
+  } else if (rv == REG_NOMATCH)
+    printf("%s: not-matched\n", string);
+  else
+    abort();
+}
+
+void test_asub(const regex_t *preg, const char *string) {
+  regmatch_t rm[10];
+  int rv = regexec(preg, string, __arraycount(rm), rm, 0);
+  if (!rv) {
+    char *buf;
+    ssize_t ss = regasub(&buf, "\\1xyz", rm, string);
+    assert(ss != -1);
+
+    printf("'%s' -> '%s'\n", string, buf);
+    free(buf);
+  } else if (rv == REG_NOMATCH)
+    printf("%s: not-matched\n", string);
+  else
+    abort();
+}
+
+int main(void) {
+  printf("regex\n");
+
+  regex_t regex;
+  int rv = regcomp(&regex, "[[:upper:]]\\([[:upper:]]\\)", 0);
+  assert(!rv);
+
+  test_matched(&regex, "abc");
+  test_matched(&regex, "ABC");
+
+  test_print_matches(&regex, "ABC");
+
+  test_nsub(&regex, "ABC DEF");
+  test_asub(&regex, "GHI JKL");
+
+  regfree(&regex);
+
+  rv = regcomp(&regex, "[[:upp:]]", 0);
+  assert(rv);
+
+  char errbuf[1024];
+  regerror(rv, &regex, errbuf, sizeof errbuf);
+  printf("error: %s\n", errbuf);
+
+  // CHECK: regex
+  // CHECK: abc: not-matched
+  // CHECK: ABC: matched
+  // CHECK: matched[0]='AB'
+  // CHECK: matched[1]='B'
+  // CHECK: 'ABC DEF' -> 'Bxyz'
+  // CHECK: 'GHI JKL' -> 'Hxyz'
+  // CHECK: error:{{.*}}
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/rmd160.cc b/test/sanitizer_common/TestCases/NetBSD/rmd160.cc
new file mode 100644
index 0000000..5b9ff0c
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/rmd160.cc
@@ -0,0 +1,133 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <rmd160.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1() {
+  RMD160_CTX ctx;
+  uint8_t entropy[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
+  uint8_t digest[RMD160_DIGEST_LENGTH];
+
+  RMD160Init(&ctx);
+  RMD160Update(&ctx, entropy, __arraycount(entropy));
+  RMD160Final(digest, &ctx);
+
+  printf("test1: '");
+  for (size_t i = 0; i < __arraycount(digest); i++)
+    printf("%02x", digest[i]);
+  printf("'\n");
+}
+
+void test2() {
+  RMD160_CTX ctx;
+  uint8_t entropy[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
+  char digest[RMD160_DIGEST_STRING_LENGTH];
+
+  RMD160Init(&ctx);
+  RMD160Update(&ctx, entropy, __arraycount(entropy));
+  char *p = RMD160End(&ctx, digest);
+  assert(p == digest);
+
+  printf("test2: '%s'\n", digest);
+}
+
+void test3() {
+  RMD160_CTX ctx;
+  uint8_t entropy[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
+
+  RMD160Init(&ctx);
+  RMD160Update(&ctx, entropy, __arraycount(entropy));
+  char *p = RMD160End(&ctx, NULL);
+  assert(strlen(p) == RMD160_DIGEST_STRING_LENGTH - 1);
+
+  printf("test3: '%s'\n", p);
+
+  free(p);
+}
+
+void test4() {
+  char digest[RMD160_DIGEST_STRING_LENGTH];
+
+  char *p = RMD160File("/etc/fstab", digest);
+  assert(p == digest);
+
+  printf("test4: '%s'\n", p);
+}
+
+void test5() {
+  char *p = RMD160File("/etc/fstab", NULL);
+  assert(strlen(p) == RMD160_DIGEST_STRING_LENGTH - 1);
+
+  printf("test5: '%s'\n", p);
+
+  free(p);
+}
+
+void test6() {
+  char digest[RMD160_DIGEST_STRING_LENGTH];
+
+  char *p = RMD160FileChunk("/etc/fstab", digest, 10, 20);
+  assert(p == digest);
+
+  printf("test6: '%s'\n", p);
+}
+
+void test7() {
+  char *p = RMD160FileChunk("/etc/fstab", NULL, 10, 20);
+  assert(strlen(p) == RMD160_DIGEST_STRING_LENGTH - 1);
+
+  printf("test7: '%s'\n", p);
+
+  free(p);
+}
+
+void test8() {
+  uint8_t entropy[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
+  char digest[RMD160_DIGEST_STRING_LENGTH];
+
+  char *p = RMD160Data(entropy, __arraycount(entropy), digest);
+  assert(p == digest);
+
+  printf("test8: '%s'\n", p);
+}
+
+void test9() {
+  uint8_t entropy[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
+
+  char *p = RMD160Data(entropy, __arraycount(entropy), NULL);
+  assert(strlen(p) == RMD160_DIGEST_STRING_LENGTH - 1);
+
+  printf("test9: '%s'\n", p);
+
+  free(p);
+}
+
+int main(void) {
+  printf("RMD160\n");
+
+  test1();
+  test2();
+  test3();
+  test4();
+  test5();
+  test6();
+  test7();
+  test8();
+  test9();
+
+  // CHECK: RMD160
+  // CHECK: test1: '2787e5a006365df6e8e799315b669dc34866783c'
+  // CHECK: test2: '2787e5a006365df6e8e799315b669dc34866783c'
+  // CHECK: test3: '2787e5a006365df6e8e799315b669dc34866783c'
+  // CHECK: test4: '{{.*}}'
+  // CHECK: test5: '{{.*}}'
+  // CHECK: test6: '{{.*}}'
+  // CHECK: test7: '{{.*}}'
+  // CHECK: test8: '2787e5a006365df6e8e799315b669dc34866783c'
+  // CHECK: test9: '2787e5a006365df6e8e799315b669dc34866783c'
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/sha1.cc b/test/sanitizer_common/TestCases/NetBSD/sha1.cc
new file mode 100644
index 0000000..ee5060a
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/sha1.cc
@@ -0,0 +1,171 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <sha1.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void test1() {
+  SHA1_CTX ctx;
+  uint8_t entropy[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
+  uint8_t digest[SHA1_DIGEST_LENGTH];
+
+  SHA1Init(&ctx);
+  SHA1Update(&ctx, entropy, __arraycount(entropy));
+  SHA1Final(digest, &ctx);
+
+  printf("test1: '");
+  for (size_t i = 0; i < __arraycount(digest); i++)
+    printf("%02x", digest[i]);
+  printf("'\n");
+}
+
+void local_SHA1Update(SHA1_CTX *context, const uint8_t *data, unsigned int len)
+{
+    unsigned int a, b;
+
+    b = context->count[0];
+    context->count[0] += len << 3;
+    if (context->count[0] < b)
+        context->count[1] += (len >> 29) + 1;
+    b = (b >> 3) & 63;
+    if ((b + len) > 63) {
+        memcpy(&context->buffer[b], data, (a = 64 - b));
+        SHA1Transform(context->state, context->buffer);
+        for ( ; a + 63 < len; a += 64)
+            SHA1Transform(context->state, &data[a]);
+        b = 0;
+    } else {
+        a = 0;
+    }
+    memcpy(&context->buffer[b], &data[a], len - a);
+}
+
+void test2() {
+  SHA1_CTX ctx;
+  uint8_t entropy[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
+  uint8_t digest[SHA1_DIGEST_LENGTH];
+
+  SHA1Init(&ctx);
+  local_SHA1Update(&ctx, entropy, __arraycount(entropy));
+  SHA1Final(digest, &ctx);
+
+  printf("test2: '");
+  for (size_t i = 0; i < __arraycount(digest); i++)
+    printf("%02x", digest[i]);
+  printf("'\n");
+}
+
+void test3() {
+  SHA1_CTX ctx;
+  uint8_t entropy[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
+  char digest[SHA1_DIGEST_STRING_LENGTH];
+
+  SHA1Init(&ctx);
+  SHA1Update(&ctx, entropy, __arraycount(entropy));
+  char *p = SHA1End(&ctx, digest);
+  assert(p == digest);
+
+  printf("test3: '%s'\n", digest);
+}
+
+void test4() {
+  SHA1_CTX ctx;
+  uint8_t entropy[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
+
+  SHA1Init(&ctx);
+  SHA1Update(&ctx, entropy, __arraycount(entropy));
+  char *p = SHA1End(&ctx, NULL);
+  assert(strlen(p) == SHA1_DIGEST_STRING_LENGTH - 1);
+
+  printf("test4: '%s'\n", p);
+
+  free(p);
+}
+
+void test5() {
+  char digest[SHA1_DIGEST_STRING_LENGTH];
+
+  char *p = SHA1File("/etc/fstab", digest);
+  assert(p == digest);
+
+  printf("test5: '%s'\n", p);
+}
+
+void test6() {
+  char *p = SHA1File("/etc/fstab", NULL);
+  assert(strlen(p) == SHA1_DIGEST_STRING_LENGTH - 1);
+
+  printf("test6: '%s'\n", p);
+
+  free(p);
+}
+
+void test7() {
+  char digest[SHA1_DIGEST_STRING_LENGTH];
+
+  char *p = SHA1FileChunk("/etc/fstab", digest, 10, 20);
+  assert(p == digest);
+
+  printf("test7: '%s'\n", p);
+}
+
+void test8() {
+  char *p = SHA1FileChunk("/etc/fstab", NULL, 10, 20);
+  assert(strlen(p) == SHA1_DIGEST_STRING_LENGTH - 1);
+
+  printf("test8: '%s'\n", p);
+
+  free(p);
+}
+
+void test9() {
+  uint8_t entropy[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
+  char digest[SHA1_DIGEST_STRING_LENGTH];
+
+  char *p = SHA1Data(entropy, __arraycount(entropy), digest);
+  assert(p == digest);
+
+  printf("test9: '%s'\n", p);
+}
+
+void test10() {
+  uint8_t entropy[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
+
+  char *p = SHA1Data(entropy, __arraycount(entropy), NULL);
+  assert(strlen(p) == SHA1_DIGEST_STRING_LENGTH - 1);
+
+  printf("test10: '%s'\n", p);
+
+  free(p);
+}
+
+int main(void) {
+  printf("SHA1\n");
+
+  test1();
+  test2();
+  test3();
+  test4();
+  test5();
+  test6();
+  test7();
+  test8();
+  test9();
+  test10();
+
+  // CHECK: SHA1
+  // CHECK: test1: '57d1b759bf3d1811135748cb0328c73b51fa6f57'
+  // CHECK: test2: '57d1b759bf3d1811135748cb0328c73b51fa6f57'
+  // CHECK: test3: '57d1b759bf3d1811135748cb0328c73b51fa6f57'
+  // CHECK: test4: '57d1b759bf3d1811135748cb0328c73b51fa6f57'
+  // CHECK: test5: '{{.*}}'
+  // CHECK: test6: '{{.*}}'
+  // CHECK: test7: '{{.*}}'
+  // CHECK: test8: '{{.*}}'
+  // CHECK: test9: '57d1b759bf3d1811135748cb0328c73b51fa6f57'
+  // CHECK: test10: '57d1b759bf3d1811135748cb0328c73b51fa6f57'
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/sha2.cc b/test/sanitizer_common/TestCases/NetBSD/sha2.cc
new file mode 100644
index 0000000..4c9066d
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/sha2.cc
@@ -0,0 +1,206 @@
+// RUN: %clangxx -O0 -g %s -DSHASIZE=224 -o %t && %run %t 2>&1 | FileCheck %s -check-prefix=CHECK-224
+// RUN: %clangxx -O0 -g %s -DSHASIZE=256 -o %t && %run %t 2>&1 | FileCheck %s -check-prefix=CHECK-256
+// RUN: %clangxx -O0 -g %s -DSHASIZE=384 -o %t && %run %t 2>&1 | FileCheck %s -check-prefix=CHECK-384
+// RUN: %clangxx -O0 -g %s -DSHASIZE=512 -o %t && %run %t 2>&1 | FileCheck %s -check-prefix=CHECK-512
+
+#include <sys/param.h>
+
+#include <assert.h>
+#include <endian.h>
+#include <sha2.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef SHASIZE
+#error SHASIZE must be defined
+#endif
+
+#define _SHA_CTX(x) SHA##x##_CTX
+#define SHA_CTX(x) _SHA_CTX(x)
+
+#define _SHA_DIGEST_LENGTH(x) SHA##x##_DIGEST_LENGTH
+#define SHA_DIGEST_LENGTH(x) _SHA_DIGEST_LENGTH(x)
+
+#define _SHA_DIGEST_STRING_LENGTH(x) SHA##x##_DIGEST_STRING_LENGTH
+#define SHA_DIGEST_STRING_LENGTH(x) _SHA_DIGEST_STRING_LENGTH(x)
+
+#define _SHA_Init(x) SHA##x##_Init
+#define SHA_Init(x) _SHA_Init(x)
+
+#define _SHA_Update(x) SHA##x##_Update
+#define SHA_Update(x) _SHA_Update(x)
+
+#define _SHA_Final(x) SHA##x##_Final
+#define SHA_Final(x) _SHA_Final(x)
+
+#define _SHA_End(x) SHA##x##_End
+#define SHA_End(x) _SHA_End(x)
+
+#define _SHA_File(x) SHA##x##_File
+#define SHA_File(x) _SHA_File(x)
+
+#define _SHA_FileChunk(x) SHA##x##_FileChunk
+#define SHA_FileChunk(x) _SHA_FileChunk(x)
+
+#define _SHA_Data(x) SHA##x##_Data
+#define SHA_Data(x) _SHA_Data(x)
+
+void test1() {
+  SHA_CTX(SHASIZE) ctx;
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+  uint8_t digest[SHA_DIGEST_LENGTH(SHASIZE)];
+
+  SHA_Init(SHASIZE)(&ctx);
+  SHA_Update(SHASIZE)(&ctx, entropy, __arraycount(entropy));
+  SHA_Final(SHASIZE)(digest, &ctx);
+
+  printf("test1: '");
+  for (size_t i = 0; i < __arraycount(digest); i++)
+    printf("%02x", digest[i]);
+  printf("'\n");
+}
+
+void test2() {
+  SHA_CTX(SHASIZE) ctx;
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+  char digest[SHA_DIGEST_STRING_LENGTH(SHASIZE)];
+
+  SHA_Init(SHASIZE)(&ctx);
+  SHA_Update(SHASIZE)(&ctx, entropy, __arraycount(entropy));
+  char *p = SHA_End(SHASIZE)(&ctx, digest);
+  assert(p == digest);
+
+  printf("test2: '%s'\n", digest);
+}
+
+void test3() {
+  SHA_CTX(SHASIZE) ctx;
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+
+  SHA_Init(SHASIZE)(&ctx);
+  SHA_Update(SHASIZE)(&ctx, entropy, __arraycount(entropy));
+  char *p = SHA_End(SHASIZE)(&ctx, NULL);
+  assert(strlen(p) == SHA_DIGEST_STRING_LENGTH(SHASIZE) - 1);
+
+  printf("test3: '%s'\n", p);
+
+  free(p);
+}
+
+void test4() {
+  char digest[SHA_DIGEST_STRING_LENGTH(SHASIZE)];
+
+  char *p = SHA_File(SHASIZE)("/etc/fstab", digest);
+  assert(p == digest);
+
+  printf("test4: '%s'\n", p);
+}
+
+void test5() {
+  char *p = SHA_File(SHASIZE)("/etc/fstab", NULL);
+  assert(strlen(p) == SHA_DIGEST_STRING_LENGTH(SHASIZE) - 1);
+
+  printf("test5: '%s'\n", p);
+
+  free(p);
+}
+
+void test6() {
+  char digest[SHA_DIGEST_STRING_LENGTH(SHASIZE)];
+
+  char *p = SHA_FileChunk(SHASIZE)("/etc/fstab", digest, 10, 20);
+  assert(p == digest);
+
+  printf("test6: '%s'\n", p);
+}
+
+void test7() {
+  char *p = SHA_FileChunk(SHASIZE)("/etc/fstab", NULL, 10, 20);
+  assert(strlen(p) == SHA_DIGEST_STRING_LENGTH(SHASIZE) - 1);
+
+  printf("test7: '%s'\n", p);
+
+  free(p);
+}
+
+void test8() {
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+  char digest[SHA_DIGEST_STRING_LENGTH(SHASIZE)];
+
+  char *p = SHA_Data(SHASIZE)(entropy, __arraycount(entropy), digest);
+  assert(p == digest);
+
+  printf("test8: '%s'\n", p);
+}
+
+void test9() {
+  uint8_t entropy[] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+
+  char *p = SHA_Data(SHASIZE)(entropy, __arraycount(entropy), NULL);
+  assert(strlen(p) == SHA_DIGEST_STRING_LENGTH(SHASIZE) - 1);
+
+  printf("test9: '%s'\n", p);
+
+  free(p);
+}
+
+int main(void) {
+  printf("SHA" ___STRING(SHASIZE) "\n");
+
+  test1();
+  test2();
+  test3();
+  test4();
+  test5();
+  test6();
+  test7();
+  test8();
+  test9();
+
+  // CHECK-224: SHA224
+  // CHECK-224: test1: '760dfb93100a6bf5996c90f678e529dc945bb2f74a211eedcf0f3a48'
+  // CHECK-224: test2: '760dfb93100a6bf5996c90f678e529dc945bb2f74a211eedcf0f3a48'
+  // CHECK-224: test3: '760dfb93100a6bf5996c90f678e529dc945bb2f74a211eedcf0f3a48'
+  // CHECK-224: test4: '{{.*}}'
+  // CHECK-224: test5: '{{.*}}'
+  // CHECK-224: test6: '{{.*}}'
+  // CHECK-224: test7: '{{.*}}'
+  // CHECK-224: test8: '760dfb93100a6bf5996c90f678e529dc945bb2f74a211eedcf0f3a48'
+  // CHECK-224: test9: '760dfb93100a6bf5996c90f678e529dc945bb2f74a211eedcf0f3a48'
+
+  // CHECK-256: SHA256
+  // CHECK-256: test1: 'bb000ddd92a0a2a346f0b531f278af06e370f86932ccafccc892d68d350f80f8'
+  // CHECK-256: test2: 'bb000ddd92a0a2a346f0b531f278af06e370f86932ccafccc892d68d350f80f8'
+  // CHECK-256: test3: 'bb000ddd92a0a2a346f0b531f278af06e370f86932ccafccc892d68d350f80f8'
+  // CHECK-256: test4: 'bb058583870ed830d9b74b4c24af7fa2ab5684f4d88158a8094a68bcf908dc48'
+  // CHECK-256: test5: 'bb058583870ed830d9b74b4c24af7fa2ab5684f4d88158a8094a68bcf908dc48'
+  // CHECK-256: test6: 'cc1c596e07913a44fe35a4d4fd76b4bd6313604fa4264e2e6fbae1db78c24b22'
+  // CHECK-256: test7: 'cc1c596e07913a44fe35a4d4fd76b4bd6313604fa4264e2e6fbae1db78c24b22'
+  // CHECK-256: test8: 'bb000ddd92a0a2a346f0b531f278af06e370f86932ccafccc892d68d350f80f8'
+  // CHECK-256: test9: 'bb000ddd92a0a2a346f0b531f278af06e370f86932ccafccc892d68d350f80f8'
+
+  // CHECK-384: SHA384
+  // CHECK-384: test1: 'f450c023b168ebd56ff916ca9b1f1f0010b8c592d28205cc91fa3056f629eed108e8bac864f01ca37a3edee596739e12'
+  // CHECK-384: test2: 'f450c023b168ebd56ff916ca9b1f1f0010b8c592d28205cc91fa3056f629eed108e8bac864f01ca37a3edee596739e12'
+  // CHECK-384: test3: 'f450c023b168ebd56ff916ca9b1f1f0010b8c592d28205cc91fa3056f629eed108e8bac864f01ca37a3edee596739e12'
+  // CHECK-384: test4: '330d1528c9828d46e200fbfe05cac41717bed2e5f87ba10d47c9d6098e94f5e902ad90d4dd9be0f4347bc026e1206abd'
+  // CHECK-384: test5: '330d1528c9828d46e200fbfe05cac41717bed2e5f87ba10d47c9d6098e94f5e902ad90d4dd9be0f4347bc026e1206abd'
+  // CHECK-384: test6: '60686e8385598c69a2309483b91c04a1e0deeef1201730607a1818d097e726a9cbde8f8b8de7ab76c1d347def17f5ab5'
+  // CHECK-384: test7: '60686e8385598c69a2309483b91c04a1e0deeef1201730607a1818d097e726a9cbde8f8b8de7ab76c1d347def17f5ab5'
+  // CHECK-384: test8: 'f450c023b168ebd56ff916ca9b1f1f0010b8c592d28205cc91fa3056f629eed108e8bac864f01ca37a3edee596739e12'
+  // CHECK-384: test9: 'f450c023b168ebd56ff916ca9b1f1f0010b8c592d28205cc91fa3056f629eed108e8bac864f01ca37a3edee596739e12'
+
+  // CHECK-512: SHA512
+  // CHECK-512: test1: '0e3f68731c0e2a6a4eab5d713c9a80dc78086b5fa7d2b5ab127277958e68d1b1dee1882b083b0106cd4319de42c0c8f452871364f5baa8a6379690612c6b844e'
+  // CHECK-512: test2: '0e3f68731c0e2a6a4eab5d713c9a80dc78086b5fa7d2b5ab127277958e68d1b1dee1882b083b0106cd4319de42c0c8f452871364f5baa8a6379690612c6b844e'
+  // CHECK-512: test3: '0e3f68731c0e2a6a4eab5d713c9a80dc78086b5fa7d2b5ab127277958e68d1b1dee1882b083b0106cd4319de42c0c8f452871364f5baa8a6379690612c6b844e'
+  // CHECK-512: test4: '56b925cd62d73643e0f5ab821e062be9157035652cfb6396cb08d84f88981b1a9dae79f3d2707ad4f821d86b5608ae93f71788724328bb6e4ed1704a985d07a7'
+  // CHECK-512: test5: '56b925cd62d73643e0f5ab821e062be9157035652cfb6396cb08d84f88981b1a9dae79f3d2707ad4f821d86b5608ae93f71788724328bb6e4ed1704a985d07a7'
+  // CHECK-512: test6: '273b577200f95cfcb1627d94c0e6f3dd1682f63b4dfcc315355a7b90586e4cfd8f65c7cb315bd2b29c7ec0942510ffaceb1f02c7041f45528a6357fd38f2fe39'
+  // CHECK-512: test7: '273b577200f95cfcb1627d94c0e6f3dd1682f63b4dfcc315355a7b90586e4cfd8f65c7cb315bd2b29c7ec0942510ffaceb1f02c7041f45528a6357fd38f2fe39'
+  // CHECK-512: test8: '0e3f68731c0e2a6a4eab5d713c9a80dc78086b5fa7d2b5ab127277958e68d1b1dee1882b083b0106cd4319de42c0c8f452871364f5baa8a6379690612c6b844e'
+  // CHECK-512: test9: '0e3f68731c0e2a6a4eab5d713c9a80dc78086b5fa7d2b5ab127277958e68d1b1dee1882b083b0106cd4319de42c0c8f452871364f5baa8a6379690612c6b844e'
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/statvfs1.cc b/test/sanitizer_common/TestCases/NetBSD/statvfs1.cc
new file mode 100644
index 0000000..40dfca3
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/statvfs1.cc
@@ -0,0 +1,58 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <sys/statvfs.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void test_statvfs1() {
+  printf("statvfs1\n");
+
+  struct statvfs buf;
+  int rv = statvfs1("/etc/fstab", &buf, ST_WAIT);
+  assert(rv != -1);
+
+  printf("fstypename='%s'\n", buf.f_fstypename);
+  printf("mntonname='%s'\n", buf.f_mntonname);
+  printf("mntfromname='%s'\n", buf.f_mntfromname);
+}
+
+void test_fstatvfs1() {
+  printf("fstatvfs1\n");
+
+  int fd = open("/etc/fstab", O_RDONLY);
+  assert(fd > 0);
+
+  struct statvfs buf;
+  int rv = fstatvfs1(fd, &buf, ST_WAIT);
+  assert(rv != -1);
+
+  printf("fstypename='%s'\n", buf.f_fstypename);
+  printf("mntonname='%s'\n", buf.f_mntonname);
+  printf("mntfromname='%s'\n", buf.f_mntfromname);
+
+  rv = close(fd);
+  assert(rv != -1);
+}
+
+int main(void) {
+  test_statvfs1();
+  test_fstatvfs1();
+
+  // CHECK: statvfs1
+  // CHECK: fstypename='{{.*}}'
+  // CHECK: mntonname='{{.*}}'
+  // CHECK: mntfromname='{{.*}}'
+  // CHECK: fstatvfs1
+  // CHECK: fstypename='{{.*}}'
+  // CHECK: mntonname='{{.*}}'
+  // CHECK: mntfromname='{{.*}}'
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/strtoi.cc b/test/sanitizer_common/TestCases/NetBSD/strtoi.cc
new file mode 100644
index 0000000..4d0d8b3
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/strtoi.cc
@@ -0,0 +1,43 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <inttypes.h>
+#include <stdio.h>
+
+void test_strtoi(const char *nptr, int base, intmax_t lo, intmax_t hi) {
+  char *p;
+  int status;
+  intmax_t i = strtoi(nptr, &p, base, lo, hi, &status);
+  printf("strtoi: conversion of '%s' to a number %s, using %jd, p=%#" PRIx8
+         "\n",
+         nptr, status ? "failed" : "successful", i, *p);
+}
+
+void test_strtou(const char *nptr, int base, intmax_t lo, intmax_t hi) {
+  char *p;
+  int status;
+  uintmax_t i = strtou(nptr, &p, base, lo, hi, &status);
+  printf("strtou: conversion of '%s' to a number %s, using %ju, p=%#" PRIx8
+         "\n",
+         nptr, status ? "failed" : "successful", i, *p);
+}
+
+int main(void) {
+  printf("strtoi\n");
+
+  test_strtoi("100", 0, 1, 100);
+  test_strtoi("100", 0, 1, 10);
+  test_strtoi("100xyz", 0, 1, 100);
+  test_strtou("100", 0, 1, 100);
+  test_strtou("100", 0, 1, 10);
+  test_strtou("100xyz", 0, 1, 100);
+
+  // CHECK: strtoi
+  // CHECK: strtoi: conversion of '100' to a number successful, using 100, p=0
+  // CHECK: strtoi: conversion of '100' to a number failed, using 10, p=0
+  // CHECK: strtoi: conversion of '100xyz' to a number failed, using 100, p=0x78
+  // CHECK: strtou: conversion of '100' to a number successful, using 100, p=0
+  // CHECK: strtou: conversion of '100' to a number failed, using 10, p=0
+  // CHECK: strtou: conversion of '100xyz' to a number failed, using 100, p=0x78
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/strtonum.cc b/test/sanitizer_common/TestCases/NetBSD/strtonum.cc
new file mode 100644
index 0000000..2f47a30
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/strtonum.cc
@@ -0,0 +1,52 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#define _OPENBSD_SOURCE
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(void) {
+  const char *errstr;
+
+  printf("strtonum\n");
+
+  long long l = strtonum("100", 1, 100, &errstr);
+  assert(!errstr);
+  printf("%lld\n", l);
+
+  l = strtonum("200", 1, 100, &errstr);
+  assert(errstr);
+  printf("%s\n", errstr);
+
+  l = strtonum("300", 1000, 1001, &errstr);
+  assert(errstr);
+  printf("%s\n", errstr);
+
+  l = strtonum("abc", 1000, 1001, &errstr);
+  assert(errstr);
+  printf("%s\n", errstr);
+
+  l = strtonum("1000", 1001, 1000, &errstr);
+  assert(errstr);
+  printf("%s\n", errstr);
+
+  l = strtonum("1000abc", 1000, 1001, &errstr);
+  assert(errstr);
+  printf("%s\n", errstr);
+
+  l = strtonum("1000.0", 1000, 1001, &errstr);
+  assert(errstr);
+  printf("%s\n", errstr);
+
+  // CHECK: strtonum
+  // CHECK: 100
+  // CHECK: too large
+  // CHECK: too small
+  // CHECK: invalid
+  // CHECK: invalid
+  // CHECK: invalid
+  // CHECK: invalid
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/sysctlgetmibinfo.cc b/test/sanitizer_common/TestCases/NetBSD/sysctlgetmibinfo.cc
new file mode 100644
index 0000000..d81c156
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/sysctlgetmibinfo.cc
@@ -0,0 +1,36 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <sys/sysctl.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void test_sysctlgetmibinfo() {
+  int mib[CTL_MAXNAME];
+  unsigned int mib_len = __arraycount(mib);
+  int rv = sysctlgetmibinfo("kern.ostype", &mib[0], &mib_len, NULL, NULL, NULL,
+                       SYSCTL_VERSION);
+  assert(!rv);
+
+  char buf[100];
+  size_t len = sizeof(buf);
+  rv = sysctl(mib, mib_len, buf, &len, NULL, 0);
+  assert(!rv);
+
+  printf("sysctlgetmibinfo: '%s' size: '%zu'\n", buf, len);
+}
+
+int main(void) {
+  printf("sysctlgetmibinfo\n");
+
+  test_sysctlgetmibinfo();
+
+  return 0;
+
+  // CHECK: sysctlgetmibinfo
+  // CHECK: sysctlgetmibinfo: '{{.*}}' size: '{{.*}}'
+}
diff --git a/test/sanitizer_common/TestCases/NetBSD/vis.cc b/test/sanitizer_common/TestCases/NetBSD/vis.cc
new file mode 100644
index 0000000..89ea259
--- /dev/null
+++ b/test/sanitizer_common/TestCases/NetBSD/vis.cc
@@ -0,0 +1,245 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <ctype.h>
+#include <err.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <vis.h>
+
+void test_vis() {
+  char visout[5];
+  int ch = toascii(0x1);
+  vis(visout, ch, VIS_SAFE | VIS_NOSLASH, 0);
+  printf("vis: %s\n", visout);
+}
+
+void test_nvis() {
+  char visout[5];
+  int ch = toascii(0x2);
+  nvis(visout, sizeof visout, ch, VIS_SAFE | VIS_NOSLASH, 0);
+  printf("nvis: %s\n", visout);
+}
+
+void test_strvis() {
+  char visout[5];
+  strvis(visout, "\3", VIS_SAFE | VIS_NOSLASH);
+  printf("strvis: %s\n", visout);
+}
+
+void test_stravis() {
+  char *visout;
+  stravis(&visout, "\4", VIS_SAFE | VIS_NOSLASH);
+  printf("stravis: %s\n", visout);
+  free(visout);
+}
+
+void test_strnvis() {
+  char visout[5];
+  strnvis(visout, sizeof visout, "\5", VIS_SAFE | VIS_NOSLASH);
+  printf("strnvis: %s\n", visout);
+}
+
+void test_strvisx() {
+  char visout[5];
+  char src[] = "\6";
+  strvisx(visout, src, sizeof src - 1 /* skip final \0 */,
+          VIS_SAFE | VIS_NOSLASH);
+  printf("strvisx: %s\n", visout);
+}
+
+void test_strnvisx() {
+  char visout[5];
+  char src[] = "\1";
+  strnvisx(visout, sizeof visout, src, sizeof src - 1 /* skip final \0 */,
+           VIS_SAFE | VIS_NOSLASH);
+  printf("strnvisx: %s\n", visout);
+}
+
+void test_strenvisx() {
+  char visout[5];
+  char src[] = "\2";
+  strenvisx(visout, sizeof visout, src, sizeof src - 1 /* skip final \0 */,
+            VIS_SAFE | VIS_NOSLASH, NULL);
+  printf("strenvisx: %s\n", visout);
+}
+
+void test_svis() {
+  char visout[5];
+  int ch = toascii(0x3);
+  svis(visout, ch, VIS_SAFE | VIS_NOSLASH, 0, "x");
+  printf("svis: %s\n", visout);
+}
+
+void test_snvis() {
+  char visout[5];
+  int ch = toascii(0x2);
+  snvis(visout, sizeof visout, ch, VIS_SAFE | VIS_NOSLASH, 0, "x");
+  printf("snvis: %s\n", visout);
+}
+
+void test_strsvis() {
+  char visout[5];
+  strsvis(visout, "\4", VIS_SAFE | VIS_NOSLASH, "x");
+  printf("strsvis: %s\n", visout);
+}
+
+void test_strsnvis() {
+  char visout[5];
+  strsnvis(visout, sizeof visout, "\5", VIS_SAFE | VIS_NOSLASH, "x");
+  printf("strsnvis: %s\n", visout);
+}
+
+void test_strsvisx() {
+  char visout[5];
+  char src[] = "\5";
+  strsvisx(visout, src, sizeof src - 1 /* skip final \0 */,
+           VIS_SAFE | VIS_NOSLASH, "x");
+  printf("strsvisx: %s\n", visout);
+}
+
+void test_strsnvisx() {
+  char visout[5];
+  char src[] = "\6";
+  strsnvisx(visout, sizeof visout, src, sizeof src - 1 /* skip final \0 */,
+            VIS_SAFE | VIS_NOSLASH, "x");
+  printf("strsnvisx: %s\n", visout);
+}
+
+void test_strsenvisx() {
+  char visout[5];
+  char src[] = "\1";
+  strsenvisx(visout, sizeof visout, src, sizeof src - 1 /* skip final \0 */,
+             VIS_SAFE | VIS_NOSLASH, "x", NULL);
+  printf("strsenvisx: %s\n", visout);
+}
+
+void test_unvis() {
+  char visout[5];
+  int ch = toascii(0x1);
+  vis(visout, ch, VIS_SAFE, 0);
+
+  int state = 0;
+  char out;
+  char *p = visout;
+  while ((ch = *(p++)) != '\0') {
+  again:
+    switch (unvis(&out, ch, &state, 0)) {
+    case 0:
+    case UNVIS_NOCHAR:
+      break;
+    case UNVIS_VALID:
+      printf("unvis: %" PRIx8 "\n", (unsigned char)out);
+      break;
+    case UNVIS_VALIDPUSH:
+      printf("unvis: %" PRIx8 "\n", (unsigned char)out);
+      goto again;
+    case UNVIS_SYNBAD:
+      errx(1, "Bad character sequence!");
+    }
+  }
+  if (unvis(&out, '\0', &state, UNVIS_END) == UNVIS_VALID)
+    printf("unvis: %" PRIx8 "\n", (unsigned char)out);
+}
+
+void test_strunvis() {
+  char visout[5];
+  int ch = toascii(0x2);
+  vis(visout, ch, VIS_SAFE, 0);
+
+  char p[5];
+  strunvis(p, visout);
+
+  char *pp = p;
+  while ((ch = *(pp++)) != '\0')
+    printf("strunvis: %" PRIx8 "\n", (unsigned char)ch);
+}
+
+void test_strnunvis() {
+  char visout[5];
+  int ch = toascii(0x3);
+  vis(visout, ch, VIS_SAFE, 0);
+
+  char p[5];
+  strnunvis(p, sizeof p, visout);
+
+  char *pp = p;
+  while ((ch = *(pp++)) != '\0')
+    printf("strnunvis: %" PRIx8 "\n", (unsigned char)ch);
+}
+
+void test_strunvisx() {
+  char visout[5];
+  int ch = toascii(0x4);
+  vis(visout, ch, VIS_SAFE, 0);
+
+  char p[5];
+  strunvisx(p, visout, VIS_SAFE);
+
+  char *pp = p;
+  while ((ch = *(pp++)) != '\0')
+    printf("strunvisx: %" PRIx8 "\n", (unsigned char)ch);
+}
+
+void test_strnunvisx() {
+  char visout[5];
+  int ch = toascii(0x5);
+  vis(visout, ch, VIS_SAFE, 0);
+
+  char p[5];
+  strnunvisx(p, sizeof p, visout, VIS_SAFE);
+
+  char *pp = p;
+  while ((ch = *(pp++)) != '\0')
+    printf("strnunvisx: %" PRIx8 "\n", (unsigned char)ch);
+}
+
+int main(void) {
+  printf("vis\n");
+
+  test_vis();
+  test_nvis();
+  test_strvis();
+  test_stravis();
+  test_strnvis();
+  test_strvisx();
+  test_strnvisx();
+  test_strenvisx();
+  test_svis();
+  test_snvis();
+  test_strsvis();
+  test_strsnvis();
+  test_strsvisx();
+  test_strsnvisx();
+  test_strsenvisx();
+  test_unvis();
+  test_strunvis();
+  test_strnunvis();
+  test_strunvisx();
+  test_strnunvisx();
+
+  // CHECK: vis
+  // CHECK: vis: ^A
+  // CHECK: nvis: ^B
+  // CHECK: strvis: ^C
+  // CHECK: stravis: ^D
+  // CHECK: strnvis: ^E
+  // CHECK: strvisx: ^F
+  // CHECK: strnvisx: ^A
+  // CHECK: strenvisx: ^B
+  // CHECK: svis: ^C
+  // CHECK: snvis: ^B
+  // CHECK: strsvis: ^D
+  // CHECK: strsnvis: ^E
+  // CHECK: strsvisx: ^E
+  // CHECK: strsnvisx: ^F
+  // CHECK: strsenvisx: ^A
+  // CHECK: unvis: 1
+  // CHECK: strunvis: 2
+  // CHECK: strnunvis: 3
+  // CHECK: strunvisx: 4
+  // CHECK: strnunvisx: 5
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc b/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc
index 87e797a..f42802a 100644
--- a/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc
+++ b/test/sanitizer_common/TestCases/Posix/dump_instruction_bytes.cc
@@ -1,11 +1,9 @@
 // Check that sanitizer prints the faulting instruction bytes on
 // dump_instruction_bytes=1
 
-// clang-format off
 // RUN: %clangxx  %s -o %t
 // RUN: %env_tool_opts=dump_instruction_bytes=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-DUMP
 // RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NODUMP
-// clang-format on
 
 // REQUIRES: x86-target-arch
 
diff --git a/test/sanitizer_common/TestCases/Posix/fseek.cc b/test/sanitizer_common/TestCases/Posix/fseek.cc
new file mode 100644
index 0000000..26f3b84
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Posix/fseek.cc
@@ -0,0 +1,53 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+//
+// UNSUPPORTED: linux, darwin, solaris
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+
+int main(void) {
+  printf("fseek\n");
+
+  FILE *fp = fopen("/etc/fstab", "r");
+  assert(fp);
+
+  int rv = fseek(fp, 10, SEEK_SET);
+  assert(!rv);
+
+  printf("position: %ld\n", ftell(fp));
+
+  rewind(fp);
+
+  printf("position: %ld\n", ftell(fp));
+
+  rv = fseeko(fp, 15, SEEK_SET);
+  assert(!rv);
+
+  printf("position: %" PRIuMAX "\n", (uintmax_t)ftello(fp));
+
+  fpos_t pos;
+  rv = fgetpos(fp, &pos);
+  assert(!rv);
+
+  rewind(fp);
+
+  printf("position: %" PRIuMAX "\n", (uintmax_t)ftello(fp));
+
+  rv = fsetpos(fp, &pos);
+  assert(!rv);
+
+  printf("position: %" PRIuMAX "\n", (uintmax_t)ftello(fp));
+
+  rv = fclose(fp);
+  assert(!rv);
+
+  // CHECK: fseek
+  // CHECK: position: 10
+  // CHECK: position: 0
+  // CHECK: position: 15
+  // CHECK: position: 0
+  // CHECK: position: 15
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/Posix/getmntinfo.cc b/test/sanitizer_common/TestCases/Posix/getmntinfo.cc
new file mode 100644
index 0000000..26c065d
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Posix/getmntinfo.cc
@@ -0,0 +1,35 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+//
+// UNSUPPORTED: linux, solaris
+
+#include <sys/types.h>
+
+#if defined(__NetBSD__)
+#include <sys/statvfs.h>
+#else
+#include <sys/mount.h>
+#endif
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(void) {
+  printf("getmntinfo\n");
+
+#if defined(__NetBSD__)
+  struct statvfs *fss;
+#else
+  struct statfs *fss;
+#endif
+  int nfss = getmntinfo(&fss, MNT_NOWAIT);
+  if (nfss <= 0)
+    errx(1, "getmntinfo");
+
+  for (int i = 0; i < nfss; i++)
+    printf("%d: %s\n", i, fss[i].f_fstypename);
+
+  // CHECK: getmntinfo
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/Posix/nl_langinfo.cc b/test/sanitizer_common/TestCases/Posix/nl_langinfo.cc
new file mode 100644
index 0000000..b812354
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Posix/nl_langinfo.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+//
+// UNSUPPORTED: linux, darwin, solaris
+
+#include <langinfo.h>
+
+#include <stdio.h>
+
+int main(void) {
+  printf("nl_langinfo\n");
+
+  char *info = nl_langinfo(DAY_1);
+
+  printf("DAY_1='%s'\n", info);
+
+  // CHECK: nl_langinfo
+  // CHECK: DAY_1='{{.*}}'
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/Posix/setvbuf.cc b/test/sanitizer_common/TestCases/Posix/setvbuf.cc
new file mode 100644
index 0000000..bc29ba4
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Posix/setvbuf.cc
@@ -0,0 +1,81 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+
+// UNSUPPORTED: solaris
+
+#include <stdio.h>
+
+void print_something() {
+  for (size_t i = 0; i < 10 * BUFSIZ; i++)
+    printf("Hello world %zu\n", i);
+}
+
+void print_one_byte(char *buf) {
+  printf("First byte is %c\n", buf[0]);
+}
+
+void test_setbuf() {
+  char buf[BUFSIZ];
+
+  setbuf(stdout, NULL);
+
+  print_something();
+
+  setbuf(stdout, buf);
+
+  print_something();
+
+  print_one_byte(buf);
+}
+
+void test_setbuffer() {
+  char buf[BUFSIZ];
+
+  setbuffer(stdout, NULL, 0);
+
+  print_something();
+
+  setbuffer(stdout, buf, BUFSIZ);
+
+  print_something();
+
+  print_one_byte(buf);
+}
+
+void test_setlinebuf() {
+  setlinebuf(stdout);
+
+  print_something();
+}
+
+void test_setvbuf() {
+  char buf[BUFSIZ];
+
+  setvbuf(stdout, NULL, _IONBF, 0);
+
+  print_something();
+
+  setvbuf(stdout, buf, _IOLBF, BUFSIZ);
+
+  print_something();
+
+  print_one_byte(buf);
+
+  setvbuf(stdout, buf, _IOFBF, BUFSIZ);
+
+  print_something();
+
+  print_one_byte(buf);
+}
+
+int main(void) {
+  printf("setvbuf\n");
+
+  test_setbuf();
+  test_setbuffer();
+  test_setlinebuf();
+  test_setvbuf();
+
+  // CHECK: setvbuf
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/Posix/sysctl.cc b/test/sanitizer_common/TestCases/Posix/sysctl.cc
new file mode 100644
index 0000000..2cb8764
--- /dev/null
+++ b/test/sanitizer_common/TestCases/Posix/sysctl.cc
@@ -0,0 +1,64 @@
+// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s
+//
+// UNSUPPORTED: linux, solaris
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <sys/sysctl.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef __arraycount
+#define __arraycount(a) (sizeof(a) / sizeof(a[0]))
+#endif
+
+void test_sysctl() {
+  char buf[100];
+  size_t len = sizeof(buf);
+  int mib[] = {CTL_KERN, KERN_OSTYPE};
+  int rv = sysctl(mib, __arraycount(mib), buf, &len, NULL, 0);
+  assert(!rv);
+
+  printf("sysctl: '%s' size: '%zu'\n", buf, len);
+}
+
+void test_sysctlbyname() {
+  char buf[100];
+  size_t len = sizeof(buf);
+  int rv = sysctlbyname("kern.ostype", buf, &len, NULL, 0);
+  assert(!rv);
+
+  printf("sysctlbyname: '%s' size: '%zu'\n", buf, len);
+}
+
+void test_sysctlnametomib() {
+  int mib[CTL_MAXNAME];
+  size_t mib_len = __arraycount(mib);
+  int rv = sysctlnametomib("kern.ostype", &mib[0], &mib_len);
+  assert(!rv);
+
+  char buf[100];
+  size_t len = sizeof(buf);
+  rv = sysctl(mib, mib_len, buf, &len, NULL, 0);
+  assert(!rv);
+
+  printf("sysctlnametomib: '%s' size: '%zu'\n", buf, len);
+}
+
+int main(void) {
+  printf("sysctl\n");
+
+  test_sysctl();
+  test_sysctlbyname();
+  test_sysctlnametomib();
+
+  // CHECK: sysctl
+  // CHECK: sysctl: '{{.*}}' size: '{{.*}}'
+  // CHECK: sysctlbyname: '{{.*}}' size: '{{.*}}'
+  // CHECK: sysctlnametomib: '{{.*}}' size: '{{.*}}'
+
+  return 0;
+}
diff --git a/test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc b/test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc
index 579ecb3..b313df8 100644
--- a/test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc
+++ b/test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc
@@ -5,7 +5,6 @@
 
 // UNSUPPORTED: i386-darwin
 // XFAIL: android
-// XFAIL: netbsd && msan
 
 // Tests __sanitizer_get_module_and_offset_for_pc.
 
diff --git a/test/sanitizer_common/ios_commands/iossim_run.py b/test/sanitizer_common/ios_commands/iossim_run.py
index 0d9ca93..e1f633e 100755
--- a/test/sanitizer_common/ios_commands/iossim_run.py
+++ b/test/sanitizer_common/ios_commands/iossim_run.py
@@ -8,7 +8,7 @@
 
 device_id = os.environ["SANITIZER_IOSSIM_TEST_DEVICE_IDENTIFIER"]
 
-for e in ["ASAN_OPTIONS", "TSAN_OPTIONS", "UBSAN_OPTIONS"]:
+for e in ["ASAN_OPTIONS", "TSAN_OPTIONS", "UBSAN_OPTIONS", "APPLE_ASAN_INIT_FOR_DLOPEN"]:
   if e in os.environ:
     os.environ["SIMCTL_CHILD_" + e] = os.environ[e]
 
diff --git a/test/tsan/Linux/thread_timedjoin.c b/test/tsan/Linux/thread_timedjoin.c
new file mode 100644
index 0000000..1d3f109
--- /dev/null
+++ b/test/tsan/Linux/thread_timedjoin.c
@@ -0,0 +1,39 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#define _GNU_SOURCE
+#include "../test.h"
+#include <errno.h>
+
+int var;
+
+void *Thread(void *x) {
+  barrier_wait(&barrier);
+  var = 1;
+  return 0;
+}
+
+static void check(int res, int expect) {
+  if (res != expect) {
+    fprintf(stderr, "Unexpected result of pthread_timedjoin_np: %d\n", res);
+    exit(1);
+  }
+}
+
+int main() {
+  barrier_init(&barrier, 2);
+  pthread_t t;
+  pthread_create(&t, 0, Thread, 0);
+  struct timespec ts;
+  clock_gettime(CLOCK_REALTIME, &ts);
+  check(pthread_timedjoin_np(t, 0, &ts), ETIMEDOUT);
+  barrier_wait(&barrier);
+  clock_gettime(CLOCK_REALTIME, &ts);
+  ts.tv_sec += 10000;
+  check(pthread_timedjoin_np(t, 0, &ts), 0);
+  var = 2;
+  fprintf(stderr, "PASS\n");
+  return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
+// CHECK: PASS
diff --git a/test/tsan/Linux/thread_tryjoin.c b/test/tsan/Linux/thread_tryjoin.c
new file mode 100644
index 0000000..675e159
--- /dev/null
+++ b/test/tsan/Linux/thread_tryjoin.c
@@ -0,0 +1,41 @@
+// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+#define _GNU_SOURCE
+#include "../test.h"
+#include <errno.h>
+
+int var;
+
+void *Thread(void *x) {
+  barrier_wait(&barrier);
+  var = 1;
+  return 0;
+}
+
+static void check(int res) {
+  if (res != EBUSY) {
+    fprintf(stderr, "Unexpected result of pthread_tryjoin_np: %d\n", res);
+    exit(1);
+  }
+}
+
+int main() {
+  barrier_init(&barrier, 2);
+  pthread_t t;
+  pthread_create(&t, 0, Thread, 0);
+  check(pthread_tryjoin_np(t, 0));
+  barrier_wait(&barrier);
+  for (;;) {
+    int res = pthread_tryjoin_np(t, 0);
+    if (!res)
+      break;
+    check(res);
+    pthread_yield();
+  }
+  var = 2;
+  fprintf(stderr, "PASS\n");
+  return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race
+// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
+// CHECK: PASS
diff --git a/test/tsan/cxa_guard_acquire.cc b/test/tsan/cxa_guard_acquire.cc
new file mode 100644
index 0000000..cdbe609
--- /dev/null
+++ b/test/tsan/cxa_guard_acquire.cc
@@ -0,0 +1,25 @@
+// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+
+namespace __tsan {
+
+void OnPotentiallyBlockingRegionBegin() {
+  printf("Enter __cxa_guard_acquire\n");
+}
+
+void OnPotentiallyBlockingRegionEnd() { printf("Exit __cxa_guard_acquire\n"); }
+
+} // namespace __tsan
+
+int main(int argc, char **argv) {
+  // CHECK: Enter main
+  printf("Enter main\n");
+  // CHECK-NEXT: Enter __cxa_guard_acquire
+  // CHECK-NEXT: Exit __cxa_guard_acquire
+  static int s = argc;
+  (void)s;
+  // CHECK-NEXT: Exit main
+  printf("Exit main\n");
+  return 0;
+}
diff --git a/test/tsan/deadlock_detector_stress_test.cc b/test/tsan/deadlock_detector_stress_test.cc
index bbaaabb..f3d2fc7 100644
--- a/test/tsan/deadlock_detector_stress_test.cc
+++ b/test/tsan/deadlock_detector_stress_test.cc
@@ -1,12 +1,12 @@
 // RUN: %clangxx_tsan %s -o %t -DLockType=PthreadMutex
-// RUN: %env_tsan_opts=detect_deadlocks=1 %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOT-SECOND
-// RUN: %env_tsan_opts=detect_deadlocks=1:second_deadlock_stack=1 %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-SECOND
+// RUN: %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOT-SECOND
+// RUN: %env_tsan_opts=second_deadlock_stack=1 %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-SECOND
 // RUN: %clangxx_tsan %s -o %t -DLockType=PthreadSpinLock
-// RUN: %env_tsan_opts=detect_deadlocks=1 %deflake %run %t | FileCheck %s
+// RUN: %deflake %run %t | FileCheck %s
 // RUN: %clangxx_tsan %s -o %t -DLockType=PthreadRWLock
-// RUN: %env_tsan_opts=detect_deadlocks=1 %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-RD
+// RUN: %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-RD
 // RUN: %clangxx_tsan %s -o %t -DLockType=PthreadRecursiveMutex
-// RUN: %env_tsan_opts=detect_deadlocks=1 %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-REC
+// RUN: %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-REC
 #include "test.h"
 #undef NDEBUG
 #include <assert.h>
diff --git a/test/tsan/mutex_cycle2.c b/test/tsan/mutex_cycle2.c
index 32659d4..0dc96d0 100644
--- a/test/tsan/mutex_cycle2.c
+++ b/test/tsan/mutex_cycle2.c
@@ -1,5 +1,5 @@
 // RUN: %clangxx_tsan %s -o %t
-// RUN:                                 not %run %t 2>&1 | FileCheck %s
+// RUN:                                   not %run %t 2>&1 | FileCheck %s
 // RUN: %env_tsan_opts=detect_deadlocks=1 not %run %t 2>&1 | FileCheck %s
 // RUN: %env_tsan_opts=detect_deadlocks=0     %run %t 2>&1 | FileCheck %s --check-prefix=DISABLED
 // RUN: echo "deadlock:main" > %t.supp
diff --git a/test/ubsan/TestCases/Integer/no-recover.cpp b/test/ubsan/TestCases/Integer/no-recover.cpp
index 515ebbd..45aeb9e 100644
--- a/test/ubsan/TestCases/Integer/no-recover.cpp
+++ b/test/ubsan/TestCases/Integer/no-recover.cpp
@@ -1,7 +1,9 @@
 // RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER
 // RUN: %clangxx -fsanitize=unsigned-integer-overflow -fno-sanitize-recover=all -fsanitize-recover=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER
 // RUN: %env_ubsan_opts=silence_unsigned_overflow=1 %run %t 2>&1 | FileCheck %s --check-prefix=SILENT-RECOVER --allow-empty
-// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fno-sanitize-recover=unsigned-integer-overflow %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=ABORT
+// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fno-sanitize-recover=unsigned-integer-overflow %s -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=ABORT
+// RUN: %env_ubsan_opts=silence_unsigned_overflow=1 not %run %t 2>&1 | FileCheck %s --check-prefix=ABORT
 
 #include <stdint.h>
 
diff --git a/test/xray/TestCases/Posix/fdr-reinit.cc b/test/xray/TestCases/Posix/fdr-reinit.cc
new file mode 100644
index 0000000..dc9888d
--- /dev/null
+++ b/test/xray/TestCases/Posix/fdr-reinit.cc
@@ -0,0 +1,73 @@
+// RUN: %clangxx_xray -g -std=c++11 %s -o %t
+// RUN: rm xray-log.fdr-reinit* || true
+// RUN: XRAY_OPTIONS="verbosity=1" %run %t
+// RUN: rm xray-log.fdr-reinit* || true
+#include "xray/xray_log_interface.h"
+#include <atomic>
+#include <cassert>
+#include <cstddef>
+#include <thread>
+
+volatile uint64_t var = 0;
+
+std::atomic_flag keep_going = ATOMIC_FLAG_INIT;
+
+[[clang::xray_always_instrument]] void __attribute__((noinline)) func() {
+  ++var;
+}
+
+int main(int argc, char *argv[]) {
+  // Start a thread that will just keep calling the function, to spam calls to
+  // the function call handler.
+  keep_going.test_and_set(std::memory_order_acquire);
+  std::thread t([] {
+    while (keep_going.test_and_set(std::memory_order_acquire))
+      func();
+  });
+
+  static constexpr char kConfig[] =
+      "buffer_size=1024:buffer_max=10:no_file_flush=true";
+
+  // Then we initialize the FDR mode implementation.
+  assert(__xray_log_select_mode("xray-fdr") ==
+         XRayLogRegisterStatus::XRAY_REGISTRATION_OK);
+  auto init_status = __xray_log_init_mode("xray-fdr", kConfig);
+  assert(init_status == XRayLogInitStatus::XRAY_LOG_INITIALIZED);
+
+  // Now we patch the instrumentation points.
+  __xray_patch();
+
+  // Spin for a bit, calling func() enough times.
+  for (auto i = 0; i < 1 << 20; ++i)
+    func();
+
+  // Then immediately finalize the implementation.
+  auto finalize_status = __xray_log_finalize();
+  assert(finalize_status == XRayLogInitStatus::XRAY_LOG_FINALIZED);
+
+  // Once we're here, we should then flush.
+  auto flush_status = __xray_log_flushLog();
+  assert(flush_status == XRayLogFlushStatus::XRAY_LOG_FLUSHED);
+
+  // Without doing anything else, we should re-initialize.
+  init_status = __xray_log_init_mode("xray-fdr", kConfig);
+  assert(init_status == XRayLogInitStatus::XRAY_LOG_INITIALIZED);
+
+  // Then we spin for a bit again calling func() enough times.
+  for (auto i = 0; i < 1 << 20; ++i)
+    func();
+
+  // Then immediately finalize the implementation.
+  finalize_status = __xray_log_finalize();
+  assert(finalize_status == XRayLogInitStatus::XRAY_LOG_FINALIZED);
+
+  // Once we're here, we should then flush.
+  flush_status = __xray_log_flushLog();
+  assert(flush_status == XRayLogFlushStatus::XRAY_LOG_FLUSHED);
+
+  // Finally, we should signal the sibling thread to stop.
+  keep_going.clear(std::memory_order_release);
+
+  // Then join.
+  t.join();
+}