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
16static heap_implementation* sCurrentHeap = NULL;
17
18
19// #pragma mark - Heap Debug API
20
21
22extern "C" status_t
23heap_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
32extern "C" status_t
33heap_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
42extern "C" void
43heap_debug_set_paranoid_validation(bool enabled)
44{
45	if (sCurrentHeap->set_paranoid_validation != NULL)
46		sCurrentHeap->set_paranoid_validation(enabled);
47}
48
49
50extern "C" void
51heap_debug_set_memory_reuse(bool enabled)
52{
53	if (sCurrentHeap->set_memory_reuse != NULL)
54		sCurrentHeap->set_memory_reuse(enabled);
55}
56
57
58extern "C" void
59heap_debug_set_debugger_calls(bool enabled)
60{
61	if (sCurrentHeap->set_debugger_calls != NULL)
62		sCurrentHeap->set_debugger_calls(enabled);
63}
64
65
66extern "C" void
67heap_debug_set_default_alignment(size_t defaultAlignment)
68{
69	if (sCurrentHeap->set_default_alignment != NULL)
70		sCurrentHeap->set_default_alignment(defaultAlignment);
71}
72
73
74extern "C" void
75heap_debug_validate_heaps()
76{
77	if (sCurrentHeap->validate_heaps != NULL)
78		sCurrentHeap->validate_heaps();
79}
80
81
82extern "C" void
83heap_debug_validate_walls()
84{
85	if (sCurrentHeap->validate_walls != NULL)
86		sCurrentHeap->validate_walls();
87}
88
89
90extern "C" void
91heap_debug_dump_allocations(bool statsOnly, thread_id thread)
92{
93	if (sCurrentHeap->dump_allocations != NULL)
94		sCurrentHeap->dump_allocations(statsOnly, thread);
95}
96
97
98extern "C" void
99heap_debug_dump_heaps(bool dumpAreas, bool dumpBins)
100{
101	if (sCurrentHeap->dump_heaps != NULL)
102		sCurrentHeap->dump_heaps(dumpAreas, dumpBins);
103}
104
105
106extern "C" void *
107heap_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
116extern "C" status_t
117heap_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
127extern "C" status_t
128heap_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
137extern "C" status_t
138heap_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
150extern "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
197extern "C" void
198__heap_terminate_after()
199{
200	if (sCurrentHeap->terminate_after != NULL)
201		sCurrentHeap->terminate_after();
202}
203
204
205extern "C" void
206__heap_before_fork(void)
207{
208}
209
210
211extern "C" void
212__heap_after_fork_child(void)
213{
214}
215
216
217extern "C" void
218__heap_after_fork_parent(void)
219{
220}
221
222
223extern "C" void
224__heap_thread_init(void)
225{
226}
227
228
229extern "C" void
230__heap_thread_exit(void)
231{
232}
233
234
235// #pragma mark - Public API
236
237
238extern "C" void*
239memalign(size_t alignment, size_t size)
240{
241	return sCurrentHeap->memalign(alignment, size);
242}
243
244
245extern "C" void*
246aligned_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
255extern "C" void*
256malloc(size_t size)
257{
258	return sCurrentHeap->malloc(size);
259}
260
261
262extern "C" void
263free(void* address)
264{
265	sCurrentHeap->free(address);
266}
267
268
269extern "C" void*
270realloc(void* address, size_t newSize)
271{
272	return sCurrentHeap->realloc(address, newSize);
273}
274
275
276extern "C" void*
277calloc(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
290extern "C" void*
291valloc(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
300extern "C" int
301posix_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
317extern "C" size_t
318malloc_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