1// Test the behavior of malloc/calloc/realloc/new when the allocation size
2// exceeds the sanitizer's allocator max allowed one.
3// By default (allocator_may_return_null=0) the process should crash. With
4// allocator_may_return_null=1 the allocator should return nullptr and set errno
5// to the appropriate error code.
6//
7// RUN: %clangxx -O0 %s -o %t
8// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
9// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t malloc 2>&1 \
10// RUN: | FileCheck %s --check-prefix=CHECK-mCRASH
11// RUN: %env_tool_opts=allocator_may_return_null=1 %run %t malloc 2>&1 \
12// RUN: | FileCheck %s --check-prefix=CHECK-NULL
13// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t calloc 2>&1 \
14// RUN: | FileCheck %s --check-prefix=CHECK-cCRASH
15// RUN: %env_tool_opts=allocator_may_return_null=1 %run %t calloc 2>&1 \
16// RUN: | FileCheck %s --check-prefix=CHECK-NULL
17// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t calloc-overflow 2>&1 \
18// RUN: | FileCheck %s --check-prefix=CHECK-coCRASH
19// RUN: %env_tool_opts=allocator_may_return_null=1 %run %t calloc-overflow 2>&1 \
20// RUN: | FileCheck %s --check-prefix=CHECK-NULL
21// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t realloc 2>&1 \
22// RUN: | FileCheck %s --check-prefix=CHECK-rCRASH
23// RUN: %env_tool_opts=allocator_may_return_null=1 %run %t realloc 2>&1 \
24// RUN: | FileCheck %s --check-prefix=CHECK-NULL
25// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t realloc-after-malloc 2>&1 \
26// RUN: | FileCheck %s --check-prefix=CHECK-mrCRASH
27// RUN: %env_tool_opts=allocator_may_return_null=1 %run %t realloc-after-malloc 2>&1 \
28// RUN: | FileCheck %s --check-prefix=CHECK-NULL
29// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t new 2>&1 \
30// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH
31// RUN: %env_tool_opts=allocator_may_return_null=1 not %run %t new 2>&1 \
32// RUN: | FileCheck %s --check-prefix=CHECK-nCRASH-OOM
33// RUN: %env_tool_opts=allocator_may_return_null=0 not %run %t new-nothrow 2>&1 \
34// RUN: | FileCheck %s --check-prefix=CHECK-nnCRASH
35// RUN: %env_tool_opts=allocator_may_return_null=1 %run %t new-nothrow 2>&1 \
36// RUN: | FileCheck %s --check-prefix=CHECK-NULL
37
38// TODO(alekseyshl): win32 is disabled due to failing errno tests, fix it there.
39// UNSUPPORTED: ubsan, target={{.*windows-msvc.*}}
40
41#include <assert.h>
42#include <errno.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <limits>
47#include <new>
48
49int main(int argc, char **argv) {
50 assert(argc == 2);
51 const char *action = argv[1];
52 fprintf(stderr, format: "%s:\n", action);
53
54 // The maximum value of all supported sanitizers (search for
55 // kMaxAllowedMallocSize). For ASan + LSan, ASan limit is used.
56 static const size_t kMaxAllowedMallocSizePlusOne =
57#if __LP64__ || defined(_WIN64)
58 (1ULL << 40) + 1;
59#else
60 (3UL << 30) + 1;
61#endif
62
63 void *x = nullptr;
64 if (!strcmp(s1: action, s2: "malloc")) {
65 x = malloc(size: kMaxAllowedMallocSizePlusOne);
66 } else if (!strcmp(s1: action, s2: "calloc")) {
67 x = calloc(nmemb: (kMaxAllowedMallocSizePlusOne / 4) + 1, size: 4);
68 } else if (!strcmp(s1: action, s2: "calloc-overflow")) {
69 volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max();
70 size_t kArraySize = 4096;
71 volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
72 x = calloc(nmemb: kArraySize, size: kArraySize2);
73 } else if (!strcmp(s1: action, s2: "realloc")) {
74 x = realloc(ptr: 0, size: kMaxAllowedMallocSizePlusOne);
75 } else if (!strcmp(s1: action, s2: "realloc-after-malloc")) {
76 char *t = (char*)malloc(size: 100);
77 *t = 42;
78 x = realloc(ptr: t, size: kMaxAllowedMallocSizePlusOne);
79 assert(*t == 42);
80 free(ptr: t);
81 } else if (!strcmp(s1: action, s2: "new")) {
82 x = operator new(kMaxAllowedMallocSizePlusOne);
83 } else if (!strcmp(s1: action, s2: "new-nothrow")) {
84 x = operator new(kMaxAllowedMallocSizePlusOne, std::nothrow);
85 } else {
86 assert(0);
87 }
88
89 // The NULL pointer is printed differently on different systems, while (long)0
90 // is always the same.
91 fprintf(stderr, format: "errno: %d, x: %lx\n", errno, (long)x);
92
93 return 0;
94}
95
96// CHECK-mCRASH: malloc:
97// CHECK-mCRASH: #{{[0-9]+.*}}allocator_returns_null.cpp
98// CHECK-mCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big.*allocator_returns_null.cpp.*}} in main
99// CHECK-cCRASH: calloc:
100// CHECK-cCRASH: #{{[0-9]+.*}}allocator_returns_null.cpp
101// CHECK-cCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big.*allocator_returns_null.cpp.*}} in main
102// CHECK-coCRASH: calloc-overflow:
103// CHECK-coCRASH: #{{[0-9]+.*}}allocator_returns_null.cpp
104// CHECK-coCRASH: {{SUMMARY: .*Sanitizer: calloc-overflow.*allocator_returns_null.cpp.*}} in main
105// CHECK-rCRASH: realloc:
106// CHECK-rCRASH: #{{[0-9]+.*}}allocator_returns_null.cpp
107// CHECK-rCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big.*allocator_returns_null.cpp.*}} in main
108// CHECK-mrCRASH: realloc-after-malloc:
109// CHECK-mrCRASH: #{{[0-9]+.*}}allocator_returns_null.cpp
110// CHECK-mrCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big.*allocator_returns_null.cpp.*}} in main
111// CHECK-nCRASH: new:
112// CHECK-nCRASH: #{{[0-9]+.*}}allocator_returns_null.cpp
113// CHECK-nCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big.*allocator_returns_null.cpp.*}} in main
114// CHECK-nCRASH-OOM: new:
115// CHECK-nCRASH-O#{{[0-9]+.*}}allocator_returns_null.cpp
116// CHECK-nCRASH-OOM: {{SUMMARY: .*Sanitizer: out-of-memory.*allocator_returns_null.cpp.*}} in main
117// CHECK-nnCRASH: new-nothrow:
118// CHECK-nnCRASH: #{{[0-9]+.*}}allocator_returns_null.cpp
119// CHECK-nnCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big.*allocator_returns_null.cpp.*}} in main
120
121// CHECK-NULL: {{malloc|calloc|calloc-overflow|realloc|realloc-after-malloc|new-nothrow}}
122// CHECK-NULL: errno: 12, x: 0
123

source code of compiler-rt/test/sanitizer_common/TestCases/allocator_returns_null.cpp