1*7bdf38e5Schristos #include "test/jemalloc_test.h" 2*7bdf38e5Schristos #include "test/san.h" 3*7bdf38e5Schristos 4*7bdf38e5Schristos #include "jemalloc/internal/safety_check.h" 5*7bdf38e5Schristos 6*7bdf38e5Schristos bool fake_abort_called; 7*7bdf38e5Schristos void fake_abort(const char *message) { 8*7bdf38e5Schristos (void)message; 9*7bdf38e5Schristos fake_abort_called = true; 10*7bdf38e5Schristos } 11*7bdf38e5Schristos 12*7bdf38e5Schristos void 13*7bdf38e5Schristos test_large_double_free_pre(void) { 14*7bdf38e5Schristos safety_check_set_abort(&fake_abort); 15*7bdf38e5Schristos fake_abort_called = false; 16*7bdf38e5Schristos } 17*7bdf38e5Schristos 18*7bdf38e5Schristos void 19*7bdf38e5Schristos test_large_double_free_post() { 20*7bdf38e5Schristos expect_b_eq(fake_abort_called, true, "Double-free check didn't fire."); 21*7bdf38e5Schristos safety_check_set_abort(NULL); 22*7bdf38e5Schristos } 23*7bdf38e5Schristos 24*7bdf38e5Schristos TEST_BEGIN(test_large_double_free_tcache) { 25*7bdf38e5Schristos test_skip_if(!config_opt_safety_checks); 26*7bdf38e5Schristos /* 27*7bdf38e5Schristos * Skip debug builds, since too many assertions will be triggered with 28*7bdf38e5Schristos * double-free before hitting the one we are interested in. 29*7bdf38e5Schristos */ 30*7bdf38e5Schristos test_skip_if(config_debug); 31*7bdf38e5Schristos 32*7bdf38e5Schristos test_large_double_free_pre(); 33*7bdf38e5Schristos char *ptr = malloc(SC_LARGE_MINCLASS); 34*7bdf38e5Schristos bool guarded = extent_is_guarded(tsdn_fetch(), ptr); 35*7bdf38e5Schristos free(ptr); 36*7bdf38e5Schristos if (!guarded) { 37*7bdf38e5Schristos free(ptr); 38*7bdf38e5Schristos } else { 39*7bdf38e5Schristos /* 40*7bdf38e5Schristos * Skip because guarded extents may unguard immediately on 41*7bdf38e5Schristos * deallocation, in which case the second free will crash before 42*7bdf38e5Schristos * reaching the intended safety check. 43*7bdf38e5Schristos */ 44*7bdf38e5Schristos fake_abort_called = true; 45*7bdf38e5Schristos } 46*7bdf38e5Schristos mallctl("thread.tcache.flush", NULL, NULL, NULL, 0); 47*7bdf38e5Schristos test_large_double_free_post(); 48*7bdf38e5Schristos } 49*7bdf38e5Schristos TEST_END 50*7bdf38e5Schristos 51*7bdf38e5Schristos TEST_BEGIN(test_large_double_free_no_tcache) { 52*7bdf38e5Schristos test_skip_if(!config_opt_safety_checks); 53*7bdf38e5Schristos test_skip_if(config_debug); 54*7bdf38e5Schristos 55*7bdf38e5Schristos test_large_double_free_pre(); 56*7bdf38e5Schristos char *ptr = mallocx(SC_LARGE_MINCLASS, MALLOCX_TCACHE_NONE); 57*7bdf38e5Schristos bool guarded = extent_is_guarded(tsdn_fetch(), ptr); 58*7bdf38e5Schristos dallocx(ptr, MALLOCX_TCACHE_NONE); 59*7bdf38e5Schristos if (!guarded) { 60*7bdf38e5Schristos dallocx(ptr, MALLOCX_TCACHE_NONE); 61*7bdf38e5Schristos } else { 62*7bdf38e5Schristos /* 63*7bdf38e5Schristos * Skip because guarded extents may unguard immediately on 64*7bdf38e5Schristos * deallocation, in which case the second free will crash before 65*7bdf38e5Schristos * reaching the intended safety check. 66*7bdf38e5Schristos */ 67*7bdf38e5Schristos fake_abort_called = true; 68*7bdf38e5Schristos } 69*7bdf38e5Schristos test_large_double_free_post(); 70*7bdf38e5Schristos } 71*7bdf38e5Schristos TEST_END 72*7bdf38e5Schristos 73*7bdf38e5Schristos int 74*7bdf38e5Schristos main(void) { 75*7bdf38e5Schristos return test(test_large_double_free_no_tcache, 76*7bdf38e5Schristos test_large_double_free_tcache); 77*7bdf38e5Schristos } 78