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