1 // RUN: %clang_scudo %s -o %t
2 // RUN: %env_scudo_opts="QuarantineSizeMb=1:QuarantineSizeKb=64"           not %run %t unused 2>&1
3 // RUN: %env_scudo_opts="QuarantineSizeMb=1:QuarantineChunksUpToSize=256"  not %run %t unused 2>&1
4 // RUN: %env_scudo_opts="QuarantineSizeKb=0:ThreadLocalQuarantineSizeKb=0"     %run %t zeroquarantine 2>&1
5 // RUN: %env_scudo_opts=QuarantineSizeKb=64                                    %run %t smallquarantine 2>&1
6 // RUN: %env_scudo_opts=QuarantineChunksUpToSize=256                           %run %t threshold 2>&1
7 // RUN: %env_scudo_opts="QuarantineSizeMb=1"                                   %run %t oldquarantine 2>&1
8 
9 // Tests that the quarantine prevents a chunk from being reused right away.
10 // Also tests that a chunk will eventually become available again for
11 // allocation when the recycling criteria has been met. Finally, tests the
12 // threshold up to which a chunk is quarantine, and the old quarantine behavior.
13 
14 #include <assert.h>
15 #include <malloc.h>
16 #include <stdlib.h>
17 #include <string.h>
18 
19 #include <sanitizer/allocator_interface.h>
20 
main(int argc,char ** argv)21 int main(int argc, char **argv)
22 {
23   void *p, *old_p;
24   size_t allocated_bytes, size = 1U << 8, alignment = 1U << 8;
25 
26   assert(argc == 2);
27   // First, warm up the allocator for the classes used.
28   p = malloc(size);
29   assert(p);
30   free(p);
31   p = malloc(size + 1);
32   assert(p);
33   free(p);
34   assert(posix_memalign(&p, alignment, size) == 0);
35   assert(p);
36   free(p);
37   assert(posix_memalign(&p, alignment, size + 1) == 0);
38   assert(p);
39   free(p);
40 
41   if (!strcmp(argv[1], "zeroquarantine")) {
42     // Verifies that a chunk is deallocated right away when the local and
43     // global quarantine sizes are 0.
44     allocated_bytes = __sanitizer_get_current_allocated_bytes();
45     p = malloc(size);
46     assert(p);
47     assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
48     free(p);
49     assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes);
50   }
51   if (!strcmp(argv[1], "smallquarantine")) {
52     // The delayed freelist will prevent a chunk from being available right
53     // away.
54     p = malloc(size);
55     assert(p);
56     old_p = p;
57     free(p);
58     p = malloc(size);
59     assert(p);
60     assert(old_p != p);
61     free(p);
62 
63     // Eventually the chunk should become available again.
64     char found = 0;
65     for (int i = 0; i < 0x200 && !found; i++) {
66       p = malloc(size);
67       assert(p);
68       found = (p == old_p);
69       free(p);
70     }
71     assert(found);
72   }
73   if (!strcmp(argv[1], "threshold")) {
74     // Verifies that a chunk of size greater than the threshold will be freed
75     // right away. Alignment has no impact on the threshold.
76     allocated_bytes = __sanitizer_get_current_allocated_bytes();
77     p = malloc(size + 1);
78     assert(p);
79     assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
80     free(p);
81     assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes);
82     assert(posix_memalign(&p, alignment, size + 1) == 0);
83     assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
84     free(p);
85     assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes);
86     // Verifies that a chunk of size lower or equal to the threshold will be
87     // quarantined.
88     p = malloc(size);
89     assert(p);
90     assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
91     free(p);
92     assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
93     allocated_bytes = __sanitizer_get_current_allocated_bytes();
94     assert(posix_memalign(&p, alignment, size) == 0);
95     assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
96     free(p);
97     assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
98   }
99   if (!strcmp(argv[1], "oldquarantine")) {
100     // Verifies that we quarantine everything if the deprecated quarantine
101     // option is specified. Alignment has no impact on the threshold.
102     allocated_bytes = __sanitizer_get_current_allocated_bytes();
103     p = malloc(size);
104     assert(p);
105     assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
106     free(p);
107     assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
108     allocated_bytes = __sanitizer_get_current_allocated_bytes();
109     assert(posix_memalign(&p, alignment, size) == 0);
110     assert(p);
111     assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
112     free(p);
113     assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
114     // Secondary backed allocation.
115     allocated_bytes = __sanitizer_get_current_allocated_bytes();
116     p = malloc(1U << 19);
117     assert(p);
118     assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
119     free(p);
120     assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
121   }
122 
123   return 0;
124 }
125