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