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