xref: /netbsd-src/external/bsd/jemalloc/dist/test/unit/prof_hook.c (revision 7bdf38e5b7a28439665f2fdeff81e36913eef7dd)
1*7bdf38e5Schristos #include "test/jemalloc_test.h"
2*7bdf38e5Schristos 
3*7bdf38e5Schristos const char *dump_filename = "/dev/null";
4*7bdf38e5Schristos 
5*7bdf38e5Schristos prof_backtrace_hook_t default_hook;
6*7bdf38e5Schristos 
7*7bdf38e5Schristos bool mock_bt_hook_called = false;
8*7bdf38e5Schristos bool mock_dump_hook_called = false;
9*7bdf38e5Schristos 
10*7bdf38e5Schristos void
11*7bdf38e5Schristos mock_bt_hook(void **vec, unsigned *len, unsigned max_len) {
12*7bdf38e5Schristos 	*len = max_len;
13*7bdf38e5Schristos 	for (unsigned i = 0; i < max_len; ++i) {
14*7bdf38e5Schristos 		vec[i] = (void *)((uintptr_t)i);
15*7bdf38e5Schristos 	}
16*7bdf38e5Schristos 	mock_bt_hook_called = true;
17*7bdf38e5Schristos }
18*7bdf38e5Schristos 
19*7bdf38e5Schristos void
20*7bdf38e5Schristos mock_bt_augmenting_hook(void **vec, unsigned *len, unsigned max_len) {
21*7bdf38e5Schristos 	default_hook(vec, len, max_len);
22*7bdf38e5Schristos 	expect_u_gt(*len, 0, "Default backtrace hook returned empty backtrace");
23*7bdf38e5Schristos 	expect_u_lt(*len, max_len,
24*7bdf38e5Schristos 	    "Default backtrace hook returned too large backtrace");
25*7bdf38e5Schristos 
26*7bdf38e5Schristos 	/* Add a separator between default frames and augmented */
27*7bdf38e5Schristos 	vec[*len] = (void *)0x030303030;
28*7bdf38e5Schristos 	(*len)++;
29*7bdf38e5Schristos 
30*7bdf38e5Schristos 	/* Add more stack frames */
31*7bdf38e5Schristos 	for (unsigned i = 0; i < 3; ++i) {
32*7bdf38e5Schristos 		if (*len == max_len) {
33*7bdf38e5Schristos 			break;
34*7bdf38e5Schristos 		}
35*7bdf38e5Schristos 		vec[*len] = (void *)((uintptr_t)i);
36*7bdf38e5Schristos 		(*len)++;
37*7bdf38e5Schristos 	}
38*7bdf38e5Schristos 
39*7bdf38e5Schristos 
40*7bdf38e5Schristos 	mock_bt_hook_called = true;
41*7bdf38e5Schristos }
42*7bdf38e5Schristos 
43*7bdf38e5Schristos void
44*7bdf38e5Schristos mock_dump_hook(const char *filename) {
45*7bdf38e5Schristos 	mock_dump_hook_called = true;
46*7bdf38e5Schristos 	expect_str_eq(filename, dump_filename,
47*7bdf38e5Schristos 	    "Incorrect file name passed to the dump hook");
48*7bdf38e5Schristos }
49*7bdf38e5Schristos 
50*7bdf38e5Schristos TEST_BEGIN(test_prof_backtrace_hook_replace) {
51*7bdf38e5Schristos 
52*7bdf38e5Schristos 	test_skip_if(!config_prof);
53*7bdf38e5Schristos 
54*7bdf38e5Schristos 	mock_bt_hook_called = false;
55*7bdf38e5Schristos 
56*7bdf38e5Schristos 	void *p0 = mallocx(1, 0);
57*7bdf38e5Schristos 	assert_ptr_not_null(p0, "Failed to allocate");
58*7bdf38e5Schristos 
59*7bdf38e5Schristos 	expect_false(mock_bt_hook_called, "Called mock hook before it's set");
60*7bdf38e5Schristos 
61*7bdf38e5Schristos 	prof_backtrace_hook_t null_hook = NULL;
62*7bdf38e5Schristos 	expect_d_eq(mallctl("experimental.hooks.prof_backtrace",
63*7bdf38e5Schristos 	    NULL, 0, (void *)&null_hook,  sizeof(null_hook)),
64*7bdf38e5Schristos 		EINVAL, "Incorrectly allowed NULL backtrace hook");
65*7bdf38e5Schristos 
66*7bdf38e5Schristos 	size_t default_hook_sz = sizeof(prof_backtrace_hook_t);
67*7bdf38e5Schristos 	prof_backtrace_hook_t hook = &mock_bt_hook;
68*7bdf38e5Schristos 	expect_d_eq(mallctl("experimental.hooks.prof_backtrace",
69*7bdf38e5Schristos 	    (void *)&default_hook, &default_hook_sz, (void *)&hook,
70*7bdf38e5Schristos 	    sizeof(hook)), 0, "Unexpected mallctl failure setting hook");
71*7bdf38e5Schristos 
72*7bdf38e5Schristos 	void *p1 = mallocx(1, 0);
73*7bdf38e5Schristos 	assert_ptr_not_null(p1, "Failed to allocate");
74*7bdf38e5Schristos 
75*7bdf38e5Schristos 	expect_true(mock_bt_hook_called, "Didn't call mock hook");
76*7bdf38e5Schristos 
77*7bdf38e5Schristos 	prof_backtrace_hook_t current_hook;
78*7bdf38e5Schristos 	size_t current_hook_sz = sizeof(prof_backtrace_hook_t);
79*7bdf38e5Schristos 	expect_d_eq(mallctl("experimental.hooks.prof_backtrace",
80*7bdf38e5Schristos 	    (void *)&current_hook, &current_hook_sz, (void *)&default_hook,
81*7bdf38e5Schristos 	    sizeof(default_hook)), 0,
82*7bdf38e5Schristos 	    "Unexpected mallctl failure resetting hook to default");
83*7bdf38e5Schristos 
84*7bdf38e5Schristos 	expect_ptr_eq(current_hook, hook,
85*7bdf38e5Schristos 	    "Hook returned by mallctl is not equal to mock hook");
86*7bdf38e5Schristos 
87*7bdf38e5Schristos 	dallocx(p1, 0);
88*7bdf38e5Schristos 	dallocx(p0, 0);
89*7bdf38e5Schristos }
90*7bdf38e5Schristos TEST_END
91*7bdf38e5Schristos 
92*7bdf38e5Schristos TEST_BEGIN(test_prof_backtrace_hook_augment) {
93*7bdf38e5Schristos 
94*7bdf38e5Schristos 	test_skip_if(!config_prof);
95*7bdf38e5Schristos 
96*7bdf38e5Schristos 	mock_bt_hook_called = false;
97*7bdf38e5Schristos 
98*7bdf38e5Schristos 	void *p0 = mallocx(1, 0);
99*7bdf38e5Schristos 	assert_ptr_not_null(p0, "Failed to allocate");
100*7bdf38e5Schristos 
101*7bdf38e5Schristos 	expect_false(mock_bt_hook_called, "Called mock hook before it's set");
102*7bdf38e5Schristos 
103*7bdf38e5Schristos 	size_t default_hook_sz = sizeof(prof_backtrace_hook_t);
104*7bdf38e5Schristos 	prof_backtrace_hook_t hook = &mock_bt_augmenting_hook;
105*7bdf38e5Schristos 	expect_d_eq(mallctl("experimental.hooks.prof_backtrace",
106*7bdf38e5Schristos 	    (void *)&default_hook, &default_hook_sz, (void *)&hook,
107*7bdf38e5Schristos 	    sizeof(hook)), 0, "Unexpected mallctl failure setting hook");
108*7bdf38e5Schristos 
109*7bdf38e5Schristos 	void *p1 = mallocx(1, 0);
110*7bdf38e5Schristos 	assert_ptr_not_null(p1, "Failed to allocate");
111*7bdf38e5Schristos 
112*7bdf38e5Schristos 	expect_true(mock_bt_hook_called, "Didn't call mock hook");
113*7bdf38e5Schristos 
114*7bdf38e5Schristos 	prof_backtrace_hook_t current_hook;
115*7bdf38e5Schristos 	size_t current_hook_sz = sizeof(prof_backtrace_hook_t);
116*7bdf38e5Schristos 	expect_d_eq(mallctl("experimental.hooks.prof_backtrace",
117*7bdf38e5Schristos 	    (void *)&current_hook, &current_hook_sz, (void *)&default_hook,
118*7bdf38e5Schristos 	    sizeof(default_hook)), 0,
119*7bdf38e5Schristos 	    "Unexpected mallctl failure resetting hook to default");
120*7bdf38e5Schristos 
121*7bdf38e5Schristos 	expect_ptr_eq(current_hook, hook,
122*7bdf38e5Schristos 	    "Hook returned by mallctl is not equal to mock hook");
123*7bdf38e5Schristos 
124*7bdf38e5Schristos 	dallocx(p1, 0);
125*7bdf38e5Schristos 	dallocx(p0, 0);
126*7bdf38e5Schristos }
127*7bdf38e5Schristos TEST_END
128*7bdf38e5Schristos 
129*7bdf38e5Schristos TEST_BEGIN(test_prof_dump_hook) {
130*7bdf38e5Schristos 
131*7bdf38e5Schristos 	test_skip_if(!config_prof);
132*7bdf38e5Schristos 
133*7bdf38e5Schristos 	mock_dump_hook_called = false;
134*7bdf38e5Schristos 
135*7bdf38e5Schristos 	expect_d_eq(mallctl("prof.dump", NULL, NULL, (void *)&dump_filename,
136*7bdf38e5Schristos 	    sizeof(dump_filename)), 0, "Failed to dump heap profile");
137*7bdf38e5Schristos 
138*7bdf38e5Schristos 	expect_false(mock_dump_hook_called, "Called dump hook before it's set");
139*7bdf38e5Schristos 
140*7bdf38e5Schristos 	size_t default_hook_sz = sizeof(prof_dump_hook_t);
141*7bdf38e5Schristos 	prof_dump_hook_t hook = &mock_dump_hook;
142*7bdf38e5Schristos 	expect_d_eq(mallctl("experimental.hooks.prof_dump",
143*7bdf38e5Schristos 	    (void *)&default_hook, &default_hook_sz, (void *)&hook,
144*7bdf38e5Schristos 	    sizeof(hook)), 0, "Unexpected mallctl failure setting hook");
145*7bdf38e5Schristos 
146*7bdf38e5Schristos 	expect_d_eq(mallctl("prof.dump", NULL, NULL, (void *)&dump_filename,
147*7bdf38e5Schristos 	    sizeof(dump_filename)), 0, "Failed to dump heap profile");
148*7bdf38e5Schristos 
149*7bdf38e5Schristos 	expect_true(mock_dump_hook_called, "Didn't call mock hook");
150*7bdf38e5Schristos 
151*7bdf38e5Schristos 	prof_dump_hook_t current_hook;
152*7bdf38e5Schristos 	size_t current_hook_sz = sizeof(prof_dump_hook_t);
153*7bdf38e5Schristos 	expect_d_eq(mallctl("experimental.hooks.prof_dump",
154*7bdf38e5Schristos 	    (void *)&current_hook, &current_hook_sz, (void *)&default_hook,
155*7bdf38e5Schristos 	    sizeof(default_hook)), 0,
156*7bdf38e5Schristos 	    "Unexpected mallctl failure resetting hook to default");
157*7bdf38e5Schristos 
158*7bdf38e5Schristos 	expect_ptr_eq(current_hook, hook,
159*7bdf38e5Schristos 	    "Hook returned by mallctl is not equal to mock hook");
160*7bdf38e5Schristos }
161*7bdf38e5Schristos TEST_END
162*7bdf38e5Schristos 
163*7bdf38e5Schristos int
164*7bdf38e5Schristos main(void) {
165*7bdf38e5Schristos 	return test(
166*7bdf38e5Schristos 	    test_prof_backtrace_hook_replace,
167*7bdf38e5Schristos 	    test_prof_backtrace_hook_augment,
168*7bdf38e5Schristos 	    test_prof_dump_hook);
169*7bdf38e5Schristos }
170