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 void *p, *old_p;
23 size_t allocated_bytes, size = 1U << 8, alignment = 1U << 8;
24
25 assert(argc == 2);
26 // First, warm up the allocator for the classes used.
27 p = malloc(size: size);
28 assert(p);
29 free(ptr: p);
30 p = malloc(size: size + 1);
31 assert(p);
32 free(ptr: p);
33 assert(posix_memalign(&p, alignment, size) == 0);
34 assert(p);
35 free(ptr: p);
36 assert(posix_memalign(&p, alignment, size + 1) == 0);
37 assert(p);
38 free(ptr: p);
39
40 if (!strcmp(s1: argv[1], s2: "zeroquarantine")) {
41 // Verifies that a chunk is deallocated right away when the local and
42 // global quarantine sizes are 0.
43 allocated_bytes = __sanitizer_get_current_allocated_bytes();
44 p = malloc(size: size);
45 assert(p);
46 assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
47 free(ptr: p);
48 assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes);
49 }
50 if (!strcmp(s1: argv[1], s2: "smallquarantine")) {
51 // The delayed freelist will prevent a chunk from being available right
52 // away.
53 p = malloc(size: size);
54 assert(p);
55 old_p = p;
56 free(ptr: p);
57 p = malloc(size: size);
58 assert(p);
59 assert(old_p != p);
60 free(ptr: p);
61
62 // Eventually the chunk should become available again.
63 char found = 0;
64 for (int i = 0; i < 0x200 && !found; i++) {
65 p = malloc(size: size);
66 assert(p);
67 found = (p == old_p);
68 free(ptr: p);
69 }
70 assert(found);
71 }
72 if (!strcmp(s1: argv[1], s2: "threshold")) {
73 // Verifies that a chunk of size greater than the threshold will be freed
74 // right away. Alignment has no impact on the threshold.
75 allocated_bytes = __sanitizer_get_current_allocated_bytes();
76 p = malloc(size: size + 1);
77 assert(p);
78 assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
79 free(ptr: p);
80 assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes);
81 assert(posix_memalign(&p, alignment, size + 1) == 0);
82 assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
83 free(ptr: p);
84 assert(__sanitizer_get_current_allocated_bytes() == allocated_bytes);
85 // Verifies that a chunk of size lower or equal to the threshold will be
86 // quarantined.
87 p = malloc(size: size);
88 assert(p);
89 assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
90 free(ptr: p);
91 assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
92 allocated_bytes = __sanitizer_get_current_allocated_bytes();
93 assert(posix_memalign(&p, alignment, size) == 0);
94 assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
95 free(ptr: p);
96 assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
97 }
98 if (!strcmp(s1: argv[1], s2: "oldquarantine")) {
99 // Verifies that we quarantine everything if the deprecated quarantine
100 // option is specified. Alignment has no impact on the threshold.
101 allocated_bytes = __sanitizer_get_current_allocated_bytes();
102 p = malloc(size: size);
103 assert(p);
104 assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
105 free(ptr: p);
106 assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
107 allocated_bytes = __sanitizer_get_current_allocated_bytes();
108 assert(posix_memalign(&p, alignment, size) == 0);
109 assert(p);
110 assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
111 free(ptr: p);
112 assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
113 // Secondary backed allocation.
114 allocated_bytes = __sanitizer_get_current_allocated_bytes();
115 p = malloc(size: 1U << 19);
116 assert(p);
117 assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
118 free(ptr: p);
119 assert(__sanitizer_get_current_allocated_bytes() > allocated_bytes);
120 }
121
122 return 0;
123}
124

source code of compiler-rt/test/scudo/quarantine.c