Home | History | Annotate | Line # | Download | only in integration
      1 #include "test/jemalloc_test.h"
      2 #include "jemalloc/jemalloc_macros.h"
      3 
      4 #define STR_HELPER(x) #x
      5 #define STR(x) STR_HELPER(x)
      6 
      7 #ifndef JEMALLOC_VERSION_GID_IDENT
      8   #error "JEMALLOC_VERSION_GID_IDENT not defined"
      9 #endif
     10 
     11 #define JOIN(x, y) x ## y
     12 #define JOIN2(x, y) JOIN(x, y)
     13 #define smallocx JOIN2(smallocx_, JEMALLOC_VERSION_GID_IDENT)
     14 
     15 typedef struct {
     16 	void *ptr;
     17 	size_t size;
     18 } smallocx_return_t;
     19 
     20 extern smallocx_return_t
     21 smallocx(size_t size, int flags);
     22 
     23 static unsigned
     24 get_nsizes_impl(const char *cmd) {
     25 	unsigned ret;
     26 	size_t z;
     27 
     28 	z = sizeof(unsigned);
     29 	expect_d_eq(mallctl(cmd, (void *)&ret, &z, NULL, 0), 0,
     30 	    "Unexpected mallctl(\"%s\", ...) failure", cmd);
     31 
     32 	return ret;
     33 }
     34 
     35 static unsigned
     36 get_nlarge(void) {
     37 	return get_nsizes_impl("arenas.nlextents");
     38 }
     39 
     40 static size_t
     41 get_size_impl(const char *cmd, size_t ind) {
     42 	size_t ret;
     43 	size_t z;
     44 	size_t mib[4];
     45 	size_t miblen = 4;
     46 
     47 	z = sizeof(size_t);
     48 	expect_d_eq(mallctlnametomib(cmd, mib, &miblen),
     49 	    0, "Unexpected mallctlnametomib(\"%s\", ...) failure", cmd);
     50 	mib[2] = ind;
     51 	z = sizeof(size_t);
     52 	expect_d_eq(mallctlbymib(mib, miblen, (void *)&ret, &z, NULL, 0),
     53 	    0, "Unexpected mallctlbymib([\"%s\", %zu], ...) failure", cmd, ind);
     54 
     55 	return ret;
     56 }
     57 
     58 static size_t
     59 get_large_size(size_t ind) {
     60 	return get_size_impl("arenas.lextent.0.size", ind);
     61 }
     62 
     63 /*
     64  * On systems which can't merge extents, tests that call this function generate
     65  * a lot of dirty memory very quickly.  Purging between cycles mitigates
     66  * potential OOM on e.g. 32-bit Windows.
     67  */
     68 static void
     69 purge(void) {
     70 	expect_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
     71 	    "Unexpected mallctl error");
     72 }
     73 
     74 /*
     75  * GCC "-Walloc-size-larger-than" warning detects when one of the memory
     76  * allocation functions is called with a size larger than the maximum size that
     77  * they support. Here we want to explicitly test that the allocation functions
     78  * do indeed fail properly when this is the case, which triggers the warning.
     79  * Therefore we disable the warning for these tests.
     80  */
     81 JEMALLOC_DIAGNOSTIC_PUSH
     82 JEMALLOC_DIAGNOSTIC_IGNORE_ALLOC_SIZE_LARGER_THAN
     83 
     84 TEST_BEGIN(test_overflow) {
     85 	size_t largemax;
     86 
     87 	largemax = get_large_size(get_nlarge()-1);
     88 
     89 	expect_ptr_null(smallocx(largemax+1, 0).ptr,
     90 	    "Expected OOM for smallocx(size=%#zx, 0)", largemax+1);
     91 
     92 	expect_ptr_null(smallocx(ZU(PTRDIFF_MAX)+1, 0).ptr,
     93 	    "Expected OOM for smallocx(size=%#zx, 0)", ZU(PTRDIFF_MAX)+1);
     94 
     95 	expect_ptr_null(smallocx(SIZE_T_MAX, 0).ptr,
     96 	    "Expected OOM for smallocx(size=%#zx, 0)", SIZE_T_MAX);
     97 
     98 	expect_ptr_null(smallocx(1, MALLOCX_ALIGN(ZU(PTRDIFF_MAX)+1)).ptr,
     99 	    "Expected OOM for smallocx(size=1, MALLOCX_ALIGN(%#zx))",
    100 	    ZU(PTRDIFF_MAX)+1);
    101 }
    102 TEST_END
    103 
    104 static void *
    105 remote_alloc(void *arg) {
    106 	unsigned arena;
    107 	size_t sz = sizeof(unsigned);
    108 	expect_d_eq(mallctl("arenas.create", (void *)&arena, &sz, NULL, 0), 0,
    109 	    "Unexpected mallctl() failure");
    110 	size_t large_sz;
    111 	sz = sizeof(size_t);
    112 	expect_d_eq(mallctl("arenas.lextent.0.size", (void *)&large_sz, &sz,
    113 	    NULL, 0), 0, "Unexpected mallctl failure");
    114 
    115 	smallocx_return_t r
    116 	    = smallocx(large_sz, MALLOCX_ARENA(arena) | MALLOCX_TCACHE_NONE);
    117 	void *ptr = r.ptr;
    118 	expect_zu_eq(r.size,
    119 	    nallocx(large_sz, MALLOCX_ARENA(arena) | MALLOCX_TCACHE_NONE),
    120 	    "Expected smalloc(size,flags).size == nallocx(size,flags)");
    121 	void **ret = (void **)arg;
    122 	*ret = ptr;
    123 
    124 	return NULL;
    125 }
    126 
    127 TEST_BEGIN(test_remote_free) {
    128 	thd_t thd;
    129 	void *ret;
    130 	thd_create(&thd, remote_alloc, (void *)&ret);
    131 	thd_join(thd, NULL);
    132 	expect_ptr_not_null(ret, "Unexpected smallocx failure");
    133 
    134 	/* Avoid TCACHE_NONE to explicitly test tcache_flush(). */
    135 	dallocx(ret, 0);
    136 	mallctl("thread.tcache.flush", NULL, NULL, NULL, 0);
    137 }
    138 TEST_END
    139 
    140 TEST_BEGIN(test_oom) {
    141 	size_t largemax;
    142 	bool oom;
    143 	void *ptrs[3];
    144 	unsigned i;
    145 
    146 	/*
    147 	 * It should be impossible to allocate three objects that each consume
    148 	 * nearly half the virtual address space.
    149 	 */
    150 	largemax = get_large_size(get_nlarge()-1);
    151 	oom = false;
    152 	for (i = 0; i < sizeof(ptrs) / sizeof(void *); i++) {
    153 		ptrs[i] = smallocx(largemax, 0).ptr;
    154 		if (ptrs[i] == NULL) {
    155 			oom = true;
    156 		}
    157 	}
    158 	expect_true(oom,
    159 	    "Expected OOM during series of calls to smallocx(size=%zu, 0)",
    160 	    largemax);
    161 	for (i = 0; i < sizeof(ptrs) / sizeof(void *); i++) {
    162 		if (ptrs[i] != NULL) {
    163 			dallocx(ptrs[i], 0);
    164 		}
    165 	}
    166 	purge();
    167 
    168 #if LG_SIZEOF_PTR == 3
    169 	expect_ptr_null(smallocx(0x8000000000000000ULL,
    170 	    MALLOCX_ALIGN(0x8000000000000000ULL)).ptr,
    171 	    "Expected OOM for smallocx()");
    172 	expect_ptr_null(smallocx(0x8000000000000000ULL,
    173 	    MALLOCX_ALIGN(0x80000000)).ptr,
    174 	    "Expected OOM for smallocx()");
    175 #else
    176 	expect_ptr_null(smallocx(0x80000000UL, MALLOCX_ALIGN(0x80000000UL)).ptr,
    177 	    "Expected OOM for smallocx()");
    178 #endif
    179 }
    180 TEST_END
    181 
    182 /* Re-enable the "-Walloc-size-larger-than=" warning */
    183 JEMALLOC_DIAGNOSTIC_POP
    184 
    185 TEST_BEGIN(test_basic) {
    186 #define MAXSZ (((size_t)1) << 23)
    187 	size_t sz;
    188 
    189 	for (sz = 1; sz < MAXSZ; sz = nallocx(sz, 0) + 1) {
    190 		smallocx_return_t ret;
    191 		size_t nsz, rsz, smz;
    192 		void *p;
    193 		nsz = nallocx(sz, 0);
    194 		expect_zu_ne(nsz, 0, "Unexpected nallocx() error");
    195 		ret = smallocx(sz, 0);
    196 		p = ret.ptr;
    197 		smz = ret.size;
    198 		expect_ptr_not_null(p,
    199 		    "Unexpected smallocx(size=%zx, flags=0) error", sz);
    200 		rsz = sallocx(p, 0);
    201 		expect_zu_ge(rsz, sz, "Real size smaller than expected");
    202 		expect_zu_eq(nsz, rsz, "nallocx()/sallocx() size mismatch");
    203 		expect_zu_eq(nsz, smz, "nallocx()/smallocx() size mismatch");
    204 		dallocx(p, 0);
    205 
    206 		ret = smallocx(sz, 0);
    207 		p = ret.ptr;
    208 		smz = ret.size;
    209 		expect_ptr_not_null(p,
    210 		    "Unexpected smallocx(size=%zx, flags=0) error", sz);
    211 		dallocx(p, 0);
    212 
    213 		nsz = nallocx(sz, MALLOCX_ZERO);
    214 		expect_zu_ne(nsz, 0, "Unexpected nallocx() error");
    215 		expect_zu_ne(smz, 0, "Unexpected smallocx() error");
    216 		ret = smallocx(sz, MALLOCX_ZERO);
    217 		p = ret.ptr;
    218 		expect_ptr_not_null(p,
    219 		    "Unexpected smallocx(size=%zx, flags=MALLOCX_ZERO) error",
    220 		    nsz);
    221 		rsz = sallocx(p, 0);
    222 		expect_zu_eq(nsz, rsz, "nallocx()/sallocx() rsize mismatch");
    223 		expect_zu_eq(nsz, smz, "nallocx()/smallocx() size mismatch");
    224 		dallocx(p, 0);
    225 		purge();
    226 	}
    227 #undef MAXSZ
    228 }
    229 TEST_END
    230 
    231 TEST_BEGIN(test_alignment_and_size) {
    232 	const char *percpu_arena;
    233 	size_t sz = sizeof(percpu_arena);
    234 
    235 	if(mallctl("opt.percpu_arena", (void *)&percpu_arena, &sz, NULL, 0) ||
    236 	    strcmp(percpu_arena, "disabled") != 0) {
    237 		test_skip("test_alignment_and_size skipped: "
    238 		    "not working with percpu arena.");
    239 	};
    240 #define MAXALIGN (((size_t)1) << 23)
    241 #define NITER 4
    242 	size_t nsz, rsz, smz, alignment, total;
    243 	unsigned i;
    244 	void *ps[NITER];
    245 
    246 	for (i = 0; i < NITER; i++) {
    247 		ps[i] = NULL;
    248 	}
    249 
    250 	for (alignment = 8;
    251 	    alignment <= MAXALIGN;
    252 	    alignment <<= 1) {
    253 		total = 0;
    254 		for (sz = 1;
    255 		    sz < 3 * alignment && sz < (1U << 31);
    256 		    sz += (alignment >> (LG_SIZEOF_PTR-1)) - 1) {
    257 			for (i = 0; i < NITER; i++) {
    258 				nsz = nallocx(sz, MALLOCX_ALIGN(alignment) |
    259 				    MALLOCX_ZERO);
    260 				expect_zu_ne(nsz, 0,
    261 				    "nallocx() error for alignment=%zu, "
    262 				    "size=%zu (%#zx)", alignment, sz, sz);
    263 				smallocx_return_t ret
    264 				    = smallocx(sz, MALLOCX_ALIGN(alignment) | MALLOCX_ZERO);
    265 				ps[i] = ret.ptr;
    266 				expect_ptr_not_null(ps[i],
    267 				    "smallocx() error for alignment=%zu, "
    268 				    "size=%zu (%#zx)", alignment, sz, sz);
    269 				rsz = sallocx(ps[i], 0);
    270 				smz = ret.size;
    271 				expect_zu_ge(rsz, sz,
    272 				    "Real size smaller than expected for "
    273 				    "alignment=%zu, size=%zu", alignment, sz);
    274 				expect_zu_eq(nsz, rsz,
    275 				    "nallocx()/sallocx() size mismatch for "
    276 				    "alignment=%zu, size=%zu", alignment, sz);
    277 				expect_zu_eq(nsz, smz,
    278 				    "nallocx()/smallocx() size mismatch for "
    279 				    "alignment=%zu, size=%zu", alignment, sz);
    280 				expect_ptr_null(
    281 				    (void *)((uintptr_t)ps[i] & (alignment-1)),
    282 				    "%p inadequately aligned for"
    283 				    " alignment=%zu, size=%zu", ps[i],
    284 				    alignment, sz);
    285 				total += rsz;
    286 				if (total >= (MAXALIGN << 1)) {
    287 					break;
    288 				}
    289 			}
    290 			for (i = 0; i < NITER; i++) {
    291 				if (ps[i] != NULL) {
    292 					dallocx(ps[i], 0);
    293 					ps[i] = NULL;
    294 				}
    295 			}
    296 		}
    297 		purge();
    298 	}
    299 #undef MAXALIGN
    300 #undef NITER
    301 }
    302 TEST_END
    303 
    304 int
    305 main(void) {
    306 	return test(
    307 	    test_overflow,
    308 	    test_oom,
    309 	    test_remote_free,
    310 	    test_basic,
    311 	    test_alignment_and_size);
    312 }
    313