xref: /llvm-project/compiler-rt/test/sanitizer_common/TestCases/max_allocation_size.cpp (revision 71e5652f47b0d02a54aa9582319648bc4c23842c)
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 
57 constexpr size_t MaxAllocationSize = size_t{2} << 20;
58 
allocate(const char * Action,size_t Size)59 static void *allocate(const char *Action, size_t Size) {
60   if (!strcmp(Action, "malloc"))
61     return malloc(Size);
62   if (!strcmp(Action, "calloc"))
63     return calloc((Size + 3) / 4, 4);
64   if (!strcmp(Action, "realloc"))
65     return realloc(nullptr, Size);
66   if (!strcmp(Action, "realloc-after-malloc")) {
67     void *P = malloc(100);
68     if (void *Ret = realloc(P, Size))
69       return Ret;
70     free(P);
71     return nullptr;
72   }
73   if (!strcmp(Action, "new"))
74     return ::operator new(Size);
75   if (!strcmp(Action, "new-nothrow"))
76     return ::operator new(Size, std::nothrow);
77   if (!strcmp(Action, "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(pstr, Size);
84   }
85   assert(0);
86 }
87 
deallocate(const char * Action,void * Ptr)88 static void deallocate(const char *Action, void *Ptr) {
89   if (!strcmp(Action, "malloc") || !strcmp(Action, "calloc") ||
90       !strcmp(Action, "realloc") || !strcmp(Action, "realloc-after-malloc") ||
91       !strcmp(Action, "strndup"))
92     return free(Ptr);
93   if (!strcmp(Action, "new"))
94     return ::operator delete(Ptr);
95   if (!strcmp(Action, "new-nothrow"))
96     return ::operator delete(Ptr, std::nothrow);
97   assert(0);
98 }
99 
main(int Argc,char ** Argv)100 int main(int Argc, char **Argv) {
101   assert(Argc == 2);
102   const char *Action = Argv[1];
103   fprintf(stderr, "%s:\n", Action);
104 
105   // Should succeed when max_allocation_size_mb is set.
106   void *volatile P = allocate(Action, MaxAllocationSize);
107   assert(P);
108   deallocate(Action, P);
109 
110   // Should fail when max_allocation_size_mb is set.
111   P = allocate(Action, MaxAllocationSize + 1);
112   // The NULL pointer is printed differently on different systems, while (long)0
113   // is always the same.
114   fprintf(stderr, "errno: %d, P: %lx\n", errno, (long)P);
115   deallocate(Action, P);
116 
117   // Should succeed when max_allocation_size_mb is set.
118   P = allocate(Action, MaxAllocationSize);
119   assert(P);
120   deallocate(Action, 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