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
39 // win32 is disabled due to failing errno tests.
40 // UNSUPPORTED: ubsan, windows-msvc
41
42 #include <assert.h>
43 #include <errno.h>
44 #include <limits>
45 #include <new>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49
allocate(const char * Action,size_t Size)50 static void *allocate(const char *Action, size_t Size) {
51 if (!strcmp(Action, "malloc"))
52 return malloc(Size);
53 if (!strcmp(Action, "calloc"))
54 return calloc((Size + 3) / 4, 4);
55 if (!strcmp(Action, "realloc"))
56 return realloc(nullptr, Size);
57 if (!strcmp(Action, "realloc-after-malloc")) {
58 void *P = malloc(100);
59 if (void *Ret = realloc(P, Size))
60 return Ret;
61 free(P);
62 return nullptr;
63 }
64 if (!strcmp(Action, "new"))
65 return ::operator new(Size);
66 if (!strcmp(Action, "new-nothrow"))
67 return ::operator new(Size, std::nothrow);
68 assert(0);
69 }
70
deallocate(const char * Action,void * Ptr)71 static void deallocate(const char *Action, void *Ptr) {
72 if (!strcmp(Action, "malloc") || !strcmp(Action, "calloc") ||
73 !strcmp(Action, "realloc") || !strcmp(Action, "realloc-after-malloc"))
74 return free(Ptr);
75 if (!strcmp(Action, "new"))
76 return ::operator delete(Ptr);
77 if (!strcmp(Action, "new-nothrow"))
78 return ::operator delete(Ptr, std::nothrow);
79 assert(0);
80 }
81
main(int Argc,char ** Argv)82 int main(int Argc, char **Argv) {
83 assert(Argc == 2);
84 const char *Action = Argv[1];
85 fprintf(stderr, "%s:\n", Action);
86
87 constexpr size_t MaxAllocationSize = size_t{2} << 20;
88
89 // Should succeed when max_allocation_size_mb is set.
90 void *volatile P = allocate(Action, MaxAllocationSize);
91 assert(P);
92 deallocate(Action, P);
93
94 // Should fail when max_allocation_size_mb is set.
95 P = allocate(Action, MaxAllocationSize + 1);
96 // The NULL pointer is printed differently on different systems, while (long)0
97 // is always the same.
98 fprintf(stderr, "errno: %d, P: %lx\n", errno, (long)P);
99 deallocate(Action, P);
100
101 // Should succeed when max_allocation_size_mb is set.
102 P = allocate(Action, MaxAllocationSize);
103 assert(P);
104 deallocate(Action, P);
105
106 return 0;
107 }
108
109 // CHECK-mCRASH: malloc:
110 // CHECK-mCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
111 // CHECK-cCRASH: calloc:
112 // CHECK-cCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
113 // CHECK-rCRASH: realloc:
114 // CHECK-rCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
115 // CHECK-mrCRASH: realloc-after-malloc:
116 // CHECK-mrCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
117 // CHECK-nCRASH: new:
118 // CHECK-nCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
119 // CHECK-nCRASH-OOM: new:
120 // CHECK-nCRASH-OOM: {{SUMMARY: .*Sanitizer: out-of-memory}}
121 // CHECK-nnCRASH: new-nothrow:
122 // CHECK-nnCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
123
124 // CHECK-NULL: {{malloc|calloc|calloc-overflow|realloc|realloc-after-malloc|new-nothrow}}
125 // CHECK-NULL: errno: 12, P: 0
126 //
127 // CHECK-NOTNULL-NOT: P: 0
128