xref: /haiku/src/system/libroot/posix/malloc/debug/malloc_debug_api.cpp (revision 9a6a20d4689307142a7ed26a1437ba47e244e73f)
1 /*
2  * Copyright 2015, Michael Lotz <mmlr@mlotz.ch>.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "malloc_debug_api.h"
8 
9 #include <malloc.h>
10 #include <string.h>
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 
15 
16 static heap_implementation* sCurrentHeap = NULL;
17 
18 
19 // #pragma mark - Heap Debug API
20 
21 
22 extern "C" status_t
23 heap_debug_start_wall_checking(int msInterval)
24 {
25 	if (sCurrentHeap->start_wall_checking != NULL)
26 		return sCurrentHeap->start_wall_checking(msInterval);
27 
28 	return B_NOT_SUPPORTED;
29 }
30 
31 
32 extern "C" status_t
33 heap_debug_stop_wall_checking()
34 {
35 	if (sCurrentHeap->stop_wall_checking != NULL)
36 		return sCurrentHeap->stop_wall_checking();
37 
38 	return B_NOT_SUPPORTED;
39 }
40 
41 
42 extern "C" void
43 heap_debug_set_paranoid_validation(bool enabled)
44 {
45 	if (sCurrentHeap->set_paranoid_validation != NULL)
46 		sCurrentHeap->set_paranoid_validation(enabled);
47 }
48 
49 
50 extern "C" void
51 heap_debug_set_memory_reuse(bool enabled)
52 {
53 	if (sCurrentHeap->set_memory_reuse != NULL)
54 		sCurrentHeap->set_memory_reuse(enabled);
55 }
56 
57 
58 extern "C" void
59 heap_debug_set_debugger_calls(bool enabled)
60 {
61 	if (sCurrentHeap->set_debugger_calls != NULL)
62 		sCurrentHeap->set_debugger_calls(enabled);
63 }
64 
65 
66 extern "C" void
67 heap_debug_set_default_alignment(size_t defaultAlignment)
68 {
69 	if (sCurrentHeap->set_default_alignment != NULL)
70 		sCurrentHeap->set_default_alignment(defaultAlignment);
71 }
72 
73 
74 extern "C" void
75 heap_debug_validate_heaps()
76 {
77 	if (sCurrentHeap->validate_heaps != NULL)
78 		sCurrentHeap->validate_heaps();
79 }
80 
81 
82 extern "C" void
83 heap_debug_validate_walls()
84 {
85 	if (sCurrentHeap->validate_walls != NULL)
86 		sCurrentHeap->validate_walls();
87 }
88 
89 
90 extern "C" void
91 heap_debug_dump_allocations(bool statsOnly, thread_id thread)
92 {
93 	if (sCurrentHeap->dump_allocations != NULL)
94 		sCurrentHeap->dump_allocations(statsOnly, thread);
95 }
96 
97 
98 extern "C" void
99 heap_debug_dump_heaps(bool dumpAreas, bool dumpBins)
100 {
101 	if (sCurrentHeap->dump_heaps != NULL)
102 		sCurrentHeap->dump_heaps(dumpAreas, dumpBins);
103 }
104 
105 
106 extern "C" void *
107 heap_debug_malloc_with_guard_page(size_t size)
108 {
109 	if (sCurrentHeap->malloc_with_guard_page != NULL)
110 		return sCurrentHeap->malloc_with_guard_page(size);
111 
112 	return NULL;
113 }
114 
115 
116 extern "C" status_t
117 heap_debug_get_allocation_info(void *address, size_t *size,
118 	thread_id *thread)
119 {
120 	if (sCurrentHeap->get_allocation_info != NULL)
121 		return sCurrentHeap->get_allocation_info(address, size, thread);
122 
123 	return B_NOT_SUPPORTED;
124 }
125 
126 
127 extern "C" status_t
128 heap_debug_set_dump_allocations_on_exit(bool enabled)
129 {
130 	if (sCurrentHeap->set_dump_allocations_on_exit != NULL)
131 		return sCurrentHeap->set_dump_allocations_on_exit(enabled);
132 
133 	return B_NOT_SUPPORTED;
134 }
135 
136 
137 extern "C" status_t
138 heap_debug_set_stack_trace_depth(size_t stackTraceDepth)
139 {
140 	if (sCurrentHeap->set_stack_trace_depth != NULL)
141 		return sCurrentHeap->set_stack_trace_depth(stackTraceDepth);
142 
143 	return B_NOT_SUPPORTED;
144 }
145 
146 
147 // #pragma mark - Init
148 
149 
150 extern "C" status_t
151 __init_heap(void)
152 {
153 	const char *mode = getenv("MALLOC_DEBUG");
154 	if (mode == NULL || strchr(mode, 'g') == NULL)
155 		sCurrentHeap = &__mallocDebugHeap;
156 	else
157 		sCurrentHeap = &__mallocGuardedHeap;
158 
159 	status_t result = sCurrentHeap->init();
160 	if (result != B_OK)
161 		return result;
162 
163 	if (mode != NULL) {
164 		if (strchr(mode, 'p') != NULL)
165 			heap_debug_set_paranoid_validation(true);
166 		if (strchr(mode, 'r') != NULL)
167 			heap_debug_set_memory_reuse(false);
168 		if (strchr(mode, 'e') != NULL)
169 			heap_debug_set_dump_allocations_on_exit(true);
170 
171 		size_t defaultAlignment = 0;
172 		const char *argument = strchr(mode, 'a');
173 		if (argument != NULL
174 			&& sscanf(argument, "a%" B_SCNuSIZE, &defaultAlignment) == 1) {
175 			heap_debug_set_default_alignment(defaultAlignment);
176 		}
177 
178 		size_t stackTraceDepth = 0;
179 		argument = strchr(mode, 's');
180 		if (argument != NULL
181 			&& sscanf(argument, "s%" B_SCNuSIZE, &stackTraceDepth) == 1) {
182 			heap_debug_set_stack_trace_depth(stackTraceDepth);
183 		}
184 
185 		int wallCheckInterval = 0;
186 		argument = strchr(mode, 'w');
187 		if (argument != NULL
188 			&& sscanf(argument, "w%d", &wallCheckInterval) == 1) {
189 			heap_debug_start_wall_checking(wallCheckInterval);
190 		}
191 	}
192 
193 	return B_OK;
194 }
195 
196 
197 extern "C" void
198 __heap_terminate_after()
199 {
200 	if (sCurrentHeap->terminate_after != NULL)
201 		sCurrentHeap->terminate_after();
202 }
203 
204 
205 extern "C" void
206 __heap_before_fork(void)
207 {
208 }
209 
210 
211 extern "C" void
212 __heap_after_fork_child(void)
213 {
214 }
215 
216 
217 extern "C" void
218 __heap_after_fork_parent(void)
219 {
220 }
221 
222 
223 extern "C" void
224 __heap_thread_init(void)
225 {
226 }
227 
228 
229 extern "C" void
230 __heap_thread_exit(void)
231 {
232 }
233 
234 
235 // #pragma mark - Public API
236 
237 
238 extern "C" void*
239 memalign(size_t alignment, size_t size)
240 {
241 	return sCurrentHeap->memalign(alignment, size);
242 }
243 
244 
245 extern "C" void*
246 aligned_alloc(size_t alignment, size_t size)
247 {
248 	if ((size % alignment) != 0)
249 		return NULL;
250 
251 	return sCurrentHeap->memalign(alignment, size);
252 }
253 
254 
255 extern "C" void*
256 malloc(size_t size)
257 {
258 	return sCurrentHeap->malloc(size);
259 }
260 
261 
262 extern "C" void
263 free(void* address)
264 {
265 	sCurrentHeap->free(address);
266 }
267 
268 
269 extern "C" void*
270 realloc(void* address, size_t newSize)
271 {
272 	return sCurrentHeap->realloc(address, newSize);
273 }
274 
275 
276 extern "C" void*
277 calloc(size_t numElements, size_t size)
278 {
279 	if (sCurrentHeap->calloc != NULL)
280 		return sCurrentHeap->calloc(numElements, size);
281 
282 	void* address = malloc(numElements * size);
283 	if (address != NULL)
284 		memset(address, 0, numElements * size);
285 
286 	return address;
287 }
288 
289 
290 extern "C" void*
291 valloc(size_t size)
292 {
293 	if (sCurrentHeap->valloc != NULL)
294 		return sCurrentHeap->valloc(size);
295 
296 	return memalign(B_PAGE_SIZE, size);
297 }
298 
299 
300 extern "C" int
301 posix_memalign(void **pointer, size_t alignment, size_t size)
302 {
303 	if (sCurrentHeap->posix_memalign != NULL)
304 		return sCurrentHeap->posix_memalign(pointer, alignment, size);
305 
306 	if (!is_valid_alignment(alignment))
307 		return EINVAL;
308 
309 	*pointer = memalign(alignment, size);
310 	if (*pointer == NULL)
311 		return ENOMEM;
312 
313 	return 0;
314 }
315 
316 
317 extern "C" size_t
318 malloc_usable_size(void *ptr)
319 {
320 	size_t size;
321 	thread_id thread;
322 
323 	if (ptr == NULL)
324 		return 0;
325 
326 	status_t res = sCurrentHeap->get_allocation_info(ptr, &size, &thread);
327 
328 	if (res != B_OK)
329 		return 0;
330 
331 	return size;
332 }
333