Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 26 Jun 2017 20:33:22 +0000 (UTC)
From:      Dimitry Andric <dim@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-vendor@freebsd.org
Subject:   svn commit: r320378 - in vendor/compiler-rt/dist: . cmake include/xray lib/asan lib/asan/scripts lib/interception lib/interception/tests lib/lsan lib/msan lib/sanitizer_common lib/sanitizer_common/...
Message-ID:  <201706262033.v5QKXMpm098882@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: dim
Date: Mon Jun 26 20:33:22 2017
New Revision: 320378
URL: https://svnweb.freebsd.org/changeset/base/320378

Log:
  Vendor import of compiler-rt trunk r306325:
  https://llvm.org/svn/llvm-project/compiler-rt/trunk@306325

Added:
  vendor/compiler-rt/dist/lib/lsan/lsan_mac.cc   (contents, props changed)
  vendor/compiler-rt/dist/test/asan/TestCases/pr33372.cc   (contents, props changed)
  vendor/compiler-rt/dist/test/lsan/TestCases/Darwin/
  vendor/compiler-rt/dist/test/lsan/TestCases/Darwin/dispatch.mm
  vendor/compiler-rt/dist/test/lsan/TestCases/Darwin/lit.local.cfg
  vendor/compiler-rt/dist/test/profile/Linux/counter_promo_for.c   (contents, props changed)
  vendor/compiler-rt/dist/test/profile/Linux/counter_promo_while.c   (contents, props changed)
  vendor/compiler-rt/dist/test/xray/TestCases/Linux/arg1-arg0-logging.cc   (contents, props changed)
Modified:
  vendor/compiler-rt/dist/CMakeLists.txt
  vendor/compiler-rt/dist/cmake/config-ix.cmake
  vendor/compiler-rt/dist/include/xray/xray_interface.h
  vendor/compiler-rt/dist/lib/asan/asan_allocator.cc
  vendor/compiler-rt/dist/lib/asan/asan_report.cc
  vendor/compiler-rt/dist/lib/asan/scripts/asan_device_setup
  vendor/compiler-rt/dist/lib/asan/weak_symbols.txt
  vendor/compiler-rt/dist/lib/interception/interception_win.cc
  vendor/compiler-rt/dist/lib/interception/tests/interception_win_test.cc
  vendor/compiler-rt/dist/lib/lsan/CMakeLists.txt
  vendor/compiler-rt/dist/lib/lsan/lsan.h
  vendor/compiler-rt/dist/lib/lsan/lsan_allocator.cc
  vendor/compiler-rt/dist/lib/lsan/lsan_common_mac.cc
  vendor/compiler-rt/dist/lib/lsan/lsan_thread.cc
  vendor/compiler-rt/dist/lib/lsan/lsan_thread.h
  vendor/compiler-rt/dist/lib/msan/msan_allocator.cc
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator.cc
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator.h
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_combined.h
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_internal.h
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_local_cache.h
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_primary32.h
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_secondary.h
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_atomic_clang.h
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_atomic_clang_other.h
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_common.h
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_linux.cc
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_linux_libcdep.cc
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_mac.cc
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_posix.cc
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_posix_libcdep.cc
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
  vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_win.cc
  vendor/compiler-rt/dist/lib/sanitizer_common/tests/sanitizer_allocator_test.cc
  vendor/compiler-rt/dist/lib/sanitizer_common/tests/sanitizer_common_test.cc
  vendor/compiler-rt/dist/lib/scudo/scudo_allocator.cpp
  vendor/compiler-rt/dist/lib/scudo/scudo_allocator_combined.h
  vendor/compiler-rt/dist/lib/scudo/scudo_allocator_secondary.h
  vendor/compiler-rt/dist/lib/tsan/rtl/tsan_mman.cc
  vendor/compiler-rt/dist/lib/ubsan/ubsan_handlers.cc
  vendor/compiler-rt/dist/lib/ubsan/ubsan_handlers.h
  vendor/compiler-rt/dist/lib/ubsan/ubsan_interface.inc
  vendor/compiler-rt/dist/lib/xray/xray_interface.cc
  vendor/compiler-rt/dist/test/asan/TestCases/Linux/allocator_oom_test.cc
  vendor/compiler-rt/dist/test/asan/TestCases/Linux/preinstalled_signal.cc
  vendor/compiler-rt/dist/test/asan/TestCases/Windows/oom.cc
  vendor/compiler-rt/dist/test/asan/lit.cfg
  vendor/compiler-rt/dist/test/esan/TestCases/workingset-midreport.cpp
  vendor/compiler-rt/dist/test/esan/TestCases/workingset-samples.cpp
  vendor/compiler-rt/dist/test/esan/TestCases/workingset-simple.cpp
  vendor/compiler-rt/dist/test/lsan/lit.common.cfg
  vendor/compiler-rt/dist/test/sanitizer_common/TestCases/sanitizer_coverage_inline8bit_counter.cc
  vendor/compiler-rt/dist/test/scudo/random_shuffle.cpp
  vendor/compiler-rt/dist/test/ubsan/TestCases/Misc/nonnull.cpp
  vendor/compiler-rt/dist/test/ubsan/TestCases/Misc/nullability.c

Modified: vendor/compiler-rt/dist/CMakeLists.txt
==============================================================================
--- vendor/compiler-rt/dist/CMakeLists.txt	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/CMakeLists.txt	Mon Jun 26 20:33:22 2017	(r320378)
@@ -7,13 +7,13 @@
 # An important constraint of the build is that it only produces libraries
 # based on the ability of the host toolchain to target various platforms.
 
+cmake_minimum_required(VERSION 3.4.3)
+
 # Check if compiler-rt is built as a standalone project.
 if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR COMPILER_RT_STANDALONE_BUILD)
   project(CompilerRT C CXX ASM)
   set(COMPILER_RT_STANDALONE_BUILD TRUE)
 endif()
-
-cmake_minimum_required(VERSION 3.4.3)
 
 # Add path for custom compiler-rt modules.
 list(INSERT CMAKE_MODULE_PATH 0

Modified: vendor/compiler-rt/dist/cmake/config-ix.cmake
==============================================================================
--- vendor/compiler-rt/dist/cmake/config-ix.cmake	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/cmake/config-ix.cmake	Mon Jun 26 20:33:22 2017	(r320378)
@@ -179,7 +179,7 @@ set(ALL_UBSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32}
 set(ALL_SAFESTACK_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM64} ${MIPS32} ${MIPS64})
 set(ALL_CFI_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64})
 set(ALL_ESAN_SUPPORTED_ARCH ${X86_64} ${MIPS64})
-set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64})
+set(ALL_SCUDO_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64})
 set(ALL_XRAY_SUPPORTED_ARCH ${X86_64} ${ARM32} ${ARM64} ${MIPS32} ${MIPS64} powerpc64le)
 
 if(APPLE)

Modified: vendor/compiler-rt/dist/include/xray/xray_interface.h
==============================================================================
--- vendor/compiler-rt/dist/include/xray/xray_interface.h	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/include/xray/xray_interface.h	Mon Jun 26 20:33:22 2017	(r320378)
@@ -60,7 +60,8 @@ extern int __xray_remove_handler();
 /// start logging their subsequent affected function calls (if patched).
 ///
 /// Returns 1 on success, 0 on error.
-extern int __xray_set_handler_arg1(void (*)(int32_t, XRayEntryType, uint64_t));
+extern int __xray_set_handler_arg1(void (*entry)(int32_t, XRayEntryType,
+                                                 uint64_t));
 
 /// Disables the XRay handler used to log first arguments of function calls.
 /// Returns 1 on success, 0 on error.

Modified: vendor/compiler-rt/dist/lib/asan/asan_allocator.cc
==============================================================================
--- vendor/compiler-rt/dist/lib/asan/asan_allocator.cc	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/asan/asan_allocator.cc	Mon Jun 26 20:33:22 2017	(r320378)
@@ -160,7 +160,7 @@ struct QuarantineCallback {
   }
 
   void *Allocate(uptr size) {
-    return get_allocator().Allocate(cache_, size, 1, false);
+    return get_allocator().Allocate(cache_, size, 1);
   }
 
   void Deallocate(void *p) {
@@ -266,7 +266,8 @@ struct Allocator {
   }
 
   void Initialize(const AllocatorOptions &options) {
-    allocator.Init(options.may_return_null, options.release_to_os_interval_ms);
+    SetAllocatorMayReturnNull(options.may_return_null);
+    allocator.Init(options.release_to_os_interval_ms);
     SharedInitCode(options);
   }
 
@@ -302,7 +303,7 @@ struct Allocator {
   }
 
   void ReInitialize(const AllocatorOptions &options) {
-    allocator.SetMayReturnNull(options.may_return_null);
+    SetAllocatorMayReturnNull(options.may_return_null);
     allocator.SetReleaseToOSIntervalMs(options.release_to_os_interval_ms);
     SharedInitCode(options);
 
@@ -323,7 +324,7 @@ struct Allocator {
     options->thread_local_quarantine_size_kb = quarantine.GetCacheSize() >> 10;
     options->min_redzone = atomic_load(&min_redzone, memory_order_acquire);
     options->max_redzone = atomic_load(&max_redzone, memory_order_acquire);
-    options->may_return_null = allocator.MayReturnNull();
+    options->may_return_null = AllocatorMayReturnNull();
     options->alloc_dealloc_mismatch =
         atomic_load(&alloc_dealloc_mismatch, memory_order_acquire);
     options->release_to_os_interval_ms = allocator.ReleaseToOSIntervalMs();
@@ -374,7 +375,7 @@ struct Allocator {
     if (UNLIKELY(!asan_inited))
       AsanInitFromRtl();
     if (RssLimitExceeded())
-      return allocator.ReturnNullOrDieOnOOM();
+      return AsanAllocator::FailureHandler::OnOOM();
     Flags &fl = *flags();
     CHECK(stack);
     const uptr min_alignment = SHADOW_GRANULARITY;
@@ -407,24 +408,22 @@ struct Allocator {
     if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) {
       Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n",
              (void*)size);
-      return allocator.ReturnNullOrDieOnBadRequest();
+      return AsanAllocator::FailureHandler::OnBadRequest();
     }
 
     AsanThread *t = GetCurrentThread();
     void *allocated;
     if (t) {
       AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
-      allocated =
-          allocator.Allocate(cache, needed_size, 8, false);
+      allocated = allocator.Allocate(cache, needed_size, 8);
     } else {
       SpinMutexLock l(&fallback_mutex);
       AllocatorCache *cache = &fallback_allocator_cache;
-      allocated =
-          allocator.Allocate(cache, needed_size, 8, false);
+      allocated = allocator.Allocate(cache, needed_size, 8);
     }
+    if (!allocated)
+      return nullptr;
 
-    if (!allocated) return allocator.ReturnNullOrDieOnOOM();
-
     if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && CanPoisonMemory()) {
       // Heap poisoning is enabled, but the allocator provides an unpoisoned
       // chunk. This is possible if CanPoisonMemory() was false for some
@@ -634,7 +633,7 @@ struct Allocator {
 
   void *Calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
     if (CallocShouldReturnNullDueToOverflow(size, nmemb))
-      return allocator.ReturnNullOrDieOnBadRequest();
+      return AsanAllocator::FailureHandler::OnBadRequest();
     void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
     // If the memory comes from the secondary allocator no need to clear it
     // as it comes directly from mmap.

Modified: vendor/compiler-rt/dist/lib/asan/asan_report.cc
==============================================================================
--- vendor/compiler-rt/dist/lib/asan/asan_report.cc	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/asan/asan_report.cc	Mon Jun 26 20:33:22 2017	(r320378)
@@ -204,6 +204,14 @@ class ScopedInErrorReport {
       error_report_callback(buffer_copy.data());
     }
 
+    if (halt_on_error_ && common_flags()->abort_on_error) {
+      // On Android the message is truncated to 512 characters.
+      // FIXME: implement "compact" error format, possibly without, or with
+      // highly compressed stack traces?
+      // FIXME: or just use the summary line as abort message?
+      SetAbortMessage(buffer_copy.data());
+    }
+
     // In halt_on_error = false mode, reset the current error object (before
     // unlocking).
     if (!halt_on_error_)

Modified: vendor/compiler-rt/dist/lib/asan/scripts/asan_device_setup
==============================================================================
--- vendor/compiler-rt/dist/lib/asan/scripts/asan_device_setup	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/asan/scripts/asan_device_setup	Mon Jun 26 20:33:22 2017	(r320378)
@@ -410,15 +410,15 @@ if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then
       install "$TMPDIR/asanwrapper" /system/bin 755
       install "$TMPDIR/asanwrapper64" /system/bin 755
 
-      adb_shell ln -s $ASAN_RT /system/lib/$ASAN_RT_SYMLINK
-      adb_shell ln -s $ASAN_RT64 /system/lib64/$ASAN_RT_SYMLINK
+      adb_shell ln -sf $ASAN_RT /system/lib/$ASAN_RT_SYMLINK
+      adb_shell ln -sf $ASAN_RT64 /system/lib64/$ASAN_RT_SYMLINK
     else
       install "$TMPDIR/$ASAN_RT" /system/lib 644
       install "$TMPDIR/app_process32" /system/bin 755 $CTX
       install "$TMPDIR/app_process.wrap" /system/bin 755 $CTX
       install "$TMPDIR/asanwrapper" /system/bin 755 $CTX
 
-      adb_shell ln -s $ASAN_RT /system/lib/$ASAN_RT_SYMLINK
+      adb_shell ln -sf $ASAN_RT /system/lib/$ASAN_RT_SYMLINK
 
       adb_shell rm /system/bin/app_process
       adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process

Modified: vendor/compiler-rt/dist/lib/asan/weak_symbols.txt
==============================================================================
--- vendor/compiler-rt/dist/lib/asan/weak_symbols.txt	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/asan/weak_symbols.txt	Mon Jun 26 20:33:22 2017	(r320378)
@@ -1,3 +1,12 @@
 ___asan_default_options
 ___asan_default_suppressions
 ___asan_on_error
+___asan_set_shadow_00
+___asan_set_shadow_f1
+___asan_set_shadow_f2
+___asan_set_shadow_f3
+___asan_set_shadow_f4
+___asan_set_shadow_f5
+___asan_set_shadow_f6
+___asan_set_shadow_f7
+___asan_set_shadow_f8

Modified: vendor/compiler-rt/dist/lib/interception/interception_win.cc
==============================================================================
--- vendor/compiler-rt/dist/lib/interception/interception_win.cc	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/interception/interception_win.cc	Mon Jun 26 20:33:22 2017	(r320378)
@@ -477,7 +477,7 @@ static size_t GetInstructionSize(uptr address, size_t*
   switch (*(u8*)address) {
     case 0xA1:  // A1 XX XX XX XX XX XX XX XX :
                 //   movabs eax, dword ptr ds:[XXXXXXXX]
-      return 8;
+      return 9;
   }
 
   switch (*(u16*)address) {
@@ -495,6 +495,11 @@ static size_t GetInstructionSize(uptr address, size_t*
     case 0x5741:  // push r15
     case 0x9066:  // Two-byte NOP
       return 2;
+
+    case 0x058B:  // 8B 05 XX XX XX XX : mov eax, dword ptr [XX XX XX XX]
+      if (rel_offset)
+        *rel_offset = 2;
+      return 6;
   }
 
   switch (0x00FFFFFF & *(u32*)address) {

Modified: vendor/compiler-rt/dist/lib/interception/tests/interception_win_test.cc
==============================================================================
--- vendor/compiler-rt/dist/lib/interception/tests/interception_win_test.cc	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/interception/tests/interception_win_test.cc	Mon Jun 26 20:33:22 2017	(r320378)
@@ -170,6 +170,13 @@ const u8 kPatchableCode5[] = {
     0x54,                                      // push    esp
 };
 
+#if SANITIZER_WINDOWS64
+u8 kLoadGlobalCode[] = {
+  0x8B, 0x05, 0x00, 0x00, 0x00, 0x00, // mov    eax [rip + global]
+  0xC3,                               // ret
+};
+#endif
+
 const u8 kUnpatchableCode1[] = {
     0xC3,                           // ret
 };
@@ -501,6 +508,10 @@ TEST(Interception, PatchableFunction) {
 #endif
   EXPECT_TRUE(TestFunctionPatching(kPatchableCode4, override));
   EXPECT_TRUE(TestFunctionPatching(kPatchableCode5, override));
+
+#if SANITIZER_WINDOWS64
+  EXPECT_TRUE(TestFunctionPatching(kLoadGlobalCode, override));
+#endif
 
   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode1, override));
   EXPECT_FALSE(TestFunctionPatching(kUnpatchableCode2, override));

Modified: vendor/compiler-rt/dist/lib/lsan/CMakeLists.txt
==============================================================================
--- vendor/compiler-rt/dist/lib/lsan/CMakeLists.txt	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/lsan/CMakeLists.txt	Mon Jun 26 20:33:22 2017	(r320378)
@@ -13,6 +13,7 @@ set(LSAN_SOURCES
   lsan_allocator.cc
   lsan_linux.cc
   lsan_interceptors.cc
+  lsan_mac.cc
   lsan_malloc_mac.cc
   lsan_preinit.cc
   lsan_thread.cc)

Modified: vendor/compiler-rt/dist/lib/lsan/lsan.h
==============================================================================
--- vendor/compiler-rt/dist/lib/lsan/lsan.h	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/lsan/lsan.h	Mon Jun 26 20:33:22 2017	(r320378)
@@ -38,6 +38,8 @@
   GET_STACK_TRACE(__sanitizer::common_flags()->malloc_context_size, \
                   common_flags()->fast_unwind_on_malloc)
 
+#define GET_STACK_TRACE_THREAD GET_STACK_TRACE(kStackTraceMax, true)
+
 namespace __lsan {
 
 void InitializeInterceptors();

Modified: vendor/compiler-rt/dist/lib/lsan/lsan_allocator.cc
==============================================================================
--- vendor/compiler-rt/dist/lib/lsan/lsan_allocator.cc	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/lsan/lsan_allocator.cc	Mon Jun 26 20:33:22 2017	(r320378)
@@ -38,8 +38,8 @@ typedef CombinedAllocator<PrimaryAllocator, AllocatorC
 static Allocator allocator;
 
 void InitializeAllocator() {
+  SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
   allocator.InitLinkerInitialized(
-      common_flags()->allocator_may_return_null,
       common_flags()->allocator_release_to_os_interval_ms);
 }
 
@@ -76,7 +76,7 @@ void *Allocate(const StackTrace &stack, uptr size, upt
     Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size);
     return nullptr;
   }
-  void *p = allocator.Allocate(GetAllocatorCache(), size, alignment, false);
+  void *p = allocator.Allocate(GetAllocatorCache(), size, alignment);
   // Do not rely on the allocator to clear the memory (it's slow).
   if (cleared && allocator.FromPrimary(p))
     memset(p, 0, size);

Modified: vendor/compiler-rt/dist/lib/lsan/lsan_common_mac.cc
==============================================================================
--- vendor/compiler-rt/dist/lib/lsan/lsan_common_mac.cc	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/lsan/lsan_common_mac.cc	Mon Jun 26 20:33:22 2017	(r320378)
@@ -79,8 +79,7 @@ void EnableInThisThread() {
 
 u32 GetCurrentThread() {
   thread_local_data_t *data = get_tls_val(false);
-  CHECK(data);
-  return data->current_thread_id;
+  return data ? data->current_thread_id : kInvalidTid;
 }
 
 void SetCurrentThread(u32 tid) { get_tls_val(true)->current_thread_id = tid; }

Added: vendor/compiler-rt/dist/lib/lsan/lsan_mac.cc
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/compiler-rt/dist/lib/lsan/lsan_mac.cc	Mon Jun 26 20:33:22 2017	(r320378)
@@ -0,0 +1,192 @@
+//===-- lsan_mac.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 LeakSanitizer, a memory leak checker.
+//
+// Mac-specific details.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
+
+#include "interception/interception.h"
+#include "lsan.h"
+#include "lsan_allocator.h"
+#include "lsan_thread.h"
+
+#include <pthread.h>
+
+namespace __lsan {
+// Support for the following functions from libdispatch on Mac OS:
+//   dispatch_async_f()
+//   dispatch_async()
+//   dispatch_sync_f()
+//   dispatch_sync()
+//   dispatch_after_f()
+//   dispatch_after()
+//   dispatch_group_async_f()
+//   dispatch_group_async()
+// TODO(glider): libdispatch API contains other functions that we don't support
+// yet.
+//
+// dispatch_sync() and dispatch_sync_f() are synchronous, although chances are
+// they can cause jobs to run on a thread different from the current one.
+// TODO(glider): if so, we need a test for this (otherwise we should remove
+// them).
+//
+// The following functions use dispatch_barrier_async_f() (which isn't a library
+// function but is exported) and are thus supported:
+//   dispatch_source_set_cancel_handler_f()
+//   dispatch_source_set_cancel_handler()
+//   dispatch_source_set_event_handler_f()
+//   dispatch_source_set_event_handler()
+//
+// The reference manual for Grand Central Dispatch is available at
+//   http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
+// The implementation details are at
+//   http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c
+
+typedef void *dispatch_group_t;
+typedef void *dispatch_queue_t;
+typedef void *dispatch_source_t;
+typedef u64 dispatch_time_t;
+typedef void (*dispatch_function_t)(void *block);
+typedef void *(*worker_t)(void *block);
+
+// A wrapper for the ObjC blocks used to support libdispatch.
+typedef struct {
+  void *block;
+  dispatch_function_t func;
+  u32 parent_tid;
+} lsan_block_context_t;
+
+ALWAYS_INLINE
+void lsan_register_worker_thread(int parent_tid) {
+  if (GetCurrentThread() == kInvalidTid) {
+    u32 tid = ThreadCreate(parent_tid, 0, true);
+    ThreadStart(tid, GetTid());
+    SetCurrentThread(tid);
+  }
+}
+
+// For use by only those functions that allocated the context via
+// alloc_lsan_context().
+extern "C" void lsan_dispatch_call_block_and_release(void *block) {
+  lsan_block_context_t *context = (lsan_block_context_t *)block;
+  VReport(2,
+          "lsan_dispatch_call_block_and_release(): "
+          "context: %p, pthread_self: %p\n",
+          block, pthread_self());
+  lsan_register_worker_thread(context->parent_tid);
+  // Call the original dispatcher for the block.
+  context->func(context->block);
+  lsan_free(context);
+}
+
+}  // namespace __lsan
+
+using namespace __lsan;  // NOLINT
+
+// Wrap |ctxt| and |func| into an lsan_block_context_t.
+// The caller retains control of the allocated context.
+extern "C" lsan_block_context_t *alloc_lsan_context(void *ctxt,
+                                                    dispatch_function_t func) {
+  GET_STACK_TRACE_THREAD;
+  lsan_block_context_t *lsan_ctxt =
+      (lsan_block_context_t *)lsan_malloc(sizeof(lsan_block_context_t), stack);
+  lsan_ctxt->block = ctxt;
+  lsan_ctxt->func = func;
+  lsan_ctxt->parent_tid = GetCurrentThread();
+  return lsan_ctxt;
+}
+
+// Define interceptor for dispatch_*_f function with the three most common
+// parameters: dispatch_queue_t, context, dispatch_function_t.
+#define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f)                        \
+  INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt,    \
+              dispatch_function_t func) {                             \
+    lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func); \
+    return REAL(dispatch_x_f)(dq, (void *)lsan_ctxt,                  \
+                              lsan_dispatch_call_block_and_release);  \
+  }
+
+INTERCEPT_DISPATCH_X_F_3(dispatch_async_f)
+INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f)
+INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f)
+
+INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, dispatch_queue_t dq,
+            void *ctxt, dispatch_function_t func) {
+  lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func);
+  return REAL(dispatch_after_f)(when, dq, (void *)lsan_ctxt,
+                                lsan_dispatch_call_block_and_release);
+}
+
+INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
+            dispatch_queue_t dq, void *ctxt, dispatch_function_t func) {
+  lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func);
+  REAL(dispatch_group_async_f)
+  (group, dq, (void *)lsan_ctxt, lsan_dispatch_call_block_and_release);
+}
+
+#if !defined(MISSING_BLOCKS_SUPPORT)
+extern "C" {
+void dispatch_async(dispatch_queue_t dq, void (^work)(void));
+void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq,
+                          void (^work)(void));
+void dispatch_after(dispatch_time_t when, dispatch_queue_t queue,
+                    void (^work)(void));
+void dispatch_source_set_cancel_handler(dispatch_source_t ds,
+                                        void (^work)(void));
+void dispatch_source_set_event_handler(dispatch_source_t ds,
+                                       void (^work)(void));
+}
+
+#define GET_LSAN_BLOCK(work)                 \
+  void (^lsan_block)(void);                  \
+  int parent_tid = GetCurrentThread();       \
+  lsan_block = ^(void) {                     \
+    lsan_register_worker_thread(parent_tid); \
+    work();                                  \
+  }
+
+INTERCEPTOR(void, dispatch_async, dispatch_queue_t dq, void (^work)(void)) {
+  GET_LSAN_BLOCK(work);
+  REAL(dispatch_async)(dq, lsan_block);
+}
+
+INTERCEPTOR(void, dispatch_group_async, dispatch_group_t dg,
+            dispatch_queue_t dq, void (^work)(void)) {
+  GET_LSAN_BLOCK(work);
+  REAL(dispatch_group_async)(dg, dq, lsan_block);
+}
+
+INTERCEPTOR(void, dispatch_after, dispatch_time_t when, dispatch_queue_t queue,
+            void (^work)(void)) {
+  GET_LSAN_BLOCK(work);
+  REAL(dispatch_after)(when, queue, lsan_block);
+}
+
+INTERCEPTOR(void, dispatch_source_set_cancel_handler, dispatch_source_t ds,
+            void (^work)(void)) {
+  if (!work) {
+    REAL(dispatch_source_set_cancel_handler)(ds, work);
+    return;
+  }
+  GET_LSAN_BLOCK(work);
+  REAL(dispatch_source_set_cancel_handler)(ds, lsan_block);
+}
+
+INTERCEPTOR(void, dispatch_source_set_event_handler, dispatch_source_t ds,
+            void (^work)(void)) {
+  GET_LSAN_BLOCK(work);
+  REAL(dispatch_source_set_event_handler)(ds, lsan_block);
+}
+#endif
+
+#endif  // SANITIZER_MAC

Modified: vendor/compiler-rt/dist/lib/lsan/lsan_thread.cc
==============================================================================
--- vendor/compiler-rt/dist/lib/lsan/lsan_thread.cc	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/lsan/lsan_thread.cc	Mon Jun 26 20:33:22 2017	(r320378)
@@ -77,7 +77,7 @@ u32 ThreadCreate(u32 parent_tid, uptr user_id, bool de
                                        /* arg */ nullptr);
 }
 
-void ThreadStart(u32 tid, tid_t os_id) {
+void ThreadStart(u32 tid, tid_t os_id, bool workerthread) {
   OnStartedArgs args;
   uptr stack_size = 0;
   uptr tls_size = 0;
@@ -87,7 +87,7 @@ void ThreadStart(u32 tid, tid_t os_id) {
   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, /*workerthread*/ false, &args);
+  thread_registry->StartThread(tid, os_id, workerthread, &args);
 }
 
 void ThreadFinish() {

Modified: vendor/compiler-rt/dist/lib/lsan/lsan_thread.h
==============================================================================
--- vendor/compiler-rt/dist/lib/lsan/lsan_thread.h	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/lsan/lsan_thread.h	Mon Jun 26 20:33:22 2017	(r320378)
@@ -45,7 +45,7 @@ class ThreadContext : public ThreadContextBase {
 
 void InitializeThreadRegistry();
 
-void ThreadStart(u32 tid, tid_t os_id);
+void ThreadStart(u32 tid, tid_t os_id, bool workerthread = false);
 void ThreadFinish();
 u32 ThreadCreate(u32 tid, uptr uid, bool detached);
 void ThreadJoin(u32 tid);

Modified: vendor/compiler-rt/dist/lib/msan/msan_allocator.cc
==============================================================================
--- vendor/compiler-rt/dist/lib/msan/msan_allocator.cc	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/msan/msan_allocator.cc	Mon Jun 26 20:33:22 2017	(r320378)
@@ -119,9 +119,8 @@ static AllocatorCache fallback_allocator_cache;
 static SpinMutex fallback_mutex;
 
 void MsanAllocatorInit() {
-  allocator.Init(
-      common_flags()->allocator_may_return_null,
-      common_flags()->allocator_release_to_os_interval_ms);
+  SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
+  allocator.Init(common_flags()->allocator_release_to_os_interval_ms);
 }
 
 AllocatorCache *GetAllocatorCache(MsanThreadLocalMallocStorage *ms) {
@@ -139,17 +138,17 @@ static void *MsanAllocate(StackTrace *stack, uptr size
   if (size > kMaxAllowedMallocSize) {
     Report("WARNING: MemorySanitizer failed to allocate %p bytes\n",
            (void *)size);
-    return allocator.ReturnNullOrDieOnBadRequest();
+    return Allocator::FailureHandler::OnBadRequest();
   }
   MsanThread *t = GetCurrentThread();
   void *allocated;
   if (t) {
     AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
-    allocated = allocator.Allocate(cache, size, alignment, false);
+    allocated = allocator.Allocate(cache, size, alignment);
   } else {
     SpinMutexLock l(&fallback_mutex);
     AllocatorCache *cache = &fallback_allocator_cache;
-    allocated = allocator.Allocate(cache, size, alignment, false);
+    allocated = allocator.Allocate(cache, size, alignment);
   }
   Metadata *meta =
       reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));
@@ -197,7 +196,7 @@ void MsanDeallocate(StackTrace *stack, void *p) {
 
 void *MsanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
   if (CallocShouldReturnNullDueToOverflow(size, nmemb))
-    return allocator.ReturnNullOrDieOnBadRequest();
+    return Allocator::FailureHandler::OnBadRequest();
   return MsanReallocate(stack, nullptr, nmemb * size, sizeof(u64), true);
 }
 

Modified: vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator.cc
==============================================================================
--- vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator.cc	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator.cc	Mon Jun 26 20:33:22 2017	(r320378)
@@ -94,8 +94,7 @@ InternalAllocator *internal_allocator() {
     SpinMutexLock l(&internal_alloc_init_mu);
     if (atomic_load(&internal_allocator_initialized, memory_order_relaxed) ==
         0) {
-      internal_allocator_instance->Init(
-          /* may_return_null */ false, kReleaseToOSIntervalNever);
+      internal_allocator_instance->Init(kReleaseToOSIntervalNever);
       atomic_store(&internal_allocator_initialized, 1, memory_order_release);
     }
   }
@@ -108,9 +107,9 @@ static void *RawInternalAlloc(uptr size, InternalAlloc
   if (cache == 0) {
     SpinMutexLock l(&internal_allocator_cache_mu);
     return internal_allocator()->Allocate(&internal_allocator_cache, size,
-                                          alignment, false);
+                                          alignment);
   }
-  return internal_allocator()->Allocate(cache, size, alignment, false);
+  return internal_allocator()->Allocate(cache, size, alignment);
 }
 
 static void *RawInternalRealloc(void *ptr, uptr size,
@@ -162,7 +161,7 @@ void *InternalRealloc(void *addr, uptr size, InternalA
 
 void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) {
   if (CallocShouldReturnNullDueToOverflow(count, size))
-    return internal_allocator()->ReturnNullOrDieOnBadRequest();
+    return InternalAllocator::FailureHandler::OnBadRequest();
   void *p = InternalAlloc(count * size, cache);
   if (p) internal_memset(p, 0, count * size);
   return p;
@@ -209,17 +208,51 @@ bool CallocShouldReturnNullDueToOverflow(uptr size, up
   return (max / size) < n;
 }
 
-static atomic_uint8_t reporting_out_of_memory = {0};
+static atomic_uint8_t allocator_out_of_memory = {0};
+static atomic_uint8_t allocator_may_return_null = {0};
 
-bool IsReportingOOM() { return atomic_load_relaxed(&reporting_out_of_memory); }
+bool IsAllocatorOutOfMemory() {
+  return atomic_load_relaxed(&allocator_out_of_memory);
+}
 
-void NORETURN ReportAllocatorCannotReturnNull(bool out_of_memory) {
-  if (out_of_memory) atomic_store_relaxed(&reporting_out_of_memory, 1);
+// Prints error message and kills the program.
+void NORETURN ReportAllocatorCannotReturnNull() {
   Report("%s's allocator is terminating the process instead of returning 0\n",
          SanitizerToolName);
   Report("If you don't like this behavior set allocator_may_return_null=1\n");
   CHECK(0);
   Die();
+}
+
+bool AllocatorMayReturnNull() {
+  return atomic_load(&allocator_may_return_null, memory_order_relaxed);
+}
+
+void SetAllocatorMayReturnNull(bool may_return_null) {
+  atomic_store(&allocator_may_return_null, may_return_null,
+               memory_order_relaxed);
+}
+
+void *ReturnNullOrDieOnFailure::OnBadRequest() {
+  if (AllocatorMayReturnNull())
+    return nullptr;
+  ReportAllocatorCannotReturnNull();
+}
+
+void *ReturnNullOrDieOnFailure::OnOOM() {
+  atomic_store_relaxed(&allocator_out_of_memory, 1);
+  if (AllocatorMayReturnNull())
+    return nullptr;
+  ReportAllocatorCannotReturnNull();
+}
+
+void *DieOnFailure::OnBadRequest() {
+  ReportAllocatorCannotReturnNull();
+}
+
+void *DieOnFailure::OnOOM() {
+  atomic_store_relaxed(&allocator_out_of_memory, 1);
+  ReportAllocatorCannotReturnNull();
 }
 
 } // namespace __sanitizer

Modified: vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator.h
==============================================================================
--- vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator.h	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator.h	Mon Jun 26 20:33:22 2017	(r320378)
@@ -24,12 +24,28 @@
 
 namespace __sanitizer {
 
-// Returns true if ReportAllocatorCannotReturnNull(true) was called.
-// Can be use to avoid memory hungry operations.
-bool IsReportingOOM();
+// Since flags are immutable and allocator behavior can be changed at runtime
+// (unit tests or ASan on Android are some examples), allocator_may_return_null
+// flag value is cached here and can be altered later.
+bool AllocatorMayReturnNull();
+void SetAllocatorMayReturnNull(bool may_return_null);
 
-// Prints error message and kills the program.
-void NORETURN ReportAllocatorCannotReturnNull(bool out_of_memory);
+// Allocator failure handling policies:
+// Implements AllocatorMayReturnNull policy, returns null when the flag is set,
+// dies otherwise.
+struct ReturnNullOrDieOnFailure {
+  static void *OnBadRequest();
+  static void *OnOOM();
+};
+// Always dies on the failure.
+struct DieOnFailure {
+  static void *OnBadRequest();
+  static void *OnOOM();
+};
+
+// Returns true if allocator detected OOM condition. Can be used to avoid memory
+// hungry operations. Set when AllocatorReturnNullOrDieOnOOM() is called.
+bool IsAllocatorOutOfMemory();
 
 // Allocators call these callbacks on mmap/munmap.
 struct NoOpMapUnmapCallback {

Modified: vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_combined.h
==============================================================================
--- vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_combined.h	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_combined.h	Mon Jun 26 20:33:22 2017	(r320378)
@@ -24,31 +24,26 @@ template <class PrimaryAllocator, class AllocatorCache
           class SecondaryAllocator>  // NOLINT
 class CombinedAllocator {
  public:
-  void InitCommon(bool may_return_null, s32 release_to_os_interval_ms) {
-    primary_.Init(release_to_os_interval_ms);
-    atomic_store(&may_return_null_, may_return_null, memory_order_relaxed);
-  }
+  typedef typename SecondaryAllocator::FailureHandler FailureHandler;
 
-  void InitLinkerInitialized(
-      bool may_return_null, s32 release_to_os_interval_ms) {
-    secondary_.InitLinkerInitialized(may_return_null);
+  void InitLinkerInitialized(s32 release_to_os_interval_ms) {
+    primary_.Init(release_to_os_interval_ms);
+    secondary_.InitLinkerInitialized();
     stats_.InitLinkerInitialized();
-    InitCommon(may_return_null, release_to_os_interval_ms);
   }
 
-  void Init(bool may_return_null, s32 release_to_os_interval_ms) {
-    secondary_.Init(may_return_null);
+  void Init(s32 release_to_os_interval_ms) {
+    primary_.Init(release_to_os_interval_ms);
+    secondary_.Init();
     stats_.Init();
-    InitCommon(may_return_null, release_to_os_interval_ms);
   }
 
-  void *Allocate(AllocatorCache *cache, uptr size, uptr alignment,
-                 bool cleared = false) {
+  void *Allocate(AllocatorCache *cache, uptr size, uptr alignment) {
     // Returning 0 on malloc(0) may break a lot of code.
     if (size == 0)
       size = 1;
     if (size + alignment < size)
-      return ReturnNullOrDieOnBadRequest();
+      return FailureHandler::OnBadRequest();
     uptr original_size = size;
     // If alignment requirements are to be fulfilled by the frontend allocator
     // rather than by the primary or secondary, passing an alignment lower than
@@ -56,49 +51,24 @@ class CombinedAllocator {
     // alignment check.
     if (alignment > 8)
       size = RoundUpTo(size, alignment);
-    void *res;
-    bool from_primary = primary_.CanAllocate(size, alignment);
     // The primary allocator should return a 2^x aligned allocation when
     // requested 2^x bytes, hence using the rounded up 'size' when being
     // serviced by the primary (this is no longer true when the primary is
     // using a non-fixed base address). The secondary takes care of the
     // alignment without such requirement, and allocating 'size' would use
     // extraneous memory, so we employ 'original_size'.
-    if (from_primary)
+    void *res;
+    if (primary_.CanAllocate(size, alignment))
       res = cache->Allocate(&primary_, primary_.ClassID(size));
     else
       res = secondary_.Allocate(&stats_, original_size, alignment);
+    if (!res)
+      return FailureHandler::OnOOM();
     if (alignment > 8)
       CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
-    // When serviced by the secondary, the chunk comes from a mmap allocation
-    // and will be zero'd out anyway. We only need to clear our the chunk if
-    // it was serviced by the primary, hence using the rounded up 'size'.
-    if (cleared && res && from_primary)
-      internal_bzero_aligned16(res, RoundUpTo(size, 16));
     return res;
   }
 
-  bool MayReturnNull() const {
-    return atomic_load(&may_return_null_, memory_order_acquire);
-  }
-
-  void *ReturnNullOrDieOnBadRequest() {
-    if (MayReturnNull())
-      return nullptr;
-    ReportAllocatorCannotReturnNull(false);
-  }
-
-  void *ReturnNullOrDieOnOOM() {
-    if (MayReturnNull())
-      return nullptr;
-    ReportAllocatorCannotReturnNull(true);
-  }
-
-  void SetMayReturnNull(bool may_return_null) {
-    secondary_.SetMayReturnNull(may_return_null);
-    atomic_store(&may_return_null_, may_return_null, memory_order_release);
-  }
-
   s32 ReleaseToOSIntervalMs() const {
     return primary_.ReleaseToOSIntervalMs();
   }
@@ -219,6 +189,5 @@ class CombinedAllocator {
   PrimaryAllocator primary_;
   SecondaryAllocator secondary_;
   AllocatorGlobalStats stats_;
-  atomic_uint8_t may_return_null_;
 };
 

Modified: vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_internal.h
==============================================================================
--- vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_internal.h	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_internal.h	Mon Jun 26 20:33:22 2017	(r320378)
@@ -47,7 +47,8 @@ typedef SizeClassAllocatorLocalCache<PrimaryInternalAl
     InternalAllocatorCache;
 
 typedef CombinedAllocator<PrimaryInternalAllocator, InternalAllocatorCache,
-                          LargeMmapAllocator<> > InternalAllocator;
+                          LargeMmapAllocator<NoOpMapUnmapCallback, DieOnFailure>
+                         > InternalAllocator;
 
 void *InternalAlloc(uptr size, InternalAllocatorCache *cache = nullptr,
                     uptr alignment = 0);

Modified: vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_local_cache.h
==============================================================================
--- vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_local_cache.h	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_local_cache.h	Mon Jun 26 20:33:22 2017	(r320378)
@@ -144,8 +144,10 @@ struct SizeClassAllocator32LocalCache {
     CHECK_NE(class_id, 0UL);
     CHECK_LT(class_id, kNumClasses);
     PerClass *c = &per_class_[class_id];
-    if (UNLIKELY(c->count == 0))
-      Refill(allocator, class_id);
+    if (UNLIKELY(c->count == 0)) {
+      if (UNLIKELY(!Refill(allocator, class_id)))
+        return nullptr;
+    }
     stats_.Add(AllocatorStatAllocated, c->class_size);
     void *res = c->batch[--c->count];
     PREFETCH(c->batch[c->count - 1]);
@@ -227,14 +229,17 @@ struct SizeClassAllocator32LocalCache {
       Deallocate(allocator, batch_class_id, b);
   }
 
-  NOINLINE void Refill(SizeClassAllocator *allocator, uptr class_id) {
+  NOINLINE bool Refill(SizeClassAllocator *allocator, uptr class_id) {
     InitCache();
     PerClass *c = &per_class_[class_id];
     TransferBatch *b = allocator->AllocateBatch(&stats_, this, class_id);
+    if (UNLIKELY(!b))
+      return false;
     CHECK_GT(b->Count(), 0);
     b->CopyToArray(c->batch);
     c->count = b->Count();
     DestroyBatch(class_id, allocator, b);
+    return true;
   }
 
   NOINLINE void Drain(SizeClassAllocator *allocator, uptr class_id) {
@@ -244,6 +249,10 @@ struct SizeClassAllocator32LocalCache {
     uptr first_idx_to_drain = c->count - cnt;
     TransferBatch *b = CreateBatch(
         class_id, allocator, (TransferBatch *)c->batch[first_idx_to_drain]);
+    // Failure to allocate a batch while releasing memory is non recoverable.
+    // TODO(alekseys): Figure out how to do it without allocating a new batch.
+    if (UNLIKELY(!b))
+      DieOnFailure::OnOOM();
     b->SetFromArray(allocator->GetRegionBeginBySizeClass(class_id),
                     &c->batch[first_idx_to_drain], cnt);
     c->count -= cnt;

Modified: vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_primary32.h
==============================================================================
--- vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_primary32.h	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_primary32.h	Mon Jun 26 20:33:22 2017	(r320378)
@@ -24,7 +24,8 @@ template<class SizeClassAllocator> struct SizeClassAll
 // be returned by MmapOrDie().
 //
 // Region:
-//   a result of a single call to MmapAlignedOrDie(kRegionSize, kRegionSize).
+//   a result of a single call to MmapAlignedOrDieOnFatalError(kRegionSize,
+//                                                             kRegionSize).
 // Since the regions are aligned by kRegionSize, there are exactly
 // kNumPossibleRegions possible regions in the address space and so we keep
 // a ByteMap possible_regions to store the size classes of each Region.
@@ -149,8 +150,9 @@ class SizeClassAllocator32 {
     CHECK_LT(class_id, kNumClasses);
     SizeClassInfo *sci = GetSizeClassInfo(class_id);
     SpinMutexLock l(&sci->mutex);
-    if (sci->free_list.empty())
-      PopulateFreeList(stat, c, sci, class_id);
+    if (sci->free_list.empty() &&
+        UNLIKELY(!PopulateFreeList(stat, c, sci, class_id)))
+      return nullptr;
     CHECK(!sci->free_list.empty());
     TransferBatch *b = sci->free_list.front();
     sci->free_list.pop_front();
@@ -277,8 +279,10 @@ class SizeClassAllocator32 {
 
   uptr AllocateRegion(AllocatorStats *stat, uptr class_id) {
     CHECK_LT(class_id, kNumClasses);
-    uptr res = reinterpret_cast<uptr>(MmapAlignedOrDie(kRegionSize, kRegionSize,
-                                      "SizeClassAllocator32"));
+    uptr res = reinterpret_cast<uptr>(MmapAlignedOrDieOnFatalError(
+        kRegionSize, kRegionSize, "SizeClassAllocator32"));
+    if (UNLIKELY(!res))
+      return 0;
     MapUnmapCallback().OnMap(res, kRegionSize);
     stat->Add(AllocatorStatMapped, kRegionSize);
     CHECK_EQ(0U, (res & (kRegionSize - 1)));
@@ -291,16 +295,20 @@ class SizeClassAllocator32 {
     return &size_class_info_array[class_id];
   }
 
-  void PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
+  bool PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
                         SizeClassInfo *sci, uptr class_id) {
     uptr size = ClassIdToSize(class_id);
     uptr reg = AllocateRegion(stat, class_id);
+    if (UNLIKELY(!reg))
+      return false;
     uptr n_chunks = kRegionSize / (size + kMetadataSize);
     uptr max_count = TransferBatch::MaxCached(class_id);
     TransferBatch *b = nullptr;
     for (uptr i = reg; i < reg + n_chunks * size; i += size) {
       if (!b) {
         b = c->CreateBatch(class_id, this, (TransferBatch*)i);
+        if (!b)
+          return false;
         b->Clear();
       }
       b->Add((void*)i);
@@ -314,6 +322,7 @@ class SizeClassAllocator32 {
       CHECK_GT(b->Count(), 0);
       sci->free_list.push_back(b);
     }
+    return true;
   }
 
   ByteMap possible_regions;

Modified: vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_secondary.h
==============================================================================
--- vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_secondary.h	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_allocator_secondary.h	Mon Jun 26 20:33:22 2017	(r320378)
@@ -17,17 +17,19 @@
 // This class can (de)allocate only large chunks of memory using mmap/unmap.
 // The main purpose of this allocator is to cover large and rare allocation
 // sizes not covered by more efficient allocators (e.g. SizeClassAllocator64).
-template <class MapUnmapCallback = NoOpMapUnmapCallback>
+template <class MapUnmapCallback = NoOpMapUnmapCallback,
+          class FailureHandlerT = ReturnNullOrDieOnFailure>
 class LargeMmapAllocator {
  public:
-  void InitLinkerInitialized(bool may_return_null) {
+  typedef FailureHandlerT FailureHandler;
+
+  void InitLinkerInitialized() {
     page_size_ = GetPageSizeCached();
-    atomic_store(&may_return_null_, may_return_null, memory_order_relaxed);
   }
 
-  void Init(bool may_return_null) {
+  void Init() {
     internal_memset(this, 0, sizeof(*this));
-    InitLinkerInitialized(may_return_null);
+    InitLinkerInitialized();
   }
 
   void *Allocate(AllocatorStats *stat, uptr size, uptr alignment) {
@@ -37,11 +39,11 @@ class LargeMmapAllocator {
       map_size += alignment;
     // Overflow.
     if (map_size < size)
-      return ReturnNullOrDieOnBadRequest();
+      return FailureHandler::OnBadRequest();
     uptr map_beg = reinterpret_cast<uptr>(
         MmapOrDieOnFatalError(map_size, "LargeMmapAllocator"));
     if (!map_beg)
-      return ReturnNullOrDieOnOOM();
+      return FailureHandler::OnOOM();
     CHECK(IsAligned(map_beg, page_size_));
     MapUnmapCallback().OnMap(map_beg, map_size);
     uptr map_end = map_beg + map_size;
@@ -75,24 +77,6 @@ class LargeMmapAllocator {
     return reinterpret_cast<void*>(res);
   }
 
-  bool MayReturnNull() const {
-    return atomic_load(&may_return_null_, memory_order_acquire);
-  }
-
-  void *ReturnNullOrDieOnBadRequest() {
-    if (MayReturnNull()) return nullptr;
-    ReportAllocatorCannotReturnNull(false);
-  }
-
-  void *ReturnNullOrDieOnOOM() {
-    if (MayReturnNull()) return nullptr;
-    ReportAllocatorCannotReturnNull(true);
-  }
-
-  void SetMayReturnNull(bool may_return_null) {
-    atomic_store(&may_return_null_, may_return_null, memory_order_release);
-  }
-
   void Deallocate(AllocatorStats *stat, void *p) {
     Header *h = GetHeader(p);
     {
@@ -278,7 +262,6 @@ class LargeMmapAllocator {
   struct Stats {
     uptr n_allocs, n_frees, currently_allocated, max_allocated, by_size_log[64];
   } stats;
-  atomic_uint8_t may_return_null_;
   SpinMutex mutex_;
 };
 

Modified: vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_atomic_clang.h
==============================================================================
--- vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_atomic_clang.h	Mon Jun 26 20:33:18 2017	(r320377)
+++ vendor/compiler-rt/dist/lib/sanitizer_common/sanitizer_atomic_clang.h	Mon Jun 26 20:33:22 2017	(r320378)
@@ -71,16 +71,25 @@ INLINE typename T::Type atomic_exchange(volatile T *a,
   return v;
 }
 
-template<typename T>
-INLINE bool atomic_compare_exchange_strong(volatile T *a,
-                                           typename T::Type *cmp,
+template <typename T>
+INLINE bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp,
                                            typename T::Type xchg,
                                            memory_order mo) {
   typedef typename T::Type Type;
   Type cmpv = *cmp;
-  Type prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg);
-  if (prev == cmpv)
-    return true;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201706262033.v5QKXMpm098882>