Home | History | Annotate | Download | only in integration
      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