1 #include "test/jemalloc_test.h" 2 3 /* 4 * Use a separate arena for xallocx() extension/contraction tests so that 5 * internal allocation e.g. by heap profiling can't interpose allocations where 6 * xallocx() would ordinarily be able to extend. 7 */ 8 static unsigned 9 arena_ind(void) { 10 static unsigned ind = 0; 11 12 if (ind == 0) { 13 size_t sz = sizeof(ind); 14 assert_d_eq(mallctl("arenas.create", (void *)&ind, &sz, NULL, 15 0), 0, "Unexpected mallctl failure creating arena"); 16 } 17 18 return ind; 19 } 20 21 TEST_BEGIN(test_same_size) { 22 void *p; 23 size_t sz, tsz; 24 25 p = mallocx(42, 0); 26 assert_ptr_not_null(p, "Unexpected mallocx() error"); 27 sz = sallocx(p, 0); 28 29 tsz = xallocx(p, sz, 0, 0); 30 assert_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz); 31 32 dallocx(p, 0); 33 } 34 TEST_END 35 36 TEST_BEGIN(test_extra_no_move) { 37 void *p; 38 size_t sz, tsz; 39 40 p = mallocx(42, 0); 41 assert_ptr_not_null(p, "Unexpected mallocx() error"); 42 sz = sallocx(p, 0); 43 44 tsz = xallocx(p, sz, sz-42, 0); 45 assert_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz); 46 47 dallocx(p, 0); 48 } 49 TEST_END 50 51 TEST_BEGIN(test_no_move_fail) { 52 void *p; 53 size_t sz, tsz; 54 55 p = mallocx(42, 0); 56 assert_ptr_not_null(p, "Unexpected mallocx() error"); 57 sz = sallocx(p, 0); 58 59 tsz = xallocx(p, sz + 5, 0, 0); 60 assert_zu_eq(tsz, sz, "Unexpected size change: %zu --> %zu", sz, tsz); 61 62 dallocx(p, 0); 63 } 64 TEST_END 65 66 static unsigned 67 get_nsizes_impl(const char *cmd) { 68 unsigned ret; 69 size_t z; 70 71 z = sizeof(unsigned); 72 assert_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0, 73 "Unexpected mallctl(\"%s\", ...) failure", cmd); 74 75 return ret; 76 } 77 78 static unsigned 79 get_nsmall(void) { 80 return get_nsizes_impl("arenas.nbins"); 81 } 82 83 static unsigned 84 get_nlarge(void) { 85 return get_nsizes_impl("arenas.nlextents"); 86 } 87 88 static size_t 89 get_size_impl(const char *cmd, size_t ind) { 90 size_t ret; 91 size_t z; 92 size_t mib[4]; 93 size_t miblen = 4; 94 95 z = sizeof(size_t); 96 assert_d_eq(mallctlnametomib(cmd, mib, &miblen), 97 0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd); 98 mib[2] = ind; 99 z = sizeof(size_t); 100 assert_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0), 101 0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind); 102 103 return ret; 104 } 105 106 static size_t 107 get_small_size(size_t ind) { 108 return get_size_impl("arenas.bin.0.size", ind); 109 } 110 111 static size_t 112 get_large_size(size_t ind) { 113 return get_size_impl("arenas.lextent.0.size", ind); 114 } 115 116 TEST_BEGIN(test_size) { 117 size_t small0, largemax; 118 void *p; 119 120 /* Get size classes. */ 121 small0 = get_small_size(0); 122 largemax = get_large_size(get_nlarge()-1); 123 124 p = mallocx(small0, 0); 125 assert_ptr_not_null(p, "Unexpected mallocx() error"); 126 127 /* Test smallest supported size. */ 128 assert_zu_eq(xallocx(p, 1, 0, 0), small0, 129 "Unexpected xallocx() behavior"); 130 131 /* Test largest supported size. */ 132 assert_zu_le(xallocx(p, largemax, 0, 0), largemax, 133 "Unexpected xallocx() behavior"); 134 135 /* Test size overflow. */ 136 assert_zu_le(xallocx(p, largemax+1, 0, 0), largemax, 137 "Unexpected xallocx() behavior"); 138 assert_zu_le(xallocx(p, SIZE_T_MAX, 0, 0), largemax, 139 "Unexpected xallocx() behavior"); 140 141 dallocx(p, 0); 142 } 143 TEST_END 144 145 TEST_BEGIN(test_size_extra_overflow) { 146 size_t small0, largemax; 147 void *p; 148 149 /* Get size classes. */ 150 small0 = get_small_size(0); 151 largemax = get_large_size(get_nlarge()-1); 152 153 p = mallocx(small0, 0); 154 assert_ptr_not_null(p, "Unexpected mallocx() error"); 155 156 /* Test overflows that can be resolved by clamping extra. */ 157 assert_zu_le(xallocx(p, largemax-1, 2, 0), largemax, 158 "Unexpected xallocx() behavior"); 159 assert_zu_le(xallocx(p, largemax, 1, 0), largemax, 160 "Unexpected xallocx() behavior"); 161 162 /* Test overflow such that largemax-size underflows. */ 163 assert_zu_le(xallocx(p, largemax+1, 2, 0), largemax, 164 "Unexpected xallocx() behavior"); 165 assert_zu_le(xallocx(p, largemax+2, 3, 0), largemax, 166 "Unexpected xallocx() behavior"); 167 assert_zu_le(xallocx(p, SIZE_T_MAX-2, 2, 0), largemax, 168 "Unexpected xallocx() behavior"); 169 assert_zu_le(xallocx(p, SIZE_T_MAX-1, 1, 0), largemax, 170 "Unexpected xallocx() behavior"); 171 172 dallocx(p, 0); 173 } 174 TEST_END 175 176 TEST_BEGIN(test_extra_small) { 177 size_t small0, small1, largemax; 178 void *p; 179 180 /* Get size classes. */ 181 small0 = get_small_size(0); 182 small1 = get_small_size(1); 183 largemax = get_large_size(get_nlarge()-1); 184 185 p = mallocx(small0, 0); 186 assert_ptr_not_null(p, "Unexpected mallocx() error"); 187 188 assert_zu_eq(xallocx(p, small1, 0, 0), small0, 189 "Unexpected xallocx() behavior"); 190 191 assert_zu_eq(xallocx(p, small1, 0, 0), small0, 192 "Unexpected xallocx() behavior"); 193 194 assert_zu_eq(xallocx(p, small0, small1 - small0, 0), small0, 195 "Unexpected xallocx() behavior"); 196 197 /* Test size+extra overflow. */ 198 assert_zu_eq(xallocx(p, small0, largemax - small0 + 1, 0), small0, 199 "Unexpected xallocx() behavior"); 200 assert_zu_eq(xallocx(p, small0, SIZE_T_MAX - small0, 0), small0, 201 "Unexpected xallocx() behavior"); 202 203 dallocx(p, 0); 204 } 205 TEST_END 206 207 TEST_BEGIN(test_extra_large) { 208 int flags = MALLOCX_ARENA(arena_ind()); 209 size_t smallmax, large1, large2, large3, largemax; 210 void *p; 211 212 /* Get size classes. */ 213 smallmax = get_small_size(get_nsmall()-1); 214 large1 = get_large_size(1); 215 large2 = get_large_size(2); 216 large3 = get_large_size(3); 217 largemax = get_large_size(get_nlarge()-1); 218 219 p = mallocx(large3, flags); 220 assert_ptr_not_null(p, "Unexpected mallocx() error"); 221 222 assert_zu_eq(xallocx(p, large3, 0, flags), large3, 223 "Unexpected xallocx() behavior"); 224 /* Test size decrease with zero extra. */ 225 assert_zu_ge(xallocx(p, large1, 0, flags), large1, 226 "Unexpected xallocx() behavior"); 227 assert_zu_ge(xallocx(p, smallmax, 0, flags), large1, 228 "Unexpected xallocx() behavior"); 229 230 if (xallocx(p, large3, 0, flags) != large3) { 231 p = rallocx(p, large3, flags); 232 assert_ptr_not_null(p, "Unexpected rallocx() failure"); 233 } 234 /* Test size decrease with non-zero extra. */ 235 assert_zu_eq(xallocx(p, large1, large3 - large1, flags), large3, 236 "Unexpected xallocx() behavior"); 237 assert_zu_eq(xallocx(p, large2, large3 - large2, flags), large3, 238 "Unexpected xallocx() behavior"); 239 assert_zu_ge(xallocx(p, large1, large2 - large1, flags), large2, 240 "Unexpected xallocx() behavior"); 241 assert_zu_ge(xallocx(p, smallmax, large1 - smallmax, flags), large1, 242 "Unexpected xallocx() behavior"); 243 244 assert_zu_ge(xallocx(p, large1, 0, flags), large1, 245 "Unexpected xallocx() behavior"); 246 /* Test size increase with zero extra. */ 247 assert_zu_le(xallocx(p, large3, 0, flags), large3, 248 "Unexpected xallocx() behavior"); 249 assert_zu_le(xallocx(p, largemax+1, 0, flags), large3, 250 "Unexpected xallocx() behavior"); 251 252 assert_zu_ge(xallocx(p, large1, 0, flags), large1, 253 "Unexpected xallocx() behavior"); 254 /* Test size increase with non-zero extra. */ 255 assert_zu_le(xallocx(p, large1, SIZE_T_MAX - large1, flags), largemax, 256 "Unexpected xallocx() behavior"); 257 258 assert_zu_ge(xallocx(p, large1, 0, flags), large1, 259 "Unexpected xallocx() behavior"); 260 /* Test size increase with non-zero extra. */ 261 assert_zu_le(xallocx(p, large1, large3 - large1, flags), large3, 262 "Unexpected xallocx() behavior"); 263 264 if (xallocx(p, large3, 0, flags) != large3) { 265 p = rallocx(p, large3, flags); 266 assert_ptr_not_null(p, "Unexpected rallocx() failure"); 267 } 268 /* Test size+extra overflow. */ 269 assert_zu_le(xallocx(p, large3, largemax - large3 + 1, flags), largemax, 270 "Unexpected xallocx() behavior"); 271 272 dallocx(p, flags); 273 } 274 TEST_END 275 276 static void 277 print_filled_extents(const void *p, uint8_t c, size_t len) { 278 const uint8_t *pc = (const uint8_t *)p; 279 size_t i, range0; 280 uint8_t c0; 281 282 malloc_printf(" p=%p, c=%#x, len=%zu:", p, c, len); 283 range0 = 0; 284 c0 = pc[0]; 285 for (i = 0; i < len; i++) { 286 if (pc[i] != c0) { 287 malloc_printf(" %#x[%zu..%zu)", c0, range0, i); 288 range0 = i; 289 c0 = pc[i]; 290 } 291 } 292 malloc_printf(" %#x[%zu..%zu)\n", c0, range0, i); 293 } 294 295 static bool 296 validate_fill(const void *p, uint8_t c, size_t offset, size_t len) { 297 const uint8_t *pc = (const uint8_t *)p; 298 bool err; 299 size_t i; 300 301 for (i = offset, err = false; i < offset+len; i++) { 302 if (pc[i] != c) { 303 err = true; 304 } 305 } 306 307 if (err) { 308 print_filled_extents(p, c, offset + len); 309 } 310 311 return err; 312 } 313 314 static void 315 test_zero(size_t szmin, size_t szmax) { 316 int flags = MALLOCX_ARENA(arena_ind()) | MALLOCX_ZERO; 317 size_t sz, nsz; 318 void *p; 319 #define FILL_BYTE 0x7aU 320 321 sz = szmax; 322 p = mallocx(sz, flags); 323 assert_ptr_not_null(p, "Unexpected mallocx() error"); 324 assert_false(validate_fill(p, 0x00, 0, sz), "Memory not filled: sz=%zu", 325 sz); 326 327 /* 328 * Fill with non-zero so that non-debug builds are more likely to detect 329 * errors. 330 */ 331 memset(p, FILL_BYTE, sz); 332 assert_false(validate_fill(p, FILL_BYTE, 0, sz), 333 "Memory not filled: sz=%zu", sz); 334 335 /* Shrink in place so that we can expect growing in place to succeed. */ 336 sz = szmin; 337 if (xallocx(p, sz, 0, flags) != sz) { 338 p = rallocx(p, sz, flags); 339 assert_ptr_not_null(p, "Unexpected rallocx() failure"); 340 } 341 assert_false(validate_fill(p, FILL_BYTE, 0, sz), 342 "Memory not filled: sz=%zu", sz); 343 344 for (sz = szmin; sz < szmax; sz = nsz) { 345 nsz = nallocx(sz+1, flags); 346 if (xallocx(p, sz+1, 0, flags) != nsz) { 347 p = rallocx(p, sz+1, flags); 348 assert_ptr_not_null(p, "Unexpected rallocx() failure"); 349 } 350 assert_false(validate_fill(p, FILL_BYTE, 0, sz), 351 "Memory not filled: sz=%zu", sz); 352 assert_false(validate_fill(p, 0x00, sz, nsz-sz), 353 "Memory not filled: sz=%zu, nsz-sz=%zu", sz, nsz-sz); 354 memset((void *)((uintptr_t)p + sz), FILL_BYTE, nsz-sz); 355 assert_false(validate_fill(p, FILL_BYTE, 0, nsz), 356 "Memory not filled: nsz=%zu", nsz); 357 } 358 359 dallocx(p, flags); 360 } 361 362 TEST_BEGIN(test_zero_large) { 363 size_t large0, large1; 364 365 /* Get size classes. */ 366 large0 = get_large_size(0); 367 large1 = get_large_size(1); 368 369 test_zero(large1, large0 * 2); 370 } 371 TEST_END 372 373 int 374 main(void) { 375 return test( 376 test_same_size, 377 test_extra_no_move, 378 test_no_move_fail, 379 test_size, 380 test_size_extra_overflow, 381 test_extra_small, 382 test_extra_large, 383 test_zero_large); 384 } 385