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