1 #include "test/jemalloc_test.h" 2 3 /* 4 * Test that large_ralloc_no_move causes a failure (returns true) when 5 * in-place extent expansion cannot succeed for either usize_max or 6 * usize_min. 7 * 8 * A previous bug omitted the ! negation on the second extent expansion 9 * attempt (usize_min fallback), causing false success (return false) when 10 * the expansion actually failed. 11 */ 12 TEST_BEGIN(test_large_ralloc_no_move_expand_fail) { 13 /* 14 * Allocate two adjacent large objects in the same arena to block 15 * in-place expansion of the first one. 16 */ 17 unsigned arena_ind; 18 size_t sz = sizeof(arena_ind); 19 expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0), 20 0, "Unexpected mallctl() failure"); 21 22 int flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE; 23 24 size_t large_sz = SC_LARGE_MINCLASS; 25 /* Allocate several blocks to prevent expansion of the first. */ 26 void *blocks[8]; 27 for (size_t i = 0; i < ARRAY_SIZE(blocks); i++) { 28 blocks[i] = mallocx(large_sz, flags); 29 expect_ptr_not_null(blocks[i], "Unexpected mallocx() failure"); 30 } 31 32 /* 33 * Try to expand blocks[0] in place. Use usize_min < usize_max to 34 * exercise the fallback path. 35 */ 36 tsd_t *tsd = tsd_fetch(); 37 edata_t *edata = emap_edata_lookup( 38 tsd_tsdn(tsd), &arena_emap_global, blocks[0]); 39 expect_ptr_not_null(edata, "Unexpected edata lookup failure"); 40 41 size_t oldusize = edata_usize_get(edata); 42 size_t usize_min = sz_s2u(oldusize + 1); 43 size_t usize_max = sz_s2u(oldusize * 2); 44 45 /* Ensure min and max are in different size classes. */ 46 if (usize_min == usize_max) { 47 usize_max = sz_s2u(usize_min + 1); 48 } 49 50 bool ret = large_ralloc_no_move( 51 tsd_tsdn(tsd), edata, usize_min, usize_max, false); 52 53 /* 54 * With adjacent allocations blocking expansion, this should fail. 55 * The bug caused ret == false (success) even when expansion failed. 56 */ 57 if (!ret) { 58 /* 59 * Expansion might actually succeed if adjacent memory 60 * is free. Verify the size actually changed. 61 */ 62 size_t newusize = edata_usize_get(edata); 63 expect_zu_ge(newusize, usize_min, 64 "Expansion reported success but size didn't change"); 65 } 66 67 for (size_t i = 0; i < ARRAY_SIZE(blocks); i++) { 68 dallocx(blocks[i], flags); 69 } 70 } 71 TEST_END 72 73 int 74 main(void) { 75 return test_no_reentrancy(test_large_ralloc_no_move_expand_fail); 76 } 77