xref: /haiku/src/system/libroot/posix/malloc/debug/heap.cpp (revision fc7456e9b1ec38c941134ed6d01c438cf289381e)
1 /*
2  * Copyright 2008-2009, Michael Lotz, mmlr@mlotz.ch.
3  * Distributed under the terms of the MIT License.
4  *
5  * Copyright 2002-2011, Axel Dörfler, axeld@pinc-software.de.
6  * Distributed under the terms of the MIT License.
7  *
8  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
9  * Distributed under the terms of the NewOS License.
10  */
11 
12 
13 #include "malloc_debug_api.h"
14 
15 #include <malloc.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdlib.h>
19 
20 #include <errno.h>
21 #include <sys/mman.h>
22 
23 #include <errno_private.h>
24 #include <locks.h>
25 #include <syscalls.h>
26 
27 #include <Debug.h>
28 #include <OS.h>
29 
30 
31 //#define TRACE_HEAP
32 #ifdef TRACE_HEAP
33 #	define INFO(x) debug_printf x
34 #else
35 #	define INFO(x) ;
36 #endif
37 
38 #undef ASSERT
39 #define ASSERT(x)	if (!(x)) panic("assert failed: %s", #x);
40 
41 
42 static void *debug_heap_memalign(size_t alignment, size_t size);
43 
44 
45 static bool sDebuggerCalls = true;
46 static bool sReuseMemory = true;
47 static bool sParanoidValidation = false;
48 static thread_id sWallCheckThread = -1;
49 static bool sStopWallChecking = false;
50 static bool sUseGuardPage = false;
51 
52 #if __cplusplus >= 201103L
53 #include <cstddef>
54 using namespace std;
55 static size_t sDefaultAlignment = alignof(max_align_t);
56 #else
57 static size_t sDefaultAlignment = 8;
58 #endif
59 
60 
61 void
62 panic(const char *format, ...)
63 {
64 	char buffer[1024];
65 
66 	va_list args;
67 	va_start(args, format);
68 	vsnprintf(buffer, sizeof(buffer), format, args);
69 	va_end(args);
70 
71 	if (sDebuggerCalls)
72 		debugger(buffer);
73 	else
74 		debug_printf("%s", buffer);
75 }
76 
77 
78 #define ROUNDUP(x, y)		(((x) + (y) - 1) / (y) * (y))
79 
80 #define HEAP_INITIAL_SIZE			1 * 1024 * 1024
81 #define HEAP_GROW_SIZE				2 * 1024 * 1024
82 #define HEAP_AREA_USE_THRESHOLD		1 * 1024 * 1024
83 
84 typedef struct heap_leak_check_info_s {
85 	size_t		size;
86 	thread_id	thread;
87 } heap_leak_check_info;
88 
89 typedef struct heap_page_s heap_page;
90 
91 typedef struct heap_area_s {
92 	area_id			area;
93 
94 	addr_t			base;
95 	size_t			size;
96 
97 	uint32			page_count;
98 	uint32			free_page_count;
99 
100 	heap_page *		free_pages;
101 	heap_page *		page_table;
102 
103 	heap_area_s *	prev;
104 	heap_area_s *	next;
105 	heap_area_s *	all_next;
106 } heap_area;
107 
108 typedef struct heap_page_s {
109 	heap_area *		area;
110 	uint16			index;
111 	uint16			bin_index : 5;
112 	uint16			free_count : 10;
113 	uint16			in_use : 1;
114 	heap_page_s *	next;
115 	heap_page_s *	prev;
116 	union {
117 		uint16			empty_index;
118 		uint16			allocation_id; // used for bin == bin_count allocations
119 	};
120 	addr_t *		free_list;
121 } heap_page;
122 
123 typedef struct heap_bin_s {
124 	mutex		lock;
125 	uint32		element_size;
126 	uint16		max_free_count;
127 	heap_page *	page_list; // sorted so that the desired page is always first
128 } heap_bin;
129 
130 typedef struct heap_allocator_s {
131 	rw_lock		area_lock;
132 	mutex		page_lock;
133 
134 	const char *name;
135 	uint32		bin_count;
136 	uint32		page_size;
137 
138 	uint32		total_pages;
139 	uint32		total_free_pages;
140 	uint32		empty_areas;
141 
142 	heap_bin *	bins;
143 	heap_area *	areas; // sorted so that the desired area is always first
144 	heap_area *	all_areas; // all areas including full ones
145 } heap_allocator;
146 
147 static const uint32 kAreaAllocationMagic = 'AAMG';
148 typedef struct area_allocation_info_s {
149 	area_id		area;
150 	void *		base;
151 	uint32		magic;
152 	size_t		size;
153 	thread_id	thread;
154 	size_t		allocation_size;
155 	size_t		allocation_alignment;
156 	void *		allocation_base;
157 } area_allocation_info;
158 
159 typedef struct heap_class_s {
160 	const char *name;
161 	uint32		initial_percentage;
162 	size_t		max_allocation_size;
163 	size_t		page_size;
164 	size_t		min_bin_size;
165 	size_t		bin_alignment;
166 	uint32		min_count_per_page;
167 	size_t		max_waste_per_page;
168 } heap_class;
169 
170 // Heap class configuration
171 #define HEAP_CLASS_COUNT 3
172 static const heap_class sHeapClasses[HEAP_CLASS_COUNT] = {
173 	{
174 		"small",					/* name */
175 		50,							/* initial percentage */
176 		B_PAGE_SIZE / 8,			/* max allocation size */
177 		B_PAGE_SIZE,				/* page size */
178 		8,							/* min bin size */
179 		4,							/* bin alignment */
180 		8,							/* min count per page */
181 		16							/* max waste per page */
182 	},
183 	{
184 		"medium",					/* name */
185 		30,							/* initial percentage */
186 		B_PAGE_SIZE * 2,			/* max allocation size */
187 		B_PAGE_SIZE * 8,			/* page size */
188 		B_PAGE_SIZE / 8,			/* min bin size */
189 		32,							/* bin alignment */
190 		4,							/* min count per page */
191 		64							/* max waste per page */
192 	},
193 	{
194 		"large",					/* name */
195 		20,							/* initial percentage */
196 		HEAP_AREA_USE_THRESHOLD,	/* max allocation size */
197 		B_PAGE_SIZE * 16,			/* page size */
198 		B_PAGE_SIZE * 2,			/* min bin size */
199 		128,						/* bin alignment */
200 		1,							/* min count per page */
201 		256							/* max waste per page */
202 	}
203 };
204 
205 static heap_allocator *sHeaps[HEAP_CLASS_COUNT];
206 
207 
208 // #pragma mark - Debug functions
209 
210 
211 static void
212 dump_page(heap_page *page)
213 {
214 	uint32 count = 0;
215 	for (addr_t *temp = page->free_list; temp != NULL; temp = (addr_t *)*temp)
216 		count++;
217 
218 	printf("\t\tpage %p: bin_index: %u; free_count: %u; empty_index: %u; "
219 		"free_list %p (%" B_PRIu32 " entr%s)\n", page, page->bin_index,
220 		page->free_count, page->empty_index, page->free_list, count,
221 		count == 1 ? "y" : "ies");
222 }
223 
224 
225 static void
226 dump_bin(heap_bin *bin)
227 {
228 	printf("\telement_size: %" B_PRIu32 "; max_free_count: %u; page_list %p;\n",
229 		bin->element_size, bin->max_free_count, bin->page_list);
230 
231 	for (heap_page *temp = bin->page_list; temp != NULL; temp = temp->next)
232 		dump_page(temp);
233 }
234 
235 
236 static void
237 dump_bin_list(heap_allocator *heap)
238 {
239 	for (uint32 i = 0; i < heap->bin_count; i++)
240 		dump_bin(&heap->bins[i]);
241 	printf("\n");
242 }
243 
244 
245 static void
246 dump_allocator_areas(heap_allocator *heap)
247 {
248 	heap_area *area = heap->all_areas;
249 	while (area) {
250 		printf("\tarea %p: area: %" B_PRId32 "; base: 0x%08lx; size: %" B_PRIuSIZE "; "
251 			"page_count: %" B_PRIu32 "; free_pages: %p (%" B_PRIu32 " entr%s)\n",
252 			area, area->area, area->base, area->size, area->page_count,
253 			area->free_pages, area->free_page_count,
254 			area->free_page_count == 1 ? "y" : "ies");
255 		area = area->all_next;
256 	}
257 
258 	printf("\n");
259 }
260 
261 
262 static void
263 dump_allocator(heap_allocator *heap, bool areas, bool bins)
264 {
265 	printf("allocator %p: name: %s; page_size: %" B_PRIu32 "; bin_count: %"
266 		B_PRIu32 "; pages: %" B_PRIu32 "; free_pages: %" B_PRIu32 "; "
267 		"empty_areas: %" B_PRIu32 "\n", heap, heap->name, heap->page_size,
268 		heap->bin_count, heap->total_pages, heap->total_free_pages,
269 		heap->empty_areas);
270 
271 	if (areas)
272 		dump_allocator_areas(heap);
273 	if (bins)
274 		dump_bin_list(heap);
275 }
276 
277 
278 static void
279 dump_allocations(bool statsOnly, thread_id thread)
280 {
281 	size_t totalSize = 0;
282 	uint32 totalCount = 0;
283 	for (uint32 classIndex = 0; classIndex < HEAP_CLASS_COUNT; classIndex++) {
284 		heap_allocator *heap = sHeaps[classIndex];
285 
286 		// go through all the pages in all the areas
287 		heap_area *area = heap->all_areas;
288 		while (area) {
289 			heap_leak_check_info *info = NULL;
290 			for (uint32 i = 0; i < area->page_count; i++) {
291 				heap_page *page = &area->page_table[i];
292 				if (!page->in_use)
293 					continue;
294 
295 				addr_t base = area->base + i * heap->page_size;
296 				if (page->bin_index < heap->bin_count) {
297 					// page is used by a small allocation bin
298 					uint32 elementCount = page->empty_index;
299 					size_t elementSize
300 						= heap->bins[page->bin_index].element_size;
301 					for (uint32 j = 0; j < elementCount;
302 							j++, base += elementSize) {
303 						// walk the free list to see if this element is in use
304 						bool elementInUse = true;
305 						for (addr_t *temp = page->free_list; temp != NULL;
306 								temp = (addr_t *)*temp) {
307 							if ((addr_t)temp == base) {
308 								elementInUse = false;
309 								break;
310 							}
311 						}
312 
313 						if (!elementInUse)
314 							continue;
315 
316 						info = (heap_leak_check_info *)(base + elementSize
317 							- sizeof(heap_leak_check_info));
318 
319 						if (thread == -1 || info->thread == thread) {
320 							// interesting...
321 							if (!statsOnly) {
322 								printf("thread: % 6" B_PRId32 "; address: "
323 									"0x%08lx; size: %" B_PRIuSIZE " bytes\n", info->thread,
324 									base, info->size);
325 							}
326 
327 							totalSize += info->size;
328 							totalCount++;
329 						}
330 					}
331 				} else {
332 					// page is used by a big allocation, find the page count
333 					uint32 pageCount = 1;
334 					while (i + pageCount < area->page_count
335 						&& area->page_table[i + pageCount].in_use
336 						&& area->page_table[i + pageCount].bin_index
337 							== heap->bin_count
338 						&& area->page_table[i + pageCount].allocation_id
339 							== page->allocation_id)
340 						pageCount++;
341 
342 					info = (heap_leak_check_info *)(base + pageCount
343 						* heap->page_size - sizeof(heap_leak_check_info));
344 
345 					if (thread == -1 || info->thread == thread) {
346 						// interesting...
347 						if (!statsOnly) {
348 							printf("thread: % 6" B_PRId32 "; address: 0x%08lx;"
349 								" size: %" B_PRIuSIZE " bytes\n", info->thread,
350 								base, info->size);
351 						}
352 
353 						totalSize += info->size;
354 						totalCount++;
355 					}
356 
357 					// skip the allocated pages
358 					i += pageCount - 1;
359 				}
360 			}
361 
362 			area = area->all_next;
363 		}
364 	}
365 
366 	printf("total allocations: %" B_PRIu32 "; total bytes: %" B_PRIuSIZE "\n", totalCount,
367 		totalSize);
368 }
369 
370 
371 static void
372 heap_validate_walls()
373 {
374 	for (uint32 classIndex = 0; classIndex < HEAP_CLASS_COUNT; classIndex++) {
375 		heap_allocator *heap = sHeaps[classIndex];
376 		ReadLocker areaReadLocker(heap->area_lock);
377 		for (uint32 i = 0; i < heap->bin_count; i++)
378 			mutex_lock(&heap->bins[i].lock);
379 		MutexLocker pageLocker(heap->page_lock);
380 
381 		// go through all the pages in all the areas
382 		heap_area *area = heap->all_areas;
383 		while (area) {
384 			heap_leak_check_info *info = NULL;
385 			for (uint32 i = 0; i < area->page_count; i++) {
386 				heap_page *page = &area->page_table[i];
387 				if (!page->in_use)
388 					continue;
389 
390 				addr_t base = area->base + i * heap->page_size;
391 				if (page->bin_index < heap->bin_count) {
392 					// page is used by a small allocation bin
393 					uint32 elementCount = page->empty_index;
394 					size_t elementSize
395 						= heap->bins[page->bin_index].element_size;
396 					for (uint32 j = 0; j < elementCount;
397 							j++, base += elementSize) {
398 						// walk the free list to see if this element is in use
399 						bool elementInUse = true;
400 						for (addr_t *temp = page->free_list; temp != NULL;
401 								temp = (addr_t *)*temp) {
402 							if ((addr_t)temp == base) {
403 								elementInUse = false;
404 								break;
405 							}
406 						}
407 
408 						if (!elementInUse)
409 							continue;
410 
411 						info = (heap_leak_check_info *)(base + elementSize
412 							- sizeof(heap_leak_check_info));
413 						if (info->size > elementSize - sizeof(addr_t)
414 								- sizeof(heap_leak_check_info)) {
415 							panic("leak check info has invalid size %" B_PRIuSIZE " for"
416 								" element size %" B_PRIuSIZE "\n", info->size, elementSize);
417 							continue;
418 						}
419 
420 						addr_t wallValue;
421 						addr_t wallAddress = base + info->size;
422 						memcpy(&wallValue, (void *)wallAddress, sizeof(addr_t));
423 						if (wallValue != wallAddress) {
424 							panic("someone wrote beyond small allocation at"
425 								" 0x%08lx; size: %" B_PRIuSIZE " bytes;"
426 								" allocated by %" B_PRId32 ";"
427 								" value: 0x%08lx\n", base, info->size,
428 								info->thread, wallValue);
429 						}
430 					}
431 				} else {
432 					// page is used by a big allocation, find the page count
433 					uint32 pageCount = 1;
434 					while (i + pageCount < area->page_count
435 						&& area->page_table[i + pageCount].in_use
436 						&& area->page_table[i + pageCount].bin_index
437 							== heap->bin_count
438 						&& area->page_table[i + pageCount].allocation_id
439 							== page->allocation_id)
440 						pageCount++;
441 
442 					info = (heap_leak_check_info *)(base + pageCount
443 						* heap->page_size - sizeof(heap_leak_check_info));
444 
445 					if (info->size > pageCount * heap->page_size
446 							- sizeof(addr_t) - sizeof(heap_leak_check_info)) {
447 						panic("leak check info has invalid size %" B_PRIuSIZE " for"
448 							" page count %" B_PRIu32 " (%" B_PRIu32 " bytes)\n", info->size,
449 							pageCount, pageCount * heap->page_size);
450 						continue;
451 					}
452 
453 					addr_t wallValue;
454 					addr_t wallAddress = base + info->size;
455 					memcpy(&wallValue, (void *)wallAddress, sizeof(addr_t));
456 					if (wallValue != wallAddress) {
457 						panic("someone wrote beyond big allocation at 0x%08lx;"
458 							" size: %" B_PRIuSIZE " bytes; allocated by %" B_PRId32 ";"
459 							" value: 0x%08lx\n", base, info->size,
460 							info->thread, wallValue);
461 					}
462 
463 					// skip the allocated pages
464 					i += pageCount - 1;
465 				}
466 			}
467 
468 			area = area->all_next;
469 		}
470 
471 		pageLocker.Unlock();
472 		for (uint32 i = 0; i < heap->bin_count; i++)
473 			mutex_unlock(&heap->bins[i].lock);
474 	}
475 }
476 
477 
478 static void
479 heap_validate_heap(heap_allocator *heap)
480 {
481 	ReadLocker areaReadLocker(heap->area_lock);
482 	for (uint32 i = 0; i < heap->bin_count; i++)
483 		mutex_lock(&heap->bins[i].lock);
484 	MutexLocker pageLocker(heap->page_lock);
485 
486 	uint32 totalPageCount = 0;
487 	uint32 totalFreePageCount = 0;
488 	heap_area *area = heap->all_areas;
489 	while (area != NULL) {
490 		// validate the free pages list
491 		uint32 freePageCount = 0;
492 		heap_page *lastPage = NULL;
493 		heap_page *page = area->free_pages;
494 		while (page) {
495 			if ((addr_t)page < (addr_t)&area->page_table[0]
496 				|| (addr_t)page >= (addr_t)&area->page_table[area->page_count])
497 				panic("free page is not part of the page table\n");
498 
499 			if (page->index >= area->page_count)
500 				panic("free page has invalid index\n");
501 
502 			if ((addr_t)&area->page_table[page->index] != (addr_t)page)
503 				panic("free page index does not lead to target page\n");
504 
505 			if (page->prev != lastPage)
506 				panic("free page entry has invalid prev link\n");
507 
508 			if (page->in_use)
509 				panic("free page marked as in use\n");
510 
511 			lastPage = page;
512 			page = page->next;
513 			freePageCount++;
514 		}
515 
516 		totalPageCount += freePageCount;
517 		totalFreePageCount += freePageCount;
518 		if (area->free_page_count != freePageCount) {
519 			panic("free page count %" B_PRIu32 " doesn't match free page list %" B_PRIu32 "\n",
520 				area->free_page_count, freePageCount);
521 		}
522 
523 		// validate the page table
524 		uint32 usedPageCount = 0;
525 		for (uint32 i = 0; i < area->page_count; i++) {
526 			if (area->page_table[i].in_use)
527 				usedPageCount++;
528 		}
529 
530 		totalPageCount += usedPageCount;
531 		if (freePageCount + usedPageCount != area->page_count) {
532 			panic("free pages and used pages do not add up "
533 				"(%" B_PRIu32 " + %" B_PRIu32 " != %" B_PRIu32 ")\n",
534 				freePageCount, usedPageCount, area->page_count);
535 		}
536 
537 		area = area->all_next;
538 	}
539 
540 	// validate the areas
541 	area = heap->areas;
542 	heap_area *lastArea = NULL;
543 	uint32 lastFreeCount = 0;
544 	while (area != NULL) {
545 		if (area->free_page_count < lastFreeCount)
546 			panic("size ordering of area list broken\n");
547 
548 		if (area->prev != lastArea)
549 			panic("area list entry has invalid prev link\n");
550 
551 		lastArea = area;
552 		lastFreeCount = area->free_page_count;
553 		area = area->next;
554 	}
555 
556 	lastArea = NULL;
557 	area = heap->all_areas;
558 	while (area != NULL) {
559 		if (lastArea != NULL && lastArea->base < area->base)
560 			panic("base ordering of all_areas list broken\n");
561 
562 		lastArea = area;
563 		area = area->all_next;
564 	}
565 
566 	// validate the bins
567 	for (uint32 i = 0; i < heap->bin_count; i++) {
568 		heap_bin *bin = &heap->bins[i];
569 		heap_page *lastPage = NULL;
570 		heap_page *page = bin->page_list;
571 		lastFreeCount = 0;
572 		while (page) {
573 			area = heap->all_areas;
574 			while (area) {
575 				if (area == page->area)
576 					break;
577 				area = area->all_next;
578 			}
579 
580 			if (area == NULL) {
581 				panic("page area not present in area list\n");
582 				page = page->next;
583 				continue;
584 			}
585 
586 			if ((addr_t)page < (addr_t)&area->page_table[0]
587 				|| (addr_t)page >= (addr_t)&area->page_table[area->page_count])
588 				panic("used page is not part of the page table\n");
589 
590 			if (page->index >= area->page_count)
591 				panic("used page has invalid index %" B_PRIu16 "\n", page->index);
592 
593 			if ((addr_t)&area->page_table[page->index] != (addr_t)page) {
594 				panic("used page index does not lead to target page"
595 					" (%p vs. %p)\n", &area->page_table[page->index],
596 					page);
597 			}
598 
599 			if (page->prev != lastPage) {
600 				panic("used page entry has invalid prev link (%p vs %p bin "
601 					"%" B_PRIu32 ")\n", page->prev, lastPage, i);
602 			}
603 
604 			if (!page->in_use)
605 				panic("used page %p marked as not in use\n", page);
606 
607 			if (page->bin_index != i) {
608 				panic("used page with bin index %" B_PRIu16 " in page list of bin %" B_PRIu32 "\n",
609 					page->bin_index, i);
610 			}
611 
612 			if (page->free_count < lastFreeCount)
613 				panic("ordering of bin page list broken\n");
614 
615 			// validate the free list
616 			uint32 freeSlotsCount = 0;
617 			addr_t *element = page->free_list;
618 			addr_t pageBase = area->base + page->index * heap->page_size;
619 			while (element) {
620 				if ((addr_t)element < pageBase
621 					|| (addr_t)element >= pageBase + heap->page_size)
622 					panic("free list entry out of page range %p\n", element);
623 
624 				if (((addr_t)element - pageBase) % bin->element_size != 0)
625 					panic("free list entry not on a element boundary\n");
626 
627 				element = (addr_t *)*element;
628 				freeSlotsCount++;
629 			}
630 
631 			uint32 slotCount = bin->max_free_count;
632 			if (page->empty_index > slotCount) {
633 				panic("empty index beyond slot count (%" B_PRIu16 " with %" B_PRIu32 " slots)\n",
634 					page->empty_index, slotCount);
635 			}
636 
637 			freeSlotsCount += (slotCount - page->empty_index);
638 			if (freeSlotsCount > slotCount)
639 				panic("more free slots than fit into the page\n");
640 
641 			lastPage = page;
642 			lastFreeCount = page->free_count;
643 			page = page->next;
644 		}
645 	}
646 
647 	pageLocker.Unlock();
648 	for (uint32 i = 0; i < heap->bin_count; i++)
649 		mutex_unlock(&heap->bins[i].lock);
650 }
651 
652 
653 // #pragma mark - Heap functions
654 
655 
656 static void
657 heap_add_area(heap_allocator *heap, area_id areaID, addr_t base, size_t size)
658 {
659 	heap_area *area = (heap_area *)base;
660 	area->area = areaID;
661 
662 	base += sizeof(heap_area);
663 	size -= sizeof(heap_area);
664 
665 	uint32 pageCount = size / heap->page_size;
666 	size_t pageTableSize = pageCount * sizeof(heap_page);
667 	area->page_table = (heap_page *)base;
668 	base += pageTableSize;
669 	size -= pageTableSize;
670 
671 	// the rest is now actually usable memory (rounded to the next page)
672 	area->base = ROUNDUP(base, B_PAGE_SIZE);
673 	area->size = size & ~(B_PAGE_SIZE - 1);
674 
675 	// now we know the real page count
676 	pageCount = area->size / heap->page_size;
677 	area->page_count = pageCount;
678 
679 	// zero out the page table and fill in page indexes
680 	memset((void *)area->page_table, 0, pageTableSize);
681 	for (uint32 i = 0; i < pageCount; i++) {
682 		area->page_table[i].area = area;
683 		area->page_table[i].index = i;
684 	}
685 
686 	// add all pages up into the free pages list
687 	for (uint32 i = 1; i < pageCount; i++) {
688 		area->page_table[i - 1].next = &area->page_table[i];
689 		area->page_table[i].prev = &area->page_table[i - 1];
690 	}
691 	area->free_pages = &area->page_table[0];
692 	area->free_page_count = pageCount;
693 	area->page_table[0].prev = NULL;
694 	area->next = NULL;
695 
696 	WriteLocker areaWriteLocker(heap->area_lock);
697 	MutexLocker pageLocker(heap->page_lock);
698 	if (heap->areas == NULL) {
699 		// it's the only (empty) area in that heap
700 		area->prev = NULL;
701 		heap->areas = area;
702 	} else {
703 		// link in this area as the last one as it is completely empty
704 		heap_area *lastArea = heap->areas;
705 		while (lastArea->next != NULL)
706 			lastArea = lastArea->next;
707 
708 		lastArea->next = area;
709 		area->prev = lastArea;
710 	}
711 
712 	// insert this area in the all_areas list so it stays ordered by base
713 	if (heap->all_areas == NULL || heap->all_areas->base < area->base) {
714 		area->all_next = heap->all_areas;
715 		heap->all_areas = area;
716 	} else {
717 		heap_area *insert = heap->all_areas;
718 		while (insert->all_next && insert->all_next->base > area->base)
719 			insert = insert->all_next;
720 
721 		area->all_next = insert->all_next;
722 		insert->all_next = area;
723 	}
724 
725 	heap->total_pages += area->page_count;
726 	heap->total_free_pages += area->free_page_count;
727 
728 	if (areaID >= 0) {
729 		// this later on deletable area is yet empty - the empty count will be
730 		// decremented as soon as this area is used for the first time
731 		heap->empty_areas++;
732 	}
733 
734 	pageLocker.Unlock();
735 	areaWriteLocker.Unlock();
736 }
737 
738 
739 static status_t
740 heap_remove_area(heap_allocator *heap, heap_area *area)
741 {
742 	if (area->free_page_count != area->page_count) {
743 		panic("tried removing heap area that has still pages in use");
744 		return B_ERROR;
745 	}
746 
747 	if (area->prev == NULL && area->next == NULL) {
748 		panic("tried removing the last non-full heap area");
749 		return B_ERROR;
750 	}
751 
752 	if (heap->areas == area)
753 		heap->areas = area->next;
754 	if (area->prev != NULL)
755 		area->prev->next = area->next;
756 	if (area->next != NULL)
757 		area->next->prev = area->prev;
758 
759 	if (heap->all_areas == area)
760 		heap->all_areas = area->all_next;
761 	else {
762 		heap_area *previous = heap->all_areas;
763 		while (previous) {
764 			if (previous->all_next == area) {
765 				previous->all_next = area->all_next;
766 				break;
767 			}
768 
769 			previous = previous->all_next;
770 		}
771 
772 		if (previous == NULL)
773 			panic("removing heap area that is not in all list");
774 	}
775 
776 	heap->total_pages -= area->page_count;
777 	heap->total_free_pages -= area->free_page_count;
778 	return B_OK;
779 }
780 
781 
782 static heap_allocator *
783 heap_create_allocator(const char *name, addr_t base, size_t size,
784 	const heap_class *heapClass)
785 {
786 	heap_allocator *heap = (heap_allocator *)base;
787 	base += sizeof(heap_allocator);
788 	size -= sizeof(heap_allocator);
789 
790 	heap->name = name;
791 	heap->page_size = heapClass->page_size;
792 	heap->total_pages = heap->total_free_pages = heap->empty_areas = 0;
793 	heap->areas = heap->all_areas = NULL;
794 	heap->bins = (heap_bin *)base;
795 
796 	heap->bin_count = 0;
797 	size_t binSize = 0, lastSize = 0;
798 	uint32 count = heap->page_size / heapClass->min_bin_size;
799 	for (; count >= heapClass->min_count_per_page; count--, lastSize = binSize) {
800 		if (heap->bin_count >= 32)
801 			panic("heap configuration invalid - max bin count reached\n");
802 
803 		binSize = (heap->page_size / count) & ~(heapClass->bin_alignment - 1);
804 		if (binSize == lastSize)
805 			continue;
806 		if (heap->page_size - count * binSize > heapClass->max_waste_per_page)
807 			continue;
808 
809 		heap_bin *bin = &heap->bins[heap->bin_count];
810 		mutex_init(&bin->lock, "heap bin lock");
811 		bin->element_size = binSize;
812 		bin->max_free_count = heap->page_size / binSize;
813 		bin->page_list = NULL;
814 		heap->bin_count++;
815 	};
816 
817 	base += heap->bin_count * sizeof(heap_bin);
818 	size -= heap->bin_count * sizeof(heap_bin);
819 
820 	rw_lock_init(&heap->area_lock, "heap area lock");
821 	mutex_init(&heap->page_lock, "heap page lock");
822 
823 	heap_add_area(heap, -1, base, size);
824 	return heap;
825 }
826 
827 
828 static inline void
829 heap_free_pages_added(heap_allocator *heap, heap_area *area, uint32 pageCount)
830 {
831 	area->free_page_count += pageCount;
832 	heap->total_free_pages += pageCount;
833 
834 	if (area->free_page_count == pageCount) {
835 		// we need to add ourselfs to the area list of the heap
836 		area->prev = NULL;
837 		area->next = heap->areas;
838 		if (area->next)
839 			area->next->prev = area;
840 		heap->areas = area;
841 	} else {
842 		// we might need to move back in the area list
843 		if (area->next && area->next->free_page_count < area->free_page_count) {
844 			// move ourselfs so the list stays ordered
845 			heap_area *insert = area->next;
846 			while (insert->next
847 				&& insert->next->free_page_count < area->free_page_count)
848 				insert = insert->next;
849 
850 			if (area->prev)
851 				area->prev->next = area->next;
852 			if (area->next)
853 				area->next->prev = area->prev;
854 			if (heap->areas == area)
855 				heap->areas = area->next;
856 
857 			area->prev = insert;
858 			area->next = insert->next;
859 			if (area->next)
860 				area->next->prev = area;
861 			insert->next = area;
862 		}
863 	}
864 
865 	if (area->free_page_count == area->page_count && area->area >= 0)
866 		heap->empty_areas++;
867 }
868 
869 
870 static inline void
871 heap_free_pages_removed(heap_allocator *heap, heap_area *area, uint32 pageCount)
872 {
873 	if (area->free_page_count == area->page_count && area->area >= 0) {
874 		// this area was completely empty
875 		heap->empty_areas--;
876 	}
877 
878 	area->free_page_count -= pageCount;
879 	heap->total_free_pages -= pageCount;
880 
881 	if (area->free_page_count == 0) {
882 		// the area is now full so we remove it from the area list
883 		if (area->prev)
884 			area->prev->next = area->next;
885 		if (area->next)
886 			area->next->prev = area->prev;
887 		if (heap->areas == area)
888 			heap->areas = area->next;
889 		area->next = area->prev = NULL;
890 	} else {
891 		// we might need to move forward in the area list
892 		if (area->prev && area->prev->free_page_count > area->free_page_count) {
893 			// move ourselfs so the list stays ordered
894 			heap_area *insert = area->prev;
895 			while (insert->prev
896 				&& insert->prev->free_page_count > area->free_page_count)
897 				insert = insert->prev;
898 
899 			if (area->prev)
900 				area->prev->next = area->next;
901 			if (area->next)
902 				area->next->prev = area->prev;
903 
904 			area->prev = insert->prev;
905 			area->next = insert;
906 			if (area->prev)
907 				area->prev->next = area;
908 			if (heap->areas == insert)
909 				heap->areas = area;
910 			insert->prev = area;
911 		}
912 	}
913 }
914 
915 
916 static inline void
917 heap_link_page(heap_page *page, heap_page **list)
918 {
919 	page->prev = NULL;
920 	page->next = *list;
921 	if (page->next)
922 		page->next->prev = page;
923 	*list = page;
924 }
925 
926 
927 static inline void
928 heap_unlink_page(heap_page *page, heap_page **list)
929 {
930 	if (page->prev)
931 		page->prev->next = page->next;
932 	if (page->next)
933 		page->next->prev = page->prev;
934 	if (list && *list == page) {
935 		*list = page->next;
936 		if (page->next)
937 			page->next->prev = NULL;
938 	}
939 }
940 
941 
942 static heap_page *
943 heap_allocate_contiguous_pages(heap_allocator *heap, uint32 pageCount,
944 	size_t alignment)
945 {
946 	heap_area *area = heap->areas;
947 	while (area) {
948 		if (area->free_page_count < pageCount) {
949 			area = area->next;
950 			continue;
951 		}
952 
953 		uint32 step = 1;
954 		uint32 firstValid = 0;
955 		const uint32 lastValid = area->page_count - pageCount + 1;
956 
957 		if (alignment > heap->page_size) {
958 			firstValid = (ROUNDUP(area->base, alignment) - area->base)
959 				/ heap->page_size;
960 			step = alignment / heap->page_size;
961 		}
962 
963 		int32 first = -1;
964 		for (uint32 i = firstValid; i < lastValid; i += step) {
965 			if (area->page_table[i].in_use)
966 				continue;
967 
968 			first = i;
969 
970 			for (uint32 j = 1; j < pageCount; j++) {
971 				if (area->page_table[i + j].in_use) {
972 					first = -1;
973 					i += j / step * step;
974 					break;
975 				}
976 			}
977 
978 			if (first >= 0)
979 				break;
980 		}
981 
982 		if (first < 0) {
983 			area = area->next;
984 			continue;
985 		}
986 
987 		for (uint32 i = first; i < first + pageCount; i++) {
988 			heap_page *page = &area->page_table[i];
989 			page->in_use = 1;
990 			page->bin_index = heap->bin_count;
991 
992 			heap_unlink_page(page, &area->free_pages);
993 
994 			page->next = page->prev = NULL;
995 			page->free_list = NULL;
996 			page->allocation_id = (uint16)first;
997 		}
998 
999 		heap_free_pages_removed(heap, area, pageCount);
1000 		return &area->page_table[first];
1001 	}
1002 
1003 	return NULL;
1004 }
1005 
1006 
1007 static void
1008 heap_add_leak_check_info(addr_t address, size_t allocated, size_t size)
1009 {
1010 	size -= sizeof(addr_t) + sizeof(heap_leak_check_info);
1011 	heap_leak_check_info *info = (heap_leak_check_info *)(address + allocated
1012 		- sizeof(heap_leak_check_info));
1013 	info->thread = find_thread(NULL);
1014 	info->size = size;
1015 
1016 	addr_t wallAddress = address + size;
1017 	memcpy((void *)wallAddress, &wallAddress, sizeof(addr_t));
1018 }
1019 
1020 
1021 static void *
1022 heap_raw_alloc(heap_allocator *heap, size_t size, size_t alignment)
1023 {
1024 	INFO(("heap %p: allocate %" B_PRIuSIZE " bytes from raw pages with"
1025 		" alignment %" B_PRIuSIZE "\n", heap, size, alignment));
1026 
1027 	uint32 pageCount = (size + heap->page_size - 1) / heap->page_size;
1028 
1029 	MutexLocker pageLocker(heap->page_lock);
1030 	heap_page *firstPage = heap_allocate_contiguous_pages(heap, pageCount,
1031 		alignment);
1032 	if (firstPage == NULL) {
1033 		INFO(("heap %p: found no contiguous pages to allocate %" B_PRIuSIZE " bytes\n",
1034 			heap, size));
1035 		return NULL;
1036 	}
1037 
1038 	addr_t address = firstPage->area->base + firstPage->index * heap->page_size;
1039 	heap_add_leak_check_info(address, pageCount * heap->page_size, size);
1040 	return (void *)address;
1041 }
1042 
1043 
1044 static void *
1045 heap_allocate_from_bin(heap_allocator *heap, uint32 binIndex, size_t size)
1046 {
1047 	heap_bin *bin = &heap->bins[binIndex];
1048 	INFO(("heap %p: allocate %" B_PRIuSIZE " bytes from bin %" B_PRIu32
1049 		" with element_size %" B_PRIu32 "\n",
1050 		heap, size, binIndex, bin->element_size));
1051 
1052 	MutexLocker binLocker(bin->lock);
1053 	heap_page *page = bin->page_list;
1054 	if (page == NULL) {
1055 		MutexLocker pageLocker(heap->page_lock);
1056 		heap_area *area = heap->areas;
1057 		if (area == NULL) {
1058 			INFO(("heap %p: no free pages to allocate %" B_PRIuSIZE " bytes\n", heap,
1059 				size));
1060 			return NULL;
1061 		}
1062 
1063 		// by design there are only areas in the list that still have
1064 		// free pages available
1065 		page = area->free_pages;
1066 		area->free_pages = page->next;
1067 		if (page->next)
1068 			page->next->prev = NULL;
1069 
1070 		heap_free_pages_removed(heap, area, 1);
1071 
1072 		if (page->in_use)
1073 			panic("got an in use page from the free pages list\n");
1074 		page->in_use = 1;
1075 
1076 		pageLocker.Unlock();
1077 
1078 		page->bin_index = binIndex;
1079 		page->free_count = bin->max_free_count;
1080 		page->empty_index = 0;
1081 		page->free_list = NULL;
1082 		page->next = page->prev = NULL;
1083 		bin->page_list = page;
1084 	}
1085 
1086 	// we have a page where we have a free slot
1087 	void *address = NULL;
1088 	if (page->free_list) {
1089 		// there's a previously freed entry we can use
1090 		address = page->free_list;
1091 		page->free_list = (addr_t *)*page->free_list;
1092 	} else {
1093 		// the page hasn't been fully allocated so use the next empty_index
1094 		address = (void *)(page->area->base + page->index * heap->page_size
1095 			+ page->empty_index * bin->element_size);
1096 		page->empty_index++;
1097 	}
1098 
1099 	page->free_count--;
1100 	if (page->free_count == 0) {
1101 		// the page is now full so we remove it from the page_list
1102 		bin->page_list = page->next;
1103 		if (page->next)
1104 			page->next->prev = NULL;
1105 		page->next = page->prev = NULL;
1106 	}
1107 
1108 	heap_add_leak_check_info((addr_t)address, bin->element_size, size);
1109 	return address;
1110 }
1111 
1112 
1113 static void *
1114 heap_memalign(heap_allocator *heap, size_t alignment, size_t size)
1115 {
1116 	INFO(("memalign(alignment = %" B_PRIuSIZE ", size = %" B_PRIuSIZE ")\n",
1117 		alignment, size));
1118 
1119 	if (!is_valid_alignment(alignment)) {
1120 		panic("memalign() with an alignment which is not a power of 2 (%" B_PRIuSIZE ")\n",
1121 			alignment);
1122 	}
1123 
1124 	size += sizeof(addr_t) + sizeof(heap_leak_check_info);
1125 
1126 	void *address = NULL;
1127 	if (alignment < B_PAGE_SIZE) {
1128 		if (alignment != 0) {
1129 			// TODO: The alignment is done by ensuring that the element size
1130 			// of the target bin is aligned with the requested alignment. This
1131 			// has the problem that it wastes space because a better (smaller)
1132 			// bin could possibly be selected. We should pick the best bin and
1133 			// check if there is an aligned block in the free list or if a new
1134 			// (page aligned) page has to be allocated anyway.
1135 			size = ROUNDUP(size, alignment);
1136 			for (uint32 i = 0; i < heap->bin_count; i++) {
1137 				if (size <= heap->bins[i].element_size
1138 					&& is_valid_alignment(heap->bins[i].element_size)) {
1139 					address = heap_allocate_from_bin(heap, i, size);
1140 					break;
1141 				}
1142 			}
1143 		} else {
1144 			for (uint32 i = 0; i < heap->bin_count; i++) {
1145 				if (size <= heap->bins[i].element_size) {
1146 					address = heap_allocate_from_bin(heap, i, size);
1147 					break;
1148 				}
1149 			}
1150 		}
1151 	}
1152 
1153 	if (address == NULL)
1154 		address = heap_raw_alloc(heap, size, alignment);
1155 
1156 	size -= sizeof(addr_t) + sizeof(heap_leak_check_info);
1157 
1158 	INFO(("memalign(): asked to allocate %" B_PRIuSIZE " bytes, returning pointer %p\n",
1159 		size, address));
1160 
1161 	if (address == NULL)
1162 		return address;
1163 
1164 	memset(address, 0xcc, size);
1165 
1166 	// make sure 0xdeadbeef is cleared if we do not overwrite the memory
1167 	// and the user does not clear it
1168 	if (((uint32 *)address)[1] == 0xdeadbeef)
1169 		((uint32 *)address)[1] = 0xcccccccc;
1170 
1171 	return address;
1172 }
1173 
1174 
1175 static status_t
1176 heap_free(heap_allocator *heap, void *address)
1177 {
1178 	if (address == NULL)
1179 		return B_OK;
1180 
1181 	ReadLocker areaReadLocker(heap->area_lock);
1182 	heap_area *area = heap->all_areas;
1183 	while (area) {
1184 		// since the all_areas list is ordered by base with the biggest
1185 		// base at the top, we need only find the first area with a base
1186 		// smaller than our address to become our only candidate for freeing
1187 		if (area->base <= (addr_t)address) {
1188 			if ((addr_t)address >= area->base + area->size) {
1189 				// none of the other areas can contain the address as the list
1190 				// is ordered
1191 				return B_ENTRY_NOT_FOUND;
1192 			}
1193 
1194 			// this area contains the allocation, we're done searching
1195 			break;
1196 		}
1197 
1198 		area = area->all_next;
1199 	}
1200 
1201 	if (area == NULL) {
1202 		// this address does not belong to us
1203 		return B_ENTRY_NOT_FOUND;
1204 	}
1205 
1206 	INFO(("free(): asked to free pointer %p\n", address));
1207 
1208 	heap_page *page = &area->page_table[((addr_t)address - area->base)
1209 		/ heap->page_size];
1210 
1211 	INFO(("free(): page %p: bin_index %d, free_count %d\n", page,
1212 		page->bin_index, page->free_count));
1213 
1214 	if (page->bin_index > heap->bin_count) {
1215 		panic("free(): page %p: invalid bin_index %d\n", page,
1216 			page->bin_index);
1217 		return B_ERROR;
1218 	}
1219 
1220 	addr_t pageBase = area->base + page->index * heap->page_size;
1221 	if (page->bin_index < heap->bin_count) {
1222 		// small allocation
1223 		heap_bin *bin = &heap->bins[page->bin_index];
1224 		if (((addr_t)address - pageBase) % bin->element_size != 0) {
1225 			panic("free(): address %p does not fall on allocation boundary"
1226 				" for page base %p and element size %" B_PRIu32 "\n", address,
1227 				(void *)pageBase, bin->element_size);
1228 			return B_ERROR;
1229 		}
1230 
1231 		MutexLocker binLocker(bin->lock);
1232 
1233 		if (((uint32 *)address)[1] == 0xdeadbeef) {
1234 			// This block looks like it was freed already, walk the free list
1235 			// on this page to make sure this address doesn't exist.
1236 			for (addr_t *temp = page->free_list; temp != NULL;
1237 					temp = (addr_t *)*temp) {
1238 				if (temp == address) {
1239 					panic("free(): address %p already exists in page free"
1240 						" list (double free)\n", address);
1241 					return B_ERROR;
1242 				}
1243 			}
1244 		}
1245 
1246 		heap_leak_check_info *info = (heap_leak_check_info *)((addr_t)address
1247 			+ bin->element_size - sizeof(heap_leak_check_info));
1248 		if (info->size > bin->element_size - sizeof(addr_t)
1249 				- sizeof(heap_leak_check_info)) {
1250 			panic("leak check info has invalid size %" B_PRIuSIZE
1251 				" for element size %" B_PRIu32 ","
1252 				" probably memory has been overwritten past allocation size\n",
1253 				info->size, bin->element_size);
1254 		}
1255 
1256 		addr_t wallValue;
1257 		addr_t wallAddress = (addr_t)address + info->size;
1258 		memcpy(&wallValue, (void *)wallAddress, sizeof(addr_t));
1259 		if (wallValue != wallAddress) {
1260 			panic("someone wrote beyond small allocation at %p;"
1261 				" size: %" B_PRIuSIZE " bytes; allocated by %" B_PRId32 ";"
1262 				" value: 0x%08lx\n",
1263 				address, info->size, info->thread, wallValue);
1264 		}
1265 
1266 		// the first 4 bytes are overwritten with the next free list pointer
1267 		// later
1268 		uint32 *dead = (uint32 *)address;
1269 		for (uint32 i = 0; i < bin->element_size / sizeof(uint32); i++)
1270 			dead[i] = 0xdeadbeef;
1271 
1272 		if (sReuseMemory) {
1273 			// add the address to the page free list
1274 			*(addr_t *)address = (addr_t)page->free_list;
1275 			page->free_list = (addr_t *)address;
1276 			page->free_count++;
1277 
1278 			if (page->free_count == bin->max_free_count) {
1279 				// we are now empty, remove the page from the bin list
1280 				MutexLocker pageLocker(heap->page_lock);
1281 				heap_unlink_page(page, &bin->page_list);
1282 				page->in_use = 0;
1283 				heap_link_page(page, &area->free_pages);
1284 				heap_free_pages_added(heap, area, 1);
1285 			} else if (page->free_count == 1) {
1286 				// we need to add ourselfs to the page list of the bin
1287 				heap_link_page(page, &bin->page_list);
1288 			} else {
1289 				// we might need to move back in the free pages list
1290 				if (page->next && page->next->free_count < page->free_count) {
1291 					// move ourselfs so the list stays ordered
1292 					heap_page *insert = page->next;
1293 					while (insert->next
1294 						&& insert->next->free_count < page->free_count)
1295 						insert = insert->next;
1296 
1297 					heap_unlink_page(page, &bin->page_list);
1298 
1299 					page->prev = insert;
1300 					page->next = insert->next;
1301 					if (page->next)
1302 						page->next->prev = page;
1303 					insert->next = page;
1304 				}
1305 			}
1306 		}
1307 	} else {
1308 		if ((addr_t)address != pageBase) {
1309 			panic("free(): large allocation address %p not on page base %p\n",
1310 				address, (void *)pageBase);
1311 			return B_ERROR;
1312 		}
1313 
1314 		// large allocation, just return the pages to the page free list
1315 		uint32 allocationID = page->allocation_id;
1316 		uint32 maxPages = area->page_count - page->index;
1317 		uint32 pageCount = 0;
1318 
1319 		MutexLocker pageLocker(heap->page_lock);
1320 		for (uint32 i = 0; i < maxPages; i++) {
1321 			// loop until we find the end of this allocation
1322 			if (!page[i].in_use || page[i].bin_index != heap->bin_count
1323 				|| page[i].allocation_id != allocationID)
1324 				break;
1325 
1326 			// this page still belongs to the same allocation
1327 			if (sReuseMemory) {
1328 				page[i].in_use = 0;
1329 				page[i].allocation_id = 0;
1330 
1331 				// return it to the free list
1332 				heap_link_page(&page[i], &area->free_pages);
1333 			}
1334 
1335 			pageCount++;
1336 		}
1337 
1338 		size_t allocationSize = pageCount * heap->page_size;
1339 		heap_leak_check_info *info = (heap_leak_check_info *)((addr_t)address
1340 			+ allocationSize - sizeof(heap_leak_check_info));
1341 		if (info->size > allocationSize - sizeof(addr_t)
1342 				- sizeof(heap_leak_check_info)) {
1343 			panic("leak check info has invalid size %" B_PRIuSIZE
1344 				" for allocation of %" B_PRIuSIZE ","
1345 				" probably memory has been overwritten past allocation size\n",
1346 				info->size, allocationSize);
1347 		}
1348 
1349 		addr_t wallValue;
1350 		addr_t wallAddress = (addr_t)address + info->size;
1351 		memcpy(&wallValue, (void *)wallAddress, sizeof(addr_t));
1352 		if (wallValue != wallAddress) {
1353 			panic("someone wrote beyond big allocation at %p;"
1354 				" size: %" B_PRIuSIZE " bytes; allocated by %" B_PRId32 "; value: 0x%08lx\n",
1355 				address, info->size, info->thread, wallValue);
1356 		}
1357 
1358 		uint32 *dead = (uint32 *)address;
1359 		for (uint32 i = 0; i < allocationSize / sizeof(uint32); i++)
1360 			dead[i] = 0xdeadbeef;
1361 
1362 		if (sReuseMemory)
1363 			heap_free_pages_added(heap, area, pageCount);
1364 	}
1365 
1366 	areaReadLocker.Unlock();
1367 
1368 	if (heap->empty_areas > 1) {
1369 		WriteLocker areaWriteLocker(heap->area_lock);
1370 		MutexLocker pageLocker(heap->page_lock);
1371 
1372 		area = heap->areas;
1373 		while (area != NULL && heap->empty_areas > 1) {
1374 			heap_area *next = area->next;
1375 			if (area->area >= 0
1376 				&& area->free_page_count == area->page_count
1377 				&& heap_remove_area(heap, area) == B_OK) {
1378 				delete_area(area->area);
1379 				heap->empty_areas--;
1380 			}
1381 
1382 			area = next;
1383 		}
1384 	}
1385 
1386 	return B_OK;
1387 }
1388 
1389 
1390 static status_t
1391 heap_realloc(heap_allocator *heap, void *address, void **newAddress,
1392 	size_t newSize)
1393 {
1394 	ReadLocker areaReadLocker(heap->area_lock);
1395 	heap_area *area = heap->all_areas;
1396 	while (area) {
1397 		// since the all_areas list is ordered by base with the biggest
1398 		// base at the top, we need only find the first area with a base
1399 		// smaller than our address to become our only candidate for
1400 		// reallocating
1401 		if (area->base <= (addr_t)address) {
1402 			if ((addr_t)address >= area->base + area->size) {
1403 				// none of the other areas can contain the address as the list
1404 				// is ordered
1405 				return B_ENTRY_NOT_FOUND;
1406 			}
1407 
1408 			// this area contains the allocation, we're done searching
1409 			break;
1410 		}
1411 
1412 		area = area->all_next;
1413 	}
1414 
1415 	if (area == NULL) {
1416 		// this address does not belong to us
1417 		return B_ENTRY_NOT_FOUND;
1418 	}
1419 
1420 	INFO(("realloc(address = %p, newSize = %" B_PRIuSIZE ")\n", address, newSize));
1421 
1422 	heap_page *page = &area->page_table[((addr_t)address - area->base)
1423 		/ heap->page_size];
1424 	if (page->bin_index > heap->bin_count) {
1425 		panic("realloc(): page %p: invalid bin_index %d\n", page,
1426 			page->bin_index);
1427 		return B_ERROR;
1428 	}
1429 
1430 	// find out the size of the old allocation first
1431 	size_t minSize = 0;
1432 	size_t maxSize = 0;
1433 	if (page->bin_index < heap->bin_count) {
1434 		// this was a small allocation
1435 		heap_bin *bin = &heap->bins[page->bin_index];
1436 		maxSize = bin->element_size;
1437 		if (page->bin_index > 0)
1438 			minSize = heap->bins[page->bin_index - 1].element_size + 1;
1439 	} else {
1440 		// this was a large allocation
1441 		uint32 allocationID = page->allocation_id;
1442 		uint32 maxPages = area->page_count - page->index;
1443 		maxSize = heap->page_size;
1444 
1445 		MutexLocker pageLocker(heap->page_lock);
1446 		for (uint32 i = 1; i < maxPages; i++) {
1447 			if (!page[i].in_use || page[i].bin_index != heap->bin_count
1448 				|| page[i].allocation_id != allocationID)
1449 				break;
1450 
1451 			minSize += heap->page_size;
1452 			maxSize += heap->page_size;
1453 		}
1454 	}
1455 
1456 	newSize += sizeof(addr_t) + sizeof(heap_leak_check_info);
1457 
1458 	// does the new allocation simply fit in the old allocation?
1459 	if (newSize > minSize && newSize <= maxSize) {
1460 		// update the size info (the info is at the end so stays where it is)
1461 		heap_leak_check_info *info = (heap_leak_check_info *)((addr_t)address
1462 			+ maxSize - sizeof(heap_leak_check_info));
1463 		newSize -= sizeof(addr_t) + sizeof(heap_leak_check_info);
1464 		*newAddress = address;
1465 
1466 		MutexLocker pageLocker(heap->page_lock);
1467 		info->size = newSize;
1468 		addr_t wallAddress = (addr_t)address + newSize;
1469 		memcpy((void *)wallAddress, &wallAddress, sizeof(addr_t));
1470 		return B_OK;
1471 	}
1472 
1473 	areaReadLocker.Unlock();
1474 
1475 	// new leak check info will be created with the malloc below
1476 	newSize -= sizeof(addr_t) + sizeof(heap_leak_check_info);
1477 
1478 	// if not, allocate a new chunk of memory
1479 	*newAddress = debug_heap_memalign(sDefaultAlignment, newSize);
1480 	if (*newAddress == NULL) {
1481 		// we tried but it didn't work out, but still the operation is done
1482 		return B_OK;
1483 	}
1484 
1485 	// copy the old data and free the old allocation
1486 	memcpy(*newAddress, address, min_c(maxSize, newSize));
1487 	heap_free(heap, address);
1488 	return B_OK;
1489 }
1490 
1491 
1492 inline uint32
1493 heap_class_for(size_t size)
1494 {
1495 	// take the extra info size into account
1496 	size += sizeof(addr_t) + sizeof(heap_leak_check_info);
1497 
1498 	uint32 index = 0;
1499 	for (; index < HEAP_CLASS_COUNT - 1; index++) {
1500 		if (size <= sHeapClasses[index].max_allocation_size)
1501 			return index;
1502 	}
1503 
1504 	return index;
1505 }
1506 
1507 
1508 static status_t
1509 heap_get_allocation_info(heap_allocator *heap, void *address, size_t *size,
1510 	thread_id *thread)
1511 {
1512 	ReadLocker areaReadLocker(heap->area_lock);
1513 	heap_area *area = heap->all_areas;
1514 	while (area) {
1515 		// since the all_areas list is ordered by base with the biggest
1516 		// base at the top, we need only find the first area with a base
1517 		// smaller than our address to become our only candidate for freeing
1518 		if (area->base <= (addr_t)address) {
1519 			if ((addr_t)address >= area->base + area->size) {
1520 				// none of the other areas can contain the address as the list
1521 				// is ordered
1522 				return B_ENTRY_NOT_FOUND;
1523 			}
1524 
1525 			// this area contains the allocation, we're done searching
1526 			break;
1527 		}
1528 
1529 		area = area->all_next;
1530 	}
1531 
1532 	if (area == NULL) {
1533 		// this address does not belong to us
1534 		return B_ENTRY_NOT_FOUND;
1535 	}
1536 
1537 	heap_page *page = &area->page_table[((addr_t)address - area->base)
1538 		/ heap->page_size];
1539 
1540 	if (page->bin_index > heap->bin_count) {
1541 		panic("get_allocation_info(): page %p: invalid bin_index %d\n", page,
1542 			page->bin_index);
1543 		return B_ERROR;
1544 	}
1545 
1546 	heap_leak_check_info *info = NULL;
1547 	addr_t pageBase = area->base + page->index * heap->page_size;
1548 	if (page->bin_index < heap->bin_count) {
1549 		// small allocation
1550 		heap_bin *bin = &heap->bins[page->bin_index];
1551 		if (((addr_t)address - pageBase) % bin->element_size != 0) {
1552 			panic("get_allocation_info(): address %p does not fall on"
1553 				" allocation boundary for page base %p and element size %" B_PRIu32 "\n",
1554 				address, (void *)pageBase, bin->element_size);
1555 			return B_ERROR;
1556 		}
1557 
1558 		MutexLocker binLocker(bin->lock);
1559 
1560 		info = (heap_leak_check_info *)((addr_t)address + bin->element_size
1561 			- sizeof(heap_leak_check_info));
1562 		if (info->size > bin->element_size - sizeof(addr_t)
1563 				- sizeof(heap_leak_check_info)) {
1564 			panic("leak check info has invalid size %" B_PRIuSIZE
1565 				" for element size %" B_PRIu32 ","
1566 				" probably memory has been overwritten past allocation size\n",
1567 				info->size, bin->element_size);
1568 			return B_ERROR;
1569 		}
1570 	} else {
1571 		if ((addr_t)address != pageBase) {
1572 			panic("get_allocation_info(): large allocation address %p not on"
1573 				" page base %p\n", address, (void *)pageBase);
1574 			return B_ERROR;
1575 		}
1576 
1577 		uint32 allocationID = page->allocation_id;
1578 		uint32 maxPages = area->page_count - page->index;
1579 		uint32 pageCount = 0;
1580 
1581 		MutexLocker pageLocker(heap->page_lock);
1582 		for (uint32 i = 0; i < maxPages; i++) {
1583 			// loop until we find the end of this allocation
1584 			if (!page[i].in_use || page[i].bin_index != heap->bin_count
1585 				|| page[i].allocation_id != allocationID)
1586 				break;
1587 
1588 			pageCount++;
1589 		}
1590 
1591 		size_t allocationSize = pageCount * heap->page_size;
1592 		info = (heap_leak_check_info *)((addr_t)address + allocationSize
1593 			- sizeof(heap_leak_check_info));
1594 		if (info->size > allocationSize - sizeof(addr_t)
1595 				- sizeof(heap_leak_check_info)) {
1596 			panic("leak check info has invalid size %" B_PRIuSIZE
1597 				" for allocation of %" B_PRIuSIZE ","
1598 				" probably memory has been overwritten past allocation size\n",
1599 				info->size, allocationSize);
1600 			return B_ERROR;
1601 		}
1602 	}
1603 
1604 	if (size != NULL)
1605 		*size = info->size;
1606 	if (thread != NULL)
1607 		*thread = info->thread;
1608 
1609 	return B_OK;
1610 }
1611 
1612 
1613 //	#pragma mark -
1614 
1615 
1616 static status_t
1617 heap_create_new_heap_area(heap_allocator *heap, const char *name, size_t size)
1618 {
1619 	void *address = NULL;
1620 	area_id heapArea = create_area(name, &address, B_ANY_ADDRESS, size,
1621 		B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
1622 	if (heapArea < B_OK) {
1623 		INFO(("heap: couldn't allocate heap area \"%s\"\n", name));
1624 		return heapArea;
1625 	}
1626 
1627 	heap_add_area(heap, heapArea, (addr_t)address, size);
1628 	if (sParanoidValidation)
1629 		heap_validate_heap(heap);
1630 
1631 	return B_OK;
1632 }
1633 
1634 
1635 static int32
1636 heap_wall_checker(void *data)
1637 {
1638 	int msInterval = (addr_t)data;
1639 	while (!sStopWallChecking) {
1640 		heap_validate_walls();
1641 		snooze(msInterval * 1000);
1642 	}
1643 
1644 	return 0;
1645 }
1646 
1647 
1648 //	#pragma mark - Heap Debug API
1649 
1650 
1651 static status_t
1652 debug_heap_start_wall_checking(int msInterval)
1653 {
1654 	if (sWallCheckThread < 0) {
1655 		sWallCheckThread = spawn_thread(heap_wall_checker, "heap wall checker",
1656 			B_LOW_PRIORITY, (void *)(addr_t)msInterval);
1657 	}
1658 
1659 	if (sWallCheckThread < 0)
1660 		return sWallCheckThread;
1661 
1662 	sStopWallChecking = false;
1663 	return resume_thread(sWallCheckThread);
1664 }
1665 
1666 
1667 static status_t
1668 debug_heap_stop_wall_checking()
1669 {
1670 	int32 result;
1671 	sStopWallChecking = true;
1672 	return wait_for_thread(sWallCheckThread, &result);
1673 }
1674 
1675 
1676 static void
1677 debug_heap_set_paranoid_validation(bool enabled)
1678 {
1679 	sParanoidValidation = enabled;
1680 }
1681 
1682 
1683 static void
1684 debug_heap_set_memory_reuse(bool enabled)
1685 {
1686 	sReuseMemory = enabled;
1687 }
1688 
1689 
1690 static void
1691 debug_heap_set_debugger_calls(bool enabled)
1692 {
1693 	sDebuggerCalls = enabled;
1694 }
1695 
1696 
1697 static void
1698 debug_heap_set_default_alignment(size_t defaultAlignment)
1699 {
1700 	sDefaultAlignment = defaultAlignment;
1701 }
1702 
1703 
1704 static void
1705 debug_heap_validate_heaps()
1706 {
1707 	for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++)
1708 		heap_validate_heap(sHeaps[i]);
1709 }
1710 
1711 
1712 static void
1713 debug_heap_dump_heaps(bool dumpAreas, bool dumpBins)
1714 {
1715 	for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++)
1716 		dump_allocator(sHeaps[i], dumpAreas, dumpBins);
1717 }
1718 
1719 
1720 static void *
1721 debug_heap_malloc_with_guard_page(size_t size)
1722 {
1723 	size_t areaSize = ROUNDUP(size + sizeof(area_allocation_info) + B_PAGE_SIZE,
1724 		B_PAGE_SIZE);
1725 	if (areaSize < size) {
1726 		// the size overflowed
1727 		return NULL;
1728 	}
1729 
1730 	void *address = NULL;
1731 	area_id allocationArea = create_area("guarded area", &address,
1732 		B_ANY_ADDRESS, areaSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
1733 	if (allocationArea < B_OK) {
1734 		panic("heap: failed to create area for guarded allocation of %" B_PRIuSIZE
1735 			" bytes\n", size);
1736 		return NULL;
1737 	}
1738 
1739 	if (mprotect((void *)((addr_t)address + areaSize - B_PAGE_SIZE),
1740 			B_PAGE_SIZE, PROT_NONE) != 0) {
1741 		panic("heap: failed to protect guard page: %s\n", strerror(errno));
1742 		delete_area(allocationArea);
1743 		return NULL;
1744 	}
1745 
1746 	area_allocation_info *info = (area_allocation_info *)address;
1747 	info->magic = kAreaAllocationMagic;
1748 	info->area = allocationArea;
1749 	info->base = address;
1750 	info->size = areaSize;
1751 	info->thread = find_thread(NULL);
1752 	info->allocation_size = size;
1753 	info->allocation_alignment = 0;
1754 
1755 	// the address is calculated so that the end of the allocation
1756 	// is at the end of the usable space of the requested area
1757 	address = (void *)((addr_t)address + areaSize - B_PAGE_SIZE - size);
1758 
1759 	INFO(("heap: allocated area %" B_PRId32 " for guarded allocation of %" B_PRIuSIZE " bytes\n",
1760 		allocationArea, size));
1761 
1762 	info->allocation_base = address;
1763 
1764 	memset(address, 0xcc, size);
1765 	return address;
1766 }
1767 
1768 
1769 static status_t
1770 debug_heap_get_allocation_info(void *address, size_t *size,
1771 	thread_id *thread)
1772 {
1773 	for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++) {
1774 		heap_allocator *heap = sHeaps[i];
1775 		if (heap_get_allocation_info(heap, address, size, thread) == B_OK)
1776 			return B_OK;
1777 	}
1778 
1779 	// or maybe it was a huge allocation using an area
1780 	area_info areaInfo;
1781 	area_id area = area_for(address);
1782 	if (area >= B_OK && get_area_info(area, &areaInfo) == B_OK) {
1783 		area_allocation_info *info = (area_allocation_info *)areaInfo.address;
1784 
1785 		// just make extra sure it was allocated by us
1786 		if (info->magic == kAreaAllocationMagic && info->area == area
1787 			&& info->size == areaInfo.size && info->base == areaInfo.address
1788 			&& info->allocation_size < areaInfo.size) {
1789 			if (size)
1790 				*size = info->allocation_size;
1791 			if (thread)
1792 				*thread = info->thread;
1793 			return B_OK;
1794 		}
1795 	}
1796 
1797 	return B_ENTRY_NOT_FOUND;
1798 }
1799 
1800 
1801 //	#pragma mark - Init
1802 
1803 
1804 static status_t
1805 debug_heap_init(void)
1806 {
1807 	// This will locate the heap base at 384 MB and reserve the next 1152 MB
1808 	// for it. They may get reclaimed by other areas, though, but the maximum
1809 	// size of the heap is guaranteed until the space is really needed.
1810 	void *heapBase = (void *)0x18000000;
1811 	status_t status = _kern_reserve_address_range((addr_t *)&heapBase,
1812 		B_EXACT_ADDRESS, 0x48000000);
1813 
1814 	area_id heapArea = create_area("heap", (void **)&heapBase,
1815 		status == B_OK ? B_EXACT_ADDRESS : B_BASE_ADDRESS,
1816 		HEAP_INITIAL_SIZE, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
1817 	if (heapArea < B_OK)
1818 		return heapArea;
1819 
1820 	addr_t base = (addr_t)heapBase;
1821 	for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++) {
1822 		size_t partSize = HEAP_INITIAL_SIZE
1823 			* sHeapClasses[i].initial_percentage / 100;
1824 		sHeaps[i] = heap_create_allocator(sHeapClasses[i].name, base, partSize,
1825 			&sHeapClasses[i]);
1826 		base += partSize;
1827 	}
1828 
1829 	return B_OK;
1830 }
1831 
1832 
1833 //	#pragma mark - Public API
1834 
1835 
1836 static void *
1837 debug_heap_memalign(size_t alignment, size_t size)
1838 {
1839 	size_t alignedSize = size + sizeof(addr_t) + sizeof(heap_leak_check_info);
1840 	if (alignment != 0 && alignment < B_PAGE_SIZE)
1841 		alignedSize = ROUNDUP(alignedSize, alignment);
1842 
1843 	if (alignedSize >= HEAP_AREA_USE_THRESHOLD) {
1844 		// don't even attempt such a huge allocation - use areas instead
1845 		size_t areaSize = ROUNDUP(size + sizeof(area_allocation_info)
1846 			+ alignment, B_PAGE_SIZE);
1847 		if (areaSize < size) {
1848 			// the size overflowed
1849 			return NULL;
1850 		}
1851 
1852 		void *address = NULL;
1853 		area_id allocationArea = create_area("memalign area", &address,
1854 			B_ANY_ADDRESS, areaSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
1855 		if (allocationArea < B_OK) {
1856 			panic("heap: failed to create area for huge allocation of %" B_PRIuSIZE
1857 				" bytes\n", size);
1858 			return NULL;
1859 		}
1860 
1861 		area_allocation_info *info = (area_allocation_info *)address;
1862 		info->magic = kAreaAllocationMagic;
1863 		info->area = allocationArea;
1864 		info->base = address;
1865 		info->size = areaSize;
1866 		info->thread = find_thread(NULL);
1867 		info->allocation_size = size;
1868 		info->allocation_alignment = alignment;
1869 
1870 		address = (void *)((addr_t)address + sizeof(area_allocation_info));
1871 		if (alignment != 0) {
1872 			address = (void *)ROUNDUP((addr_t)address, alignment);
1873 			ASSERT((addr_t)address % alignment == 0);
1874 			ASSERT((addr_t)address + size - 1 < (addr_t)info + areaSize - 1);
1875 		}
1876 
1877 		INFO(("heap: allocated area %" B_PRId32 " for huge allocation of %" B_PRIuSIZE " bytes\n",
1878 			allocationArea, size));
1879 
1880 		info->allocation_base = address;
1881 
1882 		memset(address, 0xcc, size);
1883 		return address;
1884 	}
1885 
1886 	uint32 heapClass = alignment < B_PAGE_SIZE
1887 		? heap_class_for(alignedSize) : 0;
1888 
1889 	heap_allocator *heap = sHeaps[heapClass];
1890 	void *result = heap_memalign(heap, alignment, size);
1891 	if (result == NULL) {
1892 		// add new area and try again
1893 		heap_create_new_heap_area(heap, "additional heap area", HEAP_GROW_SIZE);
1894 		result = heap_memalign(heap, alignment, size);
1895 	}
1896 
1897 	if (sParanoidValidation)
1898 		heap_validate_heap(heap);
1899 
1900 	if (result == NULL) {
1901 		panic("heap: heap has run out of memory trying to allocate %" B_PRIuSIZE " bytes\n",
1902 			size);
1903 	}
1904 
1905 	if (alignment != 0)
1906 		ASSERT((addr_t)result % alignment == 0);
1907 
1908 	return result;
1909 }
1910 
1911 
1912 static void *
1913 debug_heap_malloc(size_t size)
1914 {
1915 	if (sUseGuardPage)
1916 		return debug_heap_malloc_with_guard_page(size);
1917 
1918 	return debug_heap_memalign(sDefaultAlignment, size);
1919 }
1920 
1921 
1922 static void
1923 debug_heap_free(void *address)
1924 {
1925 	for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++) {
1926 		heap_allocator *heap = sHeaps[i];
1927 		if (heap_free(heap, address) == B_OK) {
1928 			if (sParanoidValidation)
1929 				heap_validate_heap(heap);
1930 			return;
1931 		}
1932 	}
1933 
1934 	// or maybe it was a huge allocation using an area
1935 	area_info areaInfo;
1936 	area_id area = area_for(address);
1937 	if (area >= B_OK && get_area_info(area, &areaInfo) == B_OK) {
1938 		area_allocation_info *info = (area_allocation_info *)areaInfo.address;
1939 
1940 		// just make extra sure it was allocated by us
1941 		if (info->magic == kAreaAllocationMagic && info->area == area
1942 			&& info->size == areaInfo.size && info->base == areaInfo.address
1943 			&& info->allocation_size < areaInfo.size) {
1944 			delete_area(area);
1945 			INFO(("free(): freed huge allocation by deleting area %" B_PRId32 "\n",
1946 				area));
1947 			return;
1948 		}
1949 	}
1950 
1951 	panic("free(): free failed for address %p\n", address);
1952 }
1953 
1954 
1955 static void *
1956 debug_heap_realloc(void *address, size_t newSize)
1957 {
1958 	if (address == NULL)
1959 		return debug_heap_memalign(sDefaultAlignment, newSize);
1960 
1961 	if (newSize == 0) {
1962 		free(address);
1963 		return NULL;
1964 	}
1965 
1966 	void *newAddress = NULL;
1967 	for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++) {
1968 		heap_allocator *heap = sHeaps[i];
1969 		if (heap_realloc(heap, address, &newAddress, newSize) == B_OK) {
1970 			if (sParanoidValidation)
1971 				heap_validate_heap(heap);
1972 			return newAddress;
1973 		}
1974 	}
1975 
1976 	// or maybe it was a huge allocation using an area
1977 	area_info areaInfo;
1978 	area_id area = area_for(address);
1979 	if (area >= B_OK && get_area_info(area, &areaInfo) == B_OK) {
1980 		area_allocation_info *info = (area_allocation_info *)areaInfo.address;
1981 
1982 		// just make extra sure it was allocated by us
1983 		if (info->magic == kAreaAllocationMagic && info->area == area
1984 			&& info->size == areaInfo.size && info->base == areaInfo.address
1985 			&& info->allocation_size < areaInfo.size) {
1986 			if (sUseGuardPage) {
1987 				size_t available = info->size - B_PAGE_SIZE
1988 					- sizeof(area_allocation_info);
1989 
1990 				if (available >= newSize) {
1991 					// there is enough room available for the newSize
1992 					newAddress = (void*)((addr_t)info->allocation_base
1993 						+ info->allocation_size - newSize);
1994 					INFO(("realloc(): new size %" B_PRIuSIZE
1995 						" fits in old area %" B_PRId32 " with "
1996 						"%" B_PRIuSIZE " available -> new address: %p\n",
1997 						newSize, area, available, newAddress));
1998 					memmove(newAddress, info->allocation_base,
1999 						min_c(newSize, info->allocation_size));
2000 					info->allocation_base = newAddress;
2001 					info->allocation_size = newSize;
2002 					return newAddress;
2003 				}
2004 			} else {
2005 				size_t available = info->size - ((addr_t)info->allocation_base
2006 					- (addr_t)info->base);
2007 
2008 				if (available >= newSize) {
2009 					// there is enough room available for the newSize
2010 					INFO(("realloc(): new size %" B_PRIuSIZE
2011 						" fits in old area %" B_PRId32 " with "
2012 						"%" B_PRIuSIZE " available\n",
2013 						newSize, area, available));
2014 					info->allocation_size = newSize;
2015 					return address;
2016 				}
2017 			}
2018 
2019 			// have to allocate/copy/free - TODO maybe resize the area instead?
2020 			newAddress = debug_heap_memalign(sDefaultAlignment, newSize);
2021 			if (newAddress == NULL) {
2022 				panic("realloc(): failed to allocate new block of %" B_PRIuSIZE
2023 					" bytes\n", newSize);
2024 				return NULL;
2025 			}
2026 
2027 			memcpy(newAddress, address, min_c(newSize, info->allocation_size));
2028 			delete_area(area);
2029 			INFO(("realloc(): allocated new block %p for size %" B_PRIuSIZE
2030 				" and deleted old area %" B_PRId32 "\n",
2031 				newAddress, newSize, area));
2032 			return newAddress;
2033 		}
2034 	}
2035 
2036 	panic("realloc(): failed to realloc address %p to size %" B_PRIuSIZE "\n", address,
2037 		newSize);
2038 	return NULL;
2039 }
2040 
2041 
2042 heap_implementation __mallocDebugHeap = {
2043 	debug_heap_init,
2044 	NULL,	// terminate_after
2045 
2046 	debug_heap_memalign,
2047 	debug_heap_malloc,
2048 	debug_heap_free,
2049 	debug_heap_realloc,
2050 
2051 	NULL,	// calloc
2052 	NULL,	// valloc
2053 	NULL,	// posix_memalign
2054 
2055 	debug_heap_start_wall_checking,
2056 	debug_heap_stop_wall_checking,
2057 	debug_heap_set_paranoid_validation,
2058 	debug_heap_set_memory_reuse,
2059 	debug_heap_set_debugger_calls,
2060 	debug_heap_set_default_alignment,
2061 	debug_heap_validate_heaps,
2062 	heap_validate_walls,
2063 	dump_allocations,
2064 	debug_heap_dump_heaps,
2065 	debug_heap_malloc_with_guard_page,
2066 	debug_heap_get_allocation_info,
2067 
2068 	NULL,	// set_dump_allocations_on_exit
2069 	NULL	// set_stack_trace_depth
2070 };
2071