From 9ed0bcd685f922cd96b7929d9bfa000391571fc1 Mon Sep 17 00:00:00 2001 From: Alex Shlyapnikov Date: Thu, 7 Jun 2018 23:33:33 +0000 Subject: [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 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@334248 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../TestCases/Linux/aligned_alloc-alignment.cc | 25 +++++ test/hwasan/TestCases/Linux/lit.local.cfg | 9 ++ test/hwasan/TestCases/Linux/pvalloc-overflow.cc | 46 +++++++++ test/hwasan/TestCases/Posix/lit.local.cfg | 9 ++ .../TestCases/Posix/posix_memalign-alignment.cc | 22 ++++ test/hwasan/TestCases/allocator_returns_null.cc | 115 +++++++++++++++++++++ 6 files changed, 226 insertions(+) create mode 100644 test/hwasan/TestCases/Linux/aligned_alloc-alignment.cc create mode 100644 test/hwasan/TestCases/Linux/lit.local.cfg create mode 100644 test/hwasan/TestCases/Linux/pvalloc-overflow.cc create mode 100644 test/hwasan/TestCases/Posix/lit.local.cfg create mode 100644 test/hwasan/TestCases/Posix/posix_memalign-alignment.cc create mode 100644 test/hwasan/TestCases/allocator_returns_null.cc (limited to 'test') diff --git a/test/hwasan/TestCases/Linux/aligned_alloc-alignment.cc b/test/hwasan/TestCases/Linux/aligned_alloc-alignment.cc new file mode 100644 index 000000000..a5dc7f661 --- /dev/null +++ b/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 +#include + +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/test/hwasan/TestCases/Linux/lit.local.cfg b/test/hwasan/TestCases/Linux/lit.local.cfg new file mode 100644 index 000000000..57271b807 --- /dev/null +++ b/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/test/hwasan/TestCases/Linux/pvalloc-overflow.cc b/test/hwasan/TestCases/Linux/pvalloc-overflow.cc new file mode 100644 index 000000000..a4897c127 --- /dev/null +++ b/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 +#include +#include +#include +#include +#include + +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/test/hwasan/TestCases/Posix/lit.local.cfg b/test/hwasan/TestCases/Posix/lit.local.cfg new file mode 100644 index 000000000..60a946082 --- /dev/null +++ b/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/test/hwasan/TestCases/Posix/posix_memalign-alignment.cc b/test/hwasan/TestCases/Posix/posix_memalign-alignment.cc new file mode 100644 index 000000000..1ecc39c42 --- /dev/null +++ b/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 +#include + +int main() { + void *p = reinterpret_cast(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/test/hwasan/TestCases/allocator_returns_null.cc b/test/hwasan/TestCases/allocator_returns_null.cc new file mode 100644 index 000000000..a5ba7b39f --- /dev/null +++ b/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 +#include +#include +#include +#include +#include +#include + +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::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: -- cgit v1.2.3