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