Propagating prior merge from 'llvm.org/release_40'.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e8326f0..f6eed77 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -134,7 +134,7 @@
 endif()
 append_list_if(COMPILER_RT_HAS_FNO_BUILTIN_FLAG -fno-builtin SANITIZER_COMMON_CFLAGS)
 append_list_if(COMPILER_RT_HAS_FNO_EXCEPTIONS_FLAG -fno-exceptions SANITIZER_COMMON_CFLAGS)
-if(NOT COMPILER_RT_DEBUG)
+if(NOT COMPILER_RT_DEBUG AND NOT APPLE)
   append_list_if(COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG -fomit-frame-pointer SANITIZER_COMMON_CFLAGS)
 endif()
 append_list_if(COMPILER_RT_HAS_FUNWIND_TABLES_FLAG -funwind-tables SANITIZER_COMMON_CFLAGS)
diff --git a/README.txt b/README.txt
index fc88432..2d64f00 100644
--- a/README.txt
+++ b/README.txt
@@ -8,4 +8,3 @@
 terms of the license agreement found in LICENSE.txt.
 
 ================================
-
diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake
index e0e4355..e84a066 100644
--- a/cmake/config-ix.cmake
+++ b/cmake/config-ix.cmake
@@ -199,7 +199,7 @@
     list(APPEND DARWIN_EMBEDDED_PLATFORMS ios)
     set(DARWIN_ios_MIN_VER_FLAG -miphoneos-version-min)
     set(DARWIN_ios_SANITIZER_MIN_VER_FLAG
-      ${DARWIN_ios_MIN_VER_FLAG}=7.0)
+      ${DARWIN_ios_MIN_VER_FLAG}=8.0)
   endif()
   if(COMPILER_RT_ENABLE_WATCHOS)
     list(APPEND DARWIN_EMBEDDED_PLATFORMS watchos)
diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc
index ee9b1a6..1478949 100644
--- a/lib/asan/asan_allocator.cc
+++ b/lib/asan/asan_allocator.cc
@@ -523,6 +523,18 @@
     AsanThread *t = GetCurrentThread();
     m->free_tid = t ? t->tid() : 0;
     m->free_context_id = StackDepotPut(*stack);
+
+    Flags &fl = *flags();
+    if (fl.max_free_fill_size > 0) {
+      // We have to skip the chunk header, it contains free_context_id.
+      uptr scribble_start = (uptr)m + kChunkHeaderSize + kChunkHeader2Size;
+      if (m->UsedSize() >= kChunkHeader2Size) {  // Skip Header2 in user area.
+        uptr size_to_fill = m->UsedSize() - kChunkHeader2Size;
+        size_to_fill = Min(size_to_fill, (uptr)fl.max_free_fill_size);
+        REAL(memset)((void *)scribble_start, fl.free_fill_byte, size_to_fill);
+      }
+    }
+
     // Poison the region.
     PoisonShadow(m->Beg(),
                  RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
diff --git a/lib/asan/asan_descriptions.cc b/lib/asan/asan_descriptions.cc
index 0ecbe09..822a6a6 100644
--- a/lib/asan/asan_descriptions.cc
+++ b/lib/asan/asan_descriptions.cc
@@ -252,6 +252,9 @@
     str.append("%c", var.name_pos[i]);
   }
   str.append("'");
+  if (var.line > 0) {
+    str.append(" (line %d)", var.line);
+  }
   if (pos_descr) {
     Decorator d;
     // FIXME: we may want to also print the size of the access here,
diff --git a/lib/asan/asan_flags.cc b/lib/asan/asan_flags.cc
index ad5bbff..81dcc0d 100644
--- a/lib/asan/asan_flags.cc
+++ b/lib/asan/asan_flags.cc
@@ -95,6 +95,18 @@
   RegisterCommonFlags(&ubsan_parser);
 #endif
 
+  if (SANITIZER_MAC) {
+    // Support macOS MallocScribble and MallocPreScribble:
+    // <https://developer.apple.com/library/content/documentation/Performance/
+    // Conceptual/ManagingMemory/Articles/MallocDebug.html>
+    if (GetEnv("MallocScribble")) {
+      f->max_free_fill_size = 0x1000;
+    }
+    if (GetEnv("MallocPreScribble")) {
+      f->malloc_fill_byte = 0xaa;
+    }
+  }
+
   // Override from ASan compile definition.
   const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition();
   asan_parser.ParseString(asan_compile_def);
diff --git a/lib/asan/asan_flags.inc b/lib/asan/asan_flags.inc
index 4712efb..98cbca2 100644
--- a/lib/asan/asan_flags.inc
+++ b/lib/asan/asan_flags.inc
@@ -63,8 +63,14 @@
     int, max_malloc_fill_size, 0x1000,  // By default, fill only the first 4K.
     "ASan allocator flag. max_malloc_fill_size is the maximal amount of "
     "bytes that will be filled with malloc_fill_byte on malloc.")
+ASAN_FLAG(
+    int, max_free_fill_size, 0,
+    "ASan allocator flag. max_free_fill_size is the maximal amount of "
+    "bytes that will be filled with free_fill_byte during free.")
 ASAN_FLAG(int, malloc_fill_byte, 0xbe,
           "Value used to fill the newly allocated memory.")
+ASAN_FLAG(int, free_fill_byte, 0x55,
+          "Value used to fill deallocated memory.")
 ASAN_FLAG(bool, allow_user_poisoning, true,
           "If set, user may manually mark memory regions as poisoned or "
           "unpoisoned.")
diff --git a/lib/asan/asan_mac.cc b/lib/asan/asan_mac.cc
index baf533a..38189a9 100644
--- a/lib/asan/asan_mac.cc
+++ b/lib/asan/asan_mac.cc
@@ -138,7 +138,8 @@
     t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr,
                            parent_tid, stack, /* detached */ true);
     t->Init();
-    asanThreadRegistry().StartThread(t->tid(), 0, 0);
+    asanThreadRegistry().StartThread(t->tid(), GetTid(),
+                                     /* workerthread */ true, 0);
     SetCurrentThread(t);
   }
 }
diff --git a/lib/asan/asan_report.cc b/lib/asan/asan_report.cc
index 3ad48fa..d1c3cda 100644
--- a/lib/asan/asan_report.cc
+++ b/lib/asan/asan_report.cc
@@ -88,7 +88,8 @@
   char *p;
   // This string is created by the compiler and has the following form:
   // "n alloc_1 alloc_2 ... alloc_n"
-  // where alloc_i looks like "offset size len ObjectName".
+  // where alloc_i looks like "offset size len ObjectName"
+  // or                       "offset size len ObjectName:line".
   uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
   if (n_objects == 0)
     return false;
@@ -101,7 +102,14 @@
       return false;
     }
     p++;
-    StackVarDescr var = {beg, size, p, len};
+    char *colon_pos = internal_strchr(p, ':');
+    uptr line = 0;
+    uptr name_len = len;
+    if (colon_pos != nullptr && colon_pos < p + len) {
+      name_len = colon_pos - p;
+      line = (uptr)internal_simple_strtoll(colon_pos + 1, nullptr, 10);
+    }
+    StackVarDescr var = {beg, size, p, name_len, line};
     vars->push_back(var);
     p += len;
   }
diff --git a/lib/asan/asan_report.h b/lib/asan/asan_report.h
index 5ebfda6..5a3533a 100644
--- a/lib/asan/asan_report.h
+++ b/lib/asan/asan_report.h
@@ -23,6 +23,7 @@
   uptr size;
   const char *name_pos;
   uptr name_len;
+  uptr line;
 };
 
 // Returns the number of globals close to the provided address and copies
diff --git a/lib/asan/asan_thread.cc b/lib/asan/asan_thread.cc
index 537b53d..2f9fa81 100644
--- a/lib/asan/asan_thread.cc
+++ b/lib/asan/asan_thread.cc
@@ -239,7 +239,8 @@
 thread_return_t AsanThread::ThreadStart(
     uptr os_id, atomic_uintptr_t *signal_thread_is_registered) {
   Init();
-  asanThreadRegistry().StartThread(tid(), os_id, nullptr);
+  asanThreadRegistry().StartThread(tid(), os_id, /*workerthread*/ false,
+                                   nullptr);
   if (signal_thread_is_registered)
     atomic_store(signal_thread_is_registered, 1, memory_order_release);
 
diff --git a/lib/builtins/CMakeLists.txt b/lib/builtins/CMakeLists.txt
index 3cf7861..8ba3a4e 100644
--- a/lib/builtins/CMakeLists.txt
+++ b/lib/builtins/CMakeLists.txt
@@ -132,6 +132,7 @@
   negvdi2.c
   negvsi2.c
   negvti2.c
+  os_version_check.c
   paritydi2.c
   paritysi2.c
   parityti2.c
diff --git a/lib/builtins/os_version_check.c b/lib/builtins/os_version_check.c
new file mode 100644
index 0000000..711ba60
--- /dev/null
+++ b/lib/builtins/os_version_check.c
@@ -0,0 +1,170 @@
+/* ===-- os_version_check.c - OS version checking  -------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file implements the function __isOSVersionAtLeast, used by
+ * Objective-C's @available
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifdef __APPLE__
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <dispatch/dispatch.h>
+#include <TargetConditionals.h>
+#include <dlfcn.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* These three variables hold the host's OS version. */
+static int32_t GlobalMajor, GlobalMinor, GlobalSubminor;
+static dispatch_once_t DispatchOnceCounter;
+
+/* Find and parse the SystemVersion.plist file. */
+static void parseSystemVersionPList(void *Unused) {
+  (void)Unused;
+  /* Load CoreFoundation dynamically */
+  const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull");
+  if (!NullAllocator)
+    return;
+  const CFAllocatorRef kCFAllocatorNull =
+      *(const CFAllocatorRef *)NullAllocator;
+  typeof(CFDataCreateWithBytesNoCopy) *CFDataCreateWithBytesNoCopyFunc =
+      (typeof(CFDataCreateWithBytesNoCopy) *)dlsym(
+          RTLD_DEFAULT, "CFDataCreateWithBytesNoCopy");
+  if (!CFDataCreateWithBytesNoCopyFunc)
+    return;
+  typeof(CFPropertyListCreateWithData) *CFPropertyListCreateWithDataFunc =
+      (typeof(CFPropertyListCreateWithData) *)dlsym(
+          RTLD_DEFAULT, "CFPropertyListCreateWithData");
+  /* CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it
+   * will be NULL on earlier OS versions. */
+  typeof(CFPropertyListCreateFromXMLData) *CFPropertyListCreateFromXMLDataFunc =
+      (typeof(CFPropertyListCreateFromXMLData) *)dlsym(
+          RTLD_DEFAULT, "CFPropertyListCreateFromXMLData");
+  /* CFPropertyListCreateFromXMLDataFunc is deprecated in macOS 10.10, so it
+   * might be NULL in future OS versions. */
+  if (!CFPropertyListCreateWithDataFunc && !CFPropertyListCreateFromXMLDataFunc)
+    return;
+  typeof(CFStringCreateWithCStringNoCopy) *CFStringCreateWithCStringNoCopyFunc =
+      (typeof(CFStringCreateWithCStringNoCopy) *)dlsym(
+          RTLD_DEFAULT, "CFStringCreateWithCStringNoCopy");
+  if (!CFStringCreateWithCStringNoCopyFunc)
+    return;
+  typeof(CFDictionaryGetValue) *CFDictionaryGetValueFunc =
+      (typeof(CFDictionaryGetValue) *)dlsym(RTLD_DEFAULT,
+                                            "CFDictionaryGetValue");
+  if (!CFDictionaryGetValueFunc)
+    return;
+  typeof(CFGetTypeID) *CFGetTypeIDFunc =
+      (typeof(CFGetTypeID) *)dlsym(RTLD_DEFAULT, "CFGetTypeID");
+  if (!CFGetTypeIDFunc)
+    return;
+  typeof(CFStringGetTypeID) *CFStringGetTypeIDFunc =
+      (typeof(CFStringGetTypeID) *)dlsym(RTLD_DEFAULT, "CFStringGetTypeID");
+  if (!CFStringGetTypeIDFunc)
+    return;
+  typeof(CFStringGetCString) *CFStringGetCStringFunc =
+      (typeof(CFStringGetCString) *)dlsym(RTLD_DEFAULT, "CFStringGetCString");
+  if (!CFStringGetCStringFunc)
+    return;
+  typeof(CFRelease) *CFReleaseFunc =
+      (typeof(CFRelease) *)dlsym(RTLD_DEFAULT, "CFRelease");
+  if (!CFReleaseFunc)
+    return;
+
+  char *PListPath = "/System/Library/CoreServices/SystemVersion.plist";
+
+#if TARGET_OS_SIMULATOR
+  char *PListPathPrefix = getenv("IPHONE_SIMULATOR_ROOT");
+  if (!PListPathPrefix)
+    return;
+  char FullPath[strlen(PListPathPrefix) + strlen(PListPath) + 1];
+  strcpy(FullPath, PListPathPrefix);
+  strcat(FullPath, PListPath);
+  PListPath = FullPath;
+#endif
+  FILE *PropertyList = fopen(PListPath, "r");
+  if (!PropertyList)
+    return;
+
+  /* Dynamically allocated stuff. */
+  CFDictionaryRef PListRef = NULL;
+  CFDataRef FileContentsRef = NULL;
+  UInt8 *PListBuf = NULL;
+
+  fseek(PropertyList, 0, SEEK_END);
+  long PListFileSize = ftell(PropertyList);
+  if (PListFileSize < 0)
+    goto Fail;
+  rewind(PropertyList);
+
+  PListBuf = malloc((size_t)PListFileSize);
+  if (!PListBuf)
+    goto Fail;
+
+  size_t NumRead = fread(PListBuf, 1, (size_t)PListFileSize, PropertyList);
+  if (NumRead != (size_t)PListFileSize)
+    goto Fail;
+
+  /* Get the file buffer into CF's format. We pass in a null allocator here *
+   * because we free PListBuf ourselves */
+  FileContentsRef = (*CFDataCreateWithBytesNoCopyFunc)(
+      NULL, PListBuf, (CFIndex)NumRead, kCFAllocatorNull);
+  if (!FileContentsRef)
+    goto Fail;
+
+  if (CFPropertyListCreateWithDataFunc)
+    PListRef = (*CFPropertyListCreateWithDataFunc)(
+        NULL, FileContentsRef, kCFPropertyListImmutable, NULL, NULL);
+  else
+    PListRef = (*CFPropertyListCreateFromXMLDataFunc)(
+        NULL, FileContentsRef, kCFPropertyListImmutable, NULL);
+  if (!PListRef)
+    goto Fail;
+
+  CFStringRef ProductVersion = (*CFStringCreateWithCStringNoCopyFunc)(
+      NULL, "ProductVersion", kCFStringEncodingASCII, kCFAllocatorNull);
+  if (!ProductVersion)
+    goto Fail;
+  CFTypeRef OpaqueValue = (*CFDictionaryGetValueFunc)(PListRef, ProductVersion);
+  (*CFReleaseFunc)(ProductVersion);
+  if (!OpaqueValue ||
+      (*CFGetTypeIDFunc)(OpaqueValue) != (*CFStringGetTypeIDFunc)())
+    goto Fail;
+
+  char VersionStr[32];
+  if (!(*CFStringGetCStringFunc)((CFStringRef)OpaqueValue, VersionStr,
+                                 sizeof(VersionStr), kCFStringEncodingUTF8))
+    goto Fail;
+  sscanf(VersionStr, "%d.%d.%d", &GlobalMajor, &GlobalMinor, &GlobalSubminor);
+
+Fail:
+  if (PListRef)
+    (*CFReleaseFunc)(PListRef);
+  if (FileContentsRef)
+    (*CFReleaseFunc)(FileContentsRef);
+  free(PListBuf);
+  fclose(PropertyList);
+}
+
+int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) {
+  /* Populate the global version variables, if they haven't already. */
+  dispatch_once_f(&DispatchOnceCounter, NULL, parseSystemVersionPList);
+
+  if (Major < GlobalMajor) return 1;
+  if (Major > GlobalMajor) return 0;
+  if (Minor < GlobalMinor) return 1;
+  if (Minor > GlobalMinor) return 0;
+  return Subminor <= GlobalSubminor;
+}
+
+#endif
diff --git a/lib/lsan/lsan_thread.cc b/lib/lsan/lsan_thread.cc
index 5dff4f7..f82a04a 100644
--- a/lib/lsan/lsan_thread.cc
+++ b/lib/lsan/lsan_thread.cc
@@ -97,7 +97,7 @@
   args.tls_end = args.tls_begin + tls_size;
   GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
   args.dtls = DTLS_Get();
-  thread_registry->StartThread(tid, os_id, &args);
+  thread_registry->StartThread(tid, os_id, /*workerthread*/ false, &args);
 }
 
 void ThreadFinish() {
diff --git a/lib/profile/InstrProfilingFile.c b/lib/profile/InstrProfilingFile.c
index f82080c..ba717ee 100644
--- a/lib/profile/InstrProfilingFile.c
+++ b/lib/profile/InstrProfilingFile.c
@@ -14,6 +14,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <signal.h>
 #ifdef _MSC_VER
 /* For _alloca. */
 #include <malloc.h>
@@ -59,6 +60,7 @@
 }
 
 #define MAX_PID_SIZE 16
+#define MAX_SIGNAL_HANDLERS 16
 /* Data structure holding the result of parsed filename pattern. */
 typedef struct lprofFilename {
   /* File name string possibly with %p or %h specifiers. */
@@ -79,11 +81,13 @@
    * 2 profile data files. %1m is equivalent to %m. Also %m specifier
    * can only appear once at the end of the name pattern. */
   unsigned MergePoolSize;
+  char ExitOnSignals[MAX_SIGNAL_HANDLERS];
+  unsigned NumExitSignals;
   ProfileNameSpecifier PNS;
 } lprofFilename;
 
-COMPILER_RT_WEAK lprofFilename lprofCurFilename = {0, 0, 0, {0}, {0},
-                                                   0, 0, 0, PNS_unknown};
+COMPILER_RT_WEAK lprofFilename lprofCurFilename = {
+    0, 0, 0, {0}, {0}, 0, 0, 0, {0}, 0, PNS_unknown};
 
 int getpid(void);
 static int getCurFilenameLength();
@@ -172,6 +176,16 @@
   return 0;
 }
 
+/* Create the directory holding the file, if needed. */
+static void createProfileDir(const char *Filename) {
+  size_t Length = strlen(Filename);
+  if (lprofFindFirstDirSeparator(Filename)) {
+    char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1);
+    strncpy(Copy, Filename, Length + 1);
+    __llvm_profile_recursive_mkdir(Copy);
+  }
+}
+
 /* Open the profile data for merging. It opens the file in r+b mode with
  * file locking.  If the file has content which is compatible with the
  * current process, it also reads in the profile data in the file and merge
@@ -184,6 +198,7 @@
   FILE *ProfileFile;
   int rc;
 
+  createProfileDir(ProfileFileName);
   ProfileFile = lprofOpenFileEx(ProfileFileName);
   if (!ProfileFile)
     return NULL;
@@ -233,18 +248,13 @@
   if (!Filename)
     return;
 
-  /* Create the directory holding the file, if needed. */
-  if (lprofFindFirstDirSeparator(Filename)) {
-    char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1);
-    strncpy(Copy, Filename, Length + 1);
-    __llvm_profile_recursive_mkdir(Copy);
-  }
-
   /* By pass file truncation to allow online raw profile
    * merging. */
   if (lprofCurFilename.MergePoolSize)
     return;
 
+  createProfileDir(Filename);
+
   /* Truncate the file.  Later we'll reopen and append. */
   File = fopen(Filename, "w");
   if (!File)
@@ -252,6 +262,19 @@
   fclose(File);
 }
 
+static void exitSignalHandler(int sig) {
+  (void)sig;
+  exit(0);
+}
+
+static void installExitSignalHandlers(void) {
+  unsigned I;
+  for (I = 0; I < lprofCurFilename.NumExitSignals; ++I) {
+    lprofInstallSignalHandler(lprofCurFilename.ExitOnSignals[I],
+                              exitSignalHandler);
+  }
+}
+
 static const char *DefaultProfileName = "default.profraw";
 static void resetFilenameToDefault(void) {
   if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) {
@@ -262,14 +285,25 @@
   lprofCurFilename.PNS = PNS_default;
 }
 
+static int isDigit(char C) { return C >= '0' && C <= '9'; }
+
+static int isNonZeroDigit(char C) { return C >= '1' && C <= '9'; }
+
 static int containsMergeSpecifier(const char *FilenamePat, int I) {
   return (FilenamePat[I] == 'm' ||
-          (FilenamePat[I] >= '1' && FilenamePat[I] <= '9' &&
+          (isNonZeroDigit(FilenamePat[I]) &&
            /* If FilenamePat[I] is not '\0', the next byte is guaranteed
             * to be in-bound as the string is null terminated. */
            FilenamePat[I + 1] == 'm'));
 }
 
+static int containsExitOnSignalSpecifier(const char *FilenamePat, int I) {
+  if (!isNonZeroDigit(FilenamePat[I]))
+    return 0;
+  return (FilenamePat[I + 1] == 'x') ||
+         (isDigit(FilenamePat[I + 1]) && FilenamePat[I + 2] == 'x');
+}
+
 /* Parses the pattern string \p FilenamePat and stores the result to
  * lprofcurFilename structure. */
 static int parseFilenamePattern(const char *FilenamePat,
@@ -278,6 +312,7 @@
   char *PidChars = &lprofCurFilename.PidChars[0];
   char *Hostname = &lprofCurFilename.Hostname[0];
   int MergingEnabled = 0;
+  char SignalNo;
 
   /* Clean up cached prefix.  */
   if (lprofCurFilename.ProfilePathPrefix)
@@ -327,6 +362,22 @@
           lprofCurFilename.MergePoolSize = FilenamePat[I] - '0';
           I++; /* advance to 'm' */
         }
+      } else if (containsExitOnSignalSpecifier(FilenamePat, I)) {
+        if (lprofCurFilename.NumExitSignals == MAX_SIGNAL_HANDLERS) {
+          PROF_WARN("%%x specifier has been specified too many times in %s.\n",
+                    FilenamePat);
+          return -1;
+        }
+        /* Grab the signal number. */
+        SignalNo = FilenamePat[I] - '0';
+        I++; /* advance to either another digit, or 'x' */
+        if (FilenamePat[I] != 'x') {
+          SignalNo = (SignalNo * 10) + (FilenamePat[I] - '0');
+          I++; /* advance to 'x' */
+        }
+        lprofCurFilename.ExitOnSignals[lprofCurFilename.NumExitSignals] =
+            SignalNo;
+        ++lprofCurFilename.NumExitSignals;
       }
     }
 
@@ -370,6 +421,7 @@
   }
 
   truncateCurrentFile();
+  installExitSignalHandlers();
 }
 
 /* Return buffer length that is required to store the current profile
@@ -378,11 +430,12 @@
 #define SIGLEN 24
 static int getCurFilenameLength() {
   int Len;
+  unsigned I;
   if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
     return 0;
 
   if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
-        lprofCurFilename.MergePoolSize))
+        lprofCurFilename.MergePoolSize || lprofCurFilename.NumExitSignals))
     return strlen(lprofCurFilename.FilenamePat);
 
   Len = strlen(lprofCurFilename.FilenamePat) +
@@ -390,6 +443,11 @@
         lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2);
   if (lprofCurFilename.MergePoolSize)
     Len += SIGLEN;
+  for (I = 0; I < lprofCurFilename.NumExitSignals; ++I) {
+    Len -= 3; /* Drop the '%', signal number, and the 'x'. */
+    if (lprofCurFilename.ExitOnSignals[I] >= 10)
+      --Len; /* Drop the second digit of the signal number. */
+  }
   return Len;
 }
 
@@ -405,7 +463,7 @@
     return 0;
 
   if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
-        lprofCurFilename.MergePoolSize))
+        lprofCurFilename.MergePoolSize || lprofCurFilename.NumExitSignals))
     return lprofCurFilename.FilenamePat;
 
   PidLength = strlen(lprofCurFilename.PidChars);
@@ -431,6 +489,9 @@
         J += S;
         if (FilenamePat[I] != 'm')
           I++;
+      } else if (containsExitOnSignalSpecifier(FilenamePat, I)) {
+        while (FilenamePat[I] != 'x')
+          ++I;
       }
       /* Drop any unknown substitutions. */
     } else
@@ -524,6 +585,7 @@
   int rc, Length;
   const char *Filename;
   char *FilenameBuf;
+  int PDeathSig = 0;
 
   if (lprofProfileDumped()) {
     PROF_NOTE("Profile data not written to file: %s.\n", 
@@ -550,10 +612,18 @@
     return -1;
   }
 
+  // Temporarily suspend getting SIGKILL when the parent exits.
+  PDeathSig = lprofSuspendSigKill();
+
   /* Write profile data to the file. */
   rc = writeFile(Filename);
   if (rc)
     PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
+
+  // Restore SIGKILL.
+  if (PDeathSig == 1)
+    lprofRestoreSigKill();
+
   return rc;
 }
 
diff --git a/lib/profile/InstrProfilingUtil.c b/lib/profile/InstrProfilingUtil.c
index 321c719..9b96309 100644
--- a/lib/profile/InstrProfilingUtil.c
+++ b/lib/profile/InstrProfilingUtil.c
@@ -26,9 +26,15 @@
 #include <sys/utsname.h>
 #endif
 
+#include <signal.h>
 #include <stdlib.h>
 #include <string.h>
 
+#if defined(__linux__)
+#include <signal.h>
+#include <sys/prctl.h>
+#endif
+
 COMPILER_RT_VISIBILITY
 void __llvm_profile_recursive_mkdir(char *path) {
   int i;
@@ -219,3 +225,42 @@
 #endif
   return Sep;
 }
+
+COMPILER_RT_VISIBILITY int lprofSuspendSigKill() {
+#if defined(__linux__)
+  int PDeachSig = 0;
+  /* Temporarily suspend getting SIGKILL upon exit of the parent process. */
+  if (prctl(PR_GET_PDEATHSIG, &PDeachSig) == 0 && PDeachSig == SIGKILL) {
+    fprintf(stderr, "set\n");
+    prctl(PR_SET_PDEATHSIG, 0);
+  }
+  return (PDeachSig == SIGKILL);
+#else
+  return 0;
+#endif
+}
+
+COMPILER_RT_VISIBILITY void lprofRestoreSigKill() {
+#if defined(__linux__)
+  fprintf(stderr, "restore \n");
+  prctl(PR_SET_PDEATHSIG, SIGKILL);
+#endif
+}
+
+COMPILER_RT_VISIBILITY void lprofInstallSignalHandler(int sig,
+                                                      void (*handler)(int)) {
+#ifdef _WIN32
+  void (*err)(int) = signal(sig, handler);
+  if (err == SIG_ERR)
+    PROF_WARN("Unable to install an exit signal handler for %d (errno = %d).\n",
+              sig, errno);
+#else
+  struct sigaction sigact;
+  memset(&sigact, 0, sizeof(sigact));
+  sigact.sa_handler = handler;
+  int err = sigaction(sig, &sigact, NULL);
+  if (err)
+    PROF_WARN("Unable to install an exit signal handler for %d (errno = %d).\n",
+              sig, err);
+#endif
+}
diff --git a/lib/profile/InstrProfilingUtil.h b/lib/profile/InstrProfilingUtil.h
index a80fde7..f4b5b7d 100644
--- a/lib/profile/InstrProfilingUtil.h
+++ b/lib/profile/InstrProfilingUtil.h
@@ -51,4 +51,14 @@
 unsigned lprofBoolCmpXchg(void **Ptr, void *OldV, void *NewV);
 void *lprofPtrFetchAdd(void **Mem, long ByteIncr);
 
+/* Temporarily suspend SIGKILL. Return value of 1 means a restore is needed.
+ * Other return values mean no restore is needed.
+ */
+int lprofSuspendSigKill();
+
+/* Restore previously suspended SIGKILL. */
+void lprofRestoreSigKill();
+
+void lprofInstallSignalHandler(int sig, void(*handler)(int));
+
 #endif /* PROFILE_INSTRPROFILINGUTIL_H */
diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc
index 9824a519..5f492fe 100644
--- a/lib/sanitizer_common/sanitizer_common.cc
+++ b/lib/sanitizer_common/sanitizer_common.cc
@@ -199,23 +199,24 @@
   return module;
 }
 
-void ReportErrorSummary(const char *error_message) {
+void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {
   if (!common_flags()->print_summary)
     return;
   InternalScopedString buff(kMaxSummaryLength);
-  buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message);
+  buff.append("SUMMARY: %s: %s",
+              alt_tool_name ? alt_tool_name : SanitizerToolName, error_message);
   __sanitizer_report_error_summary(buff.data());
 }
 
 #if !SANITIZER_GO
-void ReportErrorSummary(const char *error_type, const AddressInfo &info) {
-  if (!common_flags()->print_summary)
-    return;
+void ReportErrorSummary(const char *error_type, const AddressInfo &info,
+                        const char *alt_tool_name) {
+  if (!common_flags()->print_summary) return;
   InternalScopedString buff(kMaxSummaryLength);
   buff.append("%s ", error_type);
   RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style,
               common_flags()->strip_path_prefix);
-  ReportErrorSummary(buff.data());
+  ReportErrorSummary(buff.data(), alt_tool_name);
 }
 #endif
 
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index 2dabb50..e6d73e7 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -391,12 +391,16 @@
 // Construct a one-line string:
 //   SUMMARY: SanitizerToolName: error_message
 // and pass it to __sanitizer_report_error_summary.
-void ReportErrorSummary(const char *error_message);
+// If alt_tool_name is provided, it's used in place of SanitizerToolName.
+void ReportErrorSummary(const char *error_message,
+                        const char *alt_tool_name = nullptr);
 // Same as above, but construct error_message as:
 //   error_type file:line[:column][ function]
-void ReportErrorSummary(const char *error_type, const AddressInfo &info);
+void ReportErrorSummary(const char *error_type, const AddressInfo &info,
+                        const char *alt_tool_name = nullptr);
 // Same as above, but obtains AddressInfo by symbolizing top stack trace frame.
-void ReportErrorSummary(const char *error_type, const StackTrace *trace);
+void ReportErrorSummary(const char *error_type, const StackTrace *trace,
+                        const char *alt_tool_name = nullptr);
 
 // Math
 #if SANITIZER_WINDOWS && !defined(__clang__) && !defined(__GNUC__)
diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc
index 49ca961..3961aaf 100644
--- a/lib/sanitizer_common/sanitizer_common_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc
@@ -47,7 +47,8 @@
   sandboxing_callback = f;
 }
 
-void ReportErrorSummary(const char *error_type, const StackTrace *stack) {
+void ReportErrorSummary(const char *error_type, const StackTrace *stack,
+                        const char *alt_tool_name) {
 #if !SANITIZER_GO
   if (!common_flags()->print_summary)
     return;
@@ -59,7 +60,7 @@
   // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
   uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
   SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
-  ReportErrorSummary(error_type, frame->info);
+  ReportErrorSummary(error_type, frame->info, alt_tool_name);
   frame->ClearAll();
 #endif
 }
diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
index 5945ebb..a325b18 100644
--- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
@@ -171,7 +171,11 @@
   //   - not thread-safe;
   //   - does not support long traces;
   //   - not tuned for performance.
-  static const uptr kTrEventArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 30);
+  // Windows doesn't do overcommit (committed virtual memory costs swap), so
+  // programs can't reliably map such large amounts of virtual memory.
+  // TODO(etienneb): Find a way to support coverage of larger executable
+static const uptr kTrEventArrayMaxSize =
+    (SANITIZER_WORDSIZE == 32 || SANITIZER_WINDOWS) ? 1 << 22 : 1 << 30;
   u32 *tr_event_array;
   uptr tr_event_array_size;
   u32 *tr_event_pointer;
diff --git a/lib/sanitizer_common/sanitizer_thread_registry.cc b/lib/sanitizer_common/sanitizer_thread_registry.cc
index c2b75e6..c5b2e09 100644
--- a/lib/sanitizer_common/sanitizer_thread_registry.cc
+++ b/lib/sanitizer_common/sanitizer_thread_registry.cc
@@ -19,7 +19,7 @@
 ThreadContextBase::ThreadContextBase(u32 tid)
     : tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0),
       status(ThreadStatusInvalid),
-      detached(false), parent_tid(0), next(0) {
+      detached(false), workerthread(false), parent_tid(0), next(0) {
   name[0] = '\0';
 }
 
@@ -59,9 +59,10 @@
   OnFinished();
 }
 
-void ThreadContextBase::SetStarted(uptr _os_id, void *arg) {
+void ThreadContextBase::SetStarted(uptr _os_id, bool _workerthread, void *arg) {
   status = ThreadStatusRunning;
   os_id = _os_id;
+  workerthread = _workerthread;
   OnStarted(arg);
 }
 
@@ -266,14 +267,15 @@
   }
 }
 
-void ThreadRegistry::StartThread(u32 tid, uptr os_id, void *arg) {
+void ThreadRegistry::StartThread(u32 tid, uptr os_id, bool workerthread,
+                                 void *arg) {
   BlockingMutexLock l(&mtx_);
   running_threads_++;
   CHECK_LT(tid, n_contexts_);
   ThreadContextBase *tctx = threads_[tid];
   CHECK_NE(tctx, 0);
   CHECK_EQ(ThreadStatusCreated, tctx->status);
-  tctx->SetStarted(os_id, arg);
+  tctx->SetStarted(os_id, workerthread, arg);
 }
 
 void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) {
diff --git a/lib/sanitizer_common/sanitizer_thread_registry.h b/lib/sanitizer_common/sanitizer_thread_registry.h
index a27bbb3..17b1d5d 100644
--- a/lib/sanitizer_common/sanitizer_thread_registry.h
+++ b/lib/sanitizer_common/sanitizer_thread_registry.h
@@ -45,6 +45,7 @@
 
   ThreadStatus status;
   bool detached;
+  bool workerthread;
 
   u32 parent_tid;
   ThreadContextBase *next;  // For storing thread contexts in a list.
@@ -54,7 +55,7 @@
   void SetDead();
   void SetJoined(void *arg);
   void SetFinished();
-  void SetStarted(uptr _os_id, void *arg);
+  void SetStarted(uptr _os_id, bool _workerthread, void *arg);
   void SetCreated(uptr _user_id, u64 _unique_id, bool _detached,
                   u32 _parent_tid, void *arg);
   void Reset();
@@ -115,7 +116,7 @@
   void DetachThread(u32 tid, void *arg);
   void JoinThread(u32 tid, void *arg);
   void FinishThread(u32 tid);
-  void StartThread(u32 tid, uptr os_id, void *arg);
+  void StartThread(u32 tid, uptr os_id, bool workerthread, void *arg);
 
  private:
   const ThreadContextFactory context_factory_;
diff --git a/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc b/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
index 1132bfd..f8b8c12 100644
--- a/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_thread_registry_test.cc
@@ -67,7 +67,7 @@
 static void TestRegistry(ThreadRegistry *registry, bool has_quarantine) {
   // Create and start a main thread.
   EXPECT_EQ(0U, registry->CreateThread(get_uid(0), true, -1, 0));
-  registry->StartThread(0, 0, 0);
+  registry->StartThread(0, 0, false, 0);
   // Create a bunch of threads.
   for (u32 i = 1; i <= 10; i++) {
     EXPECT_EQ(i, registry->CreateThread(get_uid(i), is_detached(i), 0, 0));
@@ -75,7 +75,7 @@
   CheckThreadQuantity(registry, 11, 1, 11);
   // Start some of them.
   for (u32 i = 1; i <= 5; i++) {
-    registry->StartThread(i, 0, 0);
+    registry->StartThread(i, 0, false, 0);
   }
   CheckThreadQuantity(registry, 11, 6, 11);
   // Finish, create and start more threads.
@@ -85,7 +85,7 @@
       registry->JoinThread(i, 0);
   }
   for (u32 i = 6; i <= 10; i++) {
-    registry->StartThread(i, 0, 0);
+    registry->StartThread(i, 0, false, 0);
   }
   std::vector<u32> new_tids;
   for (u32 i = 11; i <= 15; i++) {
@@ -112,7 +112,7 @@
   }
   for (u32 i = 0; i < new_tids.size(); i++) {
     u32 tid = new_tids[i];
-    registry->StartThread(tid, 0, 0);
+    registry->StartThread(tid, 0, false, 0);
     registry->DetachThread(tid, 0);
     registry->FinishThread(tid);
   }
@@ -189,7 +189,7 @@
     tids.push_back(
         args->registry->CreateThread(0, false, 0, (void*)args->shard));
   for (int i = 0; i < kThreadsPerShard; i++)
-    args->registry->StartThread(tids[i], 0, (void*)args->shard);
+    args->registry->StartThread(tids[i], 0, false, (void*)args->shard);
   for (int i = 0; i < kThreadsPerShard; i++)
     args->registry->FinishThread(tids[i]);
   for (int i = 0; i < kThreadsPerShard; i++)
@@ -200,7 +200,7 @@
 static void ThreadedTestRegistry(ThreadRegistry *registry) {
   // Create and start a main thread.
   EXPECT_EQ(0U, registry->CreateThread(0, true, -1, 0));
-  registry->StartThread(0, 0, 0);
+  registry->StartThread(0, 0, false, 0);
   pthread_t threads[kNumShards];
   RunThreadArgs args[kNumShards];
   for (int i = 0; i < kNumShards; i++) {
diff --git a/lib/tsan/CMakeLists.txt b/lib/tsan/CMakeLists.txt
index d519545..195ecb5 100644
--- a/lib/tsan/CMakeLists.txt
+++ b/lib/tsan/CMakeLists.txt
@@ -25,6 +25,7 @@
 set(TSAN_SOURCES
   rtl/tsan_clock.cc
   rtl/tsan_debugging.cc
+  rtl/tsan_external.cc
   rtl/tsan_fd.cc
   rtl/tsan_flags.cc
   rtl/tsan_ignoreset.cc
diff --git a/lib/tsan/go/tsan_go.cc b/lib/tsan/go/tsan_go.cc
index 34625c8..7fb4eb2 100644
--- a/lib/tsan/go/tsan_go.cc
+++ b/lib/tsan/go/tsan_go.cc
@@ -214,7 +214,7 @@
   ThreadState *thr = AllocGoroutine();
   *pthr = thr;
   int goid = ThreadCreate(parent, (uptr)pc, 0, true);
-  ThreadStart(thr, goid, 0);
+  ThreadStart(thr, goid, 0, /*workerthread*/ false);
 }
 
 void __tsan_go_end(ThreadState *thr) {
diff --git a/lib/tsan/rtl/tsan_debugging.cc b/lib/tsan/rtl/tsan_debugging.cc
index d9fb686..06154bc 100644
--- a/lib/tsan/rtl/tsan_debugging.cc
+++ b/lib/tsan/rtl/tsan_debugging.cc
@@ -24,6 +24,7 @@
   if (typ == ReportTypeVptrRace) return "data-race-vptr";
   if (typ == ReportTypeUseAfterFree) return "heap-use-after-free";
   if (typ == ReportTypeVptrUseAfterFree) return "heap-use-after-free-vptr";
+  if (typ == ReportTypeExternalRace) return "external-race";
   if (typ == ReportTypeThreadLeak) return "thread-leak";
   if (typ == ReportTypeMutexDestroyLocked) return "locked-mutex-destroy";
   if (typ == ReportTypeMutexDoubleLock) return "mutex-double-lock";
@@ -127,6 +128,16 @@
 }
 
 SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_loc_object_type(void *report, uptr idx,
+                                      const char **object_type) {
+  const ReportDesc *rep = (ReportDesc *)report;
+  CHECK_LT(idx, rep->locs.Size());
+  ReportLocation *loc = rep->locs[idx];
+  *object_type = GetObjectTypeFromTag(loc->external_tag);
+  return 1;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
 int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr,
                             int *destroyed, void **trace, uptr trace_size) {
   const ReportDesc *rep = (ReportDesc *)report;
diff --git a/lib/tsan/rtl/tsan_defs.h b/lib/tsan/rtl/tsan_defs.h
index 55580a5..8a0381e 100644
--- a/lib/tsan/rtl/tsan_defs.h
+++ b/lib/tsan/rtl/tsan_defs.h
@@ -149,7 +149,8 @@
 
 // Descriptor of user's memory block.
 struct MBlock {
-  u64  siz;
+  u64  siz : 48;
+  u64  tag : 16;
   u32  stk;
   u16  tid;
 };
diff --git a/lib/tsan/rtl/tsan_external.cc b/lib/tsan/rtl/tsan_external.cc
new file mode 100644
index 0000000..dc8ec62
--- /dev/null
+++ b/lib/tsan/rtl/tsan_external.cc
@@ -0,0 +1,78 @@
+//===-- tsan_external.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 (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_rtl.h"
+
+namespace __tsan {
+
+#define CALLERPC ((uptr)__builtin_return_address(0))
+
+const uptr kMaxTag = 128;  // Limited to 65,536, since MBlock only stores tags
+                           // as 16-bit values, see tsan_defs.h.
+
+const char *registered_tags[kMaxTag];
+static atomic_uint32_t used_tags{1};  // Tag 0 means "no tag". NOLINT
+
+const char *GetObjectTypeFromTag(uptr tag) {
+  if (tag == 0) return nullptr;
+  // Invalid/corrupted tag?  Better return NULL and let the caller deal with it.
+  if (tag >= atomic_load(&used_tags, memory_order_relaxed)) return nullptr;
+  return registered_tags[tag];
+}
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__tsan_external_register_tag(const char *object_type) {
+  uptr new_tag = atomic_fetch_add(&used_tags, 1, memory_order_relaxed);
+  CHECK_LT(new_tag, kMaxTag);
+  registered_tags[new_tag] = internal_strdup(object_type);
+  return (void *)new_tag;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_external_assign_tag(void *addr, void *tag) {
+  CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed));
+  Allocator *a = allocator();
+  MBlock *b = nullptr;
+  if (a->PointerIsMine((void *)addr)) {
+    void *block_begin = a->GetBlockBegin((void *)addr);
+    if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin);
+  }
+  if (b) {
+    b->tag = (uptr)tag;
+  }
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_external_read(void *addr, void *caller_pc, void *tag) {
+  CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed));
+  ThreadState *thr = cur_thread();
+  thr->external_tag = (uptr)tag;
+  FuncEntry(thr, (uptr)caller_pc);
+  MemoryRead(thr, CALLERPC, (uptr)addr, kSizeLog8);
+  FuncExit(thr);
+  thr->external_tag = 0;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_external_write(void *addr, void *caller_pc, void *tag) {
+  CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed));
+  ThreadState *thr = cur_thread();
+  thr->external_tag = (uptr)tag;
+  FuncEntry(thr, (uptr)caller_pc);
+  MemoryWrite(thr, CALLERPC, (uptr)addr, kSizeLog8);
+  FuncExit(thr);
+  thr->external_tag = 0;
+}
+}  // extern "C"
+
+}  // namespace __tsan
diff --git a/lib/tsan/rtl/tsan_flags.inc b/lib/tsan/rtl/tsan_flags.inc
index a48545c..e9b3e35 100644
--- a/lib/tsan/rtl/tsan_flags.inc
+++ b/lib/tsan/rtl/tsan_flags.inc
@@ -79,7 +79,7 @@
 TSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
 TSAN_FLAG(bool, ignore_interceptors_accesses, false,
           "Ignore reads and writes from all interceptors.")
-TSAN_FLAG(bool, ignore_noninstrumented_modules, false,
+TSAN_FLAG(bool, ignore_noninstrumented_modules, SANITIZER_MAC ? true : false,
           "Interceptors should only detect races when called from instrumented "
           "modules.")
 TSAN_FLAG(bool, shared_ptr_interceptor, true,
diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc
index 898f32d..9bf1b28 100644
--- a/lib/tsan/rtl/tsan_interceptors.cc
+++ b/lib/tsan/rtl/tsan_interceptors.cc
@@ -881,7 +881,7 @@
       internal_sched_yield();
     Processor *proc = ProcCreate();
     ProcWire(proc, thr);
-    ThreadStart(thr, tid, GetTid());
+    ThreadStart(thr, tid, GetTid(), /*workerthread*/ false);
     atomic_store(&p->tid, 0, memory_order_release);
   }
   void *res = callback(param);
diff --git a/lib/tsan/rtl/tsan_interceptors_mac.cc b/lib/tsan/rtl/tsan_interceptors_mac.cc
index fc5eb04..f6bf8a0 100644
--- a/lib/tsan/rtl/tsan_interceptors_mac.cc
+++ b/lib/tsan/rtl/tsan_interceptors_mac.cc
@@ -281,6 +281,12 @@
   (connection, message, replyq, new_handler);
 }
 
+TSAN_INTERCEPTOR(void, xpc_connection_cancel, xpc_connection_t connection) {
+  SCOPED_TSAN_INTERCEPTOR(xpc_connection_cancel, connection);
+  Release(thr, pc, (uptr)connection);
+  REAL(xpc_connection_cancel)(connection);
+}
+
 // On macOS, libc++ is always linked dynamically, so intercepting works the
 // usual way.
 #define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR
diff --git a/lib/tsan/rtl/tsan_interface.h b/lib/tsan/rtl/tsan_interface.h
index 4e342a5..496a871 100644
--- a/lib/tsan/rtl/tsan_interface.h
+++ b/lib/tsan/rtl/tsan_interface.h
@@ -79,6 +79,15 @@
 SANITIZER_INTERFACE_ATTRIBUTE void __tsan_ignore_thread_end();
 
 SANITIZER_INTERFACE_ATTRIBUTE
+void *__tsan_external_register_tag(const char *object_type);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_external_assign_tag(void *addr, void *tag);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_external_read(void *addr, void *caller_pc, void *tag);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_external_write(void *addr, void *caller_pc, void *tag);
+
+SANITIZER_INTERFACE_ATTRIBUTE
 void __tsan_read_range(void *addr, unsigned long size);  // NOLINT
 SANITIZER_INTERFACE_ATTRIBUTE
 void __tsan_write_range(void *addr, unsigned long size);  // NOLINT
@@ -123,6 +132,10 @@
                           int *fd, int *suppressable, void **trace,
                           uptr trace_size);
 
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_loc_object_type(void *report, uptr idx,
+                                      const char **object_type);
+
 // Returns information about mutexes included in the report.
 SANITIZER_INTERFACE_ATTRIBUTE
 int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr,
diff --git a/lib/tsan/rtl/tsan_libdispatch_mac.cc b/lib/tsan/rtl/tsan_libdispatch_mac.cc
index d8c689e..8c759a3 100644
--- a/lib/tsan/rtl/tsan_libdispatch_mac.cc
+++ b/lib/tsan/rtl/tsan_libdispatch_mac.cc
@@ -93,14 +93,15 @@
   new_context->free_context_in_callback = true;
   new_context->submitted_synchronously = false;
   new_context->is_barrier_block = false;
+  new_context->non_queue_sync_object = 0;
   return new_context;
 }
 
-#define GET_QUEUE_SYNC_VARS(context, q)                      \
-  bool is_queue_serial = q && IsQueueSerial(q);              \
-  uptr sync_ptr = (uptr)q ?: context->non_queue_sync_object; \
-  uptr serial_sync = (uptr)sync_ptr;                         \
-  uptr concurrent_sync = ((uptr)sync_ptr) + sizeof(uptr);    \
+#define GET_QUEUE_SYNC_VARS(context, q)                                  \
+  bool is_queue_serial = q && IsQueueSerial(q);                          \
+  uptr sync_ptr = (uptr)q ?: context->non_queue_sync_object;             \
+  uptr serial_sync = (uptr)sync_ptr;                                     \
+  uptr concurrent_sync = sync_ptr ? ((uptr)sync_ptr) + sizeof(uptr) : 0; \
   bool serial_task = context->is_barrier_block || is_queue_serial
 
 static void dispatch_sync_pre_execute(ThreadState *thr, uptr pc,
@@ -111,8 +112,8 @@
   dispatch_queue_t q = context->queue;
   do {
     GET_QUEUE_SYNC_VARS(context, q);
-    Acquire(thr, pc, serial_sync);
-    if (serial_task) Acquire(thr, pc, concurrent_sync);
+    if (serial_sync) Acquire(thr, pc, serial_sync);
+    if (serial_task && concurrent_sync) Acquire(thr, pc, concurrent_sync);
 
     if (q) q = GetTargetQueueFromQueue(q);
   } while (q);
@@ -126,7 +127,8 @@
   dispatch_queue_t q = context->queue;
   do {
     GET_QUEUE_SYNC_VARS(context, q);
-    Release(thr, pc, serial_task ? serial_sync : concurrent_sync);
+    if (serial_task && serial_sync) Release(thr, pc, serial_sync);
+    if (!serial_task && concurrent_sync) Release(thr, pc, concurrent_sync);
 
     if (q) q = GetTargetQueueFromQueue(q);
   } while (q);
diff --git a/lib/tsan/rtl/tsan_platform_mac.cc b/lib/tsan/rtl/tsan_platform_mac.cc
index 25dd241..b8d3d55 100644
--- a/lib/tsan/rtl/tsan_platform_mac.cc
+++ b/lib/tsan/rtl/tsan_platform_mac.cc
@@ -207,7 +207,7 @@
       ThreadState *parent_thread_state = nullptr;  // No parent.
       int tid = ThreadCreate(parent_thread_state, 0, (uptr)thread, true);
       CHECK_NE(tid, 0);
-      ThreadStart(thr, tid, GetTid());
+      ThreadStart(thr, tid, GetTid(), /*workerthread*/ true);
     }
   } else if (event == PTHREAD_INTROSPECTION_THREAD_TERMINATE) {
     if (thread == pthread_self()) {
diff --git a/lib/tsan/rtl/tsan_report.cc b/lib/tsan/rtl/tsan_report.cc
index 07fd412..7de0084 100644
--- a/lib/tsan/rtl/tsan_report.cc
+++ b/lib/tsan/rtl/tsan_report.cc
@@ -90,6 +90,8 @@
     return "heap-use-after-free";
   if (typ == ReportTypeVptrUseAfterFree)
     return "heap-use-after-free (virtual call vs free)";
+  if (typ == ReportTypeExternalRace)
+    return "race on a library object";
   if (typ == ReportTypeThreadLeak)
     return "thread leak";
   if (typ == ReportTypeMutexDestroyLocked)
@@ -152,14 +154,25 @@
                 : (write ? "Previous write" : "Previous read"));
 }
 
+static const char *ExternalMopDesc(bool first, bool write) {
+  return first ? (write ? "Mutating" : "Read-only")
+               : (write ? "Previous mutating" : "Previous read-only");
+}
+
 static void PrintMop(const ReportMop *mop, bool first) {
   Decorator d;
   char thrbuf[kThreadBufSize];
   Printf("%s", d.Access());
-  Printf("  %s of size %d at %p by %s",
-      MopDesc(first, mop->write, mop->atomic),
-      mop->size, (void*)mop->addr,
-      thread_name(thrbuf, mop->tid));
+  const char *object_type = GetObjectTypeFromTag(mop->external_tag);
+  if (!object_type) {
+    Printf("  %s of size %d at %p by %s",
+           MopDesc(first, mop->write, mop->atomic), mop->size,
+           (void *)mop->addr, thread_name(thrbuf, mop->tid));
+  } else {
+    Printf("  %s access of object %s at %p by %s",
+           ExternalMopDesc(first, mop->write), object_type,
+           (void *)mop->addr, thread_name(thrbuf, mop->tid));
+  }
   PrintMutexSet(mop->mset);
   Printf(":\n");
   Printf("%s", d.EndAccess());
@@ -183,9 +196,16 @@
              global.module_offset);
   } else if (loc->type == ReportLocationHeap) {
     char thrbuf[kThreadBufSize];
-    Printf("  Location is heap block of size %zu at %p allocated by %s:\n",
-           loc->heap_chunk_size, loc->heap_chunk_start,
-           thread_name(thrbuf, loc->tid));
+    const char *object_type = GetObjectTypeFromTag(loc->external_tag);
+    if (!object_type) {
+      Printf("  Location is heap block of size %zu at %p allocated by %s:\n",
+             loc->heap_chunk_size, loc->heap_chunk_start,
+             thread_name(thrbuf, loc->tid));
+    } else {
+      Printf("  Location is %s object of size %zu at %p allocated by %s:\n",
+             object_type, loc->heap_chunk_size, loc->heap_chunk_start,
+             thread_name(thrbuf, loc->tid));
+    }
     print_stack = true;
   } else if (loc->type == ReportLocationStack) {
     Printf("  Location is stack of %s.\n\n", thread_name(thrbuf, loc->tid));
@@ -235,9 +255,15 @@
   if (rt->name && rt->name[0] != '\0')
     Printf(" '%s'", rt->name);
   char thrbuf[kThreadBufSize];
-  Printf(" (tid=%zu, %s) created by %s",
-    rt->os_id, rt->running ? "running" : "finished",
-    thread_name(thrbuf, rt->parent_tid));
+  const char *thread_status = rt->running ? "running" : "finished";
+  if (rt->workerthread) {
+    Printf(" (tid=%zu, %s) is a GCD worker thread\n", rt->os_id, thread_status);
+    Printf("\n");
+    Printf("%s", d.EndThreadDescription());
+    return;
+  }
+  Printf(" (tid=%zu, %s) created by %s", rt->os_id, thread_status,
+         thread_name(thrbuf, rt->parent_tid));
   if (rt->stack)
     Printf(" at:");
   Printf("\n");
diff --git a/lib/tsan/rtl/tsan_report.h b/lib/tsan/rtl/tsan_report.h
index d0b9d74..8d8ae0f 100644
--- a/lib/tsan/rtl/tsan_report.h
+++ b/lib/tsan/rtl/tsan_report.h
@@ -24,6 +24,7 @@
   ReportTypeVptrRace,
   ReportTypeUseAfterFree,
   ReportTypeVptrUseAfterFree,
+  ReportTypeExternalRace,
   ReportTypeThreadLeak,
   ReportTypeMutexDestroyLocked,
   ReportTypeMutexDoubleLock,
@@ -56,6 +57,7 @@
   int size;
   bool write;
   bool atomic;
+  uptr external_tag;
   Vector<ReportMopMutex> mset;
   ReportStack *stack;
 
@@ -75,6 +77,7 @@
   DataInfo global;
   uptr heap_chunk_start;
   uptr heap_chunk_size;
+  uptr external_tag;
   int tid;
   int fd;
   bool suppressable;
@@ -89,8 +92,9 @@
   int id;
   uptr os_id;
   bool running;
+  bool workerthread;
   char *name;
-  int parent_tid;
+  u32 parent_tid;
   ReportStack *stack;
 };
 
diff --git a/lib/tsan/rtl/tsan_rtl.cc b/lib/tsan/rtl/tsan_rtl.cc
index bfb8358..bc5991c 100644
--- a/lib/tsan/rtl/tsan_rtl.cc
+++ b/lib/tsan/rtl/tsan_rtl.cc
@@ -381,7 +381,7 @@
   // Initialize thread 0.
   int tid = ThreadCreate(thr, 0, 0, true);
   CHECK_EQ(tid, 0);
-  ThreadStart(thr, tid, internal_getpid());
+  ThreadStart(thr, tid, GetTid(), /*workerthread*/ false);
 #if TSAN_CONTAINS_UBSAN
   __ubsan::InitAsPlugin();
 #endif
diff --git a/lib/tsan/rtl/tsan_rtl.h b/lib/tsan/rtl/tsan_rtl.h
index 7fcb9d4..8853941 100644
--- a/lib/tsan/rtl/tsan_rtl.h
+++ b/lib/tsan/rtl/tsan_rtl.h
@@ -410,6 +410,7 @@
   bool is_dead;
   bool is_freeing;
   bool is_vptr_access;
+  uptr external_tag;
   const uptr stk_addr;
   const uptr stk_size;
   const uptr tls_addr;
@@ -564,7 +565,7 @@
   explicit ScopedReport(ReportType typ);
   ~ScopedReport();
 
-  void AddMemoryAccess(uptr addr, Shadow s, StackTrace stack,
+  void AddMemoryAccess(uptr addr, uptr external_tag, Shadow s, StackTrace stack,
                        const MutexSet *mset);
   void AddStack(StackTrace stack, bool suppressable = false);
   void AddThread(const ThreadContext *tctx, bool suppressable = false);
@@ -640,6 +641,8 @@
 bool IsExpectedReport(uptr addr, uptr size);
 void PrintMatchedBenignRaces();
 
+const char *GetObjectTypeFromTag(uptr tag);
+
 #if defined(TSAN_DEBUG_OUTPUT) && TSAN_DEBUG_OUTPUT >= 1
 # define DPrintf Printf
 #else
@@ -713,7 +716,7 @@
 void FuncExit(ThreadState *thr);
 
 int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached);
-void ThreadStart(ThreadState *thr, int tid, uptr os_id);
+void ThreadStart(ThreadState *thr, int tid, uptr os_id, bool workerthread);
 void ThreadFinish(ThreadState *thr);
 int ThreadTid(ThreadState *thr, uptr pc, uptr uid);
 void ThreadJoin(ThreadState *thr, uptr pc, int tid);
diff --git a/lib/tsan/rtl/tsan_rtl_report.cc b/lib/tsan/rtl/tsan_rtl_report.cc
index bc8944f..31b9e97 100644
--- a/lib/tsan/rtl/tsan_rtl_report.cc
+++ b/lib/tsan/rtl/tsan_rtl_report.cc
@@ -164,8 +164,8 @@
   (*rs)->suppressable = suppressable;
 }
 
-void ScopedReport::AddMemoryAccess(uptr addr, Shadow s, StackTrace stack,
-                                   const MutexSet *mset) {
+void ScopedReport::AddMemoryAccess(uptr addr, uptr external_tag, Shadow s,
+                                   StackTrace stack, const MutexSet *mset) {
   void *mem = internal_alloc(MBlockReportMop, sizeof(ReportMop));
   ReportMop *mop = new(mem) ReportMop;
   rep_->mops.PushBack(mop);
@@ -175,6 +175,7 @@
   mop->write = s.IsWrite();
   mop->atomic = s.IsAtomic();
   mop->stack = SymbolizeStack(stack);
+  mop->external_tag = external_tag;
   if (mop->stack)
     mop->stack->suppressable = true;
   for (uptr i = 0; i < mset->Size(); i++) {
@@ -202,6 +203,7 @@
   rt->running = (tctx->status == ThreadStatusRunning);
   rt->name = internal_strdup(tctx->name);
   rt->parent_tid = tctx->parent_tid;
+  rt->workerthread = tctx->workerthread;
   rt->stack = 0;
   rt->stack = SymbolizeStackId(tctx->creation_stack_id);
   if (rt->stack)
@@ -336,6 +338,7 @@
     ReportLocation *loc = ReportLocation::New(ReportLocationHeap);
     loc->heap_chunk_start = (uptr)allocator()->GetBlockBegin((void *)addr);
     loc->heap_chunk_size = b->siz;
+    loc->external_tag = b->tag;
     loc->tid = tctx ? tctx->tid : b->tid;
     loc->stack = SymbolizeStackId(b->stk);
     rep_->locs.PushBack(loc);
@@ -622,6 +625,8 @@
     typ = ReportTypeVptrRace;
   else if (freed)
     typ = ReportTypeUseAfterFree;
+  else if (thr->external_tag > 0)
+    typ = ReportTypeExternalRace;
 
   if (IsFiredSuppression(ctx, typ, addr))
     return;
@@ -650,7 +655,8 @@
   ScopedReport rep(typ);
   for (uptr i = 0; i < kMop; i++) {
     Shadow s(thr->racy_state[i]);
-    rep.AddMemoryAccess(addr, s, traces[i], i == 0 ? &thr->mset : mset2);
+    rep.AddMemoryAccess(addr, thr->external_tag, s, traces[i],
+                        i == 0 ? &thr->mset : mset2);
   }
 
   for (uptr i = 0; i < kMop; i++) {
diff --git a/lib/tsan/rtl/tsan_rtl_thread.cc b/lib/tsan/rtl/tsan_rtl_thread.cc
index 5b17dc6..7357d97 100644
--- a/lib/tsan/rtl/tsan_rtl_thread.cc
+++ b/lib/tsan/rtl/tsan_rtl_thread.cc
@@ -236,7 +236,7 @@
   return tid;
 }
 
-void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
+void ThreadStart(ThreadState *thr, int tid, uptr os_id, bool workerthread) {
   uptr stk_addr = 0;
   uptr stk_size = 0;
   uptr tls_addr = 0;
@@ -266,7 +266,7 @@
 
   ThreadRegistry *tr = ctx->thread_registry;
   OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size };
-  tr->StartThread(tid, os_id, &args);
+  tr->StartThread(tid, os_id, workerthread, &args);
 
   tr->Lock();
   thr->tctx = (ThreadContext*)tr->GetThreadLocked(tid);
diff --git a/lib/tsan/rtl/tsan_suppressions.cc b/lib/tsan/rtl/tsan_suppressions.cc
index bfb64e0..e39702b 100644
--- a/lib/tsan/rtl/tsan_suppressions.cc
+++ b/lib/tsan/rtl/tsan_suppressions.cc
@@ -74,6 +74,8 @@
     return kSuppressionRace;
   else if (typ == ReportTypeVptrUseAfterFree)
     return kSuppressionRace;
+  else if (typ == ReportTypeExternalRace)
+    return kSuppressionRace;
   else if (typ == ReportTypeThreadLeak)
     return kSuppressionThread;
   else if (typ == ReportTypeMutexDestroyLocked)
diff --git a/lib/tsan/rtl/tsan_sync.cc b/lib/tsan/rtl/tsan_sync.cc
index 44c6a26..2be0474 100644
--- a/lib/tsan/rtl/tsan_sync.cc
+++ b/lib/tsan/rtl/tsan_sync.cc
@@ -64,6 +64,7 @@
   u32 idx = block_alloc_.Alloc(&thr->proc()->block_cache);
   MBlock *b = block_alloc_.Map(idx);
   b->siz = sz;
+  b->tag = 0;
   b->tid = thr->tid;
   b->stk = CurrentStackId(thr, pc);
   u32 *meta = MemToMeta(p);
diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc
index c531c5f..742802b 100644
--- a/lib/ubsan/ubsan_diag.cc
+++ b/lib/ubsan/ubsan_diag.cc
@@ -31,15 +31,16 @@
   // will definitely be called when we print the first diagnostics message.
   if (!flags()->print_stacktrace)
     return;
-  // We can only use slow unwind, as we don't have any information about stack
-  // top/bottom.
-  // FIXME: It's better to respect "fast_unwind_on_fatal" runtime flag and
-  // fetch stack top/bottom information if we have it (e.g. if we're running
-  // under ASan).
-  if (StackTrace::WillUseFastUnwind(false))
-    return;
+
+  uptr top = 0;
+  uptr bottom = 0;
+  bool request_fast_unwind = common_flags()->fast_unwind_on_fatal;
+  if (request_fast_unwind)
+    __sanitizer::GetThreadStackTopAndBottom(false, &top, &bottom);
+
   BufferedStackTrace stack;
-  stack.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, false);
+  stack.Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom,
+               request_fast_unwind);
   stack.Print();
 }
 
@@ -79,16 +80,16 @@
       AI.line = SLoc.getLine();
       AI.column = SLoc.getColumn();
       AI.function = internal_strdup("");  // Avoid printing ?? as function name.
-      ReportErrorSummary(ErrorKind, AI);
+      ReportErrorSummary(ErrorKind, AI, GetSanititizerToolName());
       AI.Clear();
       return;
     }
   } else if (Loc.isSymbolizedStack()) {
     const AddressInfo &AI = Loc.getSymbolizedStack()->info;
-    ReportErrorSummary(ErrorKind, AI);
+    ReportErrorSummary(ErrorKind, AI, GetSanititizerToolName());
     return;
   }
-  ReportErrorSummary(ErrorKind);
+  ReportErrorSummary(ErrorKind, GetSanititizerToolName());
 }
 
 namespace {
diff --git a/lib/ubsan/ubsan_flags.cc b/lib/ubsan/ubsan_flags.cc
index e77ba55..21e2884 100644
--- a/lib/ubsan/ubsan_flags.cc
+++ b/lib/ubsan/ubsan_flags.cc
@@ -45,6 +45,7 @@
     CommonFlags cf;
     cf.CopyFrom(*common_flags());
     cf.print_summary = false;
+    cf.external_symbolizer_path = GetEnv("UBSAN_SYMBOLIZER_PATH");
     OverrideCommonFlags(cf);
   }
 
diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc
index 6ffffae..d6a8f52 100644
--- a/lib/ubsan/ubsan_handlers.cc
+++ b/lib/ubsan/ubsan_handlers.cc
@@ -38,7 +38,7 @@
 const char *TypeCheckKinds[] = {
     "load of", "store to", "reference binding to", "member access within",
     "member call on", "constructor call on", "downcast of", "downcast of",
-    "upcast of", "cast to virtual base of"};
+    "upcast of", "cast to virtual base of", "_Nonnull binding to"};
 }
 
 static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
@@ -390,7 +390,7 @@
   ScopedReport R(Opts, Loc, ET);
 
   Diag(Loc, DL_Error,
-       "value %0 is outside the range of representable values of type %2")
+       "%0 is outside the range of representable values of type %2")
       << Value(*FromType, From) << *FromType << *ToType;
 }
 
@@ -410,7 +410,8 @@
   SourceLocation Loc = Data->Loc.acquire();
   // This check could be more precise if we used different handlers for
   // -fsanitize=bool and -fsanitize=enum.
-  bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'"));
+  bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'")) ||
+                (0 == internal_strncmp(Data->Type.getTypeName(), "'BOOL'", 6));
   ErrorType ET =
       IsBool ? ErrorType::InvalidBoolLoad : ErrorType::InvalidEnumLoad;
 
@@ -472,7 +473,8 @@
   Die();
 }
 
-static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) {
+static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts,
+                                bool IsAttr) {
   SourceLocation Loc = Data->Loc.acquire();
   ErrorType ET = ErrorType::InvalidNullReturn;
 
@@ -484,21 +486,35 @@
   Diag(Loc, DL_Error, "null pointer returned from function declared to never "
                       "return null");
   if (!Data->AttrLoc.isInvalid())
-    Diag(Data->AttrLoc, DL_Note, "returns_nonnull attribute specified here");
+    Diag(Data->AttrLoc, DL_Note, "%0 specified here")
+        << (IsAttr ? "returns_nonnull attribute"
+                   : "_Nonnull return type annotation");
 }
 
 void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) {
   GET_REPORT_OPTIONS(false);
-  handleNonNullReturn(Data, Opts);
+  handleNonNullReturn(Data, Opts, true);
 }
 
 void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) {
   GET_REPORT_OPTIONS(true);
-  handleNonNullReturn(Data, Opts);
+  handleNonNullReturn(Data, Opts, true);
   Die();
 }
 
-static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) {
+void __ubsan::__ubsan_handle_nullability_return(NonNullReturnData *Data) {
+  GET_REPORT_OPTIONS(false);
+  handleNonNullReturn(Data, Opts, false);
+}
+
+void __ubsan::__ubsan_handle_nullability_return_abort(NonNullReturnData *Data) {
+  GET_REPORT_OPTIONS(true);
+  handleNonNullReturn(Data, Opts, false);
+  Die();
+}
+
+static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts,
+                             bool IsAttr) {
   SourceLocation Loc = Data->Loc.acquire();
   ErrorType ET = ErrorType::InvalidNullArgument;
 
@@ -507,20 +523,34 @@
 
   ScopedReport R(Opts, Loc, ET);
 
-  Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to "
-       "never be null") << Data->ArgIndex;
+  Diag(Loc, DL_Error,
+       "null pointer passed as argument %0, which is declared to "
+       "never be null")
+      << Data->ArgIndex;
   if (!Data->AttrLoc.isInvalid())
-    Diag(Data->AttrLoc, DL_Note, "nonnull attribute specified here");
+    Diag(Data->AttrLoc, DL_Note, "%0 specified here")
+        << (IsAttr ? "nonnull attribute" : "_Nonnull type annotation");
 }
 
 void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) {
   GET_REPORT_OPTIONS(false);
-  handleNonNullArg(Data, Opts);
+  handleNonNullArg(Data, Opts, true);
 }
 
 void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) {
   GET_REPORT_OPTIONS(true);
-  handleNonNullArg(Data, Opts);
+  handleNonNullArg(Data, Opts, true);
+  Die();
+}
+
+void __ubsan::__ubsan_handle_nullability_arg(NonNullArgData *Data) {
+  GET_REPORT_OPTIONS(false);
+  handleNonNullArg(Data, Opts, false);
+}
+
+void __ubsan::__ubsan_handle_nullability_arg_abort(NonNullArgData *Data) {
+  GET_REPORT_OPTIONS(true);
+  handleNonNullArg(Data, Opts, false);
   Die();
 }
 
diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h
index 350eb91..5857bc2 100644
--- a/lib/ubsan/ubsan_handlers.h
+++ b/lib/ubsan/ubsan_handlers.h
@@ -136,8 +136,10 @@
   SourceLocation AttrLoc;
 };
 
-/// \brief Handle returning null from function with returns_nonnull attribute.
+/// \brief Handle returning null from function with the returns_nonnull
+/// attribute, or a return type annotated with _Nonnull.
 RECOVERABLE(nonnull_return, NonNullReturnData *Data)
+RECOVERABLE(nullability_return, NonNullReturnData *Data)
 
 struct NonNullArgData {
   SourceLocation Loc;
@@ -145,8 +147,10 @@
   int ArgIndex;
 };
 
-/// \brief Handle passing null pointer to function with nonnull attribute.
+/// \brief Handle passing null pointer to a function parameter with the nonnull
+/// attribute, or a _Nonnull type annotation.
 RECOVERABLE(nonnull_arg, NonNullArgData *Data)
+RECOVERABLE(nullability_arg, NonNullArgData *Data)
 
 /// \brief Known CFI check kinds.
 /// Keep in sync with the enum of the same name in CodeGenFunction.h
diff --git a/lib/ubsan/ubsan_init.cc b/lib/ubsan/ubsan_init.cc
index b4f42c4..307bca3 100644
--- a/lib/ubsan/ubsan_init.cc
+++ b/lib/ubsan/ubsan_init.cc
@@ -23,6 +23,10 @@
 
 using namespace __ubsan;
 
+const char *__ubsan::GetSanititizerToolName() {
+  return "UndefinedBehaviorSanitizer";
+}
+
 static enum {
   UBSAN_MODE_UNKNOWN = 0,
   UBSAN_MODE_STANDALONE,
@@ -35,7 +39,7 @@
 }
 
 static void CommonStandaloneInit() {
-  SanitizerToolName = "UndefinedBehaviorSanitizer";
+  SanitizerToolName = GetSanititizerToolName();
   InitializeFlags();
   CacheBinaryName();
   __sanitizer_set_report_path(common_flags()->log_path);
diff --git a/lib/ubsan/ubsan_init.h b/lib/ubsan/ubsan_init.h
index 103ae24..f12fc2c 100644
--- a/lib/ubsan/ubsan_init.h
+++ b/lib/ubsan/ubsan_init.h
@@ -15,6 +15,9 @@
 
 namespace __ubsan {
 
+// Get the full tool name for UBSan.
+const char *GetSanititizerToolName();
+
 // Initialize UBSan as a standalone tool. Typically should be called early
 // during initialization.
 void InitAsStandalone();
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 9b9c515..addc579 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -5,9 +5,8 @@
   ${CMAKE_CURRENT_SOURCE_DIR}/lit.common.configured.in
   ${CMAKE_CURRENT_BINARY_DIR}/lit.common.configured)
 
-# BlocksRuntime and builtins testsuites are not yet ported to lit.
+# BlocksRuntime (and most of builtins) testsuites are not yet ported to lit.
 # add_subdirectory(BlocksRuntime)
-# add_subdirectory(builtins)
 
 set(SANITIZER_COMMON_LIT_TEST_DEPS)
 if(COMPILER_RT_STANDALONE_BUILD)
@@ -39,6 +38,9 @@
 # Run sanitizer tests only if we're sure that clang would produce
 # working binaries.
 if(COMPILER_RT_CAN_EXECUTE_TESTS)
+  if(COMPILER_RT_BUILD_BUILTINS)
+    add_subdirectory(builtins)
+  endif()
   if(COMPILER_RT_HAS_ASAN)
     add_subdirectory(asan)
   endif()
diff --git a/test/asan/TestCases/Darwin/scribble.cc b/test/asan/TestCases/Darwin/scribble.cc
new file mode 100644
index 0000000..33f64e1
--- /dev/null
+++ b/test/asan/TestCases/Darwin/scribble.cc
@@ -0,0 +1,57 @@
+// RUN: %clang_asan -O2 %s -o %t
+// RUN: %run %t 2>&1 | FileCheck --check-prefix=CHECK-NOSCRIBBLE %s
+// RUN: env MallocScribble=1 MallocPreScribble=1 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s
+// RUN: %env_asan_opts=max_free_fill_size=4096 %run %t 2>&1 | FileCheck --check-prefix=CHECK-SCRIBBLE %s
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct Isa {
+  const char *class_name;
+};
+
+struct MyClass {
+  long padding;
+  Isa *isa;
+  long data;
+
+  void print_my_class_name();
+};
+
+__attribute__((no_sanitize("address")))
+void MyClass::print_my_class_name() {
+  fprintf(stderr, "this = %p\n", this);
+  fprintf(stderr, "padding = 0x%lx\n", this->padding);
+  fprintf(stderr, "isa = %p\n", this->isa);
+
+  if ((uint32_t)(uintptr_t)this->isa != 0x55555555) {
+    fprintf(stderr, "class name: %s\n", this->isa->class_name);
+  }
+}
+
+int main() {
+  Isa *my_class_isa = (Isa *)malloc(sizeof(Isa));
+  memset(my_class_isa, 0x77, sizeof(Isa));
+  my_class_isa->class_name = "MyClass";
+
+  MyClass *my_object = (MyClass *)malloc(sizeof(MyClass));
+  memset(my_object, 0x88, sizeof(MyClass));
+  my_object->isa = my_class_isa;
+  my_object->data = 42;
+
+  my_object->print_my_class_name();
+  // CHECK-SCRIBBLE: class name: MyClass
+  // CHECK-NOSCRIBBLE: class name: MyClass
+
+  free(my_object);
+
+  my_object->print_my_class_name();
+  // CHECK-NOSCRIBBLE: class name: MyClass
+  // CHECK-SCRIBBLE: isa = {{(0x)?}}{{5555555555555555|55555555}}
+
+  fprintf(stderr, "okthxbai!\n");
+  // CHECK-SCRIBBLE: okthxbai!
+  // CHECK-NOSCRIBBLE: okthxbai!
+}
diff --git a/test/asan/TestCases/Linux/memmem_test.cc b/test/asan/TestCases/Linux/memmem_test.cc
index 661381c..a838cb5 100644
--- a/test/asan/TestCases/Linux/memmem_test.cc
+++ b/test/asan/TestCases/Linux/memmem_test.cc
@@ -15,10 +15,10 @@
   // A1: AddressSanitizer: stack-buffer-overflow
   // A1: {{#0.*memmem}}
   // A1-NEXT: {{#1.*main}}
-  // A1: 'a1' <== Memory access at offset
+  // A1: 'a1'{{.*}} <== Memory access at offset
   //
   // A2: AddressSanitizer: stack-buffer-overflow
   // A2: {{#0.*memmem}}
-  // A2: 'a2' <== Memory access at offset
+  // A2: 'a2'{{.*}} <== Memory access at offset
   return res == NULL;
 }
diff --git a/test/asan/TestCases/Posix/stack-use-after-return.cc b/test/asan/TestCases/Posix/stack-use-after-return.cc
index cf114be..7c03037 100644
--- a/test/asan/TestCases/Posix/stack-use-after-return.cc
+++ b/test/asan/TestCases/Posix/stack-use-after-return.cc
@@ -48,11 +48,11 @@
   // CHECK: WRITE of size 1 {{.*}} thread T0
   // CHECK:     #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-2]]
   // CHECK: is located in stack of thread T0 at offset
-  // CHECK: 'local' <== Memory access at offset {{16|32}} is inside this variable
+  // CHECK: 'local'{{.*}} <== Memory access at offset {{16|32}} is inside this variable
   // THREAD: WRITE of size 1 {{.*}} thread T{{[1-9]}}
   // THREAD:     #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-6]]
   // THREAD: is located in stack of thread T{{[1-9]}} at offset
-  // THREAD: 'local' <== Memory access at offset {{16|32}} is inside this variable
+  // THREAD: 'local'{{.*}} <== Memory access at offset {{16|32}} is inside this variable
   // CHECK-20: T0: FakeStack created:{{.*}} stack_size_log: 20
   // CHECK-24: T0: FakeStack created:{{.*}} stack_size_log: 24
 }
diff --git a/test/asan/TestCases/Windows/dll_intercept_memchr.cc b/test/asan/TestCases/Windows/dll_intercept_memchr.cc
index 4f794a2..6360cec 100644
--- a/test/asan/TestCases/Windows/dll_intercept_memchr.cc
+++ b/test/asan/TestCases/Windows/dll_intercept_memchr.cc
@@ -22,6 +22,6 @@
 // CHECK-NEXT:  test_function {{.*}}dll_intercept_memchr.cc:[[@LINE-5]]
 // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame
 // CHECK-NEXT:  test_function {{.*}}dll_intercept_memchr.cc
-// CHECK: 'buff' <== Memory access at offset {{.*}} overflows this variable
+// CHECK: 'buff'{{.*}} <== Memory access at offset {{.*}} overflows this variable
   return 0;
 }
diff --git a/test/asan/TestCases/Windows/dll_intercept_memcpy.cc b/test/asan/TestCases/Windows/dll_intercept_memcpy.cc
index 736e696..a5981fa 100644
--- a/test/asan/TestCases/Windows/dll_intercept_memcpy.cc
+++ b/test/asan/TestCases/Windows/dll_intercept_memcpy.cc
@@ -27,6 +27,6 @@
 // CHECK-NEXT:  test_function {{.*}}dll_intercept_memcpy.cc:[[@LINE-4]]
 // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame
 // CHECK-NEXT:  test_function {{.*}}dll_intercept_memcpy.cc
-// CHECK: 'buff2' <== Memory access at offset {{.*}} overflows this variable
+// CHECK: 'buff2'{{.*}} <== Memory access at offset {{.*}} overflows this variable
   return 0;
 }
diff --git a/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc b/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc
index 4e28905..f05ee21 100644
--- a/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc
+++ b/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc
@@ -29,6 +29,6 @@
 // CHECK-NEXT:  test_function {{.*}}dll_intercept_memcpy_indirect.cc:[[@LINE-5]]
 // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame
 // CHECK-NEXT:  test_function {{.*}}dll_intercept_memcpy_indirect.cc
-// CHECK: 'buff2' <== Memory access at offset {{.*}} overflows this variable
+// CHECK: 'buff2'{{.*}} <== Memory access at offset {{.*}} overflows this variable
   return 0;
 }
diff --git a/test/asan/TestCases/Windows/dll_intercept_memset.cc b/test/asan/TestCases/Windows/dll_intercept_memset.cc
index d4be376..4baa0a1 100644
--- a/test/asan/TestCases/Windows/dll_intercept_memset.cc
+++ b/test/asan/TestCases/Windows/dll_intercept_memset.cc
@@ -27,6 +27,6 @@
 // CHECK-NEXT:  test_function {{.*}}dll_intercept_memset.cc:[[@LINE-4]]
 // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame
 // CHECK-NEXT:  test_function {{.*}}dll_intercept_memset.cc
-// CHECK: 'buff' <== Memory access at offset {{.*}} overflows this variable
+// CHECK: 'buff'{{.*}} <== Memory access at offset {{.*}} overflows this variable
   return 0;
 }
diff --git a/test/asan/TestCases/Windows/dll_noreturn.cc b/test/asan/TestCases/Windows/dll_noreturn.cc
index 8b5e3d0..2f6f0c7 100644
--- a/test/asan/TestCases/Windows/dll_noreturn.cc
+++ b/test/asan/TestCases/Windows/dll_noreturn.cc
@@ -17,7 +17,7 @@
 //
 // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame
 // CHECK-NEXT:  noreturn_f{{.*}}dll_noreturn.cc
-// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] underflows this variable
+// CHECK: 'buffer'{{.*}} <== Memory access at offset [[OFFSET]] underflows this variable
 // CHECK-LABEL: SUMMARY
 }
 
diff --git a/test/asan/TestCases/Windows/dll_poison_unpoison.cc b/test/asan/TestCases/Windows/dll_poison_unpoison.cc
index 9b25a12..6bd58ec 100644
--- a/test/asan/TestCases/Windows/dll_poison_unpoison.cc
+++ b/test/asan/TestCases/Windows/dll_poison_unpoison.cc
@@ -30,6 +30,6 @@
 //
 // CHECK: [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame
 // CHECK-NEXT: test_function{{.*}}\dll_poison_unpoison.cc
-// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] is inside this variable
+// CHECK: 'buffer'{{.*}} <== Memory access at offset [[OFFSET]] is inside this variable
   return 0;
 }
diff --git a/test/asan/TestCases/Windows/dll_stack_use_after_return.cc b/test/asan/TestCases/Windows/dll_stack_use_after_return.cc
index 6428718..b6166d6 100644
--- a/test/asan/TestCases/Windows/dll_stack_use_after_return.cc
+++ b/test/asan/TestCases/Windows/dll_stack_use_after_return.cc
@@ -22,7 +22,7 @@
 //
 // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame
 // CHECK-NEXT: #0 {{.*}} foo{{.*}}dll_stack_use_after_return.cc
-// CHECK: 'stack_buffer' <== Memory access at offset [[OFFSET]] is inside this variable
+// CHECK: 'stack_buffer'{{.*}} <== Memory access at offset [[OFFSET]] is inside this variable
   return 0;
 }
 
diff --git a/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc b/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc
index dc7c7c6..75a094e 100644
--- a/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc
+++ b/test/asan/TestCases/Windows/dll_thread_stack_array_left_oob.cc
@@ -16,7 +16,7 @@
 // CHECK: Address [[ADDR]] is located in stack of thread T1 at offset [[OFFSET:.*]] in frame
 // CHECK-NEXT:  thread_proc{{.*}}dll_thread_stack_array_left_oob.cc
 //
-// CHECK: 'stack_buffer' <== Memory access at offset [[OFFSET]] underflows this variable
+// CHECK: 'stack_buffer'{{.*}} <== Memory access at offset [[OFFSET]] underflows this variable
 
   return 0;
 }
diff --git a/test/asan/TestCases/Windows/intercept_memcpy.cc b/test/asan/TestCases/Windows/intercept_memcpy.cc
index 6e45e7f..d71333d 100644
--- a/test/asan/TestCases/Windows/intercept_memcpy.cc
+++ b/test/asan/TestCases/Windows/intercept_memcpy.cc
@@ -27,5 +27,5 @@
 // CHECK-NEXT:  main {{.*}}intercept_memcpy.cc:[[@LINE-5]]
 // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame
 // CHECK-NEXT:   #0 {{.*}} main
-// CHECK: 'buff2' <== Memory access at offset {{.*}} overflows this variable
+// CHECK: 'buff2'{{.*}} <== Memory access at offset {{.*}} overflows this variable
 }
diff --git a/test/asan/TestCases/Windows/intercept_strlen.cc b/test/asan/TestCases/Windows/intercept_strlen.cc
index 928a286..938e6c9 100644
--- a/test/asan/TestCases/Windows/intercept_strlen.cc
+++ b/test/asan/TestCases/Windows/intercept_strlen.cc
@@ -22,6 +22,6 @@
 // CHECK-NEXT: main {{.*}}intercept_strlen.cc:[[@LINE-5]]
 // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame
 // CHECK-NEXT: main {{.*}}intercept_strlen.cc
-// CHECK: 'str' <== Memory access at offset {{.*}} overflows this variable
+// CHECK: 'str'{{.*}} <== Memory access at offset {{.*}} overflows this variable
   return len < 6;
 }
diff --git a/test/asan/TestCases/Windows/stack_array_left_oob.cc b/test/asan/TestCases/Windows/stack_array_left_oob.cc
index 845a1f3..8d601fc 100644
--- a/test/asan/TestCases/Windows/stack_array_left_oob.cc
+++ b/test/asan/TestCases/Windows/stack_array_left_oob.cc
@@ -12,5 +12,5 @@
 // CHECK-NEXT: {{#0 .* main .*stack_array_left_oob.cc}}:[[@LINE-3]]
 // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame
 // CHECK-NEXT: {{#0 .* main .*stack_array_left_oob.cc}}
-// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] underflows this variable
+// CHECK: 'buffer'{{.*}} <== Memory access at offset [[OFFSET]] underflows this variable
 }
diff --git a/test/asan/TestCases/Windows/stack_array_right_oob.cc b/test/asan/TestCases/Windows/stack_array_right_oob.cc
index a370246..721834d 100644
--- a/test/asan/TestCases/Windows/stack_array_right_oob.cc
+++ b/test/asan/TestCases/Windows/stack_array_right_oob.cc
@@ -12,5 +12,5 @@
 // CHECK-NEXT: {{#0 .* main .*stack_array_right_oob.cc}}:[[@LINE-3]]
 // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:.*]] in frame
 // CHECK-NEXT: {{#0 .* main .*stack_array_right_oob.cc}}
-// CHECK: 'buffer' <== Memory access at offset [[OFFSET]] overflows this variable
+// CHECK: 'buffer'{{.*}} <== Memory access at offset [[OFFSET]] overflows this variable
 }
diff --git a/test/asan/TestCases/Windows/stack_use_after_return.cc b/test/asan/TestCases/Windows/stack_use_after_return.cc
index 9c31922..ca1c142 100644
--- a/test/asan/TestCases/Windows/stack_use_after_return.cc
+++ b/test/asan/TestCases/Windows/stack_use_after_return.cc
@@ -18,5 +18,5 @@
 // CHECK: is located in stack of thread T0 at offset [[OFFSET:.*]] in frame
 // CHECK-NEXT: {{#0 0x.* in foo.*stack_use_after_return.cc}}
 //
-// CHECK: 'stack_buffer' <== Memory access at offset [[OFFSET]] is inside this variable
+// CHECK: 'stack_buffer'{{.*}} <== Memory access at offset [[OFFSET]] is inside this variable
 }
diff --git a/test/asan/TestCases/Windows/wrong_downcast_on_stack.cc b/test/asan/TestCases/Windows/wrong_downcast_on_stack.cc
index 2859ecc..7848cf3 100644
--- a/test/asan/TestCases/Windows/wrong_downcast_on_stack.cc
+++ b/test/asan/TestCases/Windows/wrong_downcast_on_stack.cc
@@ -20,7 +20,7 @@
 // CHECK-NEXT:  {{#0 0x[0-9a-f]* in main .*wrong_downcast_on_stack.cc}}:[[@LINE-3]]
 // CHECK: [[ADDR]] is located in stack of thread T0 at offset [[OFFSET:[0-9]+]] in frame
 // CHECK-NEXT:  {{#0 0x[0-9a-f]* in main }}
-// CHECK:  'p' <== Memory access at offset [[OFFSET]] overflows this variable
+// CHECK:  'p'{{.*}} <== Memory access at offset [[OFFSET]] overflows this variable
   return 0;
 }
 
diff --git a/test/asan/TestCases/stack-buffer-overflow-with-position.cc b/test/asan/TestCases/stack-buffer-overflow-with-position.cc
index 88f5825..2a575f7 100644
--- a/test/asan/TestCases/stack-buffer-overflow-with-position.cc
+++ b/test/asan/TestCases/stack-buffer-overflow-with-position.cc
@@ -30,15 +30,15 @@
   // make sure BBB and CCC are not removed;
   return *(short*)(p) + BBB[argc % 2] + CCC[argc % 2];
 }
-// CHECK-m2: 'AAA' <== {{.*}}underflows this variable
-// CHECK-m1: 'AAA' <== {{.*}}partially underflows this variable
-// CHECK-9:  'AAA' <== {{.*}}partially overflows this variable
-// CHECK-10: 'AAA' <== {{.*}}overflows this variable
-// CHECK-30: 'BBB' <== {{.*}}underflows this variable
-// CHECK-31: 'BBB' <== {{.*}}partially underflows this variable
-// CHECK-41: 'BBB' <== {{.*}}partially overflows this variable
-// CHECK-42: 'BBB' <== {{.*}}overflows this variable
-// CHECK-62: 'CCC' <== {{.*}}underflows this variable
-// CHECK-63: 'CCC' <== {{.*}}partially underflows this variable
-// CHECK-73: 'CCC' <== {{.*}}partially overflows this variable
-// CHECK-74: 'CCC' <== {{.*}}overflows this variable
+// CHECK-m2: 'AAA'{{.*}} <== {{.*}}underflows this variable
+// CHECK-m1: 'AAA'{{.*}} <== {{.*}}partially underflows this variable
+// CHECK-9:  'AAA'{{.*}} <== {{.*}}partially overflows this variable
+// CHECK-10: 'AAA'{{.*}} <== {{.*}}overflows this variable
+// CHECK-30: 'BBB'{{.*}} <== {{.*}}underflows this variable
+// CHECK-31: 'BBB'{{.*}} <== {{.*}}partially underflows this variable
+// CHECK-41: 'BBB'{{.*}} <== {{.*}}partially overflows this variable
+// CHECK-42: 'BBB'{{.*}} <== {{.*}}overflows this variable
+// CHECK-62: 'CCC'{{.*}} <== {{.*}}underflows this variable
+// CHECK-63: 'CCC'{{.*}} <== {{.*}}partially underflows this variable
+// CHECK-73: 'CCC'{{.*}} <== {{.*}}partially overflows this variable
+// CHECK-74: 'CCC'{{.*}} <== {{.*}}overflows this variable
diff --git a/test/asan/TestCases/strcasestr-1.c b/test/asan/TestCases/strcasestr-1.c
index c38871e..dccfbcd 100644
--- a/test/asan/TestCases/strcasestr-1.c
+++ b/test/asan/TestCases/strcasestr-1.c
@@ -19,7 +19,7 @@
   char s1[4] = "abC";
   __asan_poison_memory_region ((char *)&s1[2], 2);
   r = strcasestr(s1, s2);
-  // CHECK:'s1' <== Memory access at offset {{[0-9]+}} partially overflows this variable
+  // CHECK:'s1'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable
   assert(r == s1 + 2);
   return 0;
 }
diff --git a/test/asan/TestCases/strcasestr-2.c b/test/asan/TestCases/strcasestr-2.c
index 47fd692..70de2dd 100644
--- a/test/asan/TestCases/strcasestr-2.c
+++ b/test/asan/TestCases/strcasestr-2.c
@@ -20,6 +20,6 @@
   __asan_poison_memory_region ((char *)&s2[2], 2);
   r = strcasestr(s1, s2);
   assert(r == 0);
-  // CHECK:'s2' <== Memory access at offset {{[0-9]+}} partially overflows this variable
+  // CHECK:'s2'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable
   return 0;
 }
diff --git a/test/asan/TestCases/strcspn-1.c b/test/asan/TestCases/strcspn-1.c
index 6cda2e2..2a9f7d7 100644
--- a/test/asan/TestCases/strcspn-1.c
+++ b/test/asan/TestCases/strcspn-1.c
@@ -14,7 +14,7 @@
   char s1[4] = "caB";
   __asan_poison_memory_region ((char *)&s1[2], 2);
   r = strcspn(s1, s2);
-  // CHECK:'s1' <== Memory access at offset {{[0-9]+}} partially overflows this variable
+  // CHECK:'s1'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable
   assert(r == 1);
   return 0;
 }
diff --git a/test/asan/TestCases/strcspn-2.c b/test/asan/TestCases/strcspn-2.c
index 8bb4b8a..a51fb91 100644
--- a/test/asan/TestCases/strcspn-2.c
+++ b/test/asan/TestCases/strcspn-2.c
@@ -14,7 +14,7 @@
   char s2[4] = "abc";
   __asan_poison_memory_region ((char *)&s2[2], 2);
   r = strcspn(s1, s2);
-  // CHECK:'s2' <== Memory access at offset {{[0-9]+}} partially overflows this variable
+  // CHECK:'s2'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable
   assert(r == 0);
   return 0;
 }
diff --git a/test/asan/TestCases/strpbrk-1.c b/test/asan/TestCases/strpbrk-1.c
index 626e877..eb32326 100644
--- a/test/asan/TestCases/strpbrk-1.c
+++ b/test/asan/TestCases/strpbrk-1.c
@@ -14,7 +14,7 @@
   char s1[4] = "cab";
   __asan_poison_memory_region ((char *)&s1[2], 2);
   r = strpbrk(s1, s2);
-  // CHECK:'s1' <== Memory access at offset {{[0-9]+}} partially overflows this variable
+  // CHECK:'s1'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable
   assert(r == s1 + 1);
   return 0;
 }
diff --git a/test/asan/TestCases/strpbrk-2.c b/test/asan/TestCases/strpbrk-2.c
index 29f3150..1f24656 100644
--- a/test/asan/TestCases/strpbrk-2.c
+++ b/test/asan/TestCases/strpbrk-2.c
@@ -14,7 +14,7 @@
   char s2[4] = "bca";
   __asan_poison_memory_region ((char *)&s2[2], 2);
   r = strpbrk(s1, s2);
-  // CHECK:'s2' <== Memory access at offset {{[0-9]+}} partially overflows this variable
+  // CHECK:'s2'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable
   assert(r == s1);
   return 0;
 }
diff --git a/test/asan/TestCases/strspn-1.c b/test/asan/TestCases/strspn-1.c
index b0c40ea..5ddb14f 100644
--- a/test/asan/TestCases/strspn-1.c
+++ b/test/asan/TestCases/strspn-1.c
@@ -14,7 +14,7 @@
   char s1[4] = "acb";
   __asan_poison_memory_region ((char *)&s1[2], 2);
   r = strspn(s1, s2);
-  // CHECK:'s1' <== Memory access at offset {{[0-9]+}} partially overflows this variable
+  // CHECK:'s1'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable
   assert(r == 1);
   return 0;
 }
diff --git a/test/asan/TestCases/strspn-2.c b/test/asan/TestCases/strspn-2.c
index 4c89910..d564ef8 100644
--- a/test/asan/TestCases/strspn-2.c
+++ b/test/asan/TestCases/strspn-2.c
@@ -14,7 +14,7 @@
   char s2[5] = "abcd";
   __asan_poison_memory_region ((char *)&s2[3], 2);
   r = strspn(s1, s2);
-  // CHECK:'s2' <== Memory access at offset {{[0-9]+}} partially overflows this variable
+  // CHECK:'s2'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable
   assert(r >= 2);
   return 0;
 }
diff --git a/test/asan/TestCases/strstr-1.c b/test/asan/TestCases/strstr-1.c
index 06a8a8a..319cff5 100644
--- a/test/asan/TestCases/strstr-1.c
+++ b/test/asan/TestCases/strstr-1.c
@@ -15,7 +15,7 @@
   char s1[4] = "acb";
   __asan_poison_memory_region ((char *)&s1[2], 2);
   r = strstr(s1, s2);
-  // CHECK:'s1' <== Memory access at offset {{[0-9]+}} {{partially overflows this variable|is inside this variable}}
+  // CHECK:'s1'{{.*}} <== Memory access at offset {{[0-9]+}} {{partially overflows this variable|is inside this variable}}
   assert(r == s1 + 1);
   return 0;
 }
diff --git a/test/asan/TestCases/strstr-2.c b/test/asan/TestCases/strstr-2.c
index 8bc6e99..4d00c6e 100644
--- a/test/asan/TestCases/strstr-2.c
+++ b/test/asan/TestCases/strstr-2.c
@@ -15,7 +15,7 @@
   char s2[4] = "cab";
   __asan_poison_memory_region ((char *)&s2[2], 2);
   r = strstr(s1, s2);
-  // CHECK:'s2' <== Memory access at offset {{[0-9]+}} partially overflows this variable
+  // CHECK:'s2'{{.*}} <== Memory access at offset {{[0-9]+}} partially overflows this variable
   assert(r == 0);
   return 0;
 }
diff --git a/test/asan/TestCases/use-after-scope-inlined.cc b/test/asan/TestCases/use-after-scope-inlined.cc
index 98a455c..bed9814 100644
--- a/test/asan/TestCases/use-after-scope-inlined.cc
+++ b/test/asan/TestCases/use-after-scope-inlined.cc
@@ -21,8 +21,8 @@
   // CHECK: READ of size 4 at 0x{{.*}} thread T0
   // CHECK:   #0 0x{{.*}} in main
   // CHECK:      {{.*}}use-after-scope-inlined.cc:[[@LINE-4]]
-  // CHECK: Address 0x{{.*}} is located in stack of thread T0 at offset
-  // CHECK:      [[OFFSET:[^ ]*]] in frame
-  // CHECK: main
-  // CHECK:   {{\[}}[[OFFSET]], {{.*}}) 'x.i:[[@LINE-15]]'
+  // CHECK: Address 0x{{.*}} is located in stack of thread T0 at offset [[OFFSET:[^ ]*]] in frame
+  // CHECK:      {{.*}} in main
+  // CHECK:   This frame has
+  // CHECK:     {{\[}}[[OFFSET]], {{.*}}) 'x.i' (line [[@LINE-15]])
 }
diff --git a/test/asan/TestCases/use-after-scope.cc b/test/asan/TestCases/use-after-scope.cc
index d92dae6..4c5998a 100644
--- a/test/asan/TestCases/use-after-scope.cc
+++ b/test/asan/TestCases/use-after-scope.cc
@@ -1,6 +1,10 @@
 // RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \
 // RUN:     not %run %t 2>&1 | FileCheck %s
 
+// -fsanitize-address-use-after-scope is now on by default:
+// RUN: %clangxx_asan -O1 %s -o %t && \
+// RUN:     not %run %t 2>&1 | FileCheck %s
+
 volatile int *p = 0;
 
 int main() {
diff --git a/test/asan/Unit/lit.site.cfg.in b/test/asan/Unit/lit.site.cfg.in
index 55631a6..1c59a6b 100644
--- a/test/asan/Unit/lit.site.cfg.in
+++ b/test/asan/Unit/lit.site.cfg.in
@@ -27,3 +27,6 @@
 
 # Set LD_LIBRARY_PATH to pick dynamic runtime up properly.
 push_ld_library_path(config, config.compiler_rt_libdir)
+
+if config.host_os == 'Darwin':
+  config.parallelism_group = config.darwin_sanitizer_parallelism_group_func
diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg
index 7703f5a..5ebe414 100644
--- a/test/asan/lit.cfg
+++ b/test/asan/lit.cfg
@@ -241,3 +241,6 @@
 # Only run the tests on supported OSs.
 if config.host_os not in ['Linux', 'Darwin', 'FreeBSD', 'Windows']:
   config.unsupported = True
+
+if config.host_os == 'Darwin' and config.target_arch in ["x86_64", "x86_64h"]:
+  config.parallelism_group = "darwin-64bit-sanitizer"
diff --git a/test/builtins/CMakeLists.txt b/test/builtins/CMakeLists.txt
new file mode 100644
index 0000000..443e552
--- /dev/null
+++ b/test/builtins/CMakeLists.txt
@@ -0,0 +1,15 @@
+set(BUILTINS_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+
+set(BUILTINS_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS} builtins)
+set(BUILTINS_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/TestCases)
+
+# Test cases.
+configure_lit_site_cfg(
+  ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+  ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+)
+
+add_lit_testsuite(check-builtins "Running the Builtins tests"
+  ${BUILTINS_TESTSUITES}
+  DEPENDS ${BUILTINS_TEST_DEPS})
+set_target_properties(check-builtins PROPERTIES FOLDER "Compiler-RT Misc")
diff --git a/test/builtins/TestCases/Darwin/lit.local.cfg b/test/builtins/TestCases/Darwin/lit.local.cfg
new file mode 100644
index 0000000..a85dfcd
--- /dev/null
+++ b/test/builtins/TestCases/Darwin/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 ['Darwin']:
+  config.unsupported = True
diff --git a/test/builtins/TestCases/Darwin/os_version_check_test.c b/test/builtins/TestCases/Darwin/os_version_check_test.c
new file mode 100644
index 0000000..2692cd3
--- /dev/null
+++ b/test/builtins/TestCases/Darwin/os_version_check_test.c
@@ -0,0 +1,19 @@
+// RUN: %clang %s -o %t -mmacosx-version-min=10.5 -framework CoreFoundation -DMAJOR=%macos_version_major -DMINOR=%macos_version_minor -DSUBMINOR=%macos_version_subminor
+// RUN: %run %t
+
+int __isOSVersionAtLeast(int Major, int Minor, int Subminor);
+
+int main() {
+  if (!__isOSVersionAtLeast(MAJOR, MINOR, SUBMINOR))
+    return 1;
+  if (__isOSVersionAtLeast(MAJOR, MINOR, SUBMINOR + 1))
+    return 1;
+  if (SUBMINOR && __isOSVersionAtLeast(MAJOR + 1, MINOR, SUBMINOR - 1))
+    return 1;
+  if (SUBMINOR && !__isOSVersionAtLeast(MAJOR, MINOR, SUBMINOR - 1))
+    return 1;
+  if (MAJOR && !__isOSVersionAtLeast(MAJOR - 1, MINOR + 1, SUBMINOR))
+    return 1;
+
+  return 0;
+}
diff --git a/test/builtins/TestCases/Darwin/os_version_check_test_no_core_foundation.c b/test/builtins/TestCases/Darwin/os_version_check_test_no_core_foundation.c
new file mode 100644
index 0000000..4e0da35
--- /dev/null
+++ b/test/builtins/TestCases/Darwin/os_version_check_test_no_core_foundation.c
@@ -0,0 +1,12 @@
+// RUN: %clang %s -o %t -mmacosx-version-min=10.5
+// RUN: %run %t
+
+int __isOSVersionAtLeast(int Major, int Minor, int Subminor);
+
+int main() {
+  // When CoreFoundation isn't linked, we expect the system version to be 0, 0,
+  // 0.
+  if (__isOSVersionAtLeast(1, 0, 0))
+    return 1;
+  return 0;
+}
diff --git a/test/builtins/lit.cfg b/test/builtins/lit.cfg
new file mode 100644
index 0000000..0044df7
--- /dev/null
+++ b/test/builtins/lit.cfg
@@ -0,0 +1,20 @@
+# -*- Python -*-
+
+import os
+
+# Setup config name.
+config.name = 'Builtins'
+
+# Setup source root.
+config.test_source_root = os.path.dirname(__file__)
+
+# Test suffixes.
+config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm']
+
+# Define %clang and %clangxx substitutions to use in test RUN lines.
+config.substitutions.append( ("%clang ", " " + config.clang + " ") )
+
+if config.host_os == 'Darwin':
+  config.substitutions.append( ("%macos_version_major", str(config.darwin_osx_version[0])) )
+  config.substitutions.append( ("%macos_version_minor", str(config.darwin_osx_version[1])) )
+  config.substitutions.append( ("%macos_version_subminor", str(config.darwin_osx_version[2])) )
diff --git a/test/builtins/lit.site.cfg.in b/test/builtins/lit.site.cfg.in
new file mode 100644
index 0000000..c7fe82f
--- /dev/null
+++ b/test/builtins/lit.site.cfg.in
@@ -0,0 +1,7 @@
+@LIT_SITE_CFG_IN_HEADER@
+
+# Load common config for all compiler-rt lit tests.
+lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured")
+
+# Load tool-specific config that would do the real work.
+lit_config.load_config(config, "@BUILTINS_LIT_SOURCE_DIR@/lit.cfg")
diff --git a/test/lit.common.cfg b/test/lit.common.cfg
index b875992..e90d738 100644
--- a/test/lit.common.cfg
+++ b/test/lit.common.cfg
@@ -76,6 +76,9 @@
 if re.match(r'^x86_64.*-linux', config.target_triple):
       config.available_features.add("x86_64-linux")
 
+if lit.util.isMacOSTriple(config.target_triple):
+   config.available_features.add('darwin')
+
 # Use ugly construction to explicitly prohibit "clang", "clang++" etc.
 # in RUN lines.
 config.substitutions.append(
@@ -126,9 +129,11 @@
 lit.util.usePlatformSdkOnDarwin(config, lit_config)
 
 if config.host_os == 'Darwin':
+  osx_version = (10, 0, 0)
   try:
     osx_version = subprocess.check_output(["sw_vers", "-productVersion"])
     osx_version = tuple(int(x) for x in osx_version.split('.'))
+    if len(osx_version) == 2: osx_version = (osx_version[0], osx_version[1], 0)
     if osx_version >= (10, 11):
       config.available_features.add('osx-autointerception')
       config.available_features.add('osx-ld64-live_support')
@@ -141,6 +146,8 @@
   except:
     pass
 
+  config.darwin_osx_version = osx_version
+
   # Detect x86_64h
   try:
     output = subprocess.check_output(["sysctl", "hw.cpusubtype"])
@@ -216,3 +223,9 @@
 # retries. We don't do this on otther platforms because it's slower.
 if platform.system() == 'Windows':
   config.test_retry_attempts = 2
+
+# Only run up to 3 64-bit sanitized processes simultaneously on Darwin.
+# Using more scales badly and hogs the system due to inefficient handling
+# of large mmap'd regions (terabytes) by the kernel.
+if platform.system() == 'Darwin':
+  lit_config.parallelism_groups["darwin-64bit-sanitizer"] = 3
diff --git a/test/profile/Linux/instrprof-dir.c b/test/profile/Linux/instrprof-dir.c
new file mode 100644
index 0000000..9d9af6d
--- /dev/null
+++ b/test/profile/Linux/instrprof-dir.c
@@ -0,0 +1,13 @@
+// RUN: %clang_pgogen -o %t %s
+// RUN: env LLVM_PROFILE_FILE="%t.d/%m.profraw"
+// RUN: rm -fr %t.d
+// RUN: %run %t %t.d
+
+#include <errno.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+  if (access(argv[1], F_OK) == 0)
+    return 1; // %t.d should not exist yet.
+  return !(errno == ENOENT);
+}
diff --git a/test/profile/Linux/prctl.c b/test/profile/Linux/prctl.c
new file mode 100644
index 0000000..43baf65
--- /dev/null
+++ b/test/profile/Linux/prctl.c
@@ -0,0 +1,36 @@
+// RUN: %clang_pgogen -O2 -o %t %s
+// RUN: rm -rf default_*.profraw
+// RUN: %run %t && sleep 1
+// RUN: llvm-profdata show default_*.profraw 2>&1 | FileCheck %s
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+
+#define FAKE_COUNT_SZ 2000000
+/* fake counts to increse the profile size. */
+unsigned long long __attribute__((section("__llvm_prf_cnts")))
+counts[FAKE_COUNT_SZ];
+
+int main(int argc, char **argv) {
+  pid_t pid = fork();
+  if (pid == 0) {
+    int i;
+    int sum = 0;
+    /* child process: sleep 500us and get to runtime before the
+     * main process exits. */
+    prctl(PR_SET_PDEATHSIG, SIGKILL);
+    usleep(500);
+    for (i = 0; i < 5000; ++i)
+      sum += i * i * i;
+    printf("child process (%d): sum=%d\n", getpid(), sum);
+  } else if (pid > 0) {
+    /* parent process: sleep 100us to get into profile runtime first. */
+    usleep(100);
+  }
+  return 0;
+}
+
+// CHECK-NOT: Empty raw profile file
diff --git a/test/profile/instrprof-exit-on-signal.c b/test/profile/instrprof-exit-on-signal.c
new file mode 100644
index 0000000..efe1013
--- /dev/null
+++ b/test/profile/instrprof-exit-on-signal.c
@@ -0,0 +1,26 @@
+// RUN: %clang_profgen -o %t %s
+//
+// Verify SIGTERM handling.
+// RUN: %run LLVM_PROFILE_FILE="%15x%t.profraw" %t 15
+// RUN: llvm-profdata show %t.profraw | FileCheck %s
+//
+// Verify SIGUSR1 handling.
+// RUN: %run LLVM_PROFILE_FILE="%30x%t.profraw" %t 30
+// RUN: llvm-profdata show %t.profraw | FileCheck %s
+
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+// CHECK: Total functions: 1
+int main(int argc, char **argv) {
+  (void)argc;
+
+  int sig = atoi(argv[1]);
+  kill(getpid(), sig);
+  
+  while (1) {
+    /* loop forever */
+  }
+  return 1;
+}
diff --git a/test/tsan/Darwin/dispatch_main.mm b/test/tsan/Darwin/dispatch_main.mm
index 7588754..f4c1e44 100644
--- a/test/tsan/Darwin/dispatch_main.mm
+++ b/test/tsan/Darwin/dispatch_main.mm
@@ -2,7 +2,7 @@
 // quits the main thread.
 
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/dispatch_once_deadlock.mm b/test/tsan/Darwin/dispatch_once_deadlock.mm
index e88cdc0..e109f64 100644
--- a/test/tsan/Darwin/dispatch_once_deadlock.mm
+++ b/test/tsan/Darwin/dispatch_once_deadlock.mm
@@ -1,7 +1,7 @@
 // Check that calling dispatch_once from a report callback works.
 
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 not %run %t 2>&1 | FileCheck %s
+// RUN: not %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 #import <pthread.h>
diff --git a/test/tsan/Darwin/external.cc b/test/tsan/Darwin/external.cc
new file mode 100644
index 0000000..2605480
--- /dev/null
+++ b/test/tsan/Darwin/external.cc
@@ -0,0 +1,163 @@
+// RUN: %clangxx_tsan %s -shared -DSHARED_LIB \
+// RUN:                               -o %t-lib-instrumented.dylib \
+// RUN:   -install_name @rpath/`basename %t-lib-instrumented.dylib`
+
+// RUN: %clangxx_tsan %s -shared -DSHARED_LIB -fno-sanitize=thread \
+// RUN:                               -o %t-lib-noninstrumented.dylib \
+// RUN:   -install_name @rpath/`basename %t-lib-noninstrumented.dylib`
+
+// RUN: %clangxx_tsan %s -shared -DSHARED_LIB -fno-sanitize=thread -DUSE_TSAN_CALLBACKS \
+// RUN:                               -o %t-lib-noninstrumented-callbacks.dylib \
+// RUN:   -install_name @rpath/`basename %t-lib-noninstrumented-callbacks.dylib`
+
+// RUN: %clangxx_tsan %s %t-lib-instrumented.dylib -o %t-lib-instrumented
+// RUN: %clangxx_tsan %s %t-lib-noninstrumented.dylib -o %t-lib-noninstrumented
+// RUN: %clangxx_tsan %s %t-lib-noninstrumented-callbacks.dylib -o %t-lib-noninstrumented-callbacks
+
+// RUN: %deflake %run %t-lib-instrumented              2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK --check-prefix=TEST1
+// RUN:          %run %t-lib-noninstrumented           2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK --check-prefix=TEST2
+// RUN: %deflake %run %t-lib-noninstrumented-callbacks 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK --check-prefix=TEST3
+
+#include <thread>
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct MyObject;
+typedef MyObject *MyObjectRef;
+extern "C" {
+  void InitializeLibrary();
+  MyObject *ObjectCreate();
+  long ObjectRead(MyObject *);
+  void ObjectWrite(MyObject *, long);
+  void ObjectWriteAnother(MyObject *, long);
+}
+
+#if defined(SHARED_LIB)
+
+struct MyObject {
+  long _val;
+  long _another;
+};
+
+#if defined(USE_TSAN_CALLBACKS)
+static void *tag;
+void *(*callback_register_tag)(const char *object_type);
+void *(*callback_assign_tag)(void *addr, void *tag);
+void (*callback_read)(void *addr, void *caller_pc, void *tag);
+void (*callback_write)(void *addr, void *caller_pc, void *tag);
+#endif
+
+void InitializeLibrary() {
+#if defined(USE_TSAN_CALLBACKS)
+  callback_register_tag = (decltype(callback_register_tag))dlsym(RTLD_DEFAULT, "__tsan_external_register_tag");
+  callback_assign_tag = (decltype(callback_assign_tag))dlsym(RTLD_DEFAULT, "__tsan_external_assign_tag");
+  callback_read = (decltype(callback_read))dlsym(RTLD_DEFAULT, "__tsan_external_read");
+  callback_write = (decltype(callback_write))dlsym(RTLD_DEFAULT, "__tsan_external_write");
+  tag = callback_register_tag("MyLibrary::MyObject");
+#endif
+}
+
+MyObject *ObjectCreate() {
+  MyObject *ref = (MyObject *)malloc(sizeof(MyObject));
+#if defined(USE_TSAN_CALLBACKS)
+  callback_assign_tag(ref, tag);
+#endif
+  return ref;
+}
+
+long ObjectRead(MyObject *ref) {
+#if defined(USE_TSAN_CALLBACKS)
+  callback_read(ref, __builtin_return_address(0), tag);
+#endif
+  return ref->_val;
+}
+
+void ObjectWrite(MyObject *ref, long val) {
+#if defined(USE_TSAN_CALLBACKS)
+  callback_write(ref, __builtin_return_address(0), tag);
+#endif
+  ref->_val = val;
+}
+
+void ObjectWriteAnother(MyObject *ref, long val) {
+#if defined(USE_TSAN_CALLBACKS)
+  callback_write(ref, __builtin_return_address(0), tag);
+#endif
+  ref->_another = val;
+}
+
+#else  // defined(SHARED_LIB)
+
+int main(int argc, char *argv[]) {
+  InitializeLibrary();
+  
+  {
+    MyObjectRef ref = ObjectCreate();
+    std::thread t1([ref]{ ObjectRead(ref); });
+    std::thread t2([ref]{ ObjectRead(ref); });
+    t1.join();
+    t2.join();
+  }
+  
+  // CHECK-NOT: WARNING: ThreadSanitizer
+  
+  fprintf(stderr, "RR test done\n");
+  // CHECK: RR test done
+
+  {
+    MyObjectRef ref = ObjectCreate();
+    std::thread t1([ref]{ ObjectRead(ref); });
+    std::thread t2([ref]{ ObjectWrite(ref, 66); });
+    t1.join();
+    t2.join();
+  }
+  
+  // TEST1: WARNING: ThreadSanitizer: data race
+  // TEST1: {{Write|Read}} of size 8 at
+  // TEST1: Previous {{write|read}} of size 8 at
+  // TEST1: Location is heap block of size 16 at
+  
+  // TEST2-NOT: WARNING: ThreadSanitizer
+  
+  // TEST3: WARNING: ThreadSanitizer: race on a library object
+  // TEST3: {{Mutating|read-only}} access of object MyLibrary::MyObject at
+  // TEST3: {{ObjectWrite|ObjectRead}}
+  // TEST3: Previous {{mutating|read-only}} access of object MyLibrary::MyObject at
+  // TEST3: {{ObjectWrite|ObjectRead}}
+  // TEST3: Location is MyLibrary::MyObject object of size 16 at
+  // TEST3: {{ObjectCreate}}
+
+  fprintf(stderr, "RW test done\n");
+  // CHECK: RW test done
+
+  {
+    MyObjectRef ref = ObjectCreate();
+    std::thread t1([ref]{ ObjectWrite(ref, 76); });
+    std::thread t2([ref]{ ObjectWriteAnother(ref, 77); });
+    t1.join();
+    t2.join();
+  }
+  
+  // TEST1-NOT: WARNING: ThreadSanitizer: data race
+  
+  // TEST2-NOT: WARNING: ThreadSanitizer
+  
+  // TEST3: WARNING: ThreadSanitizer: race on a library object
+  // TEST3: Mutating access of object MyLibrary::MyObject at
+  // TEST3: {{ObjectWrite|ObjectWriteAnother}}
+  // TEST3: Previous mutating access of object MyLibrary::MyObject at
+  // TEST3: {{ObjectWrite|ObjectWriteAnother}}
+  // TEST3: Location is MyLibrary::MyObject object of size 16 at
+  // TEST3: {{ObjectCreate}}
+
+  fprintf(stderr, "WW test done\n");
+  // CHECK: WW test done
+}
+
+#endif  // defined(SHARED_LIB)
diff --git a/test/tsan/Darwin/gcd-after-null.mm b/test/tsan/Darwin/gcd-after-null.mm
new file mode 100644
index 0000000..7c9913c
--- /dev/null
+++ b/test/tsan/Darwin/gcd-after-null.mm
@@ -0,0 +1,23 @@
+// Regression test to make sure we don't crash when dispatch_after is called with a NULL queue.
+
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+int main(int argc, const char *argv[]) {
+  fprintf(stderr, "start\n");
+
+  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_MSEC)), NULL, ^{
+    dispatch_async(dispatch_get_main_queue(), ^{
+      CFRunLoopStop(CFRunLoopGetMain());
+    });
+  });
+  CFRunLoopRun();
+
+  fprintf(stderr, "done\n");
+  return 0;
+}
+
+// CHECK: start
+// CHECK: done
diff --git a/test/tsan/Darwin/gcd-after.mm b/test/tsan/Darwin/gcd-after.mm
index 49b6bc6..4d66c50 100644
--- a/test/tsan/Darwin/gcd-after.mm
+++ b/test/tsan/Darwin/gcd-after.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-apply-race.mm b/test/tsan/Darwin/gcd-apply-race.mm
index 028be1a..a7bf663 100644
--- a/test/tsan/Darwin/gcd-apply-race.mm
+++ b/test/tsan/Darwin/gcd-apply-race.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-apply.mm b/test/tsan/Darwin/gcd-apply.mm
index a7dc374..d9d2562 100644
--- a/test/tsan/Darwin/gcd-apply.mm
+++ b/test/tsan/Darwin/gcd-apply.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-async-norace.mm b/test/tsan/Darwin/gcd-async-norace.mm
index c7e28b4..83f8c0d 100644
--- a/test/tsan/Darwin/gcd-async-norace.mm
+++ b/test/tsan/Darwin/gcd-async-norace.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-async-race.mm b/test/tsan/Darwin/gcd-async-race.mm
index 1002a56..cb8fb4b 100644
--- a/test/tsan/Darwin/gcd-async-race.mm
+++ b/test/tsan/Darwin/gcd-async-race.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-barrier-race.mm b/test/tsan/Darwin/gcd-barrier-race.mm
index c42eaeb..c11e147 100644
--- a/test/tsan/Darwin/gcd-barrier-race.mm
+++ b/test/tsan/Darwin/gcd-barrier-race.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-barrier.mm b/test/tsan/Darwin/gcd-barrier.mm
index 6f58cae..9d4dcb2 100644
--- a/test/tsan/Darwin/gcd-barrier.mm
+++ b/test/tsan/Darwin/gcd-barrier.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-blocks.mm b/test/tsan/Darwin/gcd-blocks.mm
index e008260..1aac7e1 100644
--- a/test/tsan/Darwin/gcd-blocks.mm
+++ b/test/tsan/Darwin/gcd-blocks.mm
@@ -1,5 +1,5 @@
 // RUN: %clangxx_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-data.mm b/test/tsan/Darwin/gcd-data.mm
index a5154dc..d451cf5 100644
--- a/test/tsan/Darwin/gcd-data.mm
+++ b/test/tsan/Darwin/gcd-data.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-fd.mm b/test/tsan/Darwin/gcd-fd.mm
index 75da9cd..838cf20 100644
--- a/test/tsan/Darwin/gcd-fd.mm
+++ b/test/tsan/Darwin/gcd-fd.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-groups-destructor.mm b/test/tsan/Darwin/gcd-groups-destructor.mm
index 19c2c9b..05c65c0 100644
--- a/test/tsan/Darwin/gcd-groups-destructor.mm
+++ b/test/tsan/Darwin/gcd-groups-destructor.mm
@@ -1,5 +1,5 @@
 // RUN: %clangxx_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-groups-leave.mm b/test/tsan/Darwin/gcd-groups-leave.mm
index 6ecf85f..49fd8e2 100644
--- a/test/tsan/Darwin/gcd-groups-leave.mm
+++ b/test/tsan/Darwin/gcd-groups-leave.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-groups-norace.mm b/test/tsan/Darwin/gcd-groups-norace.mm
index 64ec386..e850169 100644
--- a/test/tsan/Darwin/gcd-groups-norace.mm
+++ b/test/tsan/Darwin/gcd-groups-norace.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-groups-stress.mm b/test/tsan/Darwin/gcd-groups-stress.mm
index 457d9af..cfe4deb 100644
--- a/test/tsan/Darwin/gcd-groups-stress.mm
+++ b/test/tsan/Darwin/gcd-groups-stress.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-io-barrier-race.mm b/test/tsan/Darwin/gcd-io-barrier-race.mm
index fffc19b..137c3b2 100644
--- a/test/tsan/Darwin/gcd-io-barrier-race.mm
+++ b/test/tsan/Darwin/gcd-io-barrier-race.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-io-barrier.mm b/test/tsan/Darwin/gcd-io-barrier.mm
index fe30138..af92b03 100644
--- a/test/tsan/Darwin/gcd-io-barrier.mm
+++ b/test/tsan/Darwin/gcd-io-barrier.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-io-cleanup.mm b/test/tsan/Darwin/gcd-io-cleanup.mm
index b15fa0d..570e37d 100644
--- a/test/tsan/Darwin/gcd-io-cleanup.mm
+++ b/test/tsan/Darwin/gcd-io-cleanup.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-io-race.mm b/test/tsan/Darwin/gcd-io-race.mm
index 0bec28f..99000fc 100644
--- a/test/tsan/Darwin/gcd-io-race.mm
+++ b/test/tsan/Darwin/gcd-io-race.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
 
 // REQUIRES: disabled
 
diff --git a/test/tsan/Darwin/gcd-io.mm b/test/tsan/Darwin/gcd-io.mm
index 4a1726d..70ded40 100644
--- a/test/tsan/Darwin/gcd-io.mm
+++ b/test/tsan/Darwin/gcd-io.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-once.mm b/test/tsan/Darwin/gcd-once.mm
index 3e4a533..70e588a 100644
--- a/test/tsan/Darwin/gcd-once.mm
+++ b/test/tsan/Darwin/gcd-once.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-semaphore-norace.mm b/test/tsan/Darwin/gcd-semaphore-norace.mm
index 20bc572..fd5d146 100644
--- a/test/tsan/Darwin/gcd-semaphore-norace.mm
+++ b/test/tsan/Darwin/gcd-semaphore-norace.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-serial-queue-norace.mm b/test/tsan/Darwin/gcd-serial-queue-norace.mm
index 95efbb7..8754b618 100644
--- a/test/tsan/Darwin/gcd-serial-queue-norace.mm
+++ b/test/tsan/Darwin/gcd-serial-queue-norace.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-source-cancel.mm b/test/tsan/Darwin/gcd-source-cancel.mm
index 86e1b28..8aa6f10 100644
--- a/test/tsan/Darwin/gcd-source-cancel.mm
+++ b/test/tsan/Darwin/gcd-source-cancel.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-source-cancel2.mm b/test/tsan/Darwin/gcd-source-cancel2.mm
index 956fe87..92b31d7 100644
--- a/test/tsan/Darwin/gcd-source-cancel2.mm
+++ b/test/tsan/Darwin/gcd-source-cancel2.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-source-event.mm b/test/tsan/Darwin/gcd-source-event.mm
index e50cb56..e707b65 100644
--- a/test/tsan/Darwin/gcd-source-event.mm
+++ b/test/tsan/Darwin/gcd-source-event.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-source-event2.mm b/test/tsan/Darwin/gcd-source-event2.mm
index c45d481..b10e474 100644
--- a/test/tsan/Darwin/gcd-source-event2.mm
+++ b/test/tsan/Darwin/gcd-source-event2.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-source-registration.mm b/test/tsan/Darwin/gcd-source-registration.mm
index db22613..d6d339f 100644
--- a/test/tsan/Darwin/gcd-source-registration.mm
+++ b/test/tsan/Darwin/gcd-source-registration.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-source-registration2.mm b/test/tsan/Darwin/gcd-source-registration2.mm
index 4431bc9..6365787 100644
--- a/test/tsan/Darwin/gcd-source-registration2.mm
+++ b/test/tsan/Darwin/gcd-source-registration2.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-source-serial.mm b/test/tsan/Darwin/gcd-source-serial.mm
index c0989fc..9922030 100644
--- a/test/tsan/Darwin/gcd-source-serial.mm
+++ b/test/tsan/Darwin/gcd-source-serial.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-suspend.mm b/test/tsan/Darwin/gcd-suspend.mm
index 3e8818a..561e7c0 100644
--- a/test/tsan/Darwin/gcd-suspend.mm
+++ b/test/tsan/Darwin/gcd-suspend.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-sync-norace.mm b/test/tsan/Darwin/gcd-sync-norace.mm
index c683524..18bf973 100644
--- a/test/tsan/Darwin/gcd-sync-norace.mm
+++ b/test/tsan/Darwin/gcd-sync-norace.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-sync-race.mm b/test/tsan/Darwin/gcd-sync-race.mm
index 650faa4..b7f3266 100644
--- a/test/tsan/Darwin/gcd-sync-race.mm
+++ b/test/tsan/Darwin/gcd-sync-race.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/gcd-target-queue-norace.mm b/test/tsan/Darwin/gcd-target-queue-norace.mm
index 36cb1b9..fbfa658 100644
--- a/test/tsan/Darwin/gcd-target-queue-norace.mm
+++ b/test/tsan/Darwin/gcd-target-queue-norace.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/ignore-noninstrumented.mm b/test/tsan/Darwin/ignore-noninstrumented.mm
index 5e44531..528e07b 100644
--- a/test/tsan/Darwin/ignore-noninstrumented.mm
+++ b/test/tsan/Darwin/ignore-noninstrumented.mm
@@ -3,7 +3,7 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
 
 // Check that without the flag, there are false positives.
-// RUN: %deflake %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-RACE
+// RUN: %env_tsan_opts=ignore_noninstrumented_modules=0 %deflake %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-RACE
 
 // With ignore_noninstrumented_modules=1, no races are reported.
 // RUN: %env_tsan_opts=ignore_noninstrumented_modules=1 %run %t 2>&1 | FileCheck %s
diff --git a/test/tsan/Darwin/ignored-interceptors.mm b/test/tsan/Darwin/ignored-interceptors.mm
index d513142..1105132 100644
--- a/test/tsan/Darwin/ignored-interceptors.mm
+++ b/test/tsan/Darwin/ignored-interceptors.mm
@@ -6,13 +6,13 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
 
 // Check that without the flag, there are false positives.
-// RUN: %deflake %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-RACE
+// RUN: %env_tsan_opts=ignore_noninstrumented_modules=0 %deflake %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-RACE
 
 // With ignore_interceptors_accesses=1, no races are reported.
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %env_tsan_opts=ignore_noninstrumented_modules=0:ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
 
 // With ignore_interceptors_accesses=1, races in user's code are still reported.
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t race 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-RACE
+// RUN: %env_tsan_opts=ignore_noninstrumented_modules=0:ignore_interceptors_accesses=1 %deflake %run %t race 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-RACE
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/libcxx-call-once.mm b/test/tsan/Darwin/libcxx-call-once.mm
index 5388e49..ba4615f 100644
--- a/test/tsan/Darwin/libcxx-call-once.mm
+++ b/test/tsan/Darwin/libcxx-call-once.mm
@@ -1,5 +1,5 @@
 // RUN: %clangxx_tsan %s -o %t -framework Foundation -std=c++11
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/libcxx-future.mm b/test/tsan/Darwin/libcxx-future.mm
index 902f267..720c2e0 100644
--- a/test/tsan/Darwin/libcxx-future.mm
+++ b/test/tsan/Darwin/libcxx-future.mm
@@ -1,5 +1,5 @@
 // RUN: %clangxx_tsan %s -o %t
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #include <iostream>
 #include <future>
diff --git a/test/tsan/Darwin/libcxx-shared-ptr-recursive.mm b/test/tsan/Darwin/libcxx-shared-ptr-recursive.mm
index eea02dc..a9a3a96 100644
--- a/test/tsan/Darwin/libcxx-shared-ptr-recursive.mm
+++ b/test/tsan/Darwin/libcxx-shared-ptr-recursive.mm
@@ -1,5 +1,5 @@
 // RUN: %clangxx_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/libcxx-shared-ptr-stress.mm b/test/tsan/Darwin/libcxx-shared-ptr-stress.mm
index 7c36729..e5cd7ed 100644
--- a/test/tsan/Darwin/libcxx-shared-ptr-stress.mm
+++ b/test/tsan/Darwin/libcxx-shared-ptr-stress.mm
@@ -1,5 +1,5 @@
 // RUN: %clangxx_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/libcxx-shared-ptr.mm b/test/tsan/Darwin/libcxx-shared-ptr.mm
index 6187c43..057ff22 100644
--- a/test/tsan/Darwin/libcxx-shared-ptr.mm
+++ b/test/tsan/Darwin/libcxx-shared-ptr.mm
@@ -1,5 +1,5 @@
 // RUN: %clangxx_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/lit.local.cfg b/test/tsan/Darwin/lit.local.cfg
index a85dfcd..e74e82d 100644
--- a/test/tsan/Darwin/lit.local.cfg
+++ b/test/tsan/Darwin/lit.local.cfg
@@ -7,3 +7,5 @@
 
 if root.host_os not in ['Darwin']:
   config.unsupported = True
+
+config.environment['TSAN_OPTIONS'] += ':ignore_noninstrumented_modules=1'
diff --git a/test/tsan/Darwin/main_tid.mm b/test/tsan/Darwin/main_tid.mm
new file mode 100644
index 0000000..af658e4
--- /dev/null
+++ b/test/tsan/Darwin/main_tid.mm
@@ -0,0 +1,46 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
+
+#import <pthread.h>
+#import <stdio.h>
+#import <stdlib.h>
+
+extern "C" {
+void __tsan_on_report(void *report);
+int __tsan_get_report_thread(void *report, unsigned long idx, int *tid,
+                             unsigned long *os_id, int *running,
+                             const char **name, int *parent_tid, void **trace,
+                             unsigned long trace_size);
+}
+
+void __tsan_on_report(void *report) {
+  fprintf(stderr, "__tsan_on_report(%p)\n", report);
+
+  int tid;
+  unsigned long os_id;
+  int running;
+  const char *name;
+  int parent_tid;
+  void *trace[16] = {0};
+  __tsan_get_report_thread(report, 0, &tid, &os_id, &running, &name, &parent_tid, trace, 16);
+  fprintf(stderr, "tid = %d, os_id = %lu\n", tid, os_id);
+}
+
+int main() {
+  fprintf(stderr, "Hello world.\n");
+
+  uint64_t threadid;
+  pthread_threadid_np(NULL, &threadid);
+  fprintf(stderr, "pthread_threadid_np = %llu\n", threadid);
+
+  pthread_mutex_t m;
+  pthread_mutex_init(&m, NULL);
+  pthread_mutex_unlock(&m);
+  fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: pthread_threadid_np = [[ADDR:[0-9]+]]
+// CHECK: WARNING: ThreadSanitizer
+// CHECK: tid = 0, os_id = [[ADDR]]
+// CHECK: Done.
diff --git a/test/tsan/Darwin/norace-objcxx-run-time.mm b/test/tsan/Darwin/norace-objcxx-run-time.mm
index 0cf729e..1de431a 100644
--- a/test/tsan/Darwin/norace-objcxx-run-time.mm
+++ b/test/tsan/Darwin/norace-objcxx-run-time.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -lc++ -fobjc-arc -lobjc -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 // Check that we do not report races between:
 // - Object retain and initialize
diff --git a/test/tsan/Darwin/objc-double-property.mm b/test/tsan/Darwin/objc-double-property.mm
index 51b10f2..c99151d 100644
--- a/test/tsan/Darwin/objc-double-property.mm
+++ b/test/tsan/Darwin/objc-double-property.mm
@@ -1,7 +1,7 @@
-// RUN: %clangxx_tsan -O0 %s -o %t -framework Foundation && %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
-// RUN: %clangxx_tsan -O1 %s -o %t -framework Foundation && %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
-// RUN: %clangxx_tsan -O2 %s -o %t -framework Foundation && %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
-// RUN: %clangxx_tsan -O3 %s -o %t -framework Foundation && %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O0 %s -o %t -framework Foundation && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O1 %s -o %t -framework Foundation && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O2 %s -o %t -framework Foundation && %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_tsan -O3 %s -o %t -framework Foundation && %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/objc-simple.mm b/test/tsan/Darwin/objc-simple.mm
index a8fc355..b62d0eb 100644
--- a/test/tsan/Darwin/objc-simple.mm
+++ b/test/tsan/Darwin/objc-simple.mm
@@ -1,7 +1,7 @@
 // Test that a simple Obj-C program runs and exits without any warnings.
 
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 
diff --git a/test/tsan/Darwin/workerthreads.mm b/test/tsan/Darwin/workerthreads.mm
new file mode 100644
index 0000000..18369fd
--- /dev/null
+++ b/test/tsan/Darwin/workerthreads.mm
@@ -0,0 +1,43 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+
+#import "../test.h"
+
+long global;
+
+int main() {
+  fprintf(stderr, "Hello world.\n");
+  print_address("addr=", 1, &global);
+  barrier_init(&barrier, 2);
+
+  global = 42;
+  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+    global = 43;
+    barrier_wait(&barrier);
+  });
+
+  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+    barrier_wait(&barrier);
+    global = 44;
+
+    dispatch_sync(dispatch_get_main_queue(), ^{
+      CFRunLoopStop(CFRunLoopGetCurrent());
+    });
+  });
+
+  CFRunLoopRun();
+  fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK: Write of size 8
+// CHECK: Previous write of size 8
+// CHECK: Location is global
+// CHECK: Thread {{.*}} is a GCD worker thread
+// CHECK-NOT: failed to restore the stack
+// CHECK: Thread {{.*}} is a GCD worker thread
+// CHECK-NOT: failed to restore the stack
+// CHECK: Done.
diff --git a/test/tsan/Darwin/xpc-cancel.mm b/test/tsan/Darwin/xpc-cancel.mm
new file mode 100644
index 0000000..5e326b7
--- /dev/null
+++ b/test/tsan/Darwin/xpc-cancel.mm
@@ -0,0 +1,37 @@
+// RUN: %clang_tsan %s -o %t -framework Foundation
+// RUN: %run %t 2>&1 | FileCheck %s
+
+#import <Foundation/Foundation.h>
+#import <xpc/xpc.h>
+
+long global;
+
+int main(int argc, const char *argv[]) {
+  fprintf(stderr, "Hello world.\n");
+
+  dispatch_queue_t server_q = dispatch_queue_create("server.queue", DISPATCH_QUEUE_CONCURRENT);
+  xpc_connection_t server_conn = xpc_connection_create(NULL, server_q);
+
+  xpc_connection_set_event_handler(server_conn, ^(xpc_object_t client) {
+    if (client == XPC_ERROR_CONNECTION_INTERRUPTED || client == XPC_ERROR_CONNECTION_INVALID) {
+      global = 43;
+      
+      dispatch_async(dispatch_get_main_queue(), ^{
+        CFRunLoopStop(CFRunLoopGetCurrent());
+      });
+    }
+  });
+  xpc_connection_resume(server_conn);
+  
+  global = 42;
+  
+  xpc_connection_cancel(server_conn);
+  
+  CFRunLoopRun();
+
+  fprintf(stderr, "Done.\n");
+}
+
+// CHECK: Hello world.
+// CHECK-NOT: WARNING: ThreadSanitizer
+// CHECK: Done.
diff --git a/test/tsan/Darwin/xpc-race.mm b/test/tsan/Darwin/xpc-race.mm
index 9141da4..eaef4e0 100644
--- a/test/tsan/Darwin/xpc-race.mm
+++ b/test/tsan/Darwin/xpc-race.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 #import <xpc/xpc.h>
diff --git a/test/tsan/Darwin/xpc.mm b/test/tsan/Darwin/xpc.mm
index a939b02..2d6de26 100644
--- a/test/tsan/Darwin/xpc.mm
+++ b/test/tsan/Darwin/xpc.mm
@@ -1,5 +1,5 @@
 // RUN: %clang_tsan %s -o %t -framework Foundation
-// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
+// RUN: %run %t 2>&1 | FileCheck %s
 
 #import <Foundation/Foundation.h>
 #import <xpc/xpc.h>
diff --git a/test/tsan/Unit/lit.site.cfg.in b/test/tsan/Unit/lit.site.cfg.in
index 23894a8..40cf096 100644
--- a/test/tsan/Unit/lit.site.cfg.in
+++ b/test/tsan/Unit/lit.site.cfg.in
@@ -11,3 +11,13 @@
 # FIXME: De-hardcode this path.
 config.test_exec_root = "@COMPILER_RT_BINARY_DIR@/lib/tsan/tests"
 config.test_source_root = config.test_exec_root
+
+if config.host_os == 'Darwin':
+  config.parallelism_group = config.darwin_sanitizer_parallelism_group_func
+
+  # On Darwin, we default to ignore_noninstrumented_modules=1, which also
+  # suppresses some races the tests are supposed to find.  See tsan/lit.cfg.
+  if 'TSAN_OPTIONS' in config.environment:
+    config.environment['TSAN_OPTIONS'] += ':ignore_noninstrumented_modules=0'
+  else:
+    config.environment['TSAN_OPTIONS'] = 'ignore_noninstrumented_modules=0'
diff --git a/test/tsan/debug_external.cc b/test/tsan/debug_external.cc
new file mode 100644
index 0000000..1b340b2
--- /dev/null
+++ b/test/tsan/debug_external.cc
@@ -0,0 +1,66 @@
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: %deflake %run %t 2>&1 | FileCheck %s
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "test.h"
+
+extern "C" {
+void __tsan_on_report(void *report);
+int __tsan_get_report_loc(void *report, unsigned long idx, const char **type,
+                          void **addr, void **start,
+                          unsigned long *size, int *tid, int *fd,
+                          int *suppressable, void **trace,
+                          unsigned long trace_size);
+int __tsan_get_report_loc_object_type(void *report, unsigned long idx,
+                                      const char **object_type);
+void *__tsan_external_register_tag(const char *object_type);
+void __tsan_external_assign_tag(void *addr, void *tag);
+}
+
+void *Thread(void *arg) {
+  barrier_wait(&barrier);
+  *((long *)arg) = 42;
+  return NULL;
+}
+
+int main() {
+  barrier_init(&barrier, 2);
+  void *tag = __tsan_external_register_tag("MyObject");
+  long *obj = (long *)malloc(sizeof(long));
+  fprintf(stderr, "obj = %p\n", obj);
+  // CHECK: obj = [[ADDR:0x[0-9a-f]+]]
+  __tsan_external_assign_tag(obj, tag);
+
+  pthread_t t;
+  pthread_create(&t, 0, Thread, obj);
+  *obj = 41;
+  barrier_wait(&barrier);
+  pthread_join(t, 0);
+  fprintf(stderr, "Done.\n");
+  return 0;
+}
+
+void __tsan_on_report(void *report) {
+  const char *type;
+  void *addr;
+  void *start;
+  unsigned long size;
+  int tid, fd, suppressable;
+  void *trace[16] = {0};
+  __tsan_get_report_loc(report, 0, &type, &addr, &start, &size, &tid, &fd,
+                        &suppressable, trace, 16);
+  fprintf(stderr, "type = %s, start = %p, size = %ld\n", type, start, size);
+  // CHECK: type = heap, start = [[ADDR]], size = 8
+
+  const char *object_type;
+  __tsan_get_report_loc_object_type(report, 0, &object_type);
+  fprintf(stderr, "object_type = %s\n", object_type);
+  // CHECK: object_type = MyObject
+}
+
+// CHECK: Done.
+// CHECK: ThreadSanitizer: reported 1 warnings
diff --git a/test/tsan/lit.cfg b/test/tsan/lit.cfg
index 5d82cc9..3c98d1f 100644
--- a/test/tsan/lit.cfg
+++ b/test/tsan/lit.cfg
@@ -24,6 +24,10 @@
   # On Darwin, we default to `abort_on_error=1`, which would make tests run
   # much slower. Let's override this and run lit tests with 'abort_on_error=0'.
   default_tsan_opts += ':abort_on_error=0'
+  # On Darwin, we default to ignore_noninstrumented_modules=1, which also
+  # suppresses some races the tests are supposed to find. Let's run without this
+  # setting, but turn it back on for Darwin tests (see Darwin/lit.local.cfg).
+  default_tsan_opts += ':ignore_noninstrumented_modules=0'
 
 # Platform-specific default TSAN_OPTIONS for lit tests.
 if default_tsan_opts:
@@ -83,3 +87,6 @@
 # because the test hangs.
 if config.target_arch != 'aarch64':
   config.available_features.add('stable-runtime')
+
+if config.host_os == 'Darwin' and config.target_arch in ["x86_64", "x86_64h"]:
+  config.parallelism_group = "darwin-64bit-sanitizer"
diff --git a/test/ubsan/TestCases/Float/cast-overflow.cpp b/test/ubsan/TestCases/Float/cast-overflow.cpp
index 5f51553..85c5049 100644
--- a/test/ubsan/TestCases/Float/cast-overflow.cpp
+++ b/test/ubsan/TestCases/Float/cast-overflow.cpp
@@ -86,42 +86,42 @@
   case '0': {
     // Note that values between 0x7ffffe00 and 0x80000000 may or may not
     // successfully round-trip, depending on the rounding mode.
-    // CHECK-0: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: value 2.14748{{.*}} is outside the range of representable values of type 'int'
+    // CHECK-0: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: 2.14748{{.*}} is outside the range of representable values of type 'int'
     static int test_int = MaxFloatRepresentableAsInt + 0x80;
     // CHECK-0: SUMMARY: {{.*}}Sanitizer: float-cast-overflow {{.*}}cast-overflow.cpp:[[@LINE-1]]
     return 0;
     }
   case '1': {
-    // CHECK-1: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: value -2.14748{{.*}} is outside the range of representable values of type 'int'
+    // CHECK-1: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: -2.14748{{.*}} is outside the range of representable values of type 'int'
     static int test_int = MinFloatRepresentableAsInt - 0x100;
     return 0;
   }
   case '2': {
-    // CHECK-2: {{.*}}cast-overflow.cpp:[[@LINE+2]]:37: runtime error: value -1 is outside the range of representable values of type 'unsigned int'
+    // CHECK-2: {{.*}}cast-overflow.cpp:[[@LINE+2]]:37: runtime error: -1 is outside the range of representable values of type 'unsigned int'
     volatile float f = -1.0;
     volatile unsigned u = (unsigned)f;
     return 0;
   }
   case '3': {
-    // CHECK-3: {{.*}}cast-overflow.cpp:[[@LINE+1]]:37: runtime error: value 4.2949{{.*}} is outside the range of representable values of type 'unsigned int'
+    // CHECK-3: {{.*}}cast-overflow.cpp:[[@LINE+1]]:37: runtime error: 4.2949{{.*}} is outside the range of representable values of type 'unsigned int'
     static int test_int = (unsigned)(MaxFloatRepresentableAsUInt + 0x100);
     return 0;
   }
 
   case '4': {
-    // CHECK-4: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: value {{.*}} is outside the range of representable values of type 'int'
+    // CHECK-4: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: {{.*}} is outside the range of representable values of type 'int'
     static int test_int = Inf;
     return 0;
   }
   case '5': {
-    // CHECK-5: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: value {{.*}} is outside the range of representable values of type 'int'
+    // CHECK-5: {{.*}}cast-overflow.cpp:[[@LINE+1]]:27: runtime error: {{.*}} is outside the range of representable values of type 'int'
     static int test_int = NaN;
     return 0;
   }
 
     // Integer -> floating point overflow.
   case '6': {
-    // CHECK-6: cast-overflow.cpp:[[@LINE+2]]:{{34: runtime error: value 0xffffff00000000000000000000000001 is outside the range of representable values of type 'float'| __int128 not supported}}
+    // CHECK-6: cast-overflow.cpp:[[@LINE+2]]:{{34: runtime error: 0xffffff00000000000000000000000001 is outside the range of representable values of type 'float'| __int128 not supported}}
 #if defined(__SIZEOF_INT128__) && !defined(_WIN32)
     static int test_int = (float)(FloatMaxAsUInt128 + 1);
     return 0;
@@ -135,16 +135,16 @@
   // FIXME: The backend cannot lower __fp16 operations on x86 yet.
   //case '7':
   //  (__fp16)65504; // ok
-  //  // CHECK-7: runtime error: value 65505 is outside the range of representable values of type '__fp16'
+  //  // CHECK-7: runtime error: 65505 is outside the range of representable values of type '__fp16'
   //  return (__fp16)65505;
 
     // Floating point -> floating point overflow.
   case '8':
-    // CHECK-8: {{.*}}cast-overflow.cpp:[[@LINE+1]]:19: runtime error: value 1e+39 is outside the range of representable values of type 'float'
+    // CHECK-8: {{.*}}cast-overflow.cpp:[[@LINE+1]]:19: runtime error: 1e+39 is outside the range of representable values of type 'float'
     return (float)1e39;
   case '9':
     volatile long double ld = 300.0;
-    // CHECK-9: {{.*}}cast-overflow.cpp:[[@LINE+1]]:14: runtime error: value 300 is outside the range of representable values of type 'char'
+    // CHECK-9: {{.*}}cast-overflow.cpp:[[@LINE+1]]:14: runtime error: 300 is outside the range of representable values of type 'char'
     char c = ld;
     return c;
   }
diff --git a/test/ubsan/TestCases/Integer/summary.cpp b/test/ubsan/TestCases/Integer/summary.cpp
index e687afa..8726c14 100644
--- a/test/ubsan/TestCases/Integer/summary.cpp
+++ b/test/ubsan/TestCases/Integer/summary.cpp
@@ -7,7 +7,7 @@
 
 int main() {
   (void)(uint64_t(10000000000000000000ull) + uint64_t(9000000000000000000ull));
-  // CHECK-NOTYPE: SUMMARY: AddressSanitizer: undefined-behavior {{.*}}summary.cpp:[[@LINE-1]]:44
-  // CHECK-TYPE: SUMMARY: AddressSanitizer: unsigned-integer-overflow {{.*}}summary.cpp:[[@LINE-2]]:44
+  // CHECK-NOTYPE: SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior {{.*}}summary.cpp:[[@LINE-1]]:44
+  // CHECK-TYPE: SUMMARY: UndefinedBehaviorSanitizer: unsigned-integer-overflow {{.*}}summary.cpp:[[@LINE-2]]:44
   return 0;
 }
diff --git a/test/ubsan/TestCases/Misc/bool.m b/test/ubsan/TestCases/Misc/bool.m
new file mode 100644
index 0000000..0430b45
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/bool.m
@@ -0,0 +1,14 @@
+// RUN: %clang -fsanitize=bool %s -O3 -o %t
+// RUN: not %run %t 2>&1 | FileCheck %s
+// RUN: %env_ubsan_opts=print_summary=1:report_error_type=1 not %run %t 2>&1 | FileCheck %s --check-prefix=SUMMARY
+
+typedef char BOOL;
+unsigned char NotABool = 123;
+
+int main(int argc, char **argv) {
+  BOOL *p = (BOOL*)&NotABool;
+
+  // CHECK: bool.m:[[@LINE+1]]:10: runtime error: load of value 123, which is not a valid value for type 'BOOL'
+  return *p;
+  // SUMMARY: SUMMARY: {{.*}}Sanitizer: invalid-bool-load {{.*}}bool.m:[[@LINE-1]]
+}
diff --git a/test/ubsan/TestCases/Misc/log-path_test.cc b/test/ubsan/TestCases/Misc/log-path_test.cc
index 5b45f0b..40bb35a 100644
--- a/test/ubsan/TestCases/Misc/log-path_test.cc
+++ b/test/ubsan/TestCases/Misc/log-path_test.cc
@@ -32,5 +32,5 @@
   return 0;
 }
 
-// CHECK-ERROR: runtime error: value -4 is outside the range of representable values of type 'unsigned int'
+// CHECK-ERROR: runtime error: -4 is outside the range of representable values of type 'unsigned int'
 
diff --git a/test/ubsan/TestCases/Misc/missing_return.cpp b/test/ubsan/TestCases/Misc/missing_return.cpp
index 6808227..7b56b97 100644
--- a/test/ubsan/TestCases/Misc/missing_return.cpp
+++ b/test/ubsan/TestCases/Misc/missing_return.cpp
@@ -1,13 +1,10 @@
 // RUN: %clangxx -fsanitize=return -g %s -O3 -o %t
 // RUN: not %run %t 2>&1 | FileCheck %s
-// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%os-STACKTRACE
+// RUN: %env_ubsan_opts=print_stacktrace=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-STACKTRACE
 
 // CHECK: missing_return.cpp:[[@LINE+1]]:5: runtime error: execution reached the end of a value-returning function without returning a value
 int f() {
-// Slow stack unwinding is not available on Darwin for now, see
-// https://code.google.com/p/address-sanitizer/issues/detail?id=137
-// CHECK-Linux-STACKTRACE: #0 {{.*}}f(){{.*}}missing_return.cpp:[[@LINE-3]]
-// CHECK-FreeBSD-STACKTRACE: #0 {{.*}}f(void){{.*}}missing_return.cpp:[[@LINE-4]]
+// CHECK-STACKTRACE: #0 {{.*}}f{{.*}}missing_return.cpp:[[@LINE-1]]
 }
 
 int main(int, char **argv) {
diff --git a/test/ubsan/TestCases/Misc/nullability.c b/test/ubsan/TestCases/Misc/nullability.c
new file mode 100644
index 0000000..37b8ddc
--- /dev/null
+++ b/test/ubsan/TestCases/Misc/nullability.c
@@ -0,0 +1,64 @@
+// RUN: %clang -w -fsanitize=nullability-arg,nullability-assign,nullability-return %s -O3 -o %t
+// RUN: %run %t foo 2>&1 | count 0
+// RUN: %run %t 2>&1 | FileCheck %s
+
+// CHECK: nullability.c:[[@LINE+2]]:51: runtime error: null pointer returned from function declared to never return null
+// CHECK-NEXT: nullability.c:[[@LINE+1]]:6: note: _Nonnull return type annotation specified here
+int *_Nonnull nonnull_retval1(int *p) { return p; }
+
+// CHECK: nullability.c:1001:19: runtime error: null pointer passed as argument 1, which is declared to never be null
+// CHECK-NEXT: nullability.c:[[@LINE+3]]:36: note: _Nonnull type annotation specified here
+// CHECK: nullability.c:1001:22: runtime error: null pointer passed as argument 2, which is declared to never be null
+// CHECK-NEXT: nullability.c:[[@LINE+1]]:56: note: _Nonnull type annotation specified here
+int *_Nonnull nonnull_retval2(int *_Nonnull arg1, int *_Nonnull arg2,
+                              int *_Nullable arg3, int *arg4, int arg5, ...) {
+  return arg1;
+}
+
+// CHECK: nullability.c:1002:15: runtime error: null pointer passed as argument 1, which is declared to never be null
+// CHECK-NEXT: nullability.c:[[@LINE+1]]:23: note: _Nonnull type annotation specified here
+void nonnull_arg(int *_Nonnull p) {}
+
+void nonnull_assign1(int *p) {
+  int *_Nonnull local;
+// CHECK: nullability.c:[[@LINE+1]]:9: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull'
+  local = p;
+}
+
+void nonnull_assign2(int *p) {
+  int *_Nonnull arr[1];
+  // CHECK: nullability.c:[[@LINE+1]]:10: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull'
+  arr[0] = p;
+}
+
+struct S1 {
+  int *_Nonnull mptr;
+};
+
+void nonnull_assign3(int *p) {
+  struct S1 s;
+  // CHECK: nullability.c:[[@LINE+1]]:10: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull'
+  s.mptr = p;
+}
+
+// CHECK: nullability.c:[[@LINE+1]]:52: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull'
+void nonnull_init1(int *p) { int *_Nonnull local = p; }
+
+// CHECK: nullability.c:[[@LINE+2]]:53: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull'
+// CHECK: nullability.c:[[@LINE+1]]:56: runtime error: _Nonnull binding to null pointer of type 'int * _Nonnull'
+void nonnull_init2(int *p) { int *_Nonnull arr[] = {p, p}; }
+
+int main(int argc, char **argv) {
+  int *p = (argc > 1) ? &argc : ((int *)0);
+
+#line 1000
+  nonnull_retval1(p);
+  nonnull_retval2(p, p, p, p, 0, 0, 0, 0);
+  nonnull_arg(p);
+  nonnull_assign1(p);
+  nonnull_assign2(p);
+  nonnull_assign3(p);
+  nonnull_init1(p);
+  nonnull_init2(p);
+  return 0;
+}
diff --git a/test/ubsan/TestCases/TypeCheck/misaligned.cpp b/test/ubsan/TestCases/TypeCheck/misaligned.cpp
index 35b1ec3..b3ff358 100644
--- a/test/ubsan/TestCases/TypeCheck/misaligned.cpp
+++ b/test/ubsan/TestCases/TypeCheck/misaligned.cpp
@@ -11,7 +11,7 @@
 // RUN: %run %t f1 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN
 // RUN: %run %t n1 2>&1 | FileCheck %s --check-prefix=CHECK-NEW
 // RUN: %run %t u1 2>&1 | FileCheck %s --check-prefix=CHECK-UPCAST
-// RUN: %env_ubsan_opts=print_stacktrace=1 %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --check-prefix=CHECK-%os-STACK-LOAD
+// RUN: %env_ubsan_opts=print_stacktrace=1 %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --check-prefix=CHECK-STACK-LOAD
 
 // RUN: %clangxx -fsanitize=alignment -fno-sanitize-recover=alignment %s -O3 -o %t
 // RUN: not %run %t w1 2>&1 | FileCheck %s --check-prefix=CHECK-WILD
@@ -47,11 +47,7 @@
     // CHECK-LOAD-NEXT: {{^ 00 00 00 01 02 03 04  05}}
     // CHECK-LOAD-NEXT: {{^             \^}}
     return *p && 0;
-    // Slow stack unwinding is disabled on Darwin for now, see
-    // https://code.google.com/p/address-sanitizer/issues/detail?id=137
-    // CHECK-Linux-STACK-LOAD: #0 {{.*}}main{{.*}}misaligned.cpp
-    // Check for the already checked line to avoid lit error reports.
-    // CHECK-Darwin-STACK-LOAD: {{ }}
+    // CHECK-STACK-LOAD: #0 {{.*}}main{{.*}}misaligned.cpp
 
   case 's':
     // CHECK-STORE: misaligned.cpp:[[@LINE+4]]{{(:5)?}}: runtime error: store to misaligned address [[PTR:0x[0-9a-f]*]] for type 'int', which requires 4 byte alignment
diff --git a/unittests/lit.common.unit.cfg b/unittests/lit.common.unit.cfg
index 2bd8f37..475b22d 100644
--- a/unittests/lit.common.unit.cfg
+++ b/unittests/lit.common.unit.cfg
@@ -28,3 +28,13 @@
     config.environment['TMP'] = os.environ['TMP']
 if 'TEMP' in os.environ:
     config.environment['TEMP'] = os.environ['TEMP']
+
+if config.host_os == 'Darwin':
+  # Only run up to 3 64-bit sanitized processes simultaneously on Darwin.
+  # Using more scales badly and hogs the system due to inefficient handling
+  # of large mmap'd regions (terabytes) by the kernel.
+  lit_config.parallelism_groups["darwin-64bit-sanitizer"] = 3
+
+  def darwin_sanitizer_parallelism_group_func(test):
+    return "darwin-64bit-sanitizer" if "x86_64" in test.file_path else ""
+  config.darwin_sanitizer_parallelism_group_func = darwin_sanitizer_parallelism_group_func