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