Add heap_debug_get_allocation_info() to retrieve the size of the allocation as

well as the thread allocating it. Can for example be used to verify that an
object or buffer is as large as expected.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35480 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz 2010-02-15 20:57:52 +00:00
parent 479e05cec9
commit c1502cf1b8
2 changed files with 139 additions and 0 deletions

View File

@ -24,6 +24,9 @@ void heap_debug_dump_heaps(bool dumpAreas, bool dumpBins);
void *heap_debug_malloc_with_guard_page(size_t size);
status_t heap_debug_get_allocation_info(void *address, size_t *size,
thread_id *thread);
#ifdef __cplusplus
}
#endif

View File

@ -126,6 +126,7 @@ typedef struct area_allocation_info_s {
void * base;
uint32 magic;
size_t size;
thread_id thread;
size_t allocation_size;
size_t allocation_alignment;
void * allocation_base;
@ -1477,6 +1478,107 @@ heap_class_for(size_t size)
}
static status_t
heap_get_allocation_info(heap_allocator *heap, void *address, size_t *size,
thread_id *thread)
{
ReadLocker areaReadLocker(heap->area_lock);
heap_area *area = heap->all_areas;
while (area) {
// since the all_areas list is ordered by base with the biggest
// base at the top, we need only find the first area with a base
// smaller than our address to become our only candidate for freeing
if (area->base <= (addr_t)address) {
if ((addr_t)address >= area->base + area->size) {
// none of the other areas can contain the address as the list
// is ordered
return B_ENTRY_NOT_FOUND;
}
// this area contains the allocation, we're done searching
break;
}
area = area->all_next;
}
if (area == NULL) {
// this address does not belong to us
return B_ENTRY_NOT_FOUND;
}
heap_page *page = &area->page_table[((addr_t)address - area->base)
/ heap->page_size];
if (page->bin_index > heap->bin_count) {
panic("get_allocation_info(): page %p: invalid bin_index %d\n", page,
page->bin_index);
return B_ERROR;
}
heap_leak_check_info *info = NULL;
addr_t pageBase = area->base + page->index * heap->page_size;
if (page->bin_index < heap->bin_count) {
// small allocation
heap_bin *bin = &heap->bins[page->bin_index];
if (((addr_t)address - pageBase) % bin->element_size != 0) {
panic("get_allocation_info(): address %p does not fall on"
" allocation boundary for page base %p and element size %lu\n",
address, (void *)pageBase, bin->element_size);
return B_ERROR;
}
MutexLocker binLocker(bin->lock);
info = (heap_leak_check_info *)((addr_t)address + bin->element_size
- sizeof(heap_leak_check_info));
if (info->size > bin->element_size - sizeof(addr_t)
- sizeof(heap_leak_check_info)) {
panic("leak check info has invalid size %lu for element size %lu,"
" probably memory has been overwritten past allocation size\n",
info->size, bin->element_size);
}
} else {
if ((addr_t)address != pageBase) {
panic("get_allocation_info(): large allocation address %p not on"
" page base %p\n", address, (void *)pageBase);
return B_ERROR;
}
uint32 allocationID = page->allocation_id;
uint32 maxPages = area->page_count - page->index;
uint32 pageCount = 0;
MutexLocker pageLocker(heap->page_lock);
for (uint32 i = 0; i < maxPages; i++) {
// loop until we find the end of this allocation
if (!page[i].in_use || page[i].bin_index != heap->bin_count
|| page[i].allocation_id != allocationID)
break;
pageCount++;
}
size_t allocationSize = pageCount * heap->page_size;
info = (heap_leak_check_info *)((addr_t)address + allocationSize
- sizeof(heap_leak_check_info));
if (info->size > allocationSize - sizeof(addr_t)
- sizeof(heap_leak_check_info)) {
panic("leak check info has invalid size %lu for allocation of %lu,"
" probably memory has been overwritten past allocation size\n",
info->size, allocationSize);
}
}
if (size != NULL)
*size = info->size;
if (thread != NULL)
*thread = info->thread;
return B_OK;
}
// #pragma mark -
@ -1609,6 +1711,7 @@ heap_debug_malloc_with_guard_page(size_t size)
info->area = allocationArea;
info->base = address;
info->size = areaSize;
info->thread = find_thread(NULL);
info->allocation_size = size;
info->allocation_alignment = 0;
@ -1626,6 +1729,38 @@ heap_debug_malloc_with_guard_page(size_t size)
}
extern "C" status_t
heap_debug_get_allocation_info(void *address, size_t *size,
thread_id *thread)
{
for (uint32 i = 0; i < HEAP_CLASS_COUNT; i++) {
heap_allocator *heap = sHeaps[i];
if (heap_get_allocation_info(heap, address, size, thread) == B_OK)
return B_OK;
}
// or maybe it was a huge allocation using an area
area_info areaInfo;
area_id area = area_for(address);
if (area >= B_OK && get_area_info(area, &areaInfo) == B_OK) {
area_allocation_info *info = (area_allocation_info *)areaInfo.address;
// just make extra sure it was allocated by us
if (info->magic == kAreaAllocationMagic && info->area == area
&& info->size == areaInfo.size && info->base == areaInfo.address
&& info->allocation_size < areaInfo.size) {
if (size)
*size = info->allocation_size;
if (thread)
*thread = info->thread;
return B_OK;
}
}
return B_ENTRY_NOT_FOUND;
}
// #pragma mark - Init
@ -1700,6 +1835,7 @@ memalign(size_t alignment, size_t size)
info->area = allocationArea;
info->base = address;
info->size = areaSize;
info->thread = find_thread(NULL);
info->allocation_size = size;
info->allocation_alignment = alignment;