17904bd94SMatt Morehouse // Test the behavior of malloc/calloc/realloc/new when the allocation size
27904bd94SMatt Morehouse // exceeds the configured max_allocation_size_mb flag.
37904bd94SMatt Morehouse // By default (allocator_may_return_null=0) the process should crash. With
47904bd94SMatt Morehouse // allocator_may_return_null=1 the allocator should return nullptr and set errno
57904bd94SMatt Morehouse // to the appropriate error code.
67904bd94SMatt Morehouse //
77904bd94SMatt Morehouse // RUN: %clangxx -O0 %s -o %t
87904bd94SMatt Morehouse // RUN: %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-NOTNULL
97904bd94SMatt Morehouse // RUN: %env_tool_opts=max_allocation_size_mb=3 %run %t malloc 2>&1 \
107904bd94SMatt Morehouse // RUN: | FileCheck %s --check-prefix=CHECK-NOTNULL
117904bd94SMatt Morehouse // RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0 \
127904bd94SMatt Morehouse // RUN: not %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-mCRASH
137904bd94SMatt Morehouse // RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \
147904bd94SMatt Morehouse // RUN: %run %t malloc 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
157904bd94SMatt Morehouse // RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0 \
167904bd94SMatt Morehouse // RUN: not %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-cCRASH
177904bd94SMatt Morehouse // RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \
187904bd94SMatt Morehouse // RUN: %run %t calloc 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
197904bd94SMatt Morehouse // RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0 \
207904bd94SMatt Morehouse // RUN: not %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-rCRASH
217904bd94SMatt Morehouse // RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \
227904bd94SMatt Morehouse // RUN: %run %t realloc 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
237904bd94SMatt Morehouse // RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0 \
247904bd94SMatt Morehouse // RUN: not %run %t realloc-after-malloc 2>&1 \
257904bd94SMatt Morehouse // RUN: | FileCheck %s --check-prefix=CHECK-mrCRASH
267904bd94SMatt Morehouse // RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \
277904bd94SMatt Morehouse // RUN: %run %t realloc-after-malloc 2>&1 \
287904bd94SMatt Morehouse // RUN: | FileCheck %s --check-prefix=CHECK-NULL
297904bd94SMatt Morehouse // RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0 \
307904bd94SMatt Morehouse // RUN: not %run %t new 2>&1 | FileCheck %s --check-prefix=CHECK-nCRASH
317904bd94SMatt Morehouse // RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \
327904bd94SMatt Morehouse // RUN: not %run %t new 2>&1 | FileCheck %s --check-prefix=CHECK-nCRASH-OOM
337904bd94SMatt Morehouse // RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0 \
347904bd94SMatt Morehouse // RUN: not %run %t new-nothrow 2>&1 \
357904bd94SMatt Morehouse // RUN: | FileCheck %s --check-prefix=CHECK-nnCRASH
367904bd94SMatt Morehouse // RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \
377904bd94SMatt Morehouse // RUN: %run %t new-nothrow 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
38*4278b7e1SPierre Gousseau // RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=0 \
39*4278b7e1SPierre Gousseau // RUN: not %run %t strndup 2>&1 | FileCheck %s --check-prefix=CHECK-sCRASH
40*4278b7e1SPierre Gousseau // RUN: %env_tool_opts=max_allocation_size_mb=2:allocator_may_return_null=1 \
41*4278b7e1SPierre Gousseau // RUN: %run %t strndup 2>&1 | FileCheck %s --check-prefix=CHECK-NULL
427904bd94SMatt Morehouse
437904bd94SMatt Morehouse // win32 is disabled due to failing errno tests.
447904bd94SMatt Morehouse // UNSUPPORTED: ubsan, windows-msvc
457904bd94SMatt Morehouse
467904bd94SMatt Morehouse #include <assert.h>
477904bd94SMatt Morehouse #include <errno.h>
487904bd94SMatt Morehouse #include <limits>
497904bd94SMatt Morehouse #include <new>
507904bd94SMatt Morehouse #include <stdio.h>
517904bd94SMatt Morehouse #include <stdlib.h>
527904bd94SMatt Morehouse #include <string.h>
537904bd94SMatt Morehouse
54*4278b7e1SPierre Gousseau constexpr size_t MaxAllocationSize = size_t{2} << 20;
55*4278b7e1SPierre Gousseau
allocate(const char * Action,size_t Size)567904bd94SMatt Morehouse static void *allocate(const char *Action, size_t Size) {
577904bd94SMatt Morehouse if (!strcmp(Action, "malloc"))
587904bd94SMatt Morehouse return malloc(Size);
597904bd94SMatt Morehouse if (!strcmp(Action, "calloc"))
607904bd94SMatt Morehouse return calloc((Size + 3) / 4, 4);
617904bd94SMatt Morehouse if (!strcmp(Action, "realloc"))
627904bd94SMatt Morehouse return realloc(nullptr, Size);
637904bd94SMatt Morehouse if (!strcmp(Action, "realloc-after-malloc")) {
647904bd94SMatt Morehouse void *P = malloc(100);
657904bd94SMatt Morehouse if (void *Ret = realloc(P, Size))
667904bd94SMatt Morehouse return Ret;
677904bd94SMatt Morehouse free(P);
687904bd94SMatt Morehouse return nullptr;
697904bd94SMatt Morehouse }
707904bd94SMatt Morehouse if (!strcmp(Action, "new"))
717904bd94SMatt Morehouse return ::operator new(Size);
727904bd94SMatt Morehouse if (!strcmp(Action, "new-nothrow"))
737904bd94SMatt Morehouse return ::operator new(Size, std::nothrow);
74*4278b7e1SPierre Gousseau if (!strcmp(Action, "strndup")) {
75*4278b7e1SPierre Gousseau static char pstr[MaxAllocationSize + 1] = {'a'};
76*4278b7e1SPierre Gousseau for (size_t i = 0; i < MaxAllocationSize + 1; i++)
77*4278b7e1SPierre Gousseau pstr[i] = 'a';
78*4278b7e1SPierre Gousseau if (Size == MaxAllocationSize)
79*4278b7e1SPierre Gousseau pstr[MaxAllocationSize - 1] = '\0';
80*4278b7e1SPierre Gousseau return strndup(pstr, Size);
81*4278b7e1SPierre Gousseau }
827904bd94SMatt Morehouse assert(0);
837904bd94SMatt Morehouse }
847904bd94SMatt Morehouse
deallocate(const char * Action,void * Ptr)857904bd94SMatt Morehouse static void deallocate(const char *Action, void *Ptr) {
867904bd94SMatt Morehouse if (!strcmp(Action, "malloc") || !strcmp(Action, "calloc") ||
87*4278b7e1SPierre Gousseau !strcmp(Action, "realloc") || !strcmp(Action, "realloc-after-malloc") ||
88*4278b7e1SPierre Gousseau !strcmp(Action, "strndup"))
897904bd94SMatt Morehouse return free(Ptr);
907904bd94SMatt Morehouse if (!strcmp(Action, "new"))
917904bd94SMatt Morehouse return ::operator delete(Ptr);
927904bd94SMatt Morehouse if (!strcmp(Action, "new-nothrow"))
937904bd94SMatt Morehouse return ::operator delete(Ptr, std::nothrow);
947904bd94SMatt Morehouse assert(0);
957904bd94SMatt Morehouse }
967904bd94SMatt Morehouse
main(int Argc,char ** Argv)977904bd94SMatt Morehouse int main(int Argc, char **Argv) {
987904bd94SMatt Morehouse assert(Argc == 2);
997904bd94SMatt Morehouse const char *Action = Argv[1];
1007904bd94SMatt Morehouse fprintf(stderr, "%s:\n", Action);
1017904bd94SMatt Morehouse
1027904bd94SMatt Morehouse // Should succeed when max_allocation_size_mb is set.
1037904bd94SMatt Morehouse void *volatile P = allocate(Action, MaxAllocationSize);
1047904bd94SMatt Morehouse assert(P);
1057904bd94SMatt Morehouse deallocate(Action, P);
1067904bd94SMatt Morehouse
1077904bd94SMatt Morehouse // Should fail when max_allocation_size_mb is set.
1087904bd94SMatt Morehouse P = allocate(Action, MaxAllocationSize + 1);
1097904bd94SMatt Morehouse // The NULL pointer is printed differently on different systems, while (long)0
1107904bd94SMatt Morehouse // is always the same.
1117904bd94SMatt Morehouse fprintf(stderr, "errno: %d, P: %lx\n", errno, (long)P);
1127904bd94SMatt Morehouse deallocate(Action, P);
1137904bd94SMatt Morehouse
1147904bd94SMatt Morehouse // Should succeed when max_allocation_size_mb is set.
1157904bd94SMatt Morehouse P = allocate(Action, MaxAllocationSize);
1167904bd94SMatt Morehouse assert(P);
1177904bd94SMatt Morehouse deallocate(Action, P);
1187904bd94SMatt Morehouse
1197904bd94SMatt Morehouse return 0;
1207904bd94SMatt Morehouse }
1217904bd94SMatt Morehouse
1227904bd94SMatt Morehouse // CHECK-mCRASH: malloc:
1237904bd94SMatt Morehouse // CHECK-mCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
1247904bd94SMatt Morehouse // CHECK-cCRASH: calloc:
1257904bd94SMatt Morehouse // CHECK-cCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
1267904bd94SMatt Morehouse // CHECK-rCRASH: realloc:
1277904bd94SMatt Morehouse // CHECK-rCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
1287904bd94SMatt Morehouse // CHECK-mrCRASH: realloc-after-malloc:
1297904bd94SMatt Morehouse // CHECK-mrCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
1307904bd94SMatt Morehouse // CHECK-nCRASH: new:
1317904bd94SMatt Morehouse // CHECK-nCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
1327904bd94SMatt Morehouse // CHECK-nCRASH-OOM: new:
1337904bd94SMatt Morehouse // CHECK-nCRASH-OOM: {{SUMMARY: .*Sanitizer: out-of-memory}}
1347904bd94SMatt Morehouse // CHECK-nnCRASH: new-nothrow:
1357904bd94SMatt Morehouse // CHECK-nnCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
136*4278b7e1SPierre Gousseau // CHECK-sCRASH: strndup:
137*4278b7e1SPierre Gousseau // CHECK-sCRASH: {{SUMMARY: .*Sanitizer: allocation-size-too-big}}
1387904bd94SMatt Morehouse
139*4278b7e1SPierre Gousseau // CHECK-NULL: {{malloc|calloc|calloc-overflow|realloc|realloc-after-malloc|new-nothrow|strndup}}
1407904bd94SMatt Morehouse // CHECK-NULL: errno: 12, P: 0
1417904bd94SMatt Morehouse //
1427904bd94SMatt Morehouse // CHECK-NOTNULL-NOT: P: 0
143