Update aosp/master compiler-rt for rebase to r222486.

Change-Id: I38047809dbac0425193c82e810315998adbb380d
diff --git a/lib/msan/CMakeLists.txt b/lib/msan/CMakeLists.txt
index 4d69a25..90d9fac 100644
--- a/lib/msan/CMakeLists.txt
+++ b/lib/msan/CMakeLists.txt
@@ -14,16 +14,15 @@
 
 set(MSAN_RTL_CFLAGS ${SANITIZER_COMMON_CFLAGS})
 append_no_rtti_flag(MSAN_RTL_CFLAGS)
-append_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE MSAN_RTL_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FPIE_FLAG -fPIE MSAN_RTL_CFLAGS)
 # Prevent clang from generating libc calls.
-append_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding MSAN_RTL_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FFREESTANDING_FLAG -ffreestanding MSAN_RTL_CFLAGS)
 
 set(MSAN_RUNTIME_LIBRARIES)
 
 # Static runtime library.
 add_custom_target(msan)
-set(arch "x86_64")
-if(CAN_TARGET_${arch})
+foreach(arch ${MSAN_SUPPORTED_ARCH})
   add_compiler_rt_runtime(clang_rt.msan-${arch} ${arch} STATIC
     SOURCES ${MSAN_RTL_SOURCES}
             $<TARGET_OBJECTS:RTInterception.${arch}>
@@ -36,7 +35,7 @@
     add_sanitizer_rt_symbols(clang_rt.msan-${arch} msan.syms.extra)
     add_dependencies(msan clang_rt.msan-${arch}-symbols)
   endif()
-endif()
+endforeach()
 
 add_compiler_rt_resource_file(msan_blacklist msan_blacklist.txt)
 add_dependencies(msan msan_blacklist)
diff --git a/lib/msan/msan.cc b/lib/msan/msan.cc
index fd7fdbb..09622c4 100644
--- a/lib/msan/msan.cc
+++ b/lib/msan/msan.cc
@@ -34,27 +34,25 @@
 static THREADLOCAL int msan_expect_umr = 0;
 static THREADLOCAL int msan_expected_umr_found = 0;
 
-static bool msan_running_under_dr;
-
 // Function argument shadow. Each argument starts at the next available 8-byte
 // aligned address.
 SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u64 __msan_param_tls[kMsanParamTlsSizeInWords];
+THREADLOCAL u64 __msan_param_tls[kMsanParamTlsSize / sizeof(u64)];
 
 // Function argument origin. Each argument starts at the same offset as the
 // corresponding shadow in (__msan_param_tls). Slightly weird, but changing this
 // would break compatibility with older prebuilt binaries.
 SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u32 __msan_param_origin_tls[kMsanParamTlsSizeInWords];
+THREADLOCAL u32 __msan_param_origin_tls[kMsanParamTlsSize / sizeof(u32)];
 
 SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u64 __msan_retval_tls[kMsanRetvalTlsSizeInWords];
+THREADLOCAL u64 __msan_retval_tls[kMsanRetvalTlsSize / sizeof(u64)];
 
 SANITIZER_INTERFACE_ATTRIBUTE
 THREADLOCAL u32 __msan_retval_origin_tls;
 
 SANITIZER_INTERFACE_ATTRIBUTE
-THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSizeInWords];
+THREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSize / sizeof(u64)];
 
 SANITIZER_INTERFACE_ATTRIBUTE
 THREADLOCAL u64 __msan_va_arg_overflow_size_tls;
@@ -63,7 +61,6 @@
 THREADLOCAL u32 __msan_origin_tls;
 
 static THREADLOCAL int is_in_symbolizer;
-static THREADLOCAL int is_in_loader;
 
 extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_track_origins;
 
@@ -79,14 +76,6 @@
 void ExitSymbolizer()  { --is_in_symbolizer; }
 bool IsInSymbolizer() { return is_in_symbolizer; }
 
-void EnterLoader() { ++is_in_loader; }
-void ExitLoader()  { --is_in_loader; }
-
-extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE
-bool __msan_is_in_loader() { return is_in_loader; }
-}
-
 static Flags msan_flags;
 
 Flags *flags() {
@@ -187,7 +176,7 @@
   ParseFlagsFromString(f, options);
 }
 
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
+void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
                    bool request_fast_unwind) {
   MsanThread *t = GetCurrentThread();
   if (!t || !StackTrace::WillUseFastUnwind(request_fast_unwind)) {
@@ -280,16 +269,19 @@
     }
   }
 
-  StackDepotHandle h = StackDepotPut_WithHandle(stack->trace, stack->size);
+  StackDepotHandle h = StackDepotPut_WithHandle(*stack);
   if (!h.valid()) return id;
-  int use_count = h.use_count();
-  if (use_count > flags()->origin_history_per_stack_limit)
-    return id;
+
+  if (flags()->origin_history_per_stack_limit > 0) {
+    int use_count = h.use_count();
+    if (use_count > flags()->origin_history_per_stack_limit) return id;
+  }
 
   u32 chained_id;
   bool inserted = ChainedOriginDepotPut(h.id(), o.id(), &chained_id);
 
-  if (inserted) h.inc_use_count_unsafe();
+  if (inserted && flags()->origin_history_per_stack_limit > 0)
+    h.inc_use_count_unsafe();
 
   return Origin(chained_id, depth).raw_id();
 }
@@ -377,6 +369,7 @@
 
   if (MSAN_REPLACE_OPERATORS_NEW_AND_DELETE)
     ReplaceOperatorsNewAndDelete();
+  DisableCoreDumperIfNecessary();
   if (StackSizeIsUnlimited()) {
     VPrintf(1, "Unlimited stack, doing reexec\n");
     // A reasonably large stack size. It is bigger than the usual 8Mb, because,
@@ -390,7 +383,7 @@
   __msan_clear_on_return();
   if (__msan_get_track_origins())
     VPrintf(1, "msan_track_origins\n");
-  if (!InitShadow(/* prot1 */ !msan_running_under_dr, /* prot2 */ true,
+  if (!InitShadow(/* prot1 */ true, /* prot2 */ true,
                   /* map_shadow */ true, __msan_get_track_origins())) {
     Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n");
     Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
@@ -401,8 +394,7 @@
     Die();
   }
 
-  Symbolizer::Init(common_flags()->external_symbolizer_path);
-  Symbolizer::Get()->AddHooks(EnterSymbolizer, ExitSymbolizer);
+  Symbolizer::GetOrInit()->AddHooks(EnterSymbolizer, ExitSymbolizer);
 
   MsanTSDInit(MsanTSDDtor);
 
@@ -482,7 +474,7 @@
   (void)sp;
   ReportUMRInsideAddressRange(__func__, x, size, offset);
   __msan::PrintWarningWithOrigin(pc, bp,
-                                 __msan_get_origin(((char *)x) + offset));
+                                 __msan_get_origin(((const char *)x) + offset));
   if (__msan::flags()->halt_on_error) {
     Printf("Exiting\n");
     Die();
@@ -495,40 +487,13 @@
   return old;
 }
 
-int  __msan_has_dynamic_component() {
-  return msan_running_under_dr;
-}
+int __msan_has_dynamic_component() { return false; }
 
 NOINLINE
 void __msan_clear_on_return() {
   __msan_param_tls[0] = 0;
 }
 
-static void* get_tls_base() {
-  u64 p;
-  asm("mov %%fs:0, %0"
-      : "=r"(p) ::);
-  return (void*)p;
-}
-
-int __msan_get_retval_tls_offset() {
-  // volatile here is needed to avoid UB, because the compiler thinks that we
-  // are doing address arithmetics on unrelated pointers, and takes some
-  // shortcuts
-  volatile sptr retval_tls_p = (sptr)&__msan_retval_tls;
-  volatile sptr tls_base_p = (sptr)get_tls_base();
-  return retval_tls_p - tls_base_p;
-}
-
-int __msan_get_param_tls_offset() {
-  // volatile here is needed to avoid UB, because the compiler thinks that we
-  // are doing address arithmetics on unrelated pointers, and takes some
-  // shortcuts
-  volatile sptr param_tls_p = (sptr)&__msan_param_tls;
-  volatile sptr tls_base_p = (sptr)get_tls_base();
-  return param_tls_p - tls_base_p;
-}
-
 void __msan_partial_poison(const void* data, void* shadow, uptr size) {
   internal_memcpy((void*)MEM_TO_SHADOW((uptr)data), shadow, size);
 }
@@ -562,11 +527,11 @@
 // 'descr' is created at compile time and contains '----' in the beginning.
 // When we see descr for the first time we replace '----' with a uniq id
 // and set the origin to (id | (31-th bit)).
-void __msan_set_alloca_origin(void *a, uptr size, const char *descr) {
+void __msan_set_alloca_origin(void *a, uptr size, char *descr) {
   __msan_set_alloca_origin4(a, size, descr, 0);
 }
 
-void __msan_set_alloca_origin4(void *a, uptr size, const char *descr, uptr pc) {
+void __msan_set_alloca_origin4(void *a, uptr size, char *descr, uptr pc) {
   static const u32 dash = '-';
   static const u32 first_timer =
       dash + (dash << 8) + (dash << 16) + (dash << 24);
@@ -654,18 +619,6 @@
   death_callback = callback;
 }
 
-void *__msan_wrap_indirect_call(void *target) {
-  return IndirectExternCall(target);
-}
-
-void __msan_dr_is_initialized() {
-  msan_running_under_dr = true;
-}
-
-void __msan_set_indirect_call_wrapper(uptr wrapper) {
-  SetIndirectCallWrapper(wrapper);
-}
-
 #if !SANITIZER_SUPPORTS_WEAK_HOOKS
 extern "C" {
 SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
diff --git a/lib/msan/msan.h b/lib/msan/msan.h
index 05a8c47..aed8738 100644
--- a/lib/msan/msan.h
+++ b/lib/msan/msan.h
@@ -25,15 +25,25 @@
 # define MSAN_REPLACE_OPERATORS_NEW_AND_DELETE 1
 #endif
 
+#if defined(__mips64)
+#define MEM_TO_SHADOW(mem)       (((uptr)mem) & ~0x4000000000ULL)
+#define SHADOW_TO_ORIGIN(shadow) (((uptr)shadow) + 0x2000000000ULL)
+#define MEM_TO_ORIGIN(mem)       (SHADOW_TO_ORIGIN(MEM_TO_SHADOW(mem)))
+#define MEM_IS_APP(mem)          ((uptr)mem >= 0xe000000000ULL)
+#define MEM_IS_SHADOW(mem) \
+  ((uptr)mem >= 0xa000000000ULL && (uptr)mem <= 0xc000000000ULL)
+#elif defined(__x86_64__)
 #define MEM_TO_SHADOW(mem)       (((uptr)mem) & ~0x400000000000ULL)
 #define SHADOW_TO_ORIGIN(shadow) (((uptr)shadow) + 0x200000000000ULL)
 #define MEM_TO_ORIGIN(mem)       (SHADOW_TO_ORIGIN(MEM_TO_SHADOW(mem)))
 #define MEM_IS_APP(mem)          ((uptr)mem >= 0x600000000000ULL)
 #define MEM_IS_SHADOW(mem) \
   ((uptr)mem >= 0x200000000000ULL && (uptr)mem <= 0x400000000000ULL)
+#endif
 
-const int kMsanParamTlsSizeInWords = 100;
-const int kMsanRetvalTlsSizeInWords = 100;
+// These constants must be kept in sync with the ones in MemorySanitizer.cc.
+const int kMsanParamTlsSize = 800;
+const int kMsanRetvalTlsSize = 800;
 
 namespace __msan {
 extern int msan_inited;
@@ -64,14 +74,11 @@
   ~SymbolizerScope() { ExitSymbolizer(); }
 };
 
-void EnterLoader();
-void ExitLoader();
-
 void MsanDie();
 void PrintWarning(uptr pc, uptr bp);
 void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin);
 
-void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
+void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
                    bool request_fast_unwind);
 
 void ReportUMR(StackTrace *stack, u32 origin);
@@ -96,27 +103,24 @@
 // the previous origin id.
 u32 ChainOrigin(u32 id, StackTrace *stack);
 
-#define GET_MALLOC_STACK_TRACE                                     \
-  StackTrace stack;                                                \
-  stack.size = 0;                                                  \
-  if (__msan_get_track_origins() && msan_inited)                   \
-    GetStackTrace(&stack, common_flags()->malloc_context_size,     \
-        StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(),           \
-        common_flags()->fast_unwind_on_malloc)
-
-#define GET_STORE_STACK_TRACE_PC_BP(pc, bp)                  \
-  StackTrace stack;                                          \
-  stack.size = 0;                                            \
-  if (__msan_get_track_origins() > 1 && msan_inited)         \
-  GetStackTrace(&stack, flags()->store_context_size, pc, bp, \
+#define GET_MALLOC_STACK_TRACE                                                 \
+  BufferedStackTrace stack;                                                    \
+  if (__msan_get_track_origins() && msan_inited)                               \
+  GetStackTrace(&stack, common_flags()->malloc_context_size,                   \
+                StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(),               \
                 common_flags()->fast_unwind_on_malloc)
 
-#define GET_FATAL_STACK_TRACE_PC_BP(pc, bp)       \
-  StackTrace stack;                               \
-  stack.size = 0;                                 \
-  if (msan_inited)                                \
-    GetStackTrace(&stack, kStackTraceMax, pc, bp, \
-                  common_flags()->fast_unwind_on_fatal)
+#define GET_STORE_STACK_TRACE_PC_BP(pc, bp)                                    \
+  BufferedStackTrace stack;                                                    \
+  if (__msan_get_track_origins() > 1 && msan_inited)                           \
+  GetStackTrace(&stack, flags()->store_context_size, pc, bp,                   \
+                common_flags()->fast_unwind_on_malloc)
+
+#define GET_FATAL_STACK_TRACE_PC_BP(pc, bp)                                    \
+  BufferedStackTrace stack;                                                    \
+  if (msan_inited)                                                             \
+  GetStackTrace(&stack, kStackTraceMax, pc, bp,                                \
+                common_flags()->fast_unwind_on_fatal)
 
 #define GET_STORE_STACK_TRACE \
   GET_STORE_STACK_TRACE_PC_BP(StackTrace::GetCurrentPc(), GET_CURRENT_FRAME())
@@ -141,10 +145,8 @@
 }  // namespace __msan
 
 #define MSAN_MALLOC_HOOK(ptr, size) \
-  if (&__msan_malloc_hook) __msan_malloc_hook(ptr, size); \
   if (&__sanitizer_malloc_hook) __sanitizer_malloc_hook(ptr, size)
 #define MSAN_FREE_HOOK(ptr) \
-  if (&__msan_free_hook) __msan_free_hook(ptr); \
   if (&__sanitizer_free_hook) __sanitizer_free_hook(ptr)
 
 #endif  // MSAN_H
diff --git a/lib/msan/msan_allocator.cc b/lib/msan/msan_allocator.cc
index fb1788f..aa1ea1d 100644
--- a/lib/msan/msan_allocator.cc
+++ b/lib/msan/msan_allocator.cc
@@ -40,14 +40,26 @@
   }
 };
 
-static const uptr kAllocatorSpace = 0x600000000000ULL;
-static const uptr kAllocatorSize   = 0x80000000000;  // 8T.
-static const uptr kMetadataSize  = sizeof(Metadata);
-static const uptr kMaxAllowedMallocSize = 8UL << 30;
+#if defined(__mips64)
+  static const uptr kMaxAllowedMallocSize = 2UL << 30;
+  static const uptr kRegionSizeLog = 20;
+  static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
+  typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+  typedef CompactSizeClassMap SizeClassMap;
 
-typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize,
+  typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, sizeof(Metadata),
+                               SizeClassMap, kRegionSizeLog, ByteMap,
+                               MsanMapUnmapCallback> PrimaryAllocator;
+#elif defined(__x86_64__)
+  static const uptr kAllocatorSpace = 0x600000000000ULL;
+  static const uptr kAllocatorSize   = 0x80000000000;  // 8T.
+  static const uptr kMetadataSize  = sizeof(Metadata);
+  static const uptr kMaxAllowedMallocSize = 8UL << 30;
+
+  typedef SizeClassAllocator64<kAllocatorSpace, kAllocatorSize, kMetadataSize,
                              DefaultSizeClassMap,
                              MsanMapUnmapCallback> PrimaryAllocator;
+#endif
 typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
 typedef LargeMmapAllocator<MsanMapUnmapCallback> SecondaryAllocator;
 typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
@@ -102,7 +114,7 @@
   } else if (flags()->poison_in_malloc) {
     __msan_poison(allocated, size);
     if (__msan_get_track_origins()) {
-      u32 stack_id = StackDepotPut(stack->trace, stack->size);
+      u32 stack_id = StackDepotPut(*stack);
       CHECK(stack_id);
       u32 id;
       ChainedOriginDepotPut(stack_id, Origin::kHeapRoot, &id);
@@ -125,7 +137,7 @@
   if (flags()->poison_in_free) {
     __msan_poison(p, size);
     if (__msan_get_track_origins()) {
-      u32 stack_id = StackDepotPut(stack->trace, stack->size);
+      u32 stack_id = StackDepotPut(*stack);
       CHECK(stack_id);
       u32 id;
       ChainedOriginDepotPut(stack_id, Origin::kHeapRoot, &id);
@@ -188,40 +200,19 @@
   allocator.GetStats(stats);
   return stats[AllocatorStatAllocated];
 }
-uptr __msan_get_current_allocated_bytes() {
-  return __sanitizer_get_current_allocated_bytes();
-}
 
 uptr __sanitizer_get_heap_size() {
   uptr stats[AllocatorStatCount];
   allocator.GetStats(stats);
   return stats[AllocatorStatMapped];
 }
-uptr __msan_get_heap_size() {
-  return __sanitizer_get_heap_size();
-}
 
 uptr __sanitizer_get_free_bytes() { return 1; }
-uptr __msan_get_free_bytes() {
-  return __sanitizer_get_free_bytes();
-}
 
 uptr __sanitizer_get_unmapped_bytes() { return 1; }
-uptr __msan_get_unmapped_bytes() {
-  return __sanitizer_get_unmapped_bytes();
-}
 
 uptr __sanitizer_get_estimated_allocated_size(uptr size) { return size; }
-uptr __msan_get_estimated_allocated_size(uptr size) {
-  return __sanitizer_get_estimated_allocated_size(size);
-}
 
 int __sanitizer_get_ownership(const void *p) { return AllocationSize(p) != 0; }
-int __msan_get_ownership(const void *p) {
-  return __sanitizer_get_ownership(p);
-}
 
 uptr __sanitizer_get_allocated_size(const void *p) { return AllocationSize(p); }
-uptr __msan_get_allocated_size(const void *p) {
-  return __sanitizer_get_allocated_size(p);
-}
diff --git a/lib/msan/msan_chained_origin_depot.cc b/lib/msan/msan_chained_origin_depot.cc
index faf0461..f3fb3c8 100644
--- a/lib/msan/msan_chained_origin_depot.cc
+++ b/lib/msan/msan_chained_origin_depot.cc
@@ -19,31 +19,6 @@
 struct ChainedOriginDepotDesc {
   u32 here_id;
   u32 prev_id;
-  u32 hash() const {
-    const u32 m = 0x5bd1e995;
-    const u32 seed = 0x9747b28c;
-    const u32 r = 24;
-    u32 h = seed;
-    u32 k = here_id;
-    k *= m;
-    k ^= k >> r;
-    k *= m;
-    h *= m;
-    h ^= k;
-
-    k = prev_id;
-    k *= m;
-    k ^= k >> r;
-    k *= m;
-    h *= m;
-    h ^= k;
-
-    h ^= h >> 13;
-    h *= m;
-    h ^= h >> 15;
-    return h;
-  }
-  bool is_valid() { return true; }
 };
 
 struct ChainedOriginDepotNode {
@@ -59,6 +34,44 @@
   static uptr storage_size(const args_type &args) {
     return sizeof(ChainedOriginDepotNode);
   }
+  /* This is murmur2 hash for the 64->32 bit case.
+     It does not behave all that well because the keys have a very biased
+     distribution (I've seen 7-element buckets with the table only 14% full).
+
+     here_id is built of
+     * (1 bits) Reserved, zero.
+     * (8 bits) Part id = bits 13..20 of the hash value of here_id's key.
+     * (23 bits) Sequential number (each part has each own sequence).
+
+     prev_id has either the same distribution as here_id (but with 3:8:21)
+     split, or one of two reserved values (-1) or (-2). Either case can
+     dominate depending on the workload.
+  */
+  static u32 hash(const args_type &args) {
+    const u32 m = 0x5bd1e995;
+    const u32 seed = 0x9747b28c;
+    const u32 r = 24;
+    u32 h = seed;
+    u32 k = args.here_id;
+    k *= m;
+    k ^= k >> r;
+    k *= m;
+    h *= m;
+    h ^= k;
+
+    k = args.prev_id;
+    k *= m;
+    k ^= k >> r;
+    k *= m;
+    h *= m;
+    h ^= k;
+
+    h ^= h >> 13;
+    h *= m;
+    h ^= h >> 15;
+    return h;
+  }
+  static bool is_valid(const args_type &args) { return true; }
   void store(const args_type &args, u32 other_hash) {
     here_id = args.here_id;
     prev_id = args.prev_id;
@@ -103,4 +116,12 @@
   return desc.here_id;
 }
 
+void ChainedOriginDepotLockAll() {
+  chainedOriginDepot.LockAll();
+}
+
+void ChainedOriginDepotUnlockAll() {
+  chainedOriginDepot.UnlockAll();
+}
+
 }  // namespace __msan
diff --git a/lib/msan/msan_chained_origin_depot.h b/lib/msan/msan_chained_origin_depot.h
index db427b0..f7a71ce 100644
--- a/lib/msan/msan_chained_origin_depot.h
+++ b/lib/msan/msan_chained_origin_depot.h
@@ -21,6 +21,9 @@
 // Retrieves a stored stack trace by the id.
 u32 ChainedOriginDepotGet(u32 id, u32 *other);
 
+void ChainedOriginDepotLockAll();
+void ChainedOriginDepotUnlockAll();
+
 }  // namespace __msan
 
 #endif  // MSAN_CHAINED_ORIGIN_DEPOT_H
diff --git a/lib/msan/msan_interceptors.cc b/lib/msan/msan_interceptors.cc
index 3394690..aa6b1ff 100644
--- a/lib/msan/msan_interceptors.cc
+++ b/lib/msan/msan_interceptors.cc
@@ -15,6 +15,7 @@
 // sanitizer_common/sanitizer_common_interceptors.h
 //===----------------------------------------------------------------------===//
 
+#include "interception/interception.h"
 #include "msan.h"
 #include "msan_chained_origin_depot.h"
 #include "msan_origin.h"
@@ -25,7 +26,6 @@
 #include "sanitizer_common/sanitizer_allocator_internal.h"
 #include "sanitizer_common/sanitizer_atomic.h"
 #include "sanitizer_common/sanitizer_common.h"
-#include "sanitizer_common/sanitizer_interception.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 #include "sanitizer_common/sanitizer_libc.h"
 #include "sanitizer_common/sanitizer_linux.h"
@@ -64,21 +64,22 @@
 } while (0)
 
 // Check that [x, x+n) range is unpoisoned.
-#define CHECK_UNPOISONED_0(x, n)                                             \
-  do {                                                                       \
-    sptr offset = __msan_test_shadow(x, n);                                  \
-    if (__msan::IsInSymbolizer()) break;                                     \
-    if (offset >= 0 && __msan::flags()->report_umrs) {                       \
-      GET_CALLER_PC_BP_SP;                                                   \
-      (void) sp;                                                             \
-      ReportUMRInsideAddressRange(__func__, x, n, offset);                   \
-      __msan::PrintWarningWithOrigin(pc, bp,                                 \
-                                     __msan_get_origin((char *)x + offset)); \
-      if (__msan::flags()->halt_on_error) {                                  \
-        Printf("Exiting\n");                                                 \
-        Die();                                                               \
-      }                                                                      \
-    }                                                                        \
+#define CHECK_UNPOISONED_0(x, n)                                               \
+  do {                                                                         \
+    sptr offset = __msan_test_shadow(x, n);                                    \
+    if (__msan::IsInSymbolizer())                                              \
+      break;                                                                   \
+    if (offset >= 0 && __msan::flags()->report_umrs) {                         \
+      GET_CALLER_PC_BP_SP;                                                     \
+      (void) sp;                                                               \
+      ReportUMRInsideAddressRange(__func__, x, n, offset);                     \
+      __msan::PrintWarningWithOrigin(                                          \
+          pc, bp, __msan_get_origin((const char *)x + offset));                \
+      if (__msan::flags()->halt_on_error) {                                    \
+        Printf("Exiting\n");                                                   \
+        Die();                                                                 \
+      }                                                                        \
+    }                                                                          \
   } while (0)
 
 // Check that [x, x+n) range is unpoisoned unless we are in a nested
@@ -88,9 +89,6 @@
     if (!IsInInterceptorScope()) CHECK_UNPOISONED_0(x, n); \
   } while (0);
 
-static void *fast_memset(void *ptr, int c, SIZE_T n);
-static void *fast_memcpy(void *dst, const void *src, SIZE_T n);
-
 INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) {
   ENSURE_MSAN_INITED();
   SIZE_T res = REAL(fread)(ptr, size, nmemb, file);
@@ -263,6 +261,7 @@
     copy_size++;  // trailing \0
   char *res = REAL(strncpy)(dest, src, n);  // NOLINT
   CopyPoison(dest, src, copy_size, &stack);
+  __msan_unpoison(dest + copy_size, n - copy_size);
   return res;
 }
 
@@ -316,11 +315,8 @@
 INTERCEPTOR(char *, gcvt, double number, SIZE_T ndigit, char *buf) {
   ENSURE_MSAN_INITED();
   char *res = REAL(gcvt)(number, ndigit, buf);
-  // DynamoRio tool will take care of unpoisoning gcvt result for us.
-  if (!__msan_has_dynamic_component()) {
-    SIZE_T n = REAL(strlen)(buf);
-    __msan_unpoison(buf, n + 1);
-  }
+  SIZE_T n = REAL(strlen)(buf);
+  __msan_unpoison(buf, n + 1);
   return res;
 }
 
@@ -350,9 +346,7 @@
 #define INTERCEPTOR_STRTO_BODY(ret_type, func, ...) \
   ENSURE_MSAN_INITED();                             \
   ret_type res = REAL(func)(__VA_ARGS__);           \
-  if (!__msan_has_dynamic_component()) {            \
-    __msan_unpoison(endptr, sizeof(*endptr));       \
-  }                                                 \
+  __msan_unpoison(endptr, sizeof(*endptr));         \
   return res;
 
 #define INTERCEPTOR_STRTO(ret_type, func)                        \
@@ -409,7 +403,7 @@
 INTERCEPTOR(int, vswprintf, void *str, uptr size, void *format, va_list ap) {
   ENSURE_MSAN_INITED();
   int res = REAL(vswprintf)(str, size, format, ap);
-  if (res >= 0 && !__msan_has_dynamic_component()) {
+  if (res >= 0) {
     __msan_unpoison(str, 4 * (res + 1));
   }
   return res;
@@ -537,7 +531,7 @@
 INTERCEPTOR(wchar_t *, wmemset, wchar_t *s, wchar_t c, SIZE_T n) {
   CHECK(MEM_IS_APP(s));
   ENSURE_MSAN_INITED();
-  wchar_t *res = (wchar_t *)fast_memset(s, c, n * sizeof(wchar_t));
+  wchar_t *res = (wchar_t *)REAL(memset)(s, c, n * sizeof(wchar_t));
   __msan_unpoison(s, n * sizeof(wchar_t));
   return res;
 }
@@ -576,20 +570,16 @@
 INTERCEPTOR(char *, fcvt, double x, int a, int *b, int *c) {
   ENSURE_MSAN_INITED();
   char *res = REAL(fcvt)(x, a, b, c);
-  if (!__msan_has_dynamic_component()) {
-    __msan_unpoison(b, sizeof(*b));
-    __msan_unpoison(c, sizeof(*c));
-  }
+  __msan_unpoison(b, sizeof(*b));
+  __msan_unpoison(c, sizeof(*c));
+  if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
   return res;
 }
 
 INTERCEPTOR(char *, getenv, char *name) {
   ENSURE_MSAN_INITED();
   char *res = REAL(getenv)(name);
-  if (!__msan_has_dynamic_component()) {
-    if (res)
-      __msan_unpoison(res, REAL(strlen)(res) + 1);
-  }
+  if (res) __msan_unpoison(res, REAL(strlen)(res) + 1);
   return res;
 }
 
@@ -843,7 +833,7 @@
   if (flags()->poison_in_malloc)
     __msan_poison(data, size);
   if (__msan_get_track_origins()) {
-    u32 stack_id = StackDepotPut(stack.trace, stack.size);
+    u32 stack_id = StackDepotPut(stack);
     u32 id;
     ChainedOriginDepotPut(stack_id, Origin::kHeapRoot, &id);
     __msan_set_origin(data, size, Origin(id, 1).raw_id());
@@ -927,17 +917,15 @@
   }
   dl_iterate_phdr_data *cbdata = (dl_iterate_phdr_data *)data;
   UnpoisonParam(3);
-  return IndirectExternCall(cbdata->callback)(info, size, cbdata->data);
+  return cbdata->callback(info, size, cbdata->data);
 }
 
 INTERCEPTOR(int, dl_iterate_phdr, dl_iterate_phdr_cb callback, void *data) {
   ENSURE_MSAN_INITED();
-  EnterLoader();
   dl_iterate_phdr_data cbdata;
   cbdata.callback = callback;
   cbdata.data = data;
   int res = REAL(dl_iterate_phdr)(msan_dl_iterate_phdr_cb, (void *)&cbdata);
-  ExitLoader();
   return res;
 }
 
@@ -977,7 +965,7 @@
   typedef void (*signal_cb)(int x);
   signal_cb cb =
       (signal_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
-  IndirectExternCall(cb)(signo);
+  cb(signo);
 }
 
 static void SignalAction(int signo, void *si, void *uc) {
@@ -990,7 +978,7 @@
   typedef void (*sigaction_cb)(int, void *, void *);
   sigaction_cb cb =
       (sigaction_cb)atomic_load(&sigactions[signo], memory_order_relaxed);
-  IndirectExternCall(cb)(signo, si, uc);
+  cb(signo, si, uc);
 }
 
 INTERCEPTOR(int, sigaction, int signo, const __sanitizer_sigaction *act,
@@ -1006,7 +994,7 @@
     __sanitizer_sigaction new_act;
     __sanitizer_sigaction *pnew_act = act ? &new_act : 0;
     if (act) {
-      internal_memcpy(pnew_act, act, sizeof(__sanitizer_sigaction));
+      REAL(memcpy)(pnew_act, act, sizeof(__sanitizer_sigaction));
       uptr cb = (uptr)pnew_act->sigaction;
       uptr new_cb = (pnew_act->sa_flags & __sanitizer::sa_siginfo)
                         ? (uptr)SignalAction
@@ -1118,7 +1106,7 @@
 void MSanAtExitWrapper(void *arg) {
   UnpoisonParam(1);
   MSanAtExitRecord *r = (MSanAtExitRecord *)arg;
-  IndirectExternCall(r->func)(r->arg);
+  r->func(r->arg);
   InternalFree(r);
 }
 
@@ -1149,34 +1137,22 @@
   return p;
 }
 
-// Linux kernel has a bug that leads to kernel deadlock if a process
-// maps TBs of memory and then calls mlock().
-static void MlockIsUnsupported() {
-  static atomic_uint8_t printed;
-  if (atomic_exchange(&printed, 1, memory_order_relaxed))
-    return;
-  VPrintf(1,
-          "INFO: MemorySanitizer ignores mlock/mlockall/munlock/munlockall\n");
+static void BeforeFork() {
+  StackDepotLockAll();
+  ChainedOriginDepotLockAll();
 }
 
-INTERCEPTOR(int, mlock, const void *addr, uptr len) {
-  MlockIsUnsupported();
-  return 0;
+static void AfterFork() {
+  ChainedOriginDepotUnlockAll();
+  StackDepotUnlockAll();
 }
 
-INTERCEPTOR(int, munlock, const void *addr, uptr len) {
-  MlockIsUnsupported();
-  return 0;
-}
-
-INTERCEPTOR(int, mlockall, int flags) {
-  MlockIsUnsupported();
-  return 0;
-}
-
-INTERCEPTOR(int, munlockall, void) {
-  MlockIsUnsupported();
-  return 0;
+INTERCEPTOR(int, fork, void) {
+  ENSURE_MSAN_INITED();
+  BeforeFork();
+  int pid = REAL(fork)();
+  AfterFork();
+  return pid;
 }
 
 struct MSanInterceptorContext {
@@ -1240,12 +1216,8 @@
   } while (false)  // FIXME
 #define COMMON_INTERCEPTOR_BLOCK_REAL(name) REAL(name)
 #define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
-#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, map)                       \
-  if (!__msan_has_dynamic_component() && map) {                                \
-    /* If msandr didn't clear the shadow before the initializers ran, we do */ \
-    /* it ourselves afterwards. */                                             \
-    ForEachMappedRegion((link_map *)map, __msan_unpoison);                     \
-  }
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, map) \
+  if (map) ForEachMappedRegion((link_map *)map, __msan_unpoison);
 
 #include "sanitizer_common/sanitizer_common_interceptors.inc"
 
@@ -1259,59 +1231,25 @@
 #define COMMON_SYSCALL_POST_WRITE_RANGE(p, s) __msan_unpoison(p, s)
 #include "sanitizer_common/sanitizer_common_syscalls.inc"
 
-// static
-void *fast_memset(void *ptr, int c, SIZE_T n) {
-  // hack until we have a really fast internal_memset
-  if (sizeof(uptr) == 8 &&
-      (n % 8) == 0 &&
-      ((uptr)ptr % 8) == 0) {
-    uptr c8 = (unsigned)c & 0xFF;
-    c8 = (c8 << 8) | c8;
-    c8 = (c8 << 16) | c8;
-    c8 = (c8 << 32) | c8;
-    uptr *p = (uptr*)ptr;
-    for (SIZE_T i = 0; i < n / 8; i++)
-      p[i] = c8;
-    return ptr;
-  }
-  return internal_memset(ptr, c, n);
-}
-
-// static
-void *fast_memcpy(void *dst, const void *src, SIZE_T n) {
-  // Same hack as in fast_memset above.
-  if (sizeof(uptr) == 8 &&
-      (n % 8) == 0 &&
-      ((uptr)dst % 8) == 0 &&
-      ((uptr)src % 8) == 0) {
-    uptr *d = (uptr*)dst;
-    uptr *s = (uptr*)src;
-    for (SIZE_T i = 0; i < n / 8; i++)
-      d[i] = s[i];
-    return dst;
-  }
-  return internal_memcpy(dst, src, n);
-}
-
 static void PoisonShadow(uptr ptr, uptr size, u8 value) {
   uptr PageSize = GetPageSizeCached();
   uptr shadow_beg = MEM_TO_SHADOW(ptr);
   uptr shadow_end = MEM_TO_SHADOW(ptr + size);
   if (value ||
       shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
-    fast_memset((void*)shadow_beg, value, shadow_end - shadow_beg);
+    REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
   } else {
     uptr page_beg = RoundUpTo(shadow_beg, PageSize);
     uptr page_end = RoundDownTo(shadow_end, PageSize);
 
     if (page_beg >= page_end) {
-      fast_memset((void *)shadow_beg, 0, shadow_end - shadow_beg);
+      REAL(memset)((void *)shadow_beg, 0, shadow_end - shadow_beg);
     } else {
       if (page_beg != shadow_beg) {
-        fast_memset((void *)shadow_beg, 0, page_beg - shadow_beg);
+        REAL(memset)((void *)shadow_beg, 0, page_beg - shadow_beg);
       }
       if (page_end != shadow_end) {
-        fast_memset((void *)page_end, 0, shadow_end - page_end);
+        REAL(memset)((void *)page_end, 0, shadow_end - page_end);
       }
       MmapFixedNoReserve(page_beg, page_end - page_beg);
     }
@@ -1319,7 +1257,7 @@
 }
 
 // These interface functions reside here so that they can use
-// fast_memset, etc.
+// REAL(memset), etc.
 void __msan_unpoison(const void *a, uptr size) {
   if (!MEM_IS_APP(a)) return;
   PoisonShadow((uptr)a, size, 0);
@@ -1338,7 +1276,7 @@
 }
 
 void __msan_clear_and_unpoison(void *a, uptr size) {
-  fast_memset(a, 0, size);
+  REAL(memset)(a, 0, size);
   PoisonShadow((uptr)a, size, 0);
 }
 
@@ -1347,7 +1285,7 @@
   if (msan_init_is_running) return REAL(memcpy)(dest, src, n);
   ENSURE_MSAN_INITED();
   GET_STORE_STACK_TRACE;
-  void *res = fast_memcpy(dest, src, n);
+  void *res = REAL(memcpy)(dest, src, n);
   CopyPoison(dest, src, n, &stack);
   return res;
 }
@@ -1356,7 +1294,7 @@
   if (!msan_inited) return internal_memset(s, c, n);
   if (msan_init_is_running) return REAL(memset)(s, c, n);
   ENSURE_MSAN_INITED();
-  void *res = fast_memset(s, c, n);
+  void *res = REAL(memset)(s, c, n);
   __msan_unpoison(s, n);
   return res;
 }
@@ -1445,7 +1383,7 @@
         *dst = dst_o;
       }
     } else {
-      fast_memcpy((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s),
+      REAL(memcpy)((void *)MEM_TO_ORIGIN(beg), (void *)MEM_TO_ORIGIN(s),
                   end - beg);
     }
   }
@@ -1455,15 +1393,15 @@
   if (!MEM_IS_APP(dst)) return;
   if (!MEM_IS_APP(src)) return;
   if (src == dst) return;
-  internal_memmove((void *)MEM_TO_SHADOW((uptr)dst),
-                   (void *)MEM_TO_SHADOW((uptr)src), size);
+  REAL(memmove)((void *)MEM_TO_SHADOW((uptr)dst),
+                (void *)MEM_TO_SHADOW((uptr)src), size);
   CopyOrigin(dst, src, size, stack);
 }
 
 void CopyPoison(void *dst, const void *src, uptr size, StackTrace *stack) {
   if (!MEM_IS_APP(dst)) return;
   if (!MEM_IS_APP(src)) return;
-  fast_memcpy((void *)MEM_TO_SHADOW((uptr)dst),
+  REAL(memcpy)((void *)MEM_TO_SHADOW((uptr)dst),
               (void *)MEM_TO_SHADOW((uptr)src), size);
   CopyOrigin(dst, src, size, stack);
 }
@@ -1597,6 +1535,7 @@
   INTERCEPT_FUNCTION(tzset);
   INTERCEPT_FUNCTION(__cxa_atexit);
   INTERCEPT_FUNCTION(shmat);
+  INTERCEPT_FUNCTION(fork);
 
   inited = 1;
 }
diff --git a/lib/msan/msan_interface_internal.h b/lib/msan/msan_interface_internal.h
index 47b47dc..8641f81 100644
--- a/lib/msan/msan_interface_internal.h
+++ b/lib/msan/msan_interface_internal.h
@@ -88,9 +88,9 @@
 SANITIZER_INTERFACE_ATTRIBUTE
 void __msan_set_origin(const void *a, uptr size, u32 origin);
 SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_set_alloca_origin(void *a, uptr size, const char *descr);
+void __msan_set_alloca_origin(void *a, uptr size, char *descr);
 SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_set_alloca_origin4(void *a, uptr size, const char *descr, uptr pc);
+void __msan_set_alloca_origin4(void *a, uptr size, char *descr, uptr pc);
 SANITIZER_INTERFACE_ATTRIBUTE
 u32 __msan_chain_origin(u32 id);
 SANITIZER_INTERFACE_ATTRIBUTE
@@ -122,16 +122,6 @@
 SANITIZER_INTERFACE_ATTRIBUTE
 int  __msan_has_dynamic_component();
 
-// Returns x such that %fs:x is the first byte of __msan_retval_tls.
-SANITIZER_INTERFACE_ATTRIBUTE
-int __msan_get_retval_tls_offset();
-SANITIZER_INTERFACE_ATTRIBUTE
-int __msan_get_param_tls_offset();
-
-// For intercepting mmap from ld.so in msandr.
-SANITIZER_INTERFACE_ATTRIBUTE
-bool __msan_is_in_loader();
-
 // For testing.
 SANITIZER_INTERFACE_ATTRIBUTE
 u32 __msan_get_umr_origin();
@@ -161,37 +151,6 @@
 SANITIZER_INTERFACE_ATTRIBUTE
 void __sanitizer_unaligned_store64(uu64 *p, u64 x);
 
-// ---------------------------
-// FIXME: Replace these functions with __sanitizer equivalent.
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_estimated_allocated_size(uptr size);
-SANITIZER_INTERFACE_ATTRIBUTE
-int __msan_get_ownership(const void *p);
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_allocated_size(const void *p);
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_current_allocated_bytes();
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_heap_size();
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_free_bytes();
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __msan_get_unmapped_bytes();
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-/* OPTIONAL */ void __msan_malloc_hook(void *ptr, uptr size);
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-/* OPTIONAL */ void __msan_free_hook(void *ptr);
-// ---------------------------
-
-SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_dr_is_initialized();
-
-SANITIZER_INTERFACE_ATTRIBUTE
-void *__msan_wrap_indirect_call(void *target);
-
-SANITIZER_INTERFACE_ATTRIBUTE
-void __msan_set_indirect_call_wrapper(uptr wrapper);
-
 SANITIZER_INTERFACE_ATTRIBUTE
 void __msan_set_death_callback(void (*callback)(void));
 }  // extern "C"
diff --git a/lib/msan/msan_linux.cc b/lib/msan/msan_linux.cc
index a8fbabb..2a970c0 100644
--- a/lib/msan/msan_linux.cc
+++ b/lib/msan/msan_linux.cc
@@ -35,8 +35,14 @@
 
 namespace __msan {
 
+#if defined(__mips64)
+static const uptr kMemBeg     = 0xe000000000;
+static const uptr kMemEnd     = 0xffffffffff;
+#elif defined(__x86_64__)
 static const uptr kMemBeg     = 0x600000000000;
 static const uptr kMemEnd     = 0x7fffffffffff;
+#endif
+
 static const uptr kShadowBeg  = MEM_TO_SHADOW(kMemBeg);
 static const uptr kShadowEnd  = MEM_TO_SHADOW(kMemEnd);
 static const uptr kBad1Beg    = 0;
diff --git a/lib/msan/msan_new_delete.cc b/lib/msan/msan_new_delete.cc
index 3bae49c..9a8e56e 100644
--- a/lib/msan/msan_new_delete.cc
+++ b/lib/msan/msan_new_delete.cc
@@ -13,7 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "msan.h"
-#include "sanitizer_common/sanitizer_interception.h"
+#include "interception/interception.h"
 
 #if MSAN_REPLACE_OPERATORS_NEW_AND_DELETE
 
diff --git a/lib/msan/msan_report.cc b/lib/msan/msan_report.cc
index 85e61e2..f4978c7 100644
--- a/lib/msan/msan_report.cc
+++ b/lib/msan/msan_report.cc
@@ -46,15 +46,15 @@
   Printf(
       "  %sUninitialized value was created by an allocation of '%s%s%s'"
       " in the stack frame of function '%s%s%s'%s\n",
-      d.Origin(), d.Name(), s, d.Origin(), d.Name(),
-      Symbolizer::Get()->Demangle(sep + 1), d.Origin(), d.End());
+      d.Origin(), d.Name(), s, d.Origin(), d.Name(), sep + 1, d.Origin(),
+      d.End());
   InternalFree(s);
 
   if (pc) {
     // For some reason function address in LLVM IR is 1 less then the address
     // of the first instruction.
-    pc += 1;
-    StackTrace::PrintStack(&pc, 1);
+    pc = StackTrace::GetNextInstructionPc(pc);
+    StackTrace(&pc, 1).Print();
   }
 }
 
@@ -77,20 +77,16 @@
       DescribeStackOrigin(so, pc);
       break;
     } else if (prev_o.isHeapRoot()) {
-      uptr size = 0;
-      const uptr *trace = StackDepotGet(stack_id, &size);
       Printf("  %sUninitialized value was created by a heap allocation%s\n",
              d.Origin(), d.End());
-      StackTrace::PrintStack(trace, size);
+      StackDepotGet(stack_id).Print();
       break;
     } else {
       // chained origin
-      uptr size = 0;
-      const uptr *trace = StackDepotGet(stack_id, &size);
       // FIXME: copied? modified? passed through? observed?
       Printf("  %sUninitialized value was stored to memory at%s\n", d.Origin(),
              d.End());
-      StackTrace::PrintStack(trace, size);
+      StackDepotGet(stack_id).Print();
       id = prev_id;
     }
   }
diff --git a/lib/msan/msan_thread.cc b/lib/msan/msan_thread.cc
index 5fe99f6..2a1e05a 100644
--- a/lib/msan/msan_thread.cc
+++ b/lib/msan/msan_thread.cc
@@ -73,7 +73,7 @@
     return 0;
   }
 
-  thread_return_t res = IndirectExternCall(start_routine_)(arg_);
+  thread_return_t res = start_routine_(arg_);
 
   return res;
 }
diff --git a/lib/msan/tests/CMakeLists.txt b/lib/msan/tests/CMakeLists.txt
index c654615..f3c11ba 100644
--- a/lib/msan/tests/CMakeLists.txt
+++ b/lib/msan/tests/CMakeLists.txt
@@ -48,7 +48,7 @@
   -lstdc++
 )
 
-append_if(COMPILER_RT_HAS_LIBDL -ldl MSAN_UNITTEST_LINK_FLAGS)
+append_list_if(COMPILER_RT_HAS_LIBDL -ldl MSAN_UNITTEST_LINK_FLAGS)
 set(MSAN_LOADABLE_LINK_FLAGS
   -fsanitize=memory
   -shared
diff --git a/lib/msan/tests/msan_loadable.cc b/lib/msan/tests/msan_loadable.cc
index db3bf48..06e880f 100644
--- a/lib/msan/tests/msan_loadable.cc
+++ b/lib/msan/tests/msan_loadable.cc
@@ -20,24 +20,6 @@
 // No name mangling.
 extern "C" {
 
-__attribute__((constructor))
-void loadable_module_init(void) {
-  if (!__msan_has_dynamic_component())
-    return;
-  // The real test is that this compare should not make an uninit.
-  if (dso_global == NULL)
-    dso_global = malloc(4);
-}
-
-__attribute__((destructor))
-void loadable_module_fini(void) {
-  if (!__msan_has_dynamic_component())
-    return;
-  free(dso_global);
-  // *Don't* overwrite it with NULL!  That would unpoison it, but our test
-  // relies on reloading at the same address and keeping the poison.
-}
-
 void **get_dso_global() {
   return &dso_global;
 }
diff --git a/lib/msan/tests/msan_test.cc b/lib/msan/tests/msan_test.cc
index f7268d6..12012a0 100644
--- a/lib/msan/tests/msan_test.cc
+++ b/lib/msan/tests/msan_test.cc
@@ -251,7 +251,6 @@
 
 
 TEST(MemorySanitizer, CallAndRet) {
-  if (!__msan_has_dynamic_component()) return;
   ReturnPoisoned<S1>();
   ReturnPoisoned<S2>();
   ReturnPoisoned<S4>();
@@ -494,14 +493,12 @@
 static char *DynRetTestStr;
 
 TEST(MemorySanitizer, DynRet) {
-  if (!__msan_has_dynamic_component()) return;
   ReturnPoisoned<S8>();
   EXPECT_NOT_POISONED(clearenv());
 }
 
 
 TEST(MemorySanitizer, DynRet1) {
-  if (!__msan_has_dynamic_component()) return;
   ReturnPoisoned<S8>();
 }
 
@@ -570,7 +567,7 @@
   EXPECT_NOT_POISONED(x[16]);
   EXPECT_NOT_POISONED(x[31]);
   fclose(f);
-  delete x;
+  delete[] x;
 }
 
 TEST(MemorySanitizer, read) {
@@ -583,7 +580,7 @@
   EXPECT_NOT_POISONED(x[16]);
   EXPECT_NOT_POISONED(x[31]);
   close(fd);
-  delete x;
+  delete[] x;
 }
 
 TEST(MemorySanitizer, pread) {
@@ -596,7 +593,7 @@
   EXPECT_NOT_POISONED(x[16]);
   EXPECT_NOT_POISONED(x[31]);
   close(fd);
-  delete x;
+  delete[] x;
 }
 
 TEST(MemorySanitizer, readv) {
@@ -1452,13 +1449,8 @@
   x[2] = 0;
   memmove(x, x + 1, (size - 1) * sizeof(T));
   EXPECT_NOT_POISONED(x[1]);
-  if (!__msan_has_dynamic_component()) {
-    // FIXME: under DR we will lose this information
-    // because accesses in memmove will unpoisin the shadow.
-    // We need to use our own memove implementation instead of libc's.
-    EXPECT_POISONED(x[0]);
-    EXPECT_POISONED(x[2]);
-  }
+  EXPECT_POISONED(x[0]);
+  EXPECT_POISONED(x[2]);
   delete [] x;
 }
 
@@ -1483,14 +1475,16 @@
 
 TEST(MemorySanitizer, strncpy) {  // NOLINT
   char* x = new char[3];
-  char* y = new char[3];
+  char* y = new char[5];
   x[0] = 'a';
   x[1] = *GetPoisoned<char>(1, 1);
-  x[2] = 0;
-  strncpy(y, x, 2);  // NOLINT
+  x[2] = '\0';
+  strncpy(y, x, 4);  // NOLINT
   EXPECT_NOT_POISONED(y[0]);
   EXPECT_POISONED(y[1]);
-  EXPECT_POISONED(y[2]);
+  EXPECT_NOT_POISONED(y[2]);
+  EXPECT_NOT_POISONED(y[3]);
+  EXPECT_POISONED(y[4]);
 }
 
 TEST(MemorySanitizer, stpcpy) {  // NOLINT
@@ -2062,8 +2056,26 @@
   char *str = fcvt(12345.6789, 10, &a, &b);
   EXPECT_NOT_POISONED(a);
   EXPECT_NOT_POISONED(b);
+  ASSERT_NE(nullptr, str);
+  EXPECT_NOT_POISONED(str[0]);
+  ASSERT_NE(0U, strlen(str));
 }
 
+TEST(MemorySanitizer, fcvt_long) {
+  int a, b;
+  break_optimization(&a);
+  break_optimization(&b);
+  EXPECT_POISONED(a);
+  EXPECT_POISONED(b);
+  char *str = fcvt(111111112345.6789, 10, &a, &b);
+  EXPECT_NOT_POISONED(a);
+  EXPECT_NOT_POISONED(b);
+  ASSERT_NE(nullptr, str);
+  EXPECT_NOT_POISONED(str[0]);
+  ASSERT_NE(0U, strlen(str));
+}
+
+
 TEST(MemorySanitizer, memchr) {
   char x[10];
   break_optimization(x);
@@ -2787,7 +2799,7 @@
   EXPECT_NOT_POISONED(s[4]);
   EXPECT_NOT_POISONED(s[5]);
   EXPECT_POISONED(s[6]);
-  delete s;
+  delete[] s;
   delete d;
 }
 
@@ -3712,56 +3724,6 @@
 }
 #endif  // defined(__clang__)
 
-TEST(MemorySanitizerDr, StoreInDSOTest) {
-  if (!__msan_has_dynamic_component()) return;
-  char* s = new char[10];
-  dso_memfill(s, 9);
-  EXPECT_NOT_POISONED(s[5]);
-  EXPECT_POISONED(s[9]);
-}
-
-int return_poisoned_int() {
-  return ReturnPoisoned<U8>();
-}
-
-TEST(MemorySanitizerDr, ReturnFromDSOTest) {
-  if (!__msan_has_dynamic_component()) return;
-  EXPECT_NOT_POISONED(dso_callfn(return_poisoned_int));
-}
-
-NOINLINE int TrashParamTLS(long long x, long long y, long long z) {  //NOLINT
-  EXPECT_POISONED(x);
-  EXPECT_POISONED(y);
-  EXPECT_POISONED(z);
-  return 0;
-}
-
-static int CheckParamTLS(long long x, long long y, long long z) {  //NOLINT
-  EXPECT_NOT_POISONED(x);
-  EXPECT_NOT_POISONED(y);
-  EXPECT_NOT_POISONED(z);
-  return 0;
-}
-
-TEST(MemorySanitizerDr, CallFromDSOTest) {
-  if (!__msan_has_dynamic_component()) return;
-  S8* x = GetPoisoned<S8>();
-  S8* y = GetPoisoned<S8>();
-  S8* z = GetPoisoned<S8>();
-  EXPECT_NOT_POISONED(TrashParamTLS(*x, *y, *z));
-  EXPECT_NOT_POISONED(dso_callfn1(CheckParamTLS));
-}
-
-static void StackStoreInDSOFn(int* x, int* y) {
-  EXPECT_NOT_POISONED(*x);
-  EXPECT_NOT_POISONED(*y);
-}
-
-TEST(MemorySanitizerDr, StackStoreInDSOTest) {
-  if (!__msan_has_dynamic_component()) return;
-  dso_stack_store(StackStoreInDSOFn, 1);
-}
-
 TEST(MemorySanitizerOrigins, SetGet) {
   EXPECT_EQ(TrackingOrigins(), __msan_get_track_origins());
   if (!TrackingOrigins()) return;