[compiler-rt] r306604 - [Sanitizers] Operator new() interceptors always die on allocation error

Alex Shlyapnikov via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 28 14:58:57 PDT 2017


Author: alekseyshl
Date: Wed Jun 28 14:58:57 2017
New Revision: 306604

URL: http://llvm.org/viewvc/llvm-project?rev=306604&view=rev
Log:
[Sanitizers] Operator new() interceptors always die on allocation error

Summary:
Operator new interceptors behavior is now controlled by their nothrow
property as well as by allocator_may_return_null flag value:

- allocator_may_return_null=* + new()        - die on allocation error
- allocator_may_return_null=0 + new(nothrow) - die on allocation error
- allocator_may_return_null=1 + new(nothrow) - return null

Ideally new() should throw std::bad_alloc exception, but that is not
trivial to achieve, hence TODO.

Reviewers: eugenis

Subscribers: kubamracek, llvm-commits

Differential Revision: https://reviews.llvm.org/D34731

Modified:
    compiler-rt/trunk/lib/asan/asan_allocator.cc
    compiler-rt/trunk/lib/asan/asan_new_delete.cc
    compiler-rt/trunk/lib/lsan/lsan_interceptors.cc
    compiler-rt/trunk/lib/msan/msan_new_delete.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator.cc
    compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator.h
    compiler-rt/trunk/lib/scudo/scudo_new_delete.cpp
    compiler-rt/trunk/lib/tsan/rtl/tsan_new_delete.cc
    compiler-rt/trunk/test/asan/TestCases/allocator_returns_null.cc
    compiler-rt/trunk/test/msan/allocator_returns_null.cc
    compiler-rt/trunk/test/scudo/sizes.cpp
    compiler-rt/trunk/test/tsan/allocator_returns_null.cc

Modified: compiler-rt/trunk/lib/asan/asan_allocator.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_allocator.cc?rev=306604&r1=306603&r2=306604&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_allocator.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_allocator.cc Wed Jun 28 14:58:57 2017
@@ -160,7 +160,11 @@ struct QuarantineCallback {
   }
 
   void *Allocate(uptr size) {
-    return get_allocator().Allocate(cache_, size, 1);
+    void *res = get_allocator().Allocate(cache_, size, 1);
+    // TODO(alekseys): Consider making quarantine OOM-friendly.
+    if (UNLIKELY(!res))
+      return DieOnFailure::OnOOM();
+    return res;
   }
 
   void Deallocate(void *p) {
@@ -524,8 +528,7 @@ struct Allocator {
 
   // Expects the chunk to already be marked as quarantined by using
   // AtomicallySetQuarantineFlagIfAllocated.
-  void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack,
-                       AllocType alloc_type) {
+  void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack) {
     CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
     CHECK_GE(m->alloc_tid, 0);
     if (SANITIZER_WORDSIZE == 64)  // On 32-bits this resides in user area.
@@ -603,7 +606,7 @@ struct Allocator {
       ReportNewDeleteSizeMismatch(p, delete_size, stack);
     }
 
-    QuarantineChunk(m, ptr, stack, alloc_type);
+    QuarantineChunk(m, ptr, stack);
   }
 
   void *Reallocate(void *old_ptr, uptr new_size, BufferedStackTrace *stack) {

Modified: compiler-rt/trunk/lib/asan/asan_new_delete.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_new_delete.cc?rev=306604&r1=306603&r2=306604&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_new_delete.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_new_delete.cc Wed Jun 28 14:58:57 2017
@@ -63,12 +63,17 @@ struct nothrow_t {};
 enum class align_val_t: size_t {};
 }  // namespace std
 
-#define OPERATOR_NEW_BODY(type) \
+// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
+#define OPERATOR_NEW_BODY(type, nothrow) \
   GET_STACK_TRACE_MALLOC;\
-  return asan_memalign(0, size, &stack, type);
-#define OPERATOR_NEW_BODY_ALIGN(type) \
+  void *res = asan_memalign(0, size, &stack, type);\
+  if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
+  return res;
+#define OPERATOR_NEW_BODY_ALIGN(type, nothrow) \
   GET_STACK_TRACE_MALLOC;\
-  return asan_memalign((uptr)align, size, &stack, type);
+  void *res = asan_memalign((uptr)align, size, &stack, type);\
+  if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
+  return res;
 
 // On OS X it's not enough to just provide our own 'operator new' and
 // 'operator delete' implementations, because they're going to be in the
@@ -79,40 +84,42 @@ enum class align_val_t: size_t {};
 // OS X we need to intercept them using their mangled names.
 #if !SANITIZER_MAC
 CXX_OPERATOR_ATTRIBUTE
-void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); }
+void *operator new(size_t size)
+{ OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/); }
 CXX_OPERATOR_ATTRIBUTE
-void *operator new[](size_t size) { OPERATOR_NEW_BODY(FROM_NEW_BR); }
+void *operator new[](size_t size)
+{ OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/); }
 CXX_OPERATOR_ATTRIBUTE
 void *operator new(size_t size, std::nothrow_t const&)
-{ OPERATOR_NEW_BODY(FROM_NEW); }
+{ OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/); }
 CXX_OPERATOR_ATTRIBUTE
 void *operator new[](size_t size, std::nothrow_t const&)
-{ OPERATOR_NEW_BODY(FROM_NEW_BR); }
+{ OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/); }
 CXX_OPERATOR_ATTRIBUTE
 void *operator new(size_t size, std::align_val_t align)
-{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW); }
+{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW, false /*nothrow*/); }
 CXX_OPERATOR_ATTRIBUTE
 void *operator new[](size_t size, std::align_val_t align)
-{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR); }
+{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, false /*nothrow*/); }
 CXX_OPERATOR_ATTRIBUTE
 void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&)
-{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW); }
+{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW, true /*nothrow*/); }
 CXX_OPERATOR_ATTRIBUTE
 void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)
-{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR); }
+{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, true /*nothrow*/); }
 
 #else  // SANITIZER_MAC
 INTERCEPTOR(void *, _Znwm, size_t size) {
-  OPERATOR_NEW_BODY(FROM_NEW);
+  OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/);
 }
 INTERCEPTOR(void *, _Znam, size_t size) {
-  OPERATOR_NEW_BODY(FROM_NEW_BR);
+  OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/);
 }
 INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
-  OPERATOR_NEW_BODY(FROM_NEW);
+  OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/);
 }
 INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
-  OPERATOR_NEW_BODY(FROM_NEW_BR);
+  OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/);
 }
 #endif
 

Modified: compiler-rt/trunk/lib/lsan/lsan_interceptors.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/lsan/lsan_interceptors.cc?rev=306604&r1=306603&r2=306604&view=diff
==============================================================================
--- compiler-rt/trunk/lib/lsan/lsan_interceptors.cc (original)
+++ compiler-rt/trunk/lib/lsan/lsan_interceptors.cc Wed Jun 28 14:58:57 2017
@@ -199,19 +199,26 @@ INTERCEPTOR(int, mprobe, void *ptr) {
 }
 #endif // SANITIZER_INTERCEPT_MCHECK_MPROBE
 
-#define OPERATOR_NEW_BODY                              \
-  ENSURE_LSAN_INITED;                                  \
-  GET_STACK_TRACE_MALLOC;                              \
-  return Allocate(stack, size, 1, kAlwaysClearMemory);
+// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
+#define OPERATOR_NEW_BODY(nothrow)                         \
+  ENSURE_LSAN_INITED;                                      \
+  GET_STACK_TRACE_MALLOC;                                  \
+  void *res = Allocate(stack, size, 1, kAlwaysClearMemory);\
+  if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
+  return res;
 
 INTERCEPTOR_ATTRIBUTE
-void *operator new(size_t size) { OPERATOR_NEW_BODY; }
+void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
 INTERCEPTOR_ATTRIBUTE
-void *operator new[](size_t size) { OPERATOR_NEW_BODY; }
+void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
 INTERCEPTOR_ATTRIBUTE
-void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+void *operator new(size_t size, std::nothrow_t const&) {
+  OPERATOR_NEW_BODY(true /*nothrow*/);
+}
 INTERCEPTOR_ATTRIBUTE
-void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+void *operator new[](size_t size, std::nothrow_t const&) {
+  OPERATOR_NEW_BODY(true /*nothrow*/);
+}
 
 #define OPERATOR_DELETE_BODY \
   ENSURE_LSAN_INITED;        \

Modified: compiler-rt/trunk/lib/msan/msan_new_delete.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/msan/msan_new_delete.cc?rev=306604&r1=306603&r2=306604&view=diff
==============================================================================
--- compiler-rt/trunk/lib/msan/msan_new_delete.cc (original)
+++ compiler-rt/trunk/lib/msan/msan_new_delete.cc Wed Jun 28 14:58:57 2017
@@ -14,6 +14,7 @@
 
 #include "msan.h"
 #include "interception/interception.h"
+#include "sanitizer_common/sanitizer_allocator.h"
 
 #if MSAN_REPLACE_OPERATORS_NEW_AND_DELETE
 
@@ -27,18 +28,25 @@ namespace std {
 }  // namespace std
 
 
-#define OPERATOR_NEW_BODY \
+// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
+#define OPERATOR_NEW_BODY(nothrow) \
   GET_MALLOC_STACK_TRACE; \
-  return MsanReallocate(&stack, 0, size, sizeof(u64), false)
+  void *res = MsanReallocate(&stack, 0, size, sizeof(u64), false);\
+  if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
+  return res
 
 INTERCEPTOR_ATTRIBUTE
-void *operator new(size_t size) { OPERATOR_NEW_BODY; }
+void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
 INTERCEPTOR_ATTRIBUTE
-void *operator new[](size_t size) { OPERATOR_NEW_BODY; }
+void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
 INTERCEPTOR_ATTRIBUTE
-void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+void *operator new(size_t size, std::nothrow_t const&) {
+  OPERATOR_NEW_BODY(true /*nothrow*/);
+}
 INTERCEPTOR_ATTRIBUTE
-void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+void *operator new[](size_t size, std::nothrow_t const&) {
+  OPERATOR_NEW_BODY(true /*nothrow*/);
+}
 
 #define OPERATOR_DELETE_BODY \
   GET_MALLOC_STACK_TRACE; \

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator.cc?rev=306604&r1=306603&r2=306604&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator.cc (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator.cc Wed Jun 28 14:58:57 2017
@@ -246,11 +246,11 @@ void *ReturnNullOrDieOnFailure::OnOOM()
   ReportAllocatorCannotReturnNull();
 }
 
-void *DieOnFailure::OnBadRequest() {
+void NORETURN *DieOnFailure::OnBadRequest() {
   ReportAllocatorCannotReturnNull();
 }
 
-void *DieOnFailure::OnOOM() {
+void NORETURN *DieOnFailure::OnOOM() {
   atomic_store_relaxed(&allocator_out_of_memory, 1);
   ReportAllocatorCannotReturnNull();
 }

Modified: compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator.h?rev=306604&r1=306603&r2=306604&view=diff
==============================================================================
--- compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator.h (original)
+++ compiler-rt/trunk/lib/sanitizer_common/sanitizer_allocator.h Wed Jun 28 14:58:57 2017
@@ -39,8 +39,8 @@ struct ReturnNullOrDieOnFailure {
 };
 // Always dies on the failure.
 struct DieOnFailure {
-  static void *OnBadRequest();
-  static void *OnOOM();
+  static void NORETURN *OnBadRequest();
+  static void NORETURN *OnOOM();
 };
 
 // Returns true if allocator detected OOM condition. Can be used to avoid memory

Modified: compiler-rt/trunk/lib/scudo/scudo_new_delete.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/scudo/scudo_new_delete.cpp?rev=306604&r1=306603&r2=306604&view=diff
==============================================================================
--- compiler-rt/trunk/lib/scudo/scudo_new_delete.cpp (original)
+++ compiler-rt/trunk/lib/scudo/scudo_new_delete.cpp Wed Jun 28 14:58:57 2017
@@ -26,13 +26,18 @@ namespace std {
 struct nothrow_t {};
 }  // namespace std
 
+// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
 CXX_OPERATOR_ATTRIBUTE
 void *operator new(size_t size) {
-  return scudoMalloc(size, FromNew);
+  void *res = scudoMalloc(size, FromNew);
+  if (UNLIKELY(!res)) DieOnFailure::OnOOM();
+  return res;
 }
 CXX_OPERATOR_ATTRIBUTE
 void *operator new[](size_t size) {
-  return scudoMalloc(size, FromNewArray);
+  void *res = scudoMalloc(size, FromNewArray);
+  if (UNLIKELY(!res)) DieOnFailure::OnOOM();
+  return res;
 }
 CXX_OPERATOR_ATTRIBUTE
 void *operator new(size_t size, std::nothrow_t const&) {

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_new_delete.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_new_delete.cc?rev=306604&r1=306603&r2=306604&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_new_delete.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_new_delete.cc Wed Jun 28 14:58:57 2017
@@ -12,6 +12,7 @@
 // Interceptors for operators new and delete.
 //===----------------------------------------------------------------------===//
 #include "interception/interception.h"
+#include "sanitizer_common/sanitizer_allocator.h"
 #include "sanitizer_common/sanitizer_internal_defs.h"
 #include "tsan_interceptors.h"
 
@@ -24,13 +25,15 @@ struct nothrow_t {};
 DECLARE_REAL(void *, malloc, uptr size)
 DECLARE_REAL(void, free, void *ptr)
 
-#define OPERATOR_NEW_BODY(mangled_name) \
+// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
+#define OPERATOR_NEW_BODY(mangled_name, nothrow) \
   if (cur_thread()->in_symbolizer) \
     return InternalAlloc(size); \
   void *p = 0; \
   {  \
     SCOPED_INTERCEPTOR_RAW(mangled_name, size); \
     p = user_alloc(thr, pc, size); \
+    if (!nothrow && UNLIKELY(!p)) DieOnFailure::OnOOM(); \
   }  \
   invoke_malloc_hook(p, size);  \
   return p;
@@ -38,25 +41,25 @@ DECLARE_REAL(void, free, void *ptr)
 SANITIZER_INTERFACE_ATTRIBUTE
 void *operator new(__sanitizer::uptr size);
 void *operator new(__sanitizer::uptr size) {
-  OPERATOR_NEW_BODY(_Znwm);
+  OPERATOR_NEW_BODY(_Znwm, false /*nothrow*/);
 }
 
 SANITIZER_INTERFACE_ATTRIBUTE
 void *operator new[](__sanitizer::uptr size);
 void *operator new[](__sanitizer::uptr size) {
-  OPERATOR_NEW_BODY(_Znam);
+  OPERATOR_NEW_BODY(_Znam, false /*nothrow*/);
 }
 
 SANITIZER_INTERFACE_ATTRIBUTE
 void *operator new(__sanitizer::uptr size, std::nothrow_t const&);
 void *operator new(__sanitizer::uptr size, std::nothrow_t const&) {
-  OPERATOR_NEW_BODY(_ZnwmRKSt9nothrow_t);
+  OPERATOR_NEW_BODY(_ZnwmRKSt9nothrow_t, true /*nothrow*/);
 }
 
 SANITIZER_INTERFACE_ATTRIBUTE
 void *operator new[](__sanitizer::uptr size, std::nothrow_t const&);
 void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) {
-  OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t);
+  OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t, true /*nothrow*/);
 }
 
 #define OPERATOR_DELETE_BODY(mangled_name) \

Modified: compiler-rt/trunk/test/asan/TestCases/allocator_returns_null.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/asan/TestCases/allocator_returns_null.cc?rev=306604&r1=306603&r2=306604&view=diff
==============================================================================
--- compiler-rt/trunk/test/asan/TestCases/allocator_returns_null.cc (original)
+++ compiler-rt/trunk/test/asan/TestCases/allocator_returns_null.cc Wed Jun 28 14:58:57 2017
@@ -1,68 +1,97 @@
-// Test the behavior of malloc/calloc/realloc when the allocation size is huge.
+// Test the behavior of malloc/calloc/realloc/new when the allocation size is
+// more than ASan allocator's max allowed one.
 // By default (allocator_may_return_null=0) the process should crash.
-// With allocator_may_return_null=1 the allocator should return 0.
+// With allocator_may_return_null=1 the allocator should return 0, except the
+// operator new(), which should crash anyway (operator new(std::nothrow) should
+// return nullptr, indeed).
 //
 // RUN: %clangxx_asan -O0 %s -o %t
 // RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
-// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
-// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mNULL
-// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
-// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cNULL
-// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
-// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coNULL
-// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
-// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rNULL
-// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
-// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrNULL
+// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-mCRASH
+// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t malloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-mNULL
+// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-cCRASH
+// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t calloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-cNULL
+// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-coCRASH
+// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t calloc-overflow 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-coNULL
+// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-rCRASH
+// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t realloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-rNULL
+// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-mrCRASH
+// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t realloc-after-malloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-mrNULL
+// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t new 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH
+// RUN: %env_asan_opts=allocator_may_return_null=1 not %run %t new 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH
+// RUN: %env_asan_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-nnCRASH
+// RUN: %env_asan_opts=allocator_may_return_null=1     %run %t new-nothrow 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-nnNULL
 
-#include <limits.h>
-#include <stdlib.h>
+#include <assert.h>
 #include <string.h>
 #include <stdio.h>
-#include <assert.h>
+#include <stdlib.h>
 #include <limits>
+#include <new>
+
 int main(int argc, char **argv) {
   // Disable stderr buffering. Needed on Windows.
   setvbuf(stderr, NULL, _IONBF, 0);
 
-  volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
   assert(argc == 2);
-  void *x = 0;
-  if (!strcmp(argv[1], "malloc")) {
-    fprintf(stderr, "malloc:\n");
-    x = malloc(size);
-  }
-  if (!strcmp(argv[1], "calloc")) {
-    fprintf(stderr, "calloc:\n");
-    x = calloc(size / 4, 4);
-  }
+  const char *action = argv[1];
+  fprintf(stderr, "%s:\n", action);
 
-  if (!strcmp(argv[1], "calloc-overflow")) {
-    fprintf(stderr, "calloc-overflow:\n");
+  static const size_t kMaxAllowedMallocSizePlusOne =
+#if __LP64__ || defined(_WIN64)
+      (1ULL << 40) + 1;
+#else
+      (3UL << 30) + 1;
+#endif
+
+  void *x = 0;
+  if (!strcmp(action, "malloc")) {
+    x = malloc(kMaxAllowedMallocSizePlusOne);
+  } else if (!strcmp(action, "calloc")) {
+    x = calloc((kMaxAllowedMallocSizePlusOne / 4) + 1, 4);
+  } else if (!strcmp(action, "calloc-overflow")) {
     volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
     size_t kArraySize = 4096;
     volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
     x = calloc(kArraySize, kArraySize2);
-  }
-
-  if (!strcmp(argv[1], "realloc")) {
-    fprintf(stderr, "realloc:\n");
-    x = realloc(0, size);
-  }
-  if (!strcmp(argv[1], "realloc-after-malloc")) {
-    fprintf(stderr, "realloc-after-malloc:\n");
+  } else if (!strcmp(action, "realloc")) {
+    x = realloc(0, kMaxAllowedMallocSizePlusOne);
+  } else if (!strcmp(action, "realloc-after-malloc")) {
     char *t = (char*)malloc(100);
     *t = 42;
-    x = realloc(t, size);
+    x = realloc(t, kMaxAllowedMallocSizePlusOne);
     assert(*t == 42);
     free(t);
+  } else if (!strcmp(action, "new")) {
+    x = operator new(kMaxAllowedMallocSizePlusOne);
+  } else if (!strcmp(action, "new-nothrow")) {
+    x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow);
+  } else {
+    assert(0);
   }
+
   // The NULL pointer is printed differently on different systems, while (long)0
   // is always the same.
   fprintf(stderr, "x: %lx\n", (long)x);
   free(x);
+
   return x != 0;
 }
+
 // CHECK-mCRASH: malloc:
 // CHECK-mCRASH: AddressSanitizer's allocator is terminating the process
 // CHECK-cCRASH: calloc:
@@ -73,6 +102,10 @@ int main(int argc, char **argv) {
 // CHECK-rCRASH: AddressSanitizer's allocator is terminating the process
 // CHECK-mrCRASH: realloc-after-malloc:
 // CHECK-mrCRASH: AddressSanitizer's allocator is terminating the process
+// CHECK-nCRASH: new:
+// CHECK-nCRASH: AddressSanitizer's allocator is terminating the process
+// CHECK-nnCRASH: new-nothrow:
+// CHECK-nnCRASH: AddressSanitizer's allocator is terminating the process
 
 // CHECK-mNULL: malloc:
 // CHECK-mNULL: x: 0
@@ -84,3 +117,5 @@ int main(int argc, char **argv) {
 // CHECK-rNULL: x: 0
 // CHECK-mrNULL: realloc-after-malloc:
 // CHECK-mrNULL: x: 0
+// CHECK-nnNULL: new-nothrow:
+// CHECK-nnNULL: x: 0

Modified: compiler-rt/trunk/test/msan/allocator_returns_null.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/msan/allocator_returns_null.cc?rev=306604&r1=306603&r2=306604&view=diff
==============================================================================
--- compiler-rt/trunk/test/msan/allocator_returns_null.cc (original)
+++ compiler-rt/trunk/test/msan/allocator_returns_null.cc Wed Jun 28 14:58:57 2017
@@ -1,63 +1,98 @@
-// Test the behavior of malloc/calloc/realloc when the allocation size is huge.
+// Test the behavior of malloc/calloc/realloc/new when the allocation size is
+// more than MSan allocator's max allowed one.
 // By default (allocator_may_return_null=0) the process should crash.
-// With allocator_may_return_null=1 the allocator should return 0.
+// With allocator_may_return_null=1 the allocator should return 0, except the
+// operator new(), which should crash anyway (operator new(std::nothrow) should
+// return nullptr, indeed).
 //
 // RUN: %clangxx_msan -O0 %s -o %t
 // RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mNULL
-// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cNULL
-// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coNULL
-// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rNULL
-// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
-// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrNULL
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t malloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-mCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t malloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-mNULL
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-cCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t calloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-cNULL
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-coCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t calloc-overflow 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-coNULL
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-rCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t realloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-rNULL
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-mrCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t realloc-after-malloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-mrNULL
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t new 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1 not %run %t new 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-nnCRASH
+// RUN: MSAN_OPTIONS=allocator_may_return_null=1     %run %t new-nothrow 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-nnNULL
 
-#include <limits.h>
-#include <stdlib.h>
+
+#include <assert.h>
 #include <string.h>
 #include <stdio.h>
-#include <assert.h>
+#include <stdlib.h>
 #include <limits>
+#include <new>
+
 int main(int argc, char **argv) {
-  volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
+  // Disable stderr buffering. Needed on Windows.
+  setvbuf(stderr, NULL, _IONBF, 0);
+
   assert(argc == 2);
-  char *x = 0;
-  if (!strcmp(argv[1], "malloc")) {
-    fprintf(stderr, "malloc:\n");
-    x = (char*)malloc(size);
-  }
-  if (!strcmp(argv[1], "calloc")) {
-    fprintf(stderr, "calloc:\n");
-    x = (char*)calloc(size / 4, 4);
-  }
+  const char *action = argv[1];
+  fprintf(stderr, "%s:\n", action);
+
+  static const size_t kMaxAllowedMallocSizePlusOne =
+#if __LP64__ || defined(_WIN64)
+      (8UL << 30) + 1;
+#else
+      (2UL << 30) + 1;
+#endif
 
-  if (!strcmp(argv[1], "calloc-overflow")) {
-    fprintf(stderr, "calloc-overflow:\n");
+  void *x = 0;
+  if (!strcmp(action, "malloc")) {
+    x = malloc(kMaxAllowedMallocSizePlusOne);
+  } else if (!strcmp(action, "calloc")) {
+    x = calloc((kMaxAllowedMallocSizePlusOne / 4) + 1, 4);
+  } else if (!strcmp(action, "calloc-overflow")) {
     volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
     size_t kArraySize = 4096;
     volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
-    x = (char*)calloc(kArraySize, kArraySize2);
-  }
-
-  if (!strcmp(argv[1], "realloc")) {
-    fprintf(stderr, "realloc:\n");
-    x = (char*)realloc(0, size);
-  }
-  if (!strcmp(argv[1], "realloc-after-malloc")) {
-    fprintf(stderr, "realloc-after-malloc:\n");
+    x = calloc(kArraySize, kArraySize2);
+  } else if (!strcmp(action, "realloc")) {
+    x = realloc(0, kMaxAllowedMallocSizePlusOne);
+  } else if (!strcmp(action, "realloc-after-malloc")) {
     char *t = (char*)malloc(100);
     *t = 42;
-    x = (char*)realloc(t, size);
+    x = realloc(t, kMaxAllowedMallocSizePlusOne);
     assert(*t == 42);
+    free(t);
+  } else if (!strcmp(action, "new")) {
+    x = operator new(kMaxAllowedMallocSizePlusOne);
+  } else if (!strcmp(action, "new-nothrow")) {
+    x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow);
+  } else {
+    assert(0);
   }
+
   // The NULL pointer is printed differently on different systems, while (long)0
   // is always the same.
   fprintf(stderr, "x: %lx\n", (long)x);
+  free(x);
+
   return x != 0;
 }
+
 // CHECK-mCRASH: malloc:
 // CHECK-mCRASH: MemorySanitizer's allocator is terminating the process
 // CHECK-cCRASH: calloc:
@@ -68,6 +103,10 @@ int main(int argc, char **argv) {
 // CHECK-rCRASH: MemorySanitizer's allocator is terminating the process
 // CHECK-mrCRASH: realloc-after-malloc:
 // CHECK-mrCRASH: MemorySanitizer's allocator is terminating the process
+// CHECK-nCRASH: new:
+// CHECK-nCRASH: MemorySanitizer's allocator is terminating the process
+// CHECK-nnCRASH: new-nothrow:
+// CHECK-nnCRASH: MemorySanitizer's allocator is terminating the process
 
 // CHECK-mNULL: malloc:
 // CHECK-mNULL: x: 0
@@ -79,3 +118,5 @@ int main(int argc, char **argv) {
 // CHECK-rNULL: x: 0
 // CHECK-mrNULL: realloc-after-malloc:
 // CHECK-mrNULL: x: 0
+// CHECK-nnNULL: new-nothrow:
+// CHECK-nnNULL: x: 0

Modified: compiler-rt/trunk/test/scudo/sizes.cpp
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/scudo/sizes.cpp?rev=306604&r1=306603&r2=306604&view=diff
==============================================================================
--- compiler-rt/trunk/test/scudo/sizes.cpp (original)
+++ compiler-rt/trunk/test/scudo/sizes.cpp Wed Jun 28 14:58:57 2017
@@ -1,8 +1,12 @@
-// RUN: %clang_scudo %s -o %t
+// RUN: %clang_scudo %s -lstdc++ -o %t
 // RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s
 // RUN: SCUDO_OPTIONS=allocator_may_return_null=1     %run %t malloc 2>&1
 // RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s
 // RUN: SCUDO_OPTIONS=allocator_may_return_null=1     %run %t calloc 2>&1
+// RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t new 2>&1 | FileCheck %s
+// RUN: SCUDO_OPTIONS=allocator_may_return_null=1 not %run %t new 2>&1 | FileCheck %s
+// RUN: SCUDO_OPTIONS=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 | FileCheck %s
+// RUN: SCUDO_OPTIONS=allocator_may_return_null=1     %run %t new-nothrow 2>&1
 // RUN:                                               %run %t usable 2>&1
 
 // Tests for various edge cases related to sizes, notably the maximum size the
@@ -15,26 +19,38 @@
 #include <string.h>
 
 #include <limits>
+#include <new>
 
-int main(int argc, char **argv)
-{
+int main(int argc, char **argv) {
   assert(argc == 2);
-  if (!strcmp(argv[1], "malloc")) {
-    // Currently the maximum size the allocator can allocate is 1ULL<<40 bytes.
-    size_t size = std::numeric_limits<size_t>::max();
-    void *p = malloc(size);
+  const char *action = argv[1];
+  fprintf(stderr, "%s:\n", action);
+
+#if __LP64__ || defined(_WIN64)
+  static const size_t kMaxAllowedMallocSize = 1ULL << 40;
+  static const size_t kChunkHeaderSize = 16;
+#else
+  static const size_t kMaxAllowedMallocSize = 2UL << 30;
+  static const size_t kChunkHeaderSize = 8;
+#endif
+
+  if (!strcmp(action, "malloc")) {
+    void *p = malloc(kMaxAllowedMallocSize);
     assert(!p);
-    size = (1ULL << 40) - 16;
-    p = malloc(size);
+    p = malloc(kMaxAllowedMallocSize - kChunkHeaderSize);
     assert(!p);
-  }
-  if (!strcmp(argv[1], "calloc")) {
+  } else if (!strcmp(action, "calloc")) {
     // Trigger an overflow in calloc.
     size_t size = std::numeric_limits<size_t>::max();
     void *p = calloc((size / 0x1000) + 1, 0x1000);
     assert(!p);
-  }
-  if (!strcmp(argv[1], "usable")) {
+  } else if (!strcmp(action, "new")) {
+    void *p = operator new(kMaxAllowedMallocSize);
+    assert(!p);
+  } else if (!strcmp(action, "new-nothrow")) {
+    void *p = operator new(kMaxAllowedMallocSize, std::nothrow);
+    assert(!p);
+  } else if (!strcmp(action, "usable")) {
     // Playing with the actual usable size of a chunk.
     void *p = malloc(1007);
     assert(p);
@@ -47,7 +63,10 @@ int main(int argc, char **argv)
     assert(size >= 2014);
     memset(p, 'B', size);
     free(p);
+  } else {
+    assert(0);
   }
+
   return 0;
 }
 

Modified: compiler-rt/trunk/test/tsan/allocator_returns_null.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/test/tsan/allocator_returns_null.cc?rev=306604&r1=306603&r2=306604&view=diff
==============================================================================
--- compiler-rt/trunk/test/tsan/allocator_returns_null.cc (original)
+++ compiler-rt/trunk/test/tsan/allocator_returns_null.cc Wed Jun 28 14:58:57 2017
@@ -1,56 +1,90 @@
-// Test the behavior of malloc/calloc/realloc when the allocation size is huge.
+// Test the behavior of malloc/calloc/realloc/new when the allocation size is
+// more than TSan allocator's max allowed one.
 // By default (allocator_may_return_null=0) the process should crash.
-// With allocator_may_return_null=1 the allocator should return 0.
+// With allocator_may_return_null=1 the allocator should return 0, except the
+// operator new(), which should crash anyway (operator new(std::nothrow) should
+// return nullptr, indeed).
 //
 // RUN: %clangxx_tsan -O0 %s -o %t
 // RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
-// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
-// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
-// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 | FileCheck %s --check-prefix=CHECK-coCRASH
-// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
-// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mrCRASH
+// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-mCRASH
+// RUN: %env_tsan_opts=allocator_may_return_null=1     %run %t malloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-mNULL
+// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-cCRASH
+// RUN: %env_tsan_opts=allocator_may_return_null=1     %run %t calloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-cNULL
+// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-coCRASH
+// RUN: %env_tsan_opts=allocator_may_return_null=1     %run %t calloc-overflow 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-coNULL
+// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-rCRASH
+// RUN: %env_tsan_opts=allocator_may_return_null=1     %run %t realloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-rNULL
+// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-mrCRASH
+// RUN: %env_tsan_opts=allocator_may_return_null=1     %run %t realloc-after-malloc 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-mrNULL
+// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t new 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH
+// RUN: %env_tsan_opts=allocator_may_return_null=1 not %run %t new 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-nCRASH
+// RUN: %env_tsan_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-nnCRASH
+// RUN: %env_tsan_opts=allocator_may_return_null=1     %run %t new-nothrow 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=CHECK-nnNULL
 
-#include <limits.h>
-#include <stdlib.h>
+#include <assert.h>
 #include <string.h>
 #include <stdio.h>
-#include <assert.h>
+#include <stdlib.h>
 #include <limits>
+#include <new>
+
 int main(int argc, char **argv) {
-  volatile size_t size = std::numeric_limits<size_t>::max() - 10000;
+  // Disable stderr buffering. Needed on Windows.
+  setvbuf(stderr, NULL, _IONBF, 0);
+
   assert(argc == 2);
-  char *x = 0;
-  if (!strcmp(argv[1], "malloc")) {
-    fprintf(stderr, "malloc:\n");
-    x = (char*)malloc(size);
-  }
-  if (!strcmp(argv[1], "calloc")) {
-    fprintf(stderr, "calloc:\n");
-    x = (char*)calloc(size / 4, 4);
-  }
+  const char *action = argv[1];
+  fprintf(stderr, "%s:\n", action);
+
+  static const size_t kMaxAllowedMallocSizePlusOne = (1ULL << 40) + 1;
 
-  if (!strcmp(argv[1], "calloc-overflow")) {
-    fprintf(stderr, "calloc-overflow:\n");
+  void *x = 0;
+  if (!strcmp(action, "malloc")) {
+    x = malloc(kMaxAllowedMallocSizePlusOne);
+  } else if (!strcmp(action, "calloc")) {
+    x = calloc((kMaxAllowedMallocSizePlusOne / 4) + 1, 4);
+  } else if (!strcmp(action, "calloc-overflow")) {
     volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
     size_t kArraySize = 4096;
     volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
-    x = (char*)calloc(kArraySize, kArraySize2);
-  }
-
-  if (!strcmp(argv[1], "realloc")) {
-    fprintf(stderr, "realloc:\n");
-    x = (char*)realloc(0, size);
-  }
-  if (!strcmp(argv[1], "realloc-after-malloc")) {
-    fprintf(stderr, "realloc-after-malloc:\n");
+    x = calloc(kArraySize, kArraySize2);
+  } else if (!strcmp(action, "realloc")) {
+    x = realloc(0, kMaxAllowedMallocSizePlusOne);
+  } else if (!strcmp(action, "realloc-after-malloc")) {
     char *t = (char*)malloc(100);
     *t = 42;
-    x = (char*)realloc(t, size);
+    x = realloc(t, kMaxAllowedMallocSizePlusOne);
     assert(*t == 42);
+  } else if (!strcmp(action, "new")) {
+    x = operator new(kMaxAllowedMallocSizePlusOne);
+  } else if (!strcmp(action, "new-nothrow")) {
+    x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow);
+  } else {
+    assert(0);
   }
-  fprintf(stderr, "x: %p\n", x);
+
+  // The NULL pointer is printed differently on different systems, while (long)0
+  // is always the same.
+  fprintf(stderr, "x: %lx\n", (long)x);
+  free(x);
   return x != 0;
 }
+
 // CHECK-mCRASH: malloc:
 // CHECK-mCRASH: ThreadSanitizer's allocator is terminating the process
 // CHECK-cCRASH: calloc:
@@ -61,4 +95,20 @@ int main(int argc, char **argv) {
 // CHECK-rCRASH: ThreadSanitizer's allocator is terminating the process
 // CHECK-mrCRASH: realloc-after-malloc:
 // CHECK-mrCRASH: ThreadSanitizer's allocator is terminating the process
+// CHECK-nCRASH: new:
+// CHECK-nCRASH: ThreadSanitizer's allocator is terminating the process
+// CHECK-nnCRASH: new-nothrow:
+// CHECK-nnCRASH: ThreadSanitizer's allocator is terminating the process
 
+// CHECK-mNULL: malloc:
+// CHECK-mNULL: x: 0
+// CHECK-cNULL: calloc:
+// CHECK-cNULL: x: 0
+// CHECK-coNULL: calloc-overflow:
+// CHECK-coNULL: x: 0
+// CHECK-rNULL: realloc:
+// CHECK-rNULL: x: 0
+// CHECK-mrNULL: realloc-after-malloc:
+// CHECK-mrNULL: x: 0
+// CHECK-nnNULL: new-nothrow:
+// CHECK-nnNULL: x: 0




More information about the llvm-commits mailing list