Creating branches/google/testing and tags/google/testing/2017-11-14 from r317716

git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/branches/google/testing@318248 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/asan/asan_fuchsia.cc b/lib/asan/asan_fuchsia.cc
index 02fb8be..0b5bff4 100644
--- a/lib/asan/asan_fuchsia.cc
+++ b/lib/asan/asan_fuchsia.cc
@@ -28,7 +28,7 @@
 namespace __asan {
 
 // The system already set up the shadow memory for us.
-// __sanitizer::GetMaxVirtualAddress has already been called by
+// __sanitizer::GetMaxUserVirtualAddress has already been called by
 // AsanInitInternal->InitializeHighMemEnd (asan_rtl.cc).
 // Just do some additional sanity checks here.
 void InitializeShadowMemory() {
diff --git a/lib/asan/asan_rtl.cc b/lib/asan/asan_rtl.cc
index 8608e4a..27e4bd8 100644
--- a/lib/asan/asan_rtl.cc
+++ b/lib/asan/asan_rtl.cc
@@ -307,7 +307,7 @@
 
 static void InitializeHighMemEnd() {
 #if !ASAN_FIXED_MAPPING
-  kHighMemEnd = GetMaxVirtualAddress();
+  kHighMemEnd = GetMaxUserVirtualAddress();
   // Increase kHighMemEnd to make sure it's properly
   // aligned together with kHighMemBeg:
   kHighMemEnd |= SHADOW_GRANULARITY * GetMmapGranularity() - 1;
diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt
index 6128abc..3fc1d05 100644
--- a/lib/builtins/CMakeLists.txt
+++ b/lib/builtins/CMakeLists.txt
@@ -454,8 +454,12 @@
 set(mips64el_SOURCES ${GENERIC_TF_SOURCES}
                      ${mips_SOURCES})
 
-set(wasm32_SOURCES ${GENERIC_SOURCES})
-set(wasm64_SOURCES ${GENERIC_SOURCES})
+set(wasm32_SOURCES
+  ${GENERIC_TF_SOURCES}
+  ${GENERIC_SOURCES})
+set(wasm64_SOURCES
+  ${GENERIC_TF_SOURCES}
+  ${GENERIC_SOURCES})
 
 add_custom_target(builtins)
 set_target_properties(builtins PROPERTIES FOLDER "Compiler-RT Misc")
diff --git a/lib/cfi/cfi.cc b/lib/cfi/cfi.cc
index f720230..f7693b3 100644
--- a/lib/cfi/cfi.cc
+++ b/lib/cfi/cfi.cc
@@ -280,7 +280,7 @@
   CHECK_EQ(0, GetShadow());
   CHECK_EQ(0, GetShadowSize());
 
-  uptr vma = GetMaxVirtualAddress();
+  uptr vma = GetMaxUserVirtualAddress();
   // Shadow is 2 -> 2**kShadowGranularity.
   SetShadowSize((vma >> (kShadowGranularity - 1)) + 1);
   VReport(1, "CFI: VMA size %zx, shadow size %zx\n", vma, GetShadowSize());
diff --git a/lib/lsan/lsan_common.cc b/lib/lsan/lsan_common.cc
index 622aae7..651bbe1 100644
--- a/lib/lsan/lsan_common.cc
+++ b/lib/lsan/lsan_common.cc
@@ -411,8 +411,9 @@
   }
 }
 
-// On Linux, handles dynamically allocated TLS blocks by treating all chunks
-// allocated from ld-linux.so as reachable.
+// On Linux, treats all chunks allocated from ld-linux.so as reachable, which
+// covers dynamically allocated TLS blocks, internal dynamic loader's loaded
+// modules accounting etc.
 // Dynamic TLS blocks contain the TLS variables of dynamically loaded modules.
 // They are allocated with a __libc_memalign() call in allocate_and_init()
 // (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those
diff --git a/lib/lsan/lsan_common_linux.cc b/lib/lsan/lsan_common_linux.cc
index 5042c7b..cdd7f03 100644
--- a/lib/lsan/lsan_common_linux.cc
+++ b/lib/lsan/lsan_common_linux.cc
@@ -20,6 +20,7 @@
 
 #include "sanitizer_common/sanitizer_common.h"
 #include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_getauxval.h"
 #include "sanitizer_common/sanitizer_linux.h"
 #include "sanitizer_common/sanitizer_stackdepot.h"
 
@@ -30,8 +31,12 @@
 static char linker_placeholder[sizeof(LoadedModule)] ALIGNED(64);
 static LoadedModule *linker = nullptr;
 
-static bool IsLinker(const char* full_name) {
-  return LibraryNameIs(full_name, kLinkerName);
+static bool IsLinker(const LoadedModule& module) {
+#if SANITIZER_USE_GETAUXVAL
+  return module.base_address() == getauxval(AT_BASE);
+#else
+  return LibraryNameIs(module.full_name(), kLinkerName);
+#endif  // SANITIZER_USE_GETAUXVAL
 }
 
 __attribute__((tls_model("initial-exec")))
@@ -49,22 +54,25 @@
   ListOfModules modules;
   modules.init();
   for (LoadedModule &module : modules) {
-    if (!IsLinker(module.full_name())) continue;
+    if (!IsLinker(module))
+      continue;
     if (linker == nullptr) {
       linker = reinterpret_cast<LoadedModule *>(linker_placeholder);
       *linker = module;
       module = LoadedModule();
     } else {
       VReport(1, "LeakSanitizer: Multiple modules match \"%s\". "
-              "TLS will not be handled correctly.\n", kLinkerName);
+              "TLS and other allocations originating from linker might be "
+              "falsely reported as leaks.\n", kLinkerName);
       linker->clear();
       linker = nullptr;
       return;
     }
   }
   if (linker == nullptr) {
-    VReport(1, "LeakSanitizer: Dynamic linker not found. "
-               "TLS will not be handled correctly.\n");
+    VReport(1, "LeakSanitizer: Dynamic linker not found. TLS and other "
+               "allocations originating from linker might be falsely reported "
+                "as leaks.\n");
   }
 }
 
diff --git a/lib/msan/msan_linux.cc b/lib/msan/msan_linux.cc
index a1191a1..4e6321f 100644
--- a/lib/msan/msan_linux.cc
+++ b/lib/msan/msan_linux.cc
@@ -120,7 +120,7 @@
     return false;
   }
 
-  const uptr maxVirtualAddress = GetMaxVirtualAddress();
+  const uptr maxVirtualAddress = GetMaxUserVirtualAddress();
 
   for (unsigned i = 0; i < kMemoryLayoutSize; ++i) {
     uptr start = kMemoryLayout[i].start;
diff --git a/lib/profile/WindowsMMap.c b/lib/profile/WindowsMMap.c
index f81d7da..0c53471 100644
--- a/lib/profile/WindowsMMap.c
+++ b/lib/profile/WindowsMMap.c
@@ -120,9 +120,61 @@
 }
 
 COMPILER_RT_VISIBILITY
-int flock(int fd, int operation)
-{
-  return -1; /* Not supported. */
+int lock(HANDLE handle, DWORD lockType, BOOL blocking) {
+  DWORD flags = lockType;
+  if (!blocking)
+    flags |= LOCKFILE_FAIL_IMMEDIATELY;
+
+  OVERLAPPED overlapped;
+  ZeroMemory(&overlapped, sizeof(OVERLAPPED));
+  overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+  BOOL result = LockFileEx(handle, flags, 0, MAXDWORD, MAXDWORD, &overlapped);
+  if (!result) {
+    DWORD dw = GetLastError();
+
+    // In non-blocking mode, return an error if the file is locked.
+    if (!blocking && dw == ERROR_LOCK_VIOLATION)
+      return -1; // EWOULDBLOCK
+
+    // If the error is ERROR_IO_PENDING, we need to wait until the operation
+    // finishes. Otherwise, we return an error.
+    if (dw != ERROR_IO_PENDING)
+      return -1;
+
+    DWORD dwNumBytes;
+    if (!GetOverlappedResult(handle, &overlapped, &dwNumBytes, TRUE))
+      return -1;
+  }
+
+  return 0;
+}
+
+COMPILER_RT_VISIBILITY
+int flock(int fd, int operation) {
+  HANDLE handle = (HANDLE)_get_osfhandle(fd);
+  if (handle == INVALID_HANDLE_VALUE)
+    return -1;
+
+  BOOL blocking = (operation & LOCK_NB) == 0;
+  int op = operation & ~LOCK_NB;
+
+  switch (op) {
+  case LOCK_EX:
+    return lock(handle, LOCKFILE_EXCLUSIVE_LOCK, blocking);
+
+  case LOCK_SH:
+    return lock(handle, 0, blocking);
+
+  case LOCK_UN:
+    if (!UnlockFile(handle, 0, 0, MAXDWORD, MAXDWORD))
+      return -1;
+    break;
+
+  default:
+    return -1;
+  }
+
+  return 0;
 }
 
 #undef DWORD_HI
diff --git a/lib/sanitizer_common/sanitizer_allocator_primary64.h b/lib/sanitizer_common/sanitizer_allocator_primary64.h
index b22f3ab..4fb2f92 100644
--- a/lib/sanitizer_common/sanitizer_allocator_primary64.h
+++ b/lib/sanitizer_common/sanitizer_allocator_primary64.h
@@ -72,11 +72,10 @@
   void Init(s32 release_to_os_interval_ms) {
     uptr TotalSpaceSize = kSpaceSize + AdditionalSize();
     if (kUsingConstantSpaceBeg) {
-      CHECK_EQ(kSpaceBeg, reinterpret_cast<uptr>(
-                              MmapFixedNoAccess(kSpaceBeg, TotalSpaceSize)));
+      CHECK_EQ(kSpaceBeg, address_range.Init(TotalSpaceSize, AllocatorName(),
+                                             kSpaceBeg));
     } else {
-      NonConstSpaceBeg =
-          reinterpret_cast<uptr>(MmapNoAccess(TotalSpaceSize));
+      NonConstSpaceBeg = address_range.Init(TotalSpaceSize, AllocatorName());
       CHECK_NE(NonConstSpaceBeg, ~(uptr)0);
     }
     SetReleaseToOSIntervalMs(release_to_os_interval_ms);
@@ -544,6 +543,9 @@
  private:
   friend class MemoryMapper;
 
+  ReservedAddressRange address_range;
+  static const char *AllocatorName() { return "sanitizer_allocator"; }
+
   static const uptr kRegionSize = kSpaceSize / kNumClassesRounded;
   // FreeArray is the array of free-d chunks (stored as 4-byte offsets).
   // In the worst case it may reguire kRegionSize/SizeClassMap::kMinSize
@@ -625,7 +627,7 @@
   }
 
   bool MapWithCallback(uptr beg, uptr size) {
-    uptr mapped = reinterpret_cast<uptr>(MmapFixedOrDieOnFatalError(beg, size));
+    uptr mapped = address_range.Map(beg, size);
     if (UNLIKELY(!mapped))
       return false;
     CHECK_EQ(beg, mapped);
@@ -634,13 +636,13 @@
   }
 
   void MapWithCallbackOrDie(uptr beg, uptr size) {
-    CHECK_EQ(beg, reinterpret_cast<uptr>(MmapFixedOrDie(beg, size)));
+    CHECK_EQ(beg, address_range.MapOrDie(beg, size));
     MapUnmapCallback().OnMap(beg, size);
   }
 
   void UnmapWithCallbackOrDie(uptr beg, uptr size) {
     MapUnmapCallback().OnUnmap(beg, size);
-    UnmapOrDie(reinterpret_cast<void *>(beg), size);
+    address_range.Unmap(beg, size);
   }
 
   bool EnsureFreeArraySpace(RegionInfo *region, uptr region_beg,
@@ -677,7 +679,10 @@
         // preventing just allocated memory from being released sooner than
         // necessary and also preventing extraneous ReleaseMemoryPagesToOS calls
         // for short lived processes.
-        region->rtoi.last_release_at_ns = NanoTime();
+        // Do it only when the feature is turned on, to avoid a potentially
+        // extraneous syscall.
+        if (ReleaseToOSIntervalMs() >= 0)
+          region->rtoi.last_release_at_ns = NanoTime();
       }
       // Do the mmap for the user memory.
       uptr map_size = kUserMapSize;
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index 14b92d9..d64d3e1 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -73,7 +73,7 @@
   return PageSizeCached;
 }
 uptr GetMmapGranularity();
-uptr GetMaxVirtualAddress();
+uptr GetMaxUserVirtualAddress();
 // Threads
 tid_t GetTid();
 uptr GetThreadSelf();
@@ -131,7 +131,8 @@
 class ReservedAddressRange {
  public:
   uptr Init(uptr size, const char *name = nullptr, uptr fixed_addr = 0);
-  uptr Map(uptr fixed_addr, uptr size, bool tolerate_enomem = false);
+  uptr Map(uptr fixed_addr, uptr size);
+  uptr MapOrDie(uptr fixed_addr, uptr size);
   void Unmap(uptr addr, uptr size);
   void *base() const { return base_; }
   uptr size() const { return size_; }
diff --git a/lib/sanitizer_common/sanitizer_common_interceptors.inc b/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 321126c..16cc070 100644
--- a/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -5835,7 +5835,7 @@
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, pthread_setcancelstate, state, oldstate);
   int res = REAL(pthread_setcancelstate)(state, oldstate);
-  if (res == 0)
+  if (res == 0 && oldstate != nullptr)
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldstate, sizeof(*oldstate));
   return res;
 }
@@ -5844,7 +5844,7 @@
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, pthread_setcanceltype, type, oldtype);
   int res = REAL(pthread_setcanceltype)(type, oldtype);
-  if (res == 0)
+  if (res == 0 && oldtype != nullptr)
     COMMON_INTERCEPTOR_WRITE_RANGE(ctx, oldtype, sizeof(*oldtype));
   return res;
 }
diff --git a/lib/sanitizer_common/sanitizer_fuchsia.cc b/lib/sanitizer_common/sanitizer_fuchsia.cc
index a2a5321..97dff0d 100644
--- a/lib/sanitizer_common/sanitizer_fuchsia.cc
+++ b/lib/sanitizer_common/sanitizer_fuchsia.cc
@@ -186,7 +186,7 @@
 
 sanitizer_shadow_bounds_t ShadowBounds;
 
-uptr GetMaxVirtualAddress() {
+uptr GetMaxUserVirtualAddress() {
   ShadowBounds = __sanitizer_shadow_bounds();
   return ShadowBounds.memory_limit - 1;
 }
@@ -246,8 +246,12 @@
 
 // Uses fixed_addr for now.
 // Will use offset instead once we've implemented this function for real.
-uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size,
-                               bool tolerate_enomem) {
+uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size) {
+  return reinterpret_cast<uptr>(MmapFixedOrDieOnFatalError(fixed_addr,
+                                                           map_size));
+}
+
+uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr map_size) {
   return reinterpret_cast<uptr>(MmapFixedOrDie(fixed_addr, map_size));
 }
 
diff --git a/lib/sanitizer_common/sanitizer_getauxval.h b/lib/sanitizer_common/sanitizer_getauxval.h
new file mode 100644
index 0000000..d0287f0
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_getauxval.h
@@ -0,0 +1,40 @@
+//===-- sanitizer_getauxval.h -----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Common getauxval() guards and definitions.
+// getauxval() is not defined until glbc version 2.16.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_GETAUXVAL_H
+#define SANITIZER_GETAUXVAL_H
+
+#include "sanitizer_platform.h"
+
+#if SANITIZER_LINUX
+
+#include <features.h>
+
+#ifndef __GLIBC_PREREQ
+#define __GLIBC_PREREQ(x, y) 0
+#endif
+
+#if __GLIBC_PREREQ(2, 16)
+# define SANITIZER_USE_GETAUXVAL 1
+#else
+# define SANITIZER_USE_GETAUXVAL 0
+#endif
+
+#if SANITIZER_USE_GETAUXVAL
+#include <sys/auxv.h>
+#endif
+
+#endif // SANITIZER_LINUX
+
+#endif // SANITIZER_GETAUXVAL_H
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index 6ea1858..ea1e795 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -18,6 +18,7 @@
 
 #include "sanitizer_common.h"
 #include "sanitizer_flags.h"
+#include "sanitizer_getauxval.h"
 #include "sanitizer_internal_defs.h"
 #include "sanitizer_libc.h"
 #include "sanitizer_linux.h"
@@ -95,20 +96,6 @@
 #include <sys/signal.h>
 #endif
 
-#ifndef __GLIBC_PREREQ
-#define __GLIBC_PREREQ(x, y) 0
-#endif
-
-#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 16)
-# define SANITIZER_USE_GETAUXVAL 1
-#else
-# define SANITIZER_USE_GETAUXVAL 0
-#endif
-
-#if SANITIZER_USE_GETAUXVAL
-#include <sys/auxv.h>
-#endif
-
 #if SANITIZER_LINUX
 // <linux/time.h>
 struct kernel_timeval {
@@ -152,6 +139,8 @@
 #include "sanitizer_syscall_linux_x86_64.inc"
 #elif SANITIZER_LINUX && defined(__aarch64__)
 #include "sanitizer_syscall_linux_aarch64.inc"
+#elif SANITIZER_LINUX && defined(__arm__)
+#include "sanitizer_syscall_linux_arm.inc"
 #else
 #include "sanitizer_syscall_generic.inc"
 #endif
@@ -965,7 +954,7 @@
 }
 #endif  // SANITIZER_WORDSIZE == 32
 
-uptr GetMaxVirtualAddress() {
+uptr GetMaxUserVirtualAddress() {
 #if SANITIZER_NETBSD && defined(__x86_64__)
   return 0x7f7ffffff000ULL;  // (0x00007f8000000000 - PAGE_SIZE)
 #elif SANITIZER_WORDSIZE == 64
diff --git a/lib/sanitizer_common/sanitizer_mac.cc b/lib/sanitizer_common/sanitizer_mac.cc
index 9fead91..7a93c11 100644
--- a/lib/sanitizer_common/sanitizer_mac.cc
+++ b/lib/sanitizer_common/sanitizer_mac.cc
@@ -849,7 +849,7 @@
 }
 #endif
 
-uptr GetMaxVirtualAddress() {
+uptr GetMaxUserVirtualAddress() {
 #if SANITIZER_WORDSIZE == 64
 # if defined(__aarch64__) && SANITIZER_IOS && !SANITIZER_IOSSIM
   // Get the maximum VM address
diff --git a/lib/sanitizer_common/sanitizer_mac_libcdep.cc b/lib/sanitizer_common/sanitizer_mac_libcdep.cc
index c95daa9..090f17c 100644
--- a/lib/sanitizer_common/sanitizer_mac_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_mac_libcdep.cc
@@ -20,7 +20,7 @@
 namespace __sanitizer {
 
 void RestrictMemoryToMaxAddress(uptr max_address) {
-  uptr size_to_mmap = GetMaxVirtualAddress() + 1 - max_address;
+  uptr size_to_mmap = GetMaxUserVirtualAddress() + 1 - max_address;
   void *res = MmapFixedNoAccess(max_address, size_to_mmap, "high gap");
   CHECK(res != MAP_FAILED);
 }
diff --git a/lib/sanitizer_common/sanitizer_posix_libcdep.cc b/lib/sanitizer_common/sanitizer_posix_libcdep.cc
index 0ba3ad4..40b5f8a 100644
--- a/lib/sanitizer_common/sanitizer_posix_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_posix_libcdep.cc
@@ -338,8 +338,13 @@
 }
 
 uptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) {
+  // We don't pass `name` along because, when you enable `decorate_proc_maps`
+  // AND actually use a named mapping AND are using a sanitizer intercepting
+  // `open` (e.g. TSAN, ESAN), then you'll get a failure during initialization.
+  // TODO(flowerhack): Fix the implementation of GetNamedMappingFd to solve
+  // this problem.
   if (fixed_addr) {
-    base_ = MmapFixedNoAccess(fixed_addr, size, name);
+    base_ = MmapFixedNoAccess(fixed_addr, size);
   } else {
     base_ = MmapNoAccess(size);
   }
@@ -350,11 +355,11 @@
 
 // Uses fixed_addr for now.
 // Will use offset instead once we've implemented this function for real.
-uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size,
-                               bool tolerate_enomem) {
-  if (tolerate_enomem) {
-    return reinterpret_cast<uptr>(MmapFixedOrDieOnFatalError(fixed_addr, size));
-  }
+uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size) {
+  return reinterpret_cast<uptr>(MmapFixedOrDieOnFatalError(fixed_addr, size));
+}
+
+uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr size) {
   return reinterpret_cast<uptr>(MmapFixedOrDie(fixed_addr, size));
 }
 
diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
index e1cb6f7..ea864e5 100644
--- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -57,6 +57,14 @@
 #include "sanitizer_mutex.h"
 #include "sanitizer_placement_new.h"
 
+// Sufficiently old kernel headers don't provide this value, but we can still
+// call prctl with it. If the runtime kernel is new enough, the prctl call will
+// have the desired effect; if the kernel is too old, the call will error and we
+// can ignore said error.
+#ifndef PR_SET_PTRACER
+#define PR_SET_PTRACER 0x59616d61
+#endif
+
 // This module works by spawning a Linux task which then attaches to every
 // thread in the caller process with ptrace. This suspends the threads, and
 // PTRACE_GETREGS can then be used to obtain their register state. The callback
@@ -433,9 +441,7 @@
     ScopedSetTracerPID scoped_set_tracer_pid(tracer_pid);
     // On some systems we have to explicitly declare that we want to be traced
     // by the tracer thread.
-#ifdef PR_SET_PTRACER
     internal_prctl(PR_SET_PTRACER, tracer_pid, 0, 0, 0);
-#endif
     // Allow the tracer thread to start.
     tracer_thread_argument.mutex.Unlock();
     // NOTE: errno is shared between this thread and the tracer thread.
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
index 5735466..e98fab0 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
@@ -95,7 +95,8 @@
     if (frames_symbolized > 0) {
       SymbolizedStack *cur = SymbolizedStack::New(addr);
       AddressInfo *info = &cur->info;
-      info->FillModuleInfo(first->info.module, first->info.module_offset);
+      info->FillModuleInfo(first->info.module, first->info.module_offset,
+                           first->info.module_arch);
       last->next = cur;
       last = cur;
     }
diff --git a/lib/sanitizer_common/sanitizer_syscall_linux_arm.inc b/lib/sanitizer_common/sanitizer_syscall_linux_arm.inc
new file mode 100644
index 0000000..a3fdb9e
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_syscall_linux_arm.inc
@@ -0,0 +1,141 @@
+//===-- sanitizer_syscall_linux_arm.inc -------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementations of internal_syscall and internal_iserror for Linux/arm.
+//
+//===----------------------------------------------------------------------===//
+
+#define SYSCALL(name) __NR_ ## name
+
+static uptr __internal_syscall(u32 nr) {
+  register u32 r8 asm("r7") = nr;
+  register u32 r0 asm("r0");
+  asm volatile("swi #0"
+               : "=r"(r0)
+               : "r"(r8)
+               : "memory", "cc");
+  return r0;
+}
+#define __internal_syscall0(n) \
+  (__internal_syscall)(n)
+
+static uptr __internal_syscall(u32 nr, u32 arg1) {
+  register u32 r8 asm("r7") = nr;
+  register u32 r0 asm("r0") = arg1;
+  asm volatile("swi #0"
+               : "=r"(r0)
+               : "r"(r8), "0"(r0)
+               : "memory", "cc");
+  return r0;
+}
+#define __internal_syscall1(n, a1) \
+  (__internal_syscall)(n, (u32)(a1))
+
+static uptr __internal_syscall(u32 nr, u32 arg1, long arg2) {
+  register u32 r8 asm("r7") = nr;
+  register u32 r0 asm("r0") = arg1;
+  register u32 r1 asm("r1") = arg2;
+  asm volatile("swi #0"
+               : "=r"(r0)
+               : "r"(r8), "0"(r0), "r"(r1)
+               : "memory", "cc");
+  return r0;
+}
+#define __internal_syscall2(n, a1, a2) \
+  (__internal_syscall)(n, (u32)(a1), (long)(a2))
+
+static uptr __internal_syscall(u32 nr, u32 arg1, long arg2, long arg3) {
+  register u32 r8 asm("r7") = nr;
+  register u32 r0 asm("r0") = arg1;
+  register u32 r1 asm("r1") = arg2;
+  register u32 r2 asm("r2") = arg3;
+  asm volatile("swi #0"
+               : "=r"(r0)
+               : "r"(r8), "0"(r0), "r"(r1), "r"(r2)
+               : "memory", "cc");
+  return r0;
+}
+#define __internal_syscall3(n, a1, a2, a3) \
+  (__internal_syscall)(n, (u32)(a1), (long)(a2), (long)(a3))
+
+static uptr __internal_syscall(u32 nr, u32 arg1, long arg2, long arg3,
+                               u32 arg4) {
+  register u32 r8 asm("r7") = nr;
+  register u32 r0 asm("r0") = arg1;
+  register u32 r1 asm("r1") = arg2;
+  register u32 r2 asm("r2") = arg3;
+  register u32 r3 asm("r3") = arg4;
+  asm volatile("swi #0"
+               : "=r"(r0)
+               : "r"(r8), "0"(r0), "r"(r1), "r"(r2), "r"(r3)
+               : "memory", "cc");
+  return r0;
+}
+#define __internal_syscall4(n, a1, a2, a3, a4) \
+  (__internal_syscall)(n, (u32)(a1), (long)(a2), (long)(a3), (long)(a4))
+
+static uptr __internal_syscall(u32 nr, u32 arg1, long arg2, long arg3,
+                               u32 arg4, long arg5) {
+  register u32 r8 asm("r7") = nr;
+  register u32 r0 asm("r0") = arg1;
+  register u32 r1 asm("r1") = arg2;
+  register u32 r2 asm("r2") = arg3;
+  register u32 r3 asm("r3") = arg4;
+  register u32 r4 asm("r4") = arg5;
+  asm volatile("swi #0"
+               : "=r"(r0)
+               : "r"(r8), "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4)
+               : "memory", "cc");
+  return r0;
+}
+#define __internal_syscall5(n, a1, a2, a3, a4, a5) \
+  (__internal_syscall)(n, (u32)(a1), (long)(a2), (long)(a3), (long)(a4), \
+                       (u32)(a5))
+
+static uptr __internal_syscall(u32 nr, u32 arg1, long arg2, long arg3,
+                               u32 arg4, long arg5, long arg6) {
+  register u32 r8 asm("r7") = nr;
+  register u32 r0 asm("r0") = arg1;
+  register u32 r1 asm("r1") = arg2;
+  register u32 r2 asm("r2") = arg3;
+  register u32 r3 asm("r3") = arg4;
+  register u32 r4 asm("r4") = arg5;
+  register u32 r5 asm("r5") = arg6;
+  asm volatile("swi #0"
+               : "=r"(r0)
+               : "r"(r8), "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5)
+               : "memory", "cc");
+  return r0;
+}
+#define __internal_syscall6(n, a1, a2, a3, a4, a5, a6) \
+  (__internal_syscall)(n, (u32)(a1), (long)(a2), (long)(a3), (long)(a4), \
+                       (u32)(a5), (long)(a6))
+
+#define __SYSCALL_NARGS_X(a1, a2, a3, a4, a5, a6, a7, a8, n, ...) n
+#define __SYSCALL_NARGS(...) \
+  __SYSCALL_NARGS_X(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0, )
+#define __SYSCALL_CONCAT_X(a, b) a##b
+#define __SYSCALL_CONCAT(a, b) __SYSCALL_CONCAT_X(a, b)
+#define __SYSCALL_DISP(b, ...) \
+  __SYSCALL_CONCAT(b, __SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__)
+
+#define internal_syscall(...) __SYSCALL_DISP(__internal_syscall, __VA_ARGS__)
+
+#define internal_syscall_ptr internal_syscall
+#define internal_syscall64 internal_syscall
+
+// Helper function used to avoid cobbler errno.
+bool internal_iserror(uptr retval, int *rverrno) {
+  if (retval >= (uptr)-4095) {
+    if (rverrno)
+      *rverrno = -retval;
+    return true;
+  }
+  return false;
+}
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index b2fd8ba..1186971 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -64,7 +64,7 @@
   return si.dwAllocationGranularity;
 }
 
-uptr GetMaxVirtualAddress() {
+uptr GetMaxUserVirtualAddress() {
   SYSTEM_INFO si;
   GetSystemInfo(&si);
   return (uptr)si.lpMaximumApplicationAddress;
@@ -237,11 +237,11 @@
 
 // Uses fixed_addr for now.
 // Will use offset instead once we've implemented this function for real.
-uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size,
-                               bool tolerate_enomem) {
-  if (tolerate_enomem) {
-    return reinterpret_cast<uptr>(MmapFixedOrDieOnFatalError(fixed_addr, size));
-  }
+uptr ReservedAddressRange::Map(uptr fixed_addr, uptr size) {
+  return reinterpret_cast<uptr>(MmapFixedOrDieOnFatalError(fixed_addr, size));
+}
+
+uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr size) {
   return reinterpret_cast<uptr>(MmapFixedOrDie(fixed_addr, size));
 }
 
diff --git a/lib/sanitizer_common/sanitizer_win_weak_interception.cc b/lib/sanitizer_common/sanitizer_win_weak_interception.cc
index 3643193..5711f5d 100644
--- a/lib/sanitizer_common/sanitizer_win_weak_interception.cc
+++ b/lib/sanitizer_common/sanitizer_win_weak_interception.cc
@@ -12,7 +12,7 @@
 // definition is provided.
 //===----------------------------------------------------------------------===//
 
-#include "sanitizer_common/sanitizer_platform.h"
+#include "sanitizer_platform.h"
 #if SANITIZER_WINDOWS && SANITIZER_DYNAMIC
 #include "sanitizer_win_weak_interception.h"
 #include "sanitizer_allocator_interface.h"
diff --git a/lib/sanitizer_common/scripts/check_lint.sh b/lib/sanitizer_common/scripts/check_lint.sh
index 82e4bc8..ec07138 100755
--- a/lib/sanitizer_common/scripts/check_lint.sh
+++ b/lib/sanitizer_common/scripts/check_lint.sh
@@ -29,6 +29,7 @@
 LSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
 LSAN_LIT_TEST_LINT_FILTER=${LSAN_RTL_LINT_FILTER},-whitespace/line_length
 DFSAN_RTL_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int,-runtime/printf,-runtime/references,-readability/function
+SCUDO_RTL_LINT_FILTER=${COMMON_LINT_FILTER}
 COMMON_RTL_INC_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int,-runtime/sizeof,-runtime/printf,-readability/fn_size
 SANITIZER_INCLUDES_LINT_FILTER=${COMMON_LINT_FILTER},-runtime/int
 
@@ -112,6 +113,11 @@
                                   ${DFSAN_RTL}/*.h &
 ${DFSAN_RTL}/scripts/check_custom_wrappers.sh >> $ERROR_LOG
 
+# Scudo
+SCUDO_RTL=${COMPILER_RT}/lib/scudo
+run_lint ${SCUDO_RTL_LINT_FILTER} ${SCUDO_RTL}/*.cpp \
+                                  ${SCUDO_RTL}/*.h &
+
 # Misc files
 FILES=${COMMON_RTL}/*.inc
 TMPFILES=""
diff --git a/lib/scudo/scudo_allocator_secondary.h b/lib/scudo/scudo_allocator_secondary.h
index dbfb225..5220b7c 100644
--- a/lib/scudo/scudo_allocator_secondary.h
+++ b/lib/scudo/scudo_allocator_secondary.h
@@ -23,7 +23,6 @@
 
 class ScudoLargeMmapAllocator {
  public:
-
   void Init() {
     PageSize = GetPageSizeCached();
   }
diff --git a/lib/scudo/scudo_crc32.h b/lib/scudo/scudo_crc32.h
index 5ffcc62..e89e430 100644
--- a/lib/scudo/scudo_crc32.h
+++ b/lib/scudo/scudo_crc32.h
@@ -40,7 +40,7 @@
   CRC32Hardware = 1,
 };
 
-const static u32 CRC32Table[] = {
+static const u32 CRC32Table[] = {
   0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
   0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
   0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
diff --git a/lib/scudo/scudo_utils.cpp b/lib/scudo/scudo_utils.cpp
index 093eafe..653b6c8 100644
--- a/lib/scudo/scudo_utils.cpp
+++ b/lib/scudo/scudo_utils.cpp
@@ -90,8 +90,7 @@
   u32 Edx;
 } CPUIDRegs;
 
-static void getCPUID(CPUIDRegs *Regs, u32 Level)
-{
+static void getCPUID(CPUIDRegs *Regs, u32 Level) {
   __get_cpuid(Level, &Regs->Eax, &Regs->Ebx, &Regs->Ecx, &Regs->Edx);
 }
 
@@ -118,8 +117,7 @@
 #  define bit_SSE4_2 bit_SSE42  // clang and gcc have different defines.
 # endif
 
-bool testCPUFeature(CPUFeature Feature)
-{
+bool testCPUFeature(CPUFeature Feature) {
   CPUIDRegs FeaturesRegs = getCPUFeatures();
 
   switch (Feature) {
diff --git a/lib/scudo/scudo_utils.h b/lib/scudo/scudo_utils.h
index 1326919..cb7300d 100644
--- a/lib/scudo/scudo_utils.h
+++ b/lib/scudo/scudo_utils.h
@@ -14,10 +14,10 @@
 #ifndef SCUDO_UTILS_H_
 #define SCUDO_UTILS_H_
 
-#include <string.h>
-
 #include "sanitizer_common/sanitizer_common.h"
 
+#include <string.h>
+
 namespace __scudo {
 
 template <class Dest, class Source>
@@ -34,7 +34,7 @@
   CRC32CPUFeature = 0,
   MaxCPUFeature,
 };
-bool testCPUFeature(CPUFeature feature);
+bool testCPUFeature(CPUFeature Feature);
 
 INLINE u64 rotl(const u64 X, int K) {
   return (X << K) | (X >> (64 - K));
diff --git a/lib/tsan/CMakeLists.txt b/lib/tsan/CMakeLists.txt
index 08974a4..f7a5d70 100644
--- a/lib/tsan/CMakeLists.txt
+++ b/lib/tsan/CMakeLists.txt
@@ -184,13 +184,15 @@
               $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
               $<TARGET_OBJECTS:RTSanitizerCommonLibc.${arch}>
               $<TARGET_OBJECTS:RTUbsan.${arch}>
-      CFLAGS ${TSAN_RTL_CFLAGS})
+      CFLAGS ${TSAN_RTL_CFLAGS}
+      PARENT_TARGET tsan)
     add_compiler_rt_runtime(clang_rt.tsan_cxx
       STATIC
       ARCHS ${arch}
       SOURCES ${TSAN_CXX_SOURCES}
               $<TARGET_OBJECTS:RTUbsan_cxx.${arch}>
-      CFLAGS ${TSAN_RTL_CFLAGS})
+      CFLAGS ${TSAN_RTL_CFLAGS}
+      PARENT_TARGET tsan)
     list(APPEND TSAN_RUNTIME_LIBRARIES clang_rt.tsan-${arch}
                                        clang_rt.tsan_cxx-${arch})
     add_sanitizer_rt_symbols(clang_rt.tsan
diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc
index 79e243a..976fe29 100644
--- a/lib/tsan/rtl/tsan_interceptors.cc
+++ b/lib/tsan/rtl/tsan_interceptors.cc
@@ -213,8 +213,6 @@
 #define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED \
   (!cur_thread()->is_inited)
 
-static sigaction_t sigactions[kSigCount];
-
 namespace __tsan {
 struct SignalDesc {
   bool armed;
@@ -233,11 +231,31 @@
   __sanitizer_sigset_t oldset;
 };
 
-// The object is 64-byte aligned, because we want hot data to be located in
-// a single cache line if possible (it's accessed in every interceptor).
-static ALIGNED(64) char libignore_placeholder[sizeof(LibIgnore)];
+// InterceptorContext holds all global data required for interceptors.
+// It's explicitly constructed in InitializeInterceptors with placement new
+// and is never destroyed. This allows usage of members with non-trivial
+// constructors and destructors.
+struct InterceptorContext {
+  // The object is 64-byte aligned, because we want hot data to be located
+  // in a single cache line if possible (it's accessed in every interceptor).
+  ALIGNED(64) LibIgnore libignore;
+  sigaction_t sigactions[kSigCount];
+#if !SANITIZER_MAC && !SANITIZER_NETBSD
+  unsigned finalize_key;
+#endif
+
+  InterceptorContext()
+      : libignore(LINKER_INITIALIZED) {
+  }
+};
+
+static ALIGNED(64) char interceptor_placeholder[sizeof(InterceptorContext)];
+InterceptorContext *interceptor_ctx() {
+  return reinterpret_cast<InterceptorContext*>(&interceptor_placeholder[0]);
+}
+
 LibIgnore *libignore() {
-  return reinterpret_cast<LibIgnore*>(&libignore_placeholder[0]);
+  return &interceptor_ctx()->libignore;
 }
 
 void InitializeLibIgnore() {
@@ -265,10 +283,6 @@
   return ctx;
 }
 
-#if !SANITIZER_MAC
-static unsigned g_thread_finalize_key;
-#endif
-
 ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
                                      uptr pc)
     : thr_(thr), pc_(pc), in_ignored_lib_(false), ignoring_(false) {
@@ -435,7 +449,7 @@
   return res;
 }
 
-#if !SANITIZER_MAC
+#if !SANITIZER_MAC && !SANITIZER_NETBSD
 static void on_exit_wrapper(int status, void *arg) {
   ThreadState *thr = cur_thread();
   uptr pc = 0;
@@ -460,6 +474,9 @@
   ThreadIgnoreEnd(thr, pc);
   return res;
 }
+#define TSAN_MAYBE_INTERCEPT_ON_EXIT TSAN_INTERCEPT(on_exit)
+#else
+#define TSAN_MAYBE_INTERCEPT_ON_EXIT
 #endif
 
 // Cleanup old bufs.
@@ -866,11 +883,12 @@
 }
 }  // namespace __tsan
 
-#if !SANITIZER_MAC
+#if !SANITIZER_MAC && !SANITIZER_NETBSD
 static void thread_finalize(void *v) {
   uptr iter = (uptr)v;
   if (iter > 1) {
-    if (pthread_setspecific(g_thread_finalize_key, (void*)(iter - 1))) {
+    if (pthread_setspecific(interceptor_ctx()->finalize_key,
+        (void*)(iter - 1))) {
       Printf("ThreadSanitizer: failed to set thread key\n");
       Die();
     }
@@ -896,9 +914,9 @@
     ThreadState *thr = cur_thread();
     // Thread-local state is not initialized yet.
     ScopedIgnoreInterceptors ignore;
-#if !SANITIZER_MAC
+#if !SANITIZER_MAC && !SANITIZER_NETBSD
     ThreadIgnoreBegin(thr, 0);
-    if (pthread_setspecific(g_thread_finalize_key,
+    if (pthread_setspecific(interceptor_ctx()->finalize_key,
                             (void *)GetPthreadDestructorIterations())) {
       Printf("ThreadSanitizer: failed to set thread key\n");
       Die();
@@ -1799,6 +1817,7 @@
 
 static void CallUserSignalHandler(ThreadState *thr, bool sync, bool acquire,
     bool sigact, int sig, my_siginfo_t *info, void *uctx) {
+  sigaction_t *sigactions = interceptor_ctx()->sigactions;
   if (acquire)
     Acquire(thr, 0, (uptr)&sigactions[sig]);
   // Signals are generally asynchronous, so if we receive a signals when
@@ -1950,6 +1969,7 @@
   // the signal handler through rtl_sigaction, very bad things will happen.
   // The handler will run synchronously and corrupt tsan per-thread state.
   SCOPED_INTERCEPTOR_RAW(sigaction, sig, act, old);
+  sigaction_t *sigactions = interceptor_ctx()->sigactions;
   if (old)
     internal_memcpy(old, &sigactions[sig], sizeof(*old));
   if (act == 0)
@@ -2445,6 +2465,17 @@
 }
 #endif
 
+#if SANITIZER_NETBSD
+TSAN_INTERCEPTOR(void, _lwp_exit) {
+  SCOPED_TSAN_INTERCEPTOR(_lwp_exit);
+  DestroyThreadState();
+  REAL(_lwp_exit)();
+}
+#define TSAN_MAYBE_INTERCEPT__LWP_EXIT TSAN_INTERCEPT(_lwp_exit)
+#else
+#define TSAN_MAYBE_INTERCEPT__LWP_EXIT
+#endif
+
 namespace __tsan {
 
 static void finalize(void *arg) {
@@ -2476,6 +2507,8 @@
   mallopt(-3, 32*1024);  // M_MMAP_THRESHOLD
 #endif
 
+  new(interceptor_ctx()) InterceptorContext();
+
   InitializeCommonInterceptors();
 
 #if !SANITIZER_MAC
@@ -2605,7 +2638,7 @@
 #if !SANITIZER_ANDROID
   TSAN_INTERCEPT(dl_iterate_phdr);
 #endif
-  TSAN_INTERCEPT(on_exit);
+  TSAN_MAYBE_INTERCEPT_ON_EXIT;
   TSAN_INTERCEPT(__cxa_atexit);
   TSAN_INTERCEPT(_exit);
 
@@ -2613,6 +2646,8 @@
   TSAN_INTERCEPT(__tls_get_addr);
 #endif
 
+  TSAN_MAYBE_INTERCEPT__LWP_EXIT;
+
 #if !SANITIZER_MAC && !SANITIZER_ANDROID
   // Need to setup it, because interceptors check that the function is resolved.
   // But atexit is emitted directly into the module, so can't be resolved.
@@ -2624,8 +2659,8 @@
     Die();
   }
 
-#if !SANITIZER_MAC
-  if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
+#if !SANITIZER_MAC && !SANITIZER_NETBSD
+  if (pthread_key_create(&interceptor_ctx()->finalize_key, &thread_finalize)) {
     Printf("ThreadSanitizer: failed to create thread key\n");
     Die();
   }
diff --git a/lib/tsan/rtl/tsan_platform_mac.cc b/lib/tsan/rtl/tsan_platform_mac.cc
index 4570286..f8d7324 100644
--- a/lib/tsan/rtl/tsan_platform_mac.cc
+++ b/lib/tsan/rtl/tsan_platform_mac.cc
@@ -231,7 +231,7 @@
 
 void InitializePlatformEarly() {
 #if defined(__aarch64__)
-  uptr max_vm = GetMaxVirtualAddress() + 1;
+  uptr max_vm = GetMaxUserVirtualAddress() + 1;
   if (max_vm != Mapping::kHiAppMemEnd) {
     Printf("ThreadSanitizer: unsupported vm address limit %p, expected %p.\n",
            max_vm, Mapping::kHiAppMemEnd);
diff --git a/test/asan/TestCases/contiguous_container_crash.cc b/test/asan/TestCases/contiguous_container_crash.cc
index af2102e..fe97928 100644
--- a/test/asan/TestCases/contiguous_container_crash.cc
+++ b/test/asan/TestCases/contiguous_container_crash.cc
@@ -4,6 +4,12 @@
 // RUN: not %run %t bad-alignment 2>&1 | FileCheck --check-prefix=CHECK-BAD-ALIGNMENT %s
 // RUN: %env_asan_opts=detect_container_overflow=0 %run %t crash
 //
+// RUN: %clangxx_asan -flto=thin -O %s -o %t.thinlto
+// RUN: not %run %t.thinlto crash 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s
+// RUN: not %run %t.thinlto bad-bounds 2>&1 | FileCheck --check-prefix=CHECK-BAD-BOUNDS %s
+// RUN: not %run %t.thinlto bad-alignment 2>&1 | FileCheck --check-prefix=CHECK-BAD-ALIGNMENT %s
+// RUN: %env_asan_opts=detect_container_overflow=0 %run %t.thinlto crash
+//
 // Test crash due to __sanitizer_annotate_contiguous_container.
 
 #include <assert.h>