1// Test the behavior of malloc/calloc/realloc/new when the allocation size
2// exceeds the configured max_allocation_size_mb flag.
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: %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-NOTNULL
9// RUN: %env_tool_opts=max_allocation_size_mb=3 %run %t malloc 2>&1 \
10// RUN: | FileCheck %s --check-prefix=CHECK-NOTNULL
11// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0 \
12// RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
13// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \
14// RUN: %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
15// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0 \
16// RUN: not %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
17// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \
18// RUN: %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
19// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0 \
20// RUN: not %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
21// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \
22// RUN: %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
23// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0 \
24// RUN: not %run %t realloc-after-malloc 2>&1 \
25// RUN: | FileCheck %s --check-prefix=CHECK-mrCRASH
26// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \
27// RUN: %run %t realloc-after-malloc 2>&1 \
28// RUN: | FileCheck %s --check-prefix=CHECK-NULL
29// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0 \
30// RUN: not %run %t new 2>&1 | FileCheck %s --check-prefix=CHECK-nCRASH
31// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \
32// RUN: not %run %t new 2>&1 | FileCheck %s --check-prefix=CHECK-nCRASH-OOM
33// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0 \
34// RUN: not %run %t new-nothrow 2>&1 \
35// RUN: | FileCheck %s --check-prefix=CHECK-nnCRASH
36// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \
37// RUN: %run %t new-nothrow 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
38// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0:fast_unwind_on_malloc=0 \
39// RUN: not %run %t strndup 2>&1 | FileCheck %s --check-prefix=CHECK-sCRASH
40// RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \
41// RUN: %run %t strndup 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
42
43// win32 is disabled due to failing errno tests.
44// UNSUPPORTED: ubsan, target={{.*windows-msvc.*}}
45
46// Symbolizer needs to allocated memory when reporting.
47// UNSUPPORTED: internal_symbolizer
48
49#include <assert.h>
50#include <errno.h>
51#include <limits>
52#include <new>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56
57constexpr size_t MaxAllocationSize = size_t{2} << 20;
58
59static void *allocate(const char *Action, size_t Size) {
60 if (!strcmp(s1: Action, s2: "malloc"))
61 return malloc(size: Size);
62 if (!strcmp(s1: Action, s2: "calloc"))
63 return calloc(nmemb: (Size + 3) / 4, size: 4);
64 if (!strcmp(s1: Action, s2: "realloc"))
65 return realloc(ptr: nullptr, size: Size);
66 if (!strcmp(s1: Action, s2: "realloc-after-malloc")) {
67 void *P = malloc(size: 100);
68 if (void *Ret = realloc(ptr: P, size: Size))
69 return Ret;
70 free(ptr: P);
71 return nullptr;
72 }
73 if (!strcmp(s1: Action, s2: "new"))
74 return ::operator new(Size);
75 if (!strcmp(Action, "new-nothrow"))
76 return ::operator new(Size, std::nothrow);
77 if (!strcmp(s1: Action, s2: "strndup")) {
78 static char pstr[MaxAllocationSize + 1] = {'a'};
79 for (size_t i = 0; i < MaxAllocationSize + 1; i++)
80 pstr[i] = 'a';
81 if (Size == MaxAllocationSize)
82 pstr[MaxAllocationSize - 1] = '\0';
83 return strndup(string: pstr, n: Size);
84 }
85 assert(0);
86}
87
88static void deallocate(const char *Action, void *Ptr) {
89 if (!strcmp(s1: Action, s2: "malloc") || !strcmp(s1: Action, s2: "calloc") ||
90 !strcmp(s1: Action, s2: "realloc") || !strcmp(s1: Action, s2: "realloc-after-malloc") ||
91 !strcmp(s1: Action, s2: "strndup"))
92 return free(ptr: Ptr);
93 if (!strcmp(s1: Action, s2: "new"))
94 return ::operator delete(Ptr);
95 if (!strcmp(Action, "new-nothrow"))
96 return ::operator delete(Ptr, std::nothrow);
97 assert(0);
98}
99
100int main(int Argc, char **Argv) {
101 assert(Argc == 2);
102 const char *Action = Argv[1];
103 fprintf(stderr, format: "%s:\n", Action);
104
105 // Should succeed when max_allocation_size_mb is set.
106 void *volatile P = allocate(Action, Size: MaxAllocationSize);
107 assert(P);
108 deallocate(Action, Ptr: P);
109
110 // Should fail when max_allocation_size_mb is set.
111 P = allocate(Action, Size: MaxAllocationSize + 1);
112 // The NULL pointer is printed differently on different systems, while (long)0
113 // is always the same.
114 fprintf(stderr, format: "errno: %d, P: %lx\n", errno, (long)P);
115 deallocate(Action, Ptr: P);
116
117 // Should succeed when max_allocation_size_mb is set.
118 P = allocate(Action, Size: MaxAllocationSize);
119 assert(P);
120 deallocate(Action, Ptr: P);
121
122 return 0;
123}
124
125// CHECK-mCRASH: malloc:
126// CHECK-mCRASH: #{{[0-9]+.*}}max_allocation_size.cpp
127// CHECK-mCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big.* in allocate}}
128// CHECK-cCRASH: calloc:
129// CHECK-cCRASH: #{{[0-9]+.*}}max_allocation_size.cpp
130// CHECK-cCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big.* in allocate}}
131// CHECK-rCRASH: realloc:
132// CHECK-rCRASH: #{{[0-9]+.*}}max_allocation_size.cpp
133// CHECK-rCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big.* in allocate}}
134// CHECK-mrCRASH: realloc-after-malloc:
135// CHECK-mrCRASH: #{{[0-9]+.*}}max_allocation_size.cpp
136// CHECK-mrCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big.* in allocate}}
137// CHECK-nCRASH: new:
138// CHECK-nCRASH: #{{[0-9]+.*}}max_allocation_size.cpp
139// CHECK-nCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big.* in allocate}}
140// CHECK-nCRASH-OOM: new:
141// CHECK-nCRASH-OOM: #{{[0-9]+.*}}max_allocation_size.cpp
142// CHECK-nCRASH-OOM: {{SUMMARY: .*Sanitizer: out-of-memory.* in allocate}}
143// CHECK-nnCRASH: new-nothrow:
144// CHECK-nnCRASH: #{{[0-9]+.*}}max_allocation_size.cpp
145// CHECK-nnCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big.* in allocate}}
146// CHECK-sCRASH: strndup:
147// CHECK-sCRASH: #{{[0-9]+.*}}max_allocation_size.cpp
148// CHECK-sCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big.*}}
149
150// CHECK-NULL: {{malloc|calloc|calloc-overflow|realloc|realloc-after-malloc|new-nothrow|strndup}}
151// CHECK-NULL: errno: 12, P: 0
152//
153// CHECK-NOTNULL-NOT: P: 0
154

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