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.
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 \
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
43 // win32 is disabled due to failing errno tests.
44 // UNSUPPORTED: ubsan, target={{.*windows-msvc.*}}
46 // Symbolizer needs to allocated memory when reporting.
47 // UNSUPPORTED: internal_symbolizer
57 constexpr size_t MaxAllocationSize
= size_t{2} << 20;
59 static void *allocate(const char *Action
, size_t Size
) {
60 if (!strcmp(Action
, "malloc"))
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
))
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
++)
81 if (Size
== MaxAllocationSize
)
82 pstr
[MaxAllocationSize
- 1] = '\0';
83 return strndup(pstr
, Size
);
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"))
93 if (!strcmp(Action
, "new"))
94 return ::operator delete(Ptr
);
95 if (!strcmp(Action
, "new-nothrow"))
96 return ::operator delete(Ptr
, std::nothrow
);
100 int main(int Argc
, char **Argv
) {
102 const char *Action
= Argv
[1];
103 fprintf(stderr
, "%s:\n", Action
);
105 // Should succeed when max_allocation_size_mb is set.
106 void *volatile P
= allocate(Action
, MaxAllocationSize
);
108 deallocate(Action
, P
);
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
);
117 // Should succeed when max_allocation_size_mb is set.
118 P
= allocate(Action
, MaxAllocationSize
);
120 deallocate(Action
, P
);
125 // CHECK-mCRASH: malloc:
126 // CHECK-mCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
127 // CHECK-cCRASH: calloc:
128 // CHECK-cCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
129 // CHECK-rCRASH: realloc:
130 // CHECK-rCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
131 // CHECK-mrCRASH: realloc-after-malloc:
132 // CHECK-mrCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
133 // CHECK-nCRASH: new:
134 // CHECK-nCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
135 // CHECK-nCRASH-OOM: new:
136 // CHECK-nCRASH-OOM: {{SUMMARY: .*Sanitizer: out-of-memory}}
137 // CHECK-nnCRASH: new-nothrow:
138 // CHECK-nnCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
139 // CHECK-sCRASH: strndup:
140 // CHECK-sCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
142 // CHECK-NULL: {{malloc|calloc|calloc-overflow|realloc|realloc-after-malloc|new-nothrow|strndup}}
143 // CHECK-NULL: errno: 12, P: 0
145 // CHECK-NOTNULL-NOT: P: 0