summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Shlyapnikov <alekseys@google.com>2018-06-07 23:33:33 +0000
committerAlex Shlyapnikov <alekseys@google.com>2018-06-07 23:33:33 +0000
commitaf1272918541ac6c8cfe0925a69ca7b17e4ebdb7 (patch)
tree912f188c0afe408514ecbe7629da72a412b162a3
parentdb8d205fbfe9ca7e38a7892b1202867d49de704d (diff)
downloadbcm5719-llvm-af1272918541ac6c8cfe0925a69ca7b17e4ebdb7.tar.gz
bcm5719-llvm-af1272918541ac6c8cfe0925a69ca7b17e4ebdb7.zip
[HWASan] Report proper error on allocator failures instead of CHECK(0)-ing
Summary: Currently many allocator specific errors (OOM, for example) are reported as a text message and CHECK(0) termination, not stack, no details, not too helpful nor informative. To improve the situation, detailed and structured errors were defined and reported under the appropriate conditions. Reviewers: eugenis Subscribers: kubamracek, delcypher, llvm-commits, #sanitizers Differential Revision: https://reviews.llvm.org/D47798 llvm-svn: 334248
-rw-r--r--compiler-rt/lib/hwasan/hwasan.cc5
-rw-r--r--compiler-rt/lib/hwasan/hwasan.h11
-rw-r--r--compiler-rt/lib/hwasan/hwasan_allocator.cc56
-rw-r--r--compiler-rt/lib/hwasan/hwasan_interceptors.cc1
-rw-r--r--compiler-rt/lib/hwasan/hwasan_linux.cc1
-rw-r--r--compiler-rt/lib/hwasan/hwasan_new_delete.cc5
-rw-r--r--compiler-rt/lib/hwasan/hwasan_report.cc9
-rw-r--r--compiler-rt/lib/hwasan/hwasan_report.h36
-rw-r--r--compiler-rt/test/hwasan/TestCases/Linux/aligned_alloc-alignment.cc25
-rw-r--r--compiler-rt/test/hwasan/TestCases/Linux/lit.local.cfg9
-rw-r--r--compiler-rt/test/hwasan/TestCases/Linux/pvalloc-overflow.cc46
-rw-r--r--compiler-rt/test/hwasan/TestCases/Posix/lit.local.cfg9
-rw-r--r--compiler-rt/test/hwasan/TestCases/Posix/posix_memalign-alignment.cc22
-rw-r--r--compiler-rt/test/hwasan/TestCases/allocator_returns_null.cc115
14 files changed, 315 insertions, 35 deletions
diff --git a/compiler-rt/lib/hwasan/hwasan.cc b/compiler-rt/lib/hwasan/hwasan.cc
index d300e0bde41..05818e1ca09 100644
--- a/compiler-rt/lib/hwasan/hwasan.cc
+++ b/compiler-rt/lib/hwasan/hwasan.cc
@@ -1,4 +1,4 @@
-//===-- hwasan.cc -----------------------------------------------------------===//
+//===-- hwasan.cc ---------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -14,8 +14,9 @@
#include "hwasan.h"
#include "hwasan_mapping.h"
-#include "hwasan_thread.h"
#include "hwasan_poisoning.h"
+#include "hwasan_report.h"
+#include "hwasan_thread.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_flags.h"
diff --git a/compiler-rt/lib/hwasan/hwasan.h b/compiler-rt/lib/hwasan/hwasan.h
index 3c6b44f7f11..47d1d057a0d 100644
--- a/compiler-rt/lib/hwasan/hwasan.h
+++ b/compiler-rt/lib/hwasan/hwasan.h
@@ -1,4 +1,4 @@
-//===-- hwasan.h --------------------------------------------------*- C++ -*-===//
+//===-- hwasan.h ------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@@ -97,15 +97,6 @@ void PrintWarning(uptr pc, uptr bp);
void GetStackTrace(BufferedStackTrace *stack, uptr max_s, uptr pc, uptr bp,
void *context, bool request_fast_unwind);
-void ReportInvalidAccess(StackTrace *stack, u32 origin);
-void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size,
- bool is_store);
-void ReportStats();
-void ReportAtExitStatistics();
-void DescribeMemoryRange(const void *x, uptr size);
-void ReportInvalidAccessInsideAddressRange(const char *what, const void *start, uptr size,
- uptr offset);
-
// Returns a "chained" origin id, pointing to the given stack trace followed by
// the previous origin id.
u32 ChainOrigin(u32 id, StackTrace *stack);
diff --git a/compiler-rt/lib/hwasan/hwasan_allocator.cc b/compiler-rt/lib/hwasan/hwasan_allocator.cc
index 3a9da80d928..c2b9b0b6958 100644
--- a/compiler-rt/lib/hwasan/hwasan_allocator.cc
+++ b/compiler-rt/lib/hwasan/hwasan_allocator.cc
@@ -1,4 +1,4 @@
-//===-- hwasan_allocator.cc --------------------------- ---------------------===//
+//===-- hwasan_allocator.cc ------------------------- ---------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,6 +15,7 @@
#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_allocator_checks.h"
#include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "sanitizer_common/sanitizer_allocator_report.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_errno.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
@@ -127,9 +128,12 @@ static void *HwasanAllocate(StackTrace *stack, uptr size, uptr alignment,
size = RoundUpTo(size, kShadowAlignment);
if (size > kMaxAllowedMallocSize) {
- Report("WARNING: HWAddressSanitizer failed to allocate %p bytes\n",
- (void *)size);
- return ReturnNullOrDieOnFailure::OnBadRequest();
+ if (AllocatorMayReturnNull()) {
+ Report("WARNING: HWAddressSanitizer failed to allocate 0x%zx bytes\n",
+ size);
+ return nullptr;
+ }
+ ReportAllocationSizeTooBig(size, kMaxAllowedMallocSize, stack);
}
HwasanThread *t = GetCurrentThread();
void *allocated;
@@ -141,8 +145,12 @@ static void *HwasanAllocate(StackTrace *stack, uptr size, uptr alignment,
AllocatorCache *cache = &fallback_allocator_cache;
allocated = allocator.Allocate(cache, size, alignment);
}
- if (UNLIKELY(!allocated))
- return ReturnNullOrDieOnFailure::OnOOM();
+ if (UNLIKELY(!allocated)) {
+ SetAllocatorOutOfMemory();
+ if (AllocatorMayReturnNull())
+ return nullptr;
+ ReportOutOfMemory(size, stack);
+ }
Metadata *meta =
reinterpret_cast<Metadata *>(allocator.GetMetaData(allocated));
meta->state = CHUNK_ALLOCATED;
@@ -224,6 +232,15 @@ void *HwasanReallocate(StackTrace *stack, void *user_old_p, uptr new_size,
return new_p;
}
+void *HwasanCalloc(StackTrace *stack, uptr nmemb, uptr size) {
+ if (UNLIKELY(CheckForCallocOverflow(size, nmemb))) {
+ if (AllocatorMayReturnNull())
+ return nullptr;
+ ReportCallocOverflow(nmemb, size, stack);
+ }
+ return HwasanAllocate(stack, nmemb * size, sizeof(u64), true);
+}
+
HwasanChunkView FindHeapChunkByAddress(uptr address) {
void *block = allocator.GetBlockBegin(reinterpret_cast<void*>(address));
if (!block)
@@ -247,9 +264,7 @@ void *hwasan_malloc(uptr size, StackTrace *stack) {
}
void *hwasan_calloc(uptr nmemb, uptr size, StackTrace *stack) {
- if (UNLIKELY(CheckForCallocOverflow(size, nmemb)))
- return SetErrnoOnNull(ReturnNullOrDieOnFailure::OnBadRequest());
- return SetErrnoOnNull(HwasanAllocate(stack, nmemb * size, sizeof(u64), true));
+ return SetErrnoOnNull(HwasanCalloc(stack, nmemb, size));
}
void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack) {
@@ -263,14 +278,17 @@ void *hwasan_realloc(void *ptr, uptr size, StackTrace *stack) {
}
void *hwasan_valloc(uptr size, StackTrace *stack) {
- return SetErrnoOnNull(HwasanAllocate(stack, size, GetPageSizeCached(), false));
+ return SetErrnoOnNull(
+ HwasanAllocate(stack, size, GetPageSizeCached(), false));
}
void *hwasan_pvalloc(uptr size, StackTrace *stack) {
uptr PageSize = GetPageSizeCached();
if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) {
errno = errno_ENOMEM;
- return ReturnNullOrDieOnFailure::OnBadRequest();
+ if (AllocatorMayReturnNull())
+ return nullptr;
+ ReportPvallocOverflow(size, stack);
}
// pvalloc(0) should allocate one page.
size = size ? RoundUpTo(size, PageSize) : PageSize;
@@ -280,7 +298,9 @@ void *hwasan_pvalloc(uptr size, StackTrace *stack) {
void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) {
if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(alignment, size))) {
errno = errno_EINVAL;
- return ReturnNullOrDieOnFailure::OnBadRequest();
+ if (AllocatorMayReturnNull())
+ return nullptr;
+ ReportInvalidAlignedAllocAlignment(size, alignment, stack);
}
return SetErrnoOnNull(HwasanAllocate(stack, size, alignment, false));
}
@@ -288,7 +308,9 @@ void *hwasan_aligned_alloc(uptr alignment, uptr size, StackTrace *stack) {
void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack) {
if (UNLIKELY(!IsPowerOfTwo(alignment))) {
errno = errno_EINVAL;
- return ReturnNullOrDieOnFailure::OnBadRequest();
+ if (AllocatorMayReturnNull())
+ return nullptr;
+ ReportInvalidAllocationAlignment(alignment, stack);
}
return SetErrnoOnNull(HwasanAllocate(stack, size, alignment, false));
}
@@ -296,18 +318,20 @@ void *hwasan_memalign(uptr alignment, uptr size, StackTrace *stack) {
int hwasan_posix_memalign(void **memptr, uptr alignment, uptr size,
StackTrace *stack) {
if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) {
- ReturnNullOrDieOnFailure::OnBadRequest();
- return errno_EINVAL;
+ if (AllocatorMayReturnNull())
+ return errno_EINVAL;
+ ReportInvalidPosixMemalignAlignment(alignment, stack);
}
void *ptr = HwasanAllocate(stack, size, alignment, false);
if (UNLIKELY(!ptr))
+ // OOM error is already taken care of by HwasanAllocate.
return errno_ENOMEM;
CHECK(IsAligned((uptr)ptr, alignment));
*memptr = ptr;
return 0;
}
-} // namespace __hwasan
+} // namespace __hwasan
using namespace __hwasan;
diff --git a/compiler-rt/lib/hwasan/hwasan_interceptors.cc b/compiler-rt/lib/hwasan/hwasan_interceptors.cc
index dfd35b59cec..66aab95db56 100644
--- a/compiler-rt/lib/hwasan/hwasan_interceptors.cc
+++ b/compiler-rt/lib/hwasan/hwasan_interceptors.cc
@@ -20,6 +20,7 @@
#include "hwasan_mapping.h"
#include "hwasan_thread.h"
#include "hwasan_poisoning.h"
+#include "hwasan_report.h"
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_allocator_interface.h"
diff --git a/compiler-rt/lib/hwasan/hwasan_linux.cc b/compiler-rt/lib/hwasan/hwasan_linux.cc
index 3d7923047ce..068fd768559 100644
--- a/compiler-rt/lib/hwasan/hwasan_linux.cc
+++ b/compiler-rt/lib/hwasan/hwasan_linux.cc
@@ -20,6 +20,7 @@
#include "hwasan_dynamic_shadow.h"
#include "hwasan_interface_internal.h"
#include "hwasan_mapping.h"
+#include "hwasan_report.h"
#include "hwasan_thread.h"
#include <elf.h>
diff --git a/compiler-rt/lib/hwasan/hwasan_new_delete.cc b/compiler-rt/lib/hwasan/hwasan_new_delete.cc
index 3ccc26734bf..63ca74edd48 100644
--- a/compiler-rt/lib/hwasan/hwasan_new_delete.cc
+++ b/compiler-rt/lib/hwasan/hwasan_new_delete.cc
@@ -1,4 +1,4 @@
-//===-- hwasan_new_delete.cc ------------------------------------------------===//
+//===-- hwasan_new_delete.cc ----------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -15,6 +15,7 @@
#include "hwasan.h"
#include "interception/interception.h"
#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_report.h"
#if HWASAN_REPLACE_OPERATORS_NEW_AND_DELETE
@@ -32,7 +33,7 @@ namespace std {
#define OPERATOR_NEW_BODY(nothrow) \
GET_MALLOC_STACK_TRACE; \
void *res = hwasan_malloc(size, &stack);\
- if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
+ if (!nothrow && UNLIKELY(!res)) ReportOutOfMemory(size, &stack);\
return res
INTERCEPTOR_ATTRIBUTE
diff --git a/compiler-rt/lib/hwasan/hwasan_report.cc b/compiler-rt/lib/hwasan/hwasan_report.cc
index 438a153f0ca..16e9016ea35 100644
--- a/compiler-rt/lib/hwasan/hwasan_report.cc
+++ b/compiler-rt/lib/hwasan/hwasan_report.cc
@@ -1,4 +1,4 @@
-//===-- hwasan_report.cc ----------------------------------------------------===//
+//===-- hwasan_report.cc --------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -37,9 +37,9 @@ static StackTrace GetStackTraceFromId(u32 id) {
class Decorator: public __sanitizer::SanitizerCommonDecorator {
public:
Decorator() : SanitizerCommonDecorator() { }
- const char *Allocation() { return Magenta(); }
- const char *Origin() { return Magenta(); }
- const char *Name() { return Green(); }
+ const char *Allocation() const { return Magenta(); }
+ const char *Origin() const { return Magenta(); }
+ const char *Name() const { return Green(); }
};
struct HeapAddressDescription {
@@ -130,5 +130,4 @@ void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size,
ReportErrorSummary("tag-mismatch", stack);
}
-
} // namespace __hwasan
diff --git a/compiler-rt/lib/hwasan/hwasan_report.h b/compiler-rt/lib/hwasan/hwasan_report.h
new file mode 100644
index 00000000000..bb33f1a8730
--- /dev/null
+++ b/compiler-rt/lib/hwasan/hwasan_report.h
@@ -0,0 +1,36 @@
+//===-- hwasan_report.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file is a part of HWAddressSanitizer. HWASan-private header for error
+/// reporting functions.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef HWASAN_REPORT_H
+#define HWASAN_REPORT_H
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+
+namespace __hwasan {
+
+void ReportInvalidAccess(StackTrace *stack, u32 origin);
+void ReportStats();
+void ReportInvalidAccessInsideAddressRange(const char *what, const void *start,
+ uptr size, uptr offset);
+void ReportTagMismatch(StackTrace *stack, uptr addr, uptr access_size,
+ bool is_store);
+
+void ReportAtExitStatistics();
+
+
+} // namespace __hwasan
+
+#endif // HWASAN_REPORT_H
diff --git a/compiler-rt/test/hwasan/TestCases/Linux/aligned_alloc-alignment.cc b/compiler-rt/test/hwasan/TestCases/Linux/aligned_alloc-alignment.cc
new file mode 100644
index 00000000000..a5dc7f661c7
--- /dev/null
+++ b/compiler-rt/test/hwasan/TestCases/Linux/aligned_alloc-alignment.cc
@@ -0,0 +1,25 @@
+// RUN: %clangxx_hwasan -O0 %s -o %t
+// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s
+// RUN: %env_hwasan_opts=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
+
+// UNSUPPORTED: android
+
+// REQUIRES: stable-runtime
+
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void *aligned_alloc(size_t alignment, size_t size);
+
+int main() {
+ void *p = aligned_alloc(17, 100);
+ // CHECK: ERROR: HWAddressSanitizer: invalid alignment requested in aligned_alloc: 17
+ // CHECK: {{#0 0x.* in .*}}{{aligned_alloc|memalign}}
+ // CHECK: {{#1 0x.* in main .*aligned_alloc-alignment.cc:}}[[@LINE-3]]
+ // CHECK: SUMMARY: HWAddressSanitizer: invalid-aligned-alloc-alignment
+
+ printf("pointer after failed aligned_alloc: %zd\n", (size_t)p);
+ // CHECK-NULL: pointer after failed aligned_alloc: 0
+
+ return 0;
+}
diff --git a/compiler-rt/test/hwasan/TestCases/Linux/lit.local.cfg b/compiler-rt/test/hwasan/TestCases/Linux/lit.local.cfg
new file mode 100644
index 00000000000..57271b8078a
--- /dev/null
+++ b/compiler-rt/test/hwasan/TestCases/Linux/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 ['Linux']:
+ config.unsupported = True
diff --git a/compiler-rt/test/hwasan/TestCases/Linux/pvalloc-overflow.cc b/compiler-rt/test/hwasan/TestCases/Linux/pvalloc-overflow.cc
new file mode 100644
index 00000000000..a4897c1279e
--- /dev/null
+++ b/compiler-rt/test/hwasan/TestCases/Linux/pvalloc-overflow.cc
@@ -0,0 +1,46 @@
+// RUN: %clangxx_hwasan -O0 %s -o %t
+// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t m1 2>&1 | FileCheck %s
+// RUN: %env_hwasan_opts=allocator_may_return_null=1 %run %t m1 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
+// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t psm1 2>&1 | FileCheck %s
+// RUN: %env_hwasan_opts=allocator_may_return_null=1 %run %t psm1 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
+
+// UNSUPPORTED: android
+
+// REQUIRES: stable-runtime
+
+// Checks that pvalloc overflows are caught. If the allocator is allowed to
+// return null, the errno should be set to ENOMEM.
+
+#include <assert.h>
+#include <errno.h>
+#include <malloc.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[]) {
+ assert(argc == 2);
+ const char *action = argv[1];
+
+ const size_t page_size = sysconf(_SC_PAGESIZE);
+
+ void *p = nullptr;
+ if (!strcmp(action, "m1")) {
+ p = pvalloc((uintptr_t)-1);
+ } else if (!strcmp(action, "psm1")) {
+ p = pvalloc((uintptr_t)-(page_size - 1));
+ } else {
+ assert(0);
+ }
+
+ fprintf(stderr, "errno: %d\n", errno);
+
+ return p != nullptr;
+}
+
+// CHECK: {{ERROR: HWAddressSanitizer: pvalloc parameters overflow: size .* rounded up to system page size .* cannot be represented in type size_t}}
+// CHECK: {{#0 0x.* in .*pvalloc}}
+// CHECK: {{#1 0x.* in main .*pvalloc-overflow.cc:}}
+// CHECK: SUMMARY: HWAddressSanitizer: pvalloc-overflow
+
+// CHECK-NULL: errno: 12
diff --git a/compiler-rt/test/hwasan/TestCases/Posix/lit.local.cfg b/compiler-rt/test/hwasan/TestCases/Posix/lit.local.cfg
new file mode 100644
index 00000000000..60a9460820a
--- /dev/null
+++ b/compiler-rt/test/hwasan/TestCases/Posix/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 in ['Windows']:
+ config.unsupported = True
diff --git a/compiler-rt/test/hwasan/TestCases/Posix/posix_memalign-alignment.cc b/compiler-rt/test/hwasan/TestCases/Posix/posix_memalign-alignment.cc
new file mode 100644
index 00000000000..1ecc39c42f2
--- /dev/null
+++ b/compiler-rt/test/hwasan/TestCases/Posix/posix_memalign-alignment.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_hwasan -O0 %s -o %t
+// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s
+// RUN: %env_hwasan_opts=allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
+
+// REQUIRES: stable-runtime
+
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+ void *p = reinterpret_cast<void*>(42);
+ int res = posix_memalign(&p, 17, 100);
+ // CHECK: ERROR: HWAddressSanitizer: invalid alignment requested in posix_memalign: 17
+ // CHECK: {{#0 0x.* in .*posix_memalign}}
+ // CHECK: {{#1 0x.* in main .*posix_memalign-alignment.cc:}}[[@LINE-3]]
+ // CHECK: SUMMARY: HWAddressSanitizer: invalid-posix-memalign-alignment
+
+ printf("pointer after failed posix_memalign: %zd\n", (size_t)p);
+ // CHECK-NULL: pointer after failed posix_memalign: 42
+
+ return 0;
+}
diff --git a/compiler-rt/test/hwasan/TestCases/allocator_returns_null.cc b/compiler-rt/test/hwasan/TestCases/allocator_returns_null.cc
new file mode 100644
index 00000000000..a5ba7b39fa1
--- /dev/null
+++ b/compiler-rt/test/hwasan/TestCases/allocator_returns_null.cc
@@ -0,0 +1,115 @@
+// Test the behavior of malloc/calloc/realloc/new when the allocation size
+// exceeds the HWASan 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 and set errno to
+// the appropriate error code.
+//
+// RUN: %clangxx_hwasan -O0 %s -o %t
+// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
+// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-mCRASH
+// RUN: %env_hwasan_opts=allocator_may_return_null=1 %run %t malloc 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-mNULL
+// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-cCRASH
+// RUN: %env_hwasan_opts=allocator_may_return_null=1 %run %t calloc 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-cNULL
+// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-coCRASH
+// RUN: %env_hwasan_opts=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-coNULL
+// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-rCRASH
+// RUN: %env_hwasan_opts=allocator_may_return_null=1 %run %t realloc 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-rNULL
+// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-mrCRASH
+// RUN: %env_hwasan_opts=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-mrNULL
+// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t new 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH
+// RUN: %env_hwasan_opts=allocator_may_return_null=1 not %run %t new 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH-OOM
+// RUN: %env_hwasan_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-nnCRASH
+// RUN: %env_hwasan_opts=allocator_may_return_null=1 %run %t new-nothrow 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-nnNULL
+
+// REQUIRES: stable-runtime
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits>
+#include <new>
+
+int main(int argc, char **argv) {
+ assert(argc == 2);
+ const char *action = argv[1];
+ fprintf(stderr, "%s:\n", action);
+
+ static const size_t kMaxAllowedMallocSizePlusOne = (2UL << 30) + 1;
+
+ void *x = nullptr;
+ 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);
+ } 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, 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);
+ }
+
+ fprintf(stderr, "errno: %d\n", errno);
+
+ free(x);
+
+ return x != nullptr;
+}
+
+// CHECK-mCRASH: malloc:
+// CHECK-mCRASH: SUMMARY: HWAddressSanitizer: allocation-size-too-big
+// CHECK-cCRASH: calloc:
+// CHECK-cCRASH: SUMMARY: HWAddressSanitizer: allocation-size-too-big
+// CHECK-coCRASH: calloc-overflow:
+// CHECK-coCRASH: SUMMARY: HWAddressSanitizer: calloc-overflow
+// CHECK-rCRASH: realloc:
+// CHECK-rCRASH: SUMMARY: HWAddressSanitizer: allocation-size-too-big
+// CHECK-mrCRASH: realloc-after-malloc:
+// CHECK-mrCRASH: SUMMARY: HWAddressSanitizer: allocation-size-too-big
+// CHECK-nCRASH: new:
+// CHECK-nCRASH: SUMMARY: HWAddressSanitizer: allocation-size-too-big
+// CHECK-nCRASH-OOM: new:
+// CHECK-nCRASH-OOM: SUMMARY: HWAddressSanitizer: out-of-memory
+// CHECK-nnCRASH: new-nothrow:
+// CHECK-nnCRASH: SUMMARY: HWAddressSanitizer: allocation-size-too-big
+
+// CHECK-mNULL: malloc:
+// CHECK-mNULL: errno: 12
+// CHECK-cNULL: calloc:
+// CHECK-cNULL: errno: 12
+// CHECK-coNULL: calloc-overflow:
+// CHECK-coNULL: errno: 12
+// CHECK-rNULL: realloc:
+// CHECK-rNULL: errno: 12
+// CHECK-mrNULL: realloc-after-malloc:
+// CHECK-mrNULL: errno: 12
+// CHECK-nnNULL: new-nothrow:
OpenPOWER on IntegriCloud