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
21int 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