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