malloc_debug_leak.cpp revision 72bbd423579bb971dc06cdd3c06201faf3fe95e6
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (C) 2008 The Android Open Source Project 3d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt * All rights reserved. 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * Redistribution and use in source and binary forms, with or without 6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * modification, are permitted provided that the following conditions 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * are met: 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * * Redistributions of source code must retain the above copyright 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * notice, this list of conditions and the following disclaimer. 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * * Redistributions in binary form must reproduce the above copyright 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * notice, this list of conditions and the following disclaimer in 12d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt * the documentation and/or other materials provided with the 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * distribution. 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt * SUCH DAMAGE. 27d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt */ 28d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt 29d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt#include <arpa/inet.h> 30d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt#include <dlfcn.h> 31d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt#include <errno.h> 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <fcntl.h> 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <pthread.h> 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <stdarg.h> 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <stddef.h> 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <stdint.h> 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <stdio.h> 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <stdlib.h> 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <string.h> 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <sys/select.h> 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <sys/socket.h> 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <sys/system_properties.h> 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <sys/types.h> 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <sys/un.h> 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <unistd.h> 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <unwind.h> 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "debug_stacktrace.h" 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "malloc_debug_common.h" 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "private/libc_logging.h" 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "private/ScopedPthreadMutexLocker.h" 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// This file should be included into the build only when 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// MALLOC_LEAK_CHECK, or MALLOC_QEMU_INSTRUMENT, or both 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// macros are defined. 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef MALLOC_LEAK_CHECK 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#error MALLOC_LEAK_CHECK is not defined. 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif // !MALLOC_LEAK_CHECK 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// Global variables defined in malloc_debug_common.c 6261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtextern int gMallocLeakZygoteChild; 6361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtextern pthread_mutex_t g_allocations_mutex; 6461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtextern HashTable g_hash_table; 6561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 6661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt// ============================================================================= 67fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt// stack trace functions 6861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt// ============================================================================= 6961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 7061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#define GUARD 0x48151642 7161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#define DEBUG 0 7261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt 7361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt// ============================================================================= 7461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt// Structures 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// ============================================================================= 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct AllocationEntry { 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HashEntry* entry; 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt uint32_t guard; 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} __attribute__((aligned(MALLOC_ALIGNMENT))); 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic inline AllocationEntry* to_header(void* mem) { 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return reinterpret_cast<AllocationEntry*>(mem) - 1; 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic inline const AllocationEntry* const_to_header(const void* mem) { 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return reinterpret_cast<const AllocationEntry*>(mem) - 1; 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// ============================================================================= 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// Hash Table functions 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// ============================================================================= 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic uint32_t get_hash(uintptr_t* backtrace, size_t numEntries) { 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (backtrace == NULL) return 0; 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int hash = 0; 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t i; 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0 ; i < numEntries ; i++) { 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hash = (hash * 33) + (backtrace[i] >> 2); 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return hash; 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic HashEntry* find_entry(HashTable* table, int slot, 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt uintptr_t* backtrace, size_t numEntries, size_t size) { 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HashEntry* entry = table->slots[slot]; 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (entry != NULL) { 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt //debug_log("backtrace: %p, entry: %p entry->backtrace: %p\n", 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // backtrace, entry, (entry != NULL) ? entry->backtrace : NULL); 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See if the entry matches exactly. We compare the "size" field, 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * including the flag bits. 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (entry->size == size && entry->numEntries == numEntries && 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt !memcmp(backtrace, entry->backtrace, numEntries * sizeof(uintptr_t))) { 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return entry; 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry = entry->next; 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic HashEntry* record_backtrace(uintptr_t* backtrace, size_t numEntries, size_t size) { 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t hash = get_hash(backtrace, numEntries); 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t slot = hash % HASHTABLE_SIZE; 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (size & SIZE_FLAG_MASK) { 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt debug_log("malloc_debug: allocation %zx exceeds bit width\n", size); 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt abort(); 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (gMallocLeakZygoteChild) { 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size |= SIZE_FLAG_ZYGOTE_CHILD; 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HashEntry* entry = find_entry(&g_hash_table, slot, backtrace, numEntries, size); 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (entry != NULL) { 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->allocations++; 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // create a new entry 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry = static_cast<HashEntry*>(Malloc(malloc)(sizeof(HashEntry) + numEntries*sizeof(uintptr_t))); 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!entry) { 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->allocations = 1; 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->slot = slot; 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->prev = NULL; 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->next = g_hash_table.slots[slot]; 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->numEntries = numEntries; 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->size = size; 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt memcpy(entry->backtrace, backtrace, numEntries * sizeof(uintptr_t)); 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt g_hash_table.slots[slot] = entry; 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (entry->next != NULL) { 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->next->prev = entry; 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // we just added an entry, increase the size of the hashtable 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt g_hash_table.count++; 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return entry; 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int is_valid_entry(HashEntry* entry) { 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (entry != NULL) { 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0 ; i < HASHTABLE_SIZE ; i++) { 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HashEntry* e1 = g_hash_table.slots[i]; 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (e1 != NULL) { 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (e1 == entry) { 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt e1 = e1->next; 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void remove_entry(HashEntry* entry) { 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HashEntry* prev = entry->prev; 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt HashEntry* next = entry->next; 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (prev != NULL) entry->prev->next = next; 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (next != NULL) entry->next->prev = prev; 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (prev == NULL) { 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // we are the head of the list. set the head to be next 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt g_hash_table.slots[entry->slot] = entry->next; 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // we just removed and entry, decrease the size of the hashtable 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt g_hash_table.count--; 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// ============================================================================= 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// malloc fill functions 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// ============================================================================= 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define CHK_FILL_FREE 0xef 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define CHK_SENTINEL_VALUE 0xeb 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtextern "C" void* fill_calloc(size_t n_elements, size_t elem_size) { 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Malloc(calloc)(n_elements, elem_size); 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtextern "C" void* fill_malloc(size_t bytes) { 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void* buffer = Malloc(malloc)(bytes); 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buffer) { 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt memset(buffer, CHK_SENTINEL_VALUE, bytes); 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return buffer; 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtextern "C" void fill_free(void* mem) { 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t bytes = Malloc(malloc_usable_size)(mem); 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt memset(mem, CHK_FILL_FREE, bytes); 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt Malloc(free)(mem); 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtextern "C" void* fill_realloc(void* mem, size_t bytes) { 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t oldSize = Malloc(malloc_usable_size)(mem); 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void* newMem = Malloc(realloc)(mem, bytes); 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (newMem) { 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // If this is larger than before, fill the extra with our pattern. 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t newSize = Malloc(malloc_usable_size)(newMem); 238c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt if (newSize > oldSize) { 239c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt memset(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(newMem)+oldSize), CHK_FILL_FREE, newSize-oldSize); 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return newMem; 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtextern "C" void* fill_memalign(size_t alignment, size_t bytes) { 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void* buffer = Malloc(memalign)(alignment, bytes); 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (buffer) { 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt memset(buffer, CHK_SENTINEL_VALUE, bytes); 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return buffer; 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtextern "C" size_t fill_malloc_usable_size(const void* mem) { 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Since we didn't allocate extra bytes before or after, we can 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // report the normal usable size here. 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return Malloc(malloc_usable_size)(mem); 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// ============================================================================= 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// malloc leak functions 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt// ============================================================================= 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic uint32_t MEMALIGN_GUARD = 0xA1A41520; 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtextern "C" void* leak_malloc(size_t bytes) { 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // allocate enough space infront of the allocation to store the pointer for 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // the alloc structure. This will making free'ing the structer really fast! 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // 1. allocate enough memory and include our header 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // 2. set the base pointer to be right after our header 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t size = bytes + sizeof(AllocationEntry); 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (size < bytes) { // Overflow. 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void* base = Malloc(malloc)(size); 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (base != NULL) { 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ScopedPthreadMutexLocker locker(&g_allocations_mutex); 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt uintptr_t backtrace[BACKTRACE_SIZE]; 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t numEntries = get_backtrace(backtrace, BACKTRACE_SIZE); 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt AllocationEntry* header = reinterpret_cast<AllocationEntry*>(base); 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt header->entry = record_backtrace(backtrace, numEntries, bytes); 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt header->guard = GUARD; 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 288c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt // now increment base to point to after our header. 289c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt // this should just work since our header is 8 bytes. 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt base = reinterpret_cast<AllocationEntry*>(base) + 1; 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return base; 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtextern "C" void leak_free(void* mem) { 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (mem != NULL) { 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ScopedPthreadMutexLocker locker(&g_allocations_mutex); 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // check the guard to make sure it is valid 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt AllocationEntry* header = to_header(mem); 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 303d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt if (header->guard != GUARD) { 304d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt // could be a memaligned block 305d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt if (header->guard == MEMALIGN_GUARD) { 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // For memaligned blocks, header->entry points to the memory 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // allocated through leak_malloc. 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt header = to_header(header->entry); 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 310d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt } 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 312d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt if (header->guard == GUARD || is_valid_entry(header->entry)) { 313c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt // decrement the allocations 314c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt HashEntry* entry = header->entry; 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt entry->allocations--; 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (entry->allocations <= 0) { 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt remove_entry(entry); 318d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt Malloc(free)(entry); 319d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt } 320d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // now free the memory! 322d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt Malloc(free)(header); 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else { 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt debug_log("WARNING bad header guard: '0x%x'! and invalid entry: %p\n", 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt header->guard, header->entry); 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtextern "C" void* leak_calloc(size_t n_elements, size_t elem_size) { 331d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt /* Fail on overflow - just to be safe even though this code runs only 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * within the debugging C library, not the production one */ 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (n_elements && MAX_SIZE_T / n_elements < elem_size) { 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 335d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt } 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t size = n_elements * elem_size; 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void* ptr = leak_malloc(size); 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ptr != NULL) { 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt memset(ptr, 0, size); 340d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt } 341d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt return ptr; 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 343d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt 344d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidtextern "C" void* leak_realloc(void* oldMem, size_t bytes) { 345b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt if (oldMem == NULL) { 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return leak_malloc(bytes); 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void* newMem = NULL; 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt AllocationEntry* header = to_header(oldMem); 351d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt if (header->guard == MEMALIGN_GUARD) { 352d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt // Get the real header. 353d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt header = to_header(header->entry); 354d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt } else if (header->guard != GUARD) { 355d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt debug_log("WARNING bad header guard: '0x%x'! and invalid entry: %p\n", 356d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt header->guard, header->entry); 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt newMem = leak_malloc(bytes); 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (newMem != NULL) { 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t oldSize = header->entry->size & ~SIZE_FLAG_MASK; 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t copySize = (oldSize <= bytes) ? oldSize : bytes; 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt memcpy(newMem, oldMem, copySize); 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt leak_free(oldMem); 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return newMem; 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtextern "C" void* leak_memalign(size_t alignment, size_t bytes) { 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // we can just use malloc 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (alignment <= MALLOC_ALIGNMENT) { 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return leak_malloc(bytes); 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // need to make sure it's a power of two 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (alignment & (alignment-1)) { 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt alignment = 1L << (31 - __builtin_clz(alignment)); 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // here, alignment is at least MALLOC_ALIGNMENT<<1 bytes 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // we will align by at least MALLOC_ALIGNMENT bytes 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // and at most alignment-MALLOC_ALIGNMENT bytes 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t size = (alignment-MALLOC_ALIGNMENT) + bytes; 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (size < bytes) { // Overflow. 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt void* base = leak_malloc(size); 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (base != NULL) { 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt uintptr_t ptr = reinterpret_cast<uintptr_t>(base); 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if ((ptr % alignment) == 0) { 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return base; 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // align the pointer 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ptr += ((-ptr) % alignment); 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Already allocated enough space for the header. This assumes 4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // that the malloc alignment is at least 8, otherwise, this is 4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // not guaranteed to have the space for the header. 4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt AllocationEntry* header = to_header(reinterpret_cast<void*>(ptr)); 4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt header->guard = MEMALIGN_GUARD; 4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt header->entry = reinterpret_cast<HashEntry*>(base); 4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return reinterpret_cast<void*>(ptr); 4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return base; 4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtextern "C" size_t leak_malloc_usable_size(const void* mem) { 4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (mem != NULL) { 4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // Check the guard to make sure it is valid. 4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const AllocationEntry* header = const_to_header((void*)mem); 4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (header->guard == MEMALIGN_GUARD) { 4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // If this is a memalign'd pointer, then grab the header from 4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // entry. 4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt header = const_to_header(header->entry); 4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else if (header->guard != GUARD) { 4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt debug_log("WARNING bad header guard: '0x%x'! and invalid entry: %p\n", 4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt header->guard, header->entry); 4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t ret = Malloc(malloc_usable_size)(header); 4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret != 0) { 4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt // The usable area starts at 'mem' and stops at 'header+ret'. 4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return reinterpret_cast<uintptr_t>(header) + ret - reinterpret_cast<uintptr_t>(mem); 4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt