1 #include "test/jemalloc_test.h"
2
3 #ifdef JEMALLOC_FILL
4 const char *malloc_conf =
5 "abort:false,junk:true,zero:false,redzone:true,quarantine:0";
6 #endif
7
8 static arena_dalloc_junk_small_t *arena_dalloc_junk_small_orig;
9 static arena_dalloc_junk_large_t *arena_dalloc_junk_large_orig;
10 static huge_dalloc_junk_t *huge_dalloc_junk_orig;
11 static void *most_recently_junked;
12
13 static void
arena_dalloc_junk_small_intercept(void * ptr,arena_bin_info_t * bin_info)14 arena_dalloc_junk_small_intercept(void *ptr, arena_bin_info_t *bin_info)
15 {
16 size_t i;
17
18 arena_dalloc_junk_small_orig(ptr, bin_info);
19 for (i = 0; i < bin_info->reg_size; i++) {
20 assert_c_eq(((char *)ptr)[i], 0x5a,
21 "Missing junk fill for byte %zu/%zu of deallocated region",
22 i, bin_info->reg_size);
23 }
24 most_recently_junked = ptr;
25 }
26
27 static void
arena_dalloc_junk_large_intercept(void * ptr,size_t usize)28 arena_dalloc_junk_large_intercept(void *ptr, size_t usize)
29 {
30 size_t i;
31
32 arena_dalloc_junk_large_orig(ptr, usize);
33 for (i = 0; i < usize; i++) {
34 assert_c_eq(((char *)ptr)[i], 0x5a,
35 "Missing junk fill for byte %zu/%zu of deallocated region",
36 i, usize);
37 }
38 most_recently_junked = ptr;
39 }
40
41 static void
huge_dalloc_junk_intercept(void * ptr,size_t usize)42 huge_dalloc_junk_intercept(void *ptr, size_t usize)
43 {
44
45 huge_dalloc_junk_orig(ptr, usize);
46 /*
47 * The conditions under which junk filling actually occurs are nuanced
48 * enough that it doesn't make sense to duplicate the decision logic in
49 * test code, so don't actually check that the region is junk-filled.
50 */
51 most_recently_junked = ptr;
52 }
53
54 static void
test_junk(size_t sz_min,size_t sz_max)55 test_junk(size_t sz_min, size_t sz_max)
56 {
57 char *s;
58 size_t sz_prev, sz, i;
59
60 arena_dalloc_junk_small_orig = arena_dalloc_junk_small;
61 arena_dalloc_junk_small = arena_dalloc_junk_small_intercept;
62 arena_dalloc_junk_large_orig = arena_dalloc_junk_large;
63 arena_dalloc_junk_large = arena_dalloc_junk_large_intercept;
64 huge_dalloc_junk_orig = huge_dalloc_junk;
65 huge_dalloc_junk = huge_dalloc_junk_intercept;
66
67 sz_prev = 0;
68 s = (char *)mallocx(sz_min, 0);
69 assert_ptr_not_null((void *)s, "Unexpected mallocx() failure");
70
71 for (sz = sallocx(s, 0); sz <= sz_max;
72 sz_prev = sz, sz = sallocx(s, 0)) {
73 if (sz_prev > 0) {
74 assert_c_eq(s[0], 'a',
75 "Previously allocated byte %zu/%zu is corrupted",
76 ZU(0), sz_prev);
77 assert_c_eq(s[sz_prev-1], 'a',
78 "Previously allocated byte %zu/%zu is corrupted",
79 sz_prev-1, sz_prev);
80 }
81
82 for (i = sz_prev; i < sz; i++) {
83 assert_c_eq(s[i], 0xa5,
84 "Newly allocated byte %zu/%zu isn't junk-filled",
85 i, sz);
86 s[i] = 'a';
87 }
88
89 if (xallocx(s, sz+1, 0, 0) == sz) {
90 void *junked = (void *)s;
91
92 s = (char *)rallocx(s, sz+1, 0);
93 assert_ptr_not_null((void *)s,
94 "Unexpected rallocx() failure");
95 assert_ptr_eq(most_recently_junked, junked,
96 "Expected region of size %zu to be junk-filled",
97 sz);
98 }
99 }
100
101 dallocx(s, 0);
102 assert_ptr_eq(most_recently_junked, (void *)s,
103 "Expected region of size %zu to be junk-filled", sz);
104
105 arena_dalloc_junk_small = arena_dalloc_junk_small_orig;
106 arena_dalloc_junk_large = arena_dalloc_junk_large_orig;
107 huge_dalloc_junk = huge_dalloc_junk_orig;
108 }
109
TEST_BEGIN(test_junk_small)110 TEST_BEGIN(test_junk_small)
111 {
112
113 test_skip_if(!config_fill);
114 test_junk(1, SMALL_MAXCLASS-1);
115 }
116 TEST_END
117
TEST_BEGIN(test_junk_large)118 TEST_BEGIN(test_junk_large)
119 {
120
121 test_skip_if(!config_fill);
122 test_junk(SMALL_MAXCLASS+1, arena_maxclass);
123 }
124 TEST_END
125
TEST_BEGIN(test_junk_huge)126 TEST_BEGIN(test_junk_huge)
127 {
128
129 test_skip_if(!config_fill);
130 test_junk(arena_maxclass+1, chunksize*2);
131 }
132 TEST_END
133
134 arena_ralloc_junk_large_t *arena_ralloc_junk_large_orig;
135 static void *most_recently_trimmed;
136
137 static void
arena_ralloc_junk_large_intercept(void * ptr,size_t old_usize,size_t usize)138 arena_ralloc_junk_large_intercept(void *ptr, size_t old_usize, size_t usize)
139 {
140
141 arena_ralloc_junk_large_orig(ptr, old_usize, usize);
142 assert_zu_eq(old_usize, arena_maxclass, "Unexpected old_usize");
143 assert_zu_eq(usize, arena_maxclass-PAGE, "Unexpected usize");
144 most_recently_trimmed = ptr;
145 }
146
TEST_BEGIN(test_junk_large_ralloc_shrink)147 TEST_BEGIN(test_junk_large_ralloc_shrink)
148 {
149 void *p1, *p2;
150
151 p1 = mallocx(arena_maxclass, 0);
152 assert_ptr_not_null(p1, "Unexpected mallocx() failure");
153
154 arena_ralloc_junk_large_orig = arena_ralloc_junk_large;
155 arena_ralloc_junk_large = arena_ralloc_junk_large_intercept;
156
157 p2 = rallocx(p1, arena_maxclass-PAGE, 0);
158 assert_ptr_eq(p1, p2, "Unexpected move during shrink");
159
160 arena_ralloc_junk_large = arena_ralloc_junk_large_orig;
161
162 assert_ptr_eq(most_recently_trimmed, p1,
163 "Expected trimmed portion of region to be junk-filled");
164 }
165 TEST_END
166
167 static bool detected_redzone_corruption;
168
169 static void
arena_redzone_corruption_replacement(void * ptr,size_t usize,bool after,size_t offset,uint8_t byte)170 arena_redzone_corruption_replacement(void *ptr, size_t usize, bool after,
171 size_t offset, uint8_t byte)
172 {
173
174 detected_redzone_corruption = true;
175 }
176
TEST_BEGIN(test_junk_redzone)177 TEST_BEGIN(test_junk_redzone)
178 {
179 char *s;
180 arena_redzone_corruption_t *arena_redzone_corruption_orig;
181
182 test_skip_if(!config_fill);
183
184 arena_redzone_corruption_orig = arena_redzone_corruption;
185 arena_redzone_corruption = arena_redzone_corruption_replacement;
186
187 /* Test underflow. */
188 detected_redzone_corruption = false;
189 s = (char *)mallocx(1, 0);
190 assert_ptr_not_null((void *)s, "Unexpected mallocx() failure");
191 s[-1] = 0xbb;
192 dallocx(s, 0);
193 assert_true(detected_redzone_corruption,
194 "Did not detect redzone corruption");
195
196 /* Test overflow. */
197 detected_redzone_corruption = false;
198 s = (char *)mallocx(1, 0);
199 assert_ptr_not_null((void *)s, "Unexpected mallocx() failure");
200 s[sallocx(s, 0)] = 0xbb;
201 dallocx(s, 0);
202 assert_true(detected_redzone_corruption,
203 "Did not detect redzone corruption");
204
205 arena_redzone_corruption = arena_redzone_corruption_orig;
206 }
207 TEST_END
208
209 int
main(void)210 main(void)
211 {
212
213 return (test(
214 test_junk_small,
215 test_junk_large,
216 test_junk_huge,
217 test_junk_large_ralloc_shrink,
218 test_junk_redzone));
219 }
220