11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * All rights reserved.
41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Redistribution and use in source and binary forms, with or without
61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * modification, are permitted provided that the following conditions
71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * are met:
81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *  * Redistributions of source code must retain the above copyright
91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *  * Redistributions in binary form must reproduce the above copyright
111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer in
121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    the documentation and/or other materials provided with the
131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    distribution.
141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * SUCH DAMAGE.
271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
287f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang
297f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang#include <dlfcn.h>
301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <errno.h>
317f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang#include <fcntl.h>
321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <pthread.h>
337f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang#include <stdarg.h>
347f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang#include <stddef.h>
357f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang#include <stdint.h>
361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdio.h>
371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdlib.h>
381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <string.h>
391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <unistd.h>
401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <unwind.h>
411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
427f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang#include <arpa/inet.h>
431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/select.h>
447f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang#include <sys/socket.h>
451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/system_properties.h>
467f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang#include <sys/types.h>
477f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang#include <sys/un.h>
481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "dlmalloc.h"
501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "logd.h"
51b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkine#include "malloc_debug_common.h"
521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
53b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkine// This file should be included into the build only when
54b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkine// MALLOC_LEAK_CHECK, or MALLOC_QEMU_INSTRUMENT, or both
55b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkine// macros are defined.
56b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkine#ifndef MALLOC_LEAK_CHECK
57b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkine#error MALLOC_LEAK_CHECK is not defined.
58b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkine#endif  // !MALLOC_LEAK_CHECK
591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
60b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkine// Global variables defined in malloc_debug_common.c
61b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkineextern int gMallocLeakZygoteChild;
62b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkineextern pthread_mutex_t gAllocationsMutex;
63b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkineextern HashTable gHashTable;
641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project// =============================================================================
66e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev// stack trace functions
6739f3745cf30efe38482ffead1c32f4e62f6fe32eAndy McFadden// =============================================================================
6839f3745cf30efe38482ffead1c32f4e62f6fe32eAndy McFadden
699862f5e08bcbf51c80542fb148fc505df140cb95Jin Wei#ifndef MALLOC_ALIGNMENT
709862f5e08bcbf51c80542fb148fc505df140cb95Jin Wei#define MALLOC_ALIGNMENT    ((size_t)8U)
719862f5e08bcbf51c80542fb148fc505df140cb95Jin Wei#endif
721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define GUARD               0x48151642
731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define DEBUG               0
741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project// =============================================================================
761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project// Structures
771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project// =============================================================================
78c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes
791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstruct AllocationEntry {
801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    HashEntry* entry;
811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    uint32_t guard;
821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project};
831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
84c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesstatic AllocationEntry* to_header(void* mem) {
85c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes  return reinterpret_cast<AllocationEntry*>(mem) - 1;
86c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes}
871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project// =============================================================================
891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project// Hash Table functions
901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project// =============================================================================
91c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes
92c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesstatic uint32_t get_hash(intptr_t* backtrace, size_t numEntries) {
931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (backtrace == NULL) return 0;
941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    int hash = 0;
961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    size_t i;
971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    for (i = 0 ; i < numEntries ; i++) {
981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        hash = (hash * 33) + (backtrace[i] >> 2);
991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return hash;
1021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic HashEntry* find_entry(HashTable* table, int slot,
105c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        intptr_t* backtrace, size_t numEntries, size_t size) {
1061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    HashEntry* entry = table->slots[slot];
1071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    while (entry != NULL) {
1081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        //debug_log("backtrace: %p, entry: %p entry->backtrace: %p\n",
1091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        //        backtrace, entry, (entry != NULL) ? entry->backtrace : NULL);
1101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        /*
1111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * See if the entry matches exactly.  We compare the "size" field,
1121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         * including the flag bits.
1131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project         */
1141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (entry->size == size && entry->numEntries == numEntries &&
1151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                !memcmp(backtrace, entry->backtrace, numEntries * sizeof(intptr_t))) {
1161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return entry;
1171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
1181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        entry = entry->next;
1201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
1211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return NULL;
1231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
125c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesstatic HashEntry* record_backtrace(intptr_t* backtrace, size_t numEntries, size_t size) {
1261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    size_t hash = get_hash(backtrace, numEntries);
1271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    size_t slot = hash % HASHTABLE_SIZE;
1281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (size & SIZE_FLAG_MASK) {
1301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        debug_log("malloc_debug: allocation %zx exceeds bit width\n", size);
1311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        abort();
1321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
1331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
134c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes    if (gMallocLeakZygoteChild) {
1351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        size |= SIZE_FLAG_ZYGOTE_CHILD;
136c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes    }
1371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    HashEntry* entry = find_entry(&gHashTable, slot, backtrace, numEntries, size);
1391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (entry != NULL) {
1411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        entry->allocations++;
1421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else {
1431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        // create a new entry
144c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        entry = static_cast<HashEntry*>(dlmalloc(sizeof(HashEntry) + numEntries*sizeof(intptr_t)));
145c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        if (!entry) {
1465751c54bf1c84ad9b1e23a6909c59431c973deaeAndré Goddard Rosa            return NULL;
147c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        }
1481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        entry->allocations = 1;
1491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        entry->slot = slot;
1501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        entry->prev = NULL;
1511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        entry->next = gHashTable.slots[slot];
1521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        entry->numEntries = numEntries;
1531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        entry->size = size;
1541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        memcpy(entry->backtrace, backtrace, numEntries * sizeof(intptr_t));
1561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        gHashTable.slots[slot] = entry;
1581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (entry->next != NULL) {
1601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            entry->next->prev = entry;
1611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
1621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        // we just added an entry, increase the size of the hashtable
1641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        gHashTable.count++;
1651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
1661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return entry;
1681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
170c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesstatic int is_valid_entry(HashEntry* entry) {
1711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (entry != NULL) {
1721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        int i;
1731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        for (i = 0 ; i < HASHTABLE_SIZE ; i++) {
1741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            HashEntry* e1 = gHashTable.slots[i];
1751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            while (e1 != NULL) {
1771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                if (e1 == entry) {
1781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    return 1;
1791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                }
1801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                e1 = e1->next;
1821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
1831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
1841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
1851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return 0;
1871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
189c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesstatic void remove_entry(HashEntry* entry) {
1901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    HashEntry* prev = entry->prev;
1911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    HashEntry* next = entry->next;
1921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (prev != NULL) entry->prev->next = next;
1941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (next != NULL) entry->next->prev = prev;
1951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (prev == NULL) {
1971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        // we are the head of the list. set the head to be next
1981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        gHashTable.slots[entry->slot] = entry->next;
1991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // we just removed and entry, decrease the size of the hashtable
2021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    gHashTable.count--;
2031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project// =============================================================================
206e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev// malloc fill functions
2071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project// =============================================================================
2081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define CHK_FILL_FREE           0xef
210c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes#define CHK_SENTINEL_VALUE      0xeb
211c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes
212c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesextern "C" void* fill_calloc(size_t n_elements, size_t elem_size) {
213c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes    return dlcalloc(n_elements, elem_size);
214c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes}
2151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
216c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesextern "C" void* fill_malloc(size_t bytes) {
2171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    void* buffer = dlmalloc(bytes);
2181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (buffer) {
2191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        memset(buffer, CHK_SENTINEL_VALUE, bytes);
2201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return buffer;
2221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
224c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesextern "C" void fill_free(void* mem) {
2251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    size_t bytes = dlmalloc_usable_size(mem);
2261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    memset(mem, CHK_FILL_FREE, bytes);
2271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    dlfree(mem);
2281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
230c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesextern "C" void* fill_realloc(void* mem, size_t bytes) {
2311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    void* buffer = fill_malloc(bytes);
2321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (mem == NULL) {
2331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return buffer;
2341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (buffer) {
2361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        size_t old_size = dlmalloc_usable_size(mem);
2371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        size_t size = (bytes < old_size)?(bytes):(old_size);
2381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        memcpy(buffer, mem, size);
2391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        fill_free(mem);
2401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return buffer;
2421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
244c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesextern "C" void* fill_memalign(size_t alignment, size_t bytes) {
2451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    void* buffer = dlmemalign(alignment, bytes);
2461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (buffer) {
2471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        memset(buffer, CHK_SENTINEL_VALUE, bytes);
2481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return buffer;
2501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project// =============================================================================
2531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project// malloc leak functions
2541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project// =============================================================================
2551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
256c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesstatic void* MEMALIGN_GUARD = reinterpret_cast<void*>(0xA1A41520);
2571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
258c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesextern __LIBC_HIDDEN__ int get_backtrace(intptr_t* addrs, size_t max_entries);
259e1dd3c287ba836281de0197670018bd9bbfbd62bIliyan Malchev
260c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesextern "C" void* leak_malloc(size_t bytes) {
2611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // allocate enough space infront of the allocation to store the pointer for
2621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // the alloc structure. This will making free'ing the structer really fast!
2631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // 1. allocate enough memory and include our header
2651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // 2. set the base pointer to be right after our header
2661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2677f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang    size_t size = bytes + sizeof(AllocationEntry);
2687f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang    if (size < bytes) { // Overflow.
2697f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang        return NULL;
2707f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang    }
2717f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang
2727f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang    void* base = dlmalloc(size);
2731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (base != NULL) {
274c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        ScopedPthreadMutexLocker locker(&gAllocationsMutex);
2751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
276c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        intptr_t backtrace[BACKTRACE_SIZE];
277c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        size_t numEntries = get_backtrace(backtrace, BACKTRACE_SIZE);
278b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkine
279c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        AllocationEntry* header = reinterpret_cast<AllocationEntry*>(base);
280c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        header->entry = record_backtrace(backtrace, numEntries, bytes);
281c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        header->guard = GUARD;
282b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkine
283c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        // now increment base to point to after our header.
284c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        // this should just work since our header is 8 bytes.
285c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        base = reinterpret_cast<AllocationEntry*>(base) + 1;
2861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
2871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return base;
2891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
291c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesextern "C" void leak_free(void* mem) {
2921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (mem != NULL) {
293c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        ScopedPthreadMutexLocker locker(&gAllocationsMutex);
2941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        // check the guard to make sure it is valid
296c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        AllocationEntry* header = to_header(mem);
297b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkine
2981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (header->guard != GUARD) {
2991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            // could be a memaligned block
300c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes            if (reinterpret_cast<void**>(mem)[-1] == MEMALIGN_GUARD) {
301c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes                mem = reinterpret_cast<void**>(mem)[-2];
302c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes                header = to_header(mem);
3031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
3041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
305b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkine
3061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (header->guard == GUARD || is_valid_entry(header->entry)) {
3071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            // decrement the allocations
3081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            HashEntry* entry = header->entry;
3091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            entry->allocations--;
3101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            if (entry->allocations <= 0) {
3111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                remove_entry(entry);
3121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                dlfree(entry);
3131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            }
3141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            // now free the memory!
3161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            dlfree(header);
3171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        } else {
3181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            debug_log("WARNING bad header guard: '0x%x'! and invalid entry: %p\n",
3191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                    header->guard, header->entry);
3201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
3211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
324c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesextern "C" void* leak_calloc(size_t n_elements, size_t elem_size) {
3251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* Fail on overflow - just to be safe even though this code runs only
3261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project     * within the debugging C library, not the production one */
3271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (n_elements && MAX_SIZE_T / n_elements < elem_size) {
3281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return NULL;
3291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
330c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes    size_t size = n_elements * elem_size;
331c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes    void* ptr  = leak_malloc(size);
3321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (ptr != NULL) {
3331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        memset(ptr, 0, size);
3341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return ptr;
3361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
338c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesextern "C" void* leak_realloc(void* oldMem, size_t bytes) {
3391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (oldMem == NULL) {
3401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return leak_malloc(bytes);
3411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    void* newMem = NULL;
343c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes    AllocationEntry* header = to_header(oldMem);
3441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (header && header->guard == GUARD) {
3451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        size_t oldSize = header->entry->size & ~SIZE_FLAG_MASK;
3461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        newMem = leak_malloc(bytes);
3471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        if (newMem != NULL) {
3481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            size_t copySize = (oldSize <= bytes) ? oldSize : bytes;
3491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            memcpy(newMem, oldMem, copySize);
3501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            leak_free(oldMem);
3511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        }
3521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } else {
3531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        newMem = dlrealloc(oldMem, bytes);
3541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return newMem;
3561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
358c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughesextern "C" void* leak_memalign(size_t alignment, size_t bytes) {
3591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // we can just use malloc
360c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes    if (alignment <= MALLOC_ALIGNMENT) {
3611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        return leak_malloc(bytes);
362c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes    }
3631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // need to make sure it's a power of two
365c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes    if (alignment & (alignment-1)) {
3661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        alignment = 1L << (31 - __builtin_clz(alignment));
367c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes    }
368b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkine
3691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // here, aligment is at least MALLOC_ALIGNMENT<<1 bytes
3701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // we will align by at least MALLOC_ALIGNMENT bytes
3711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // and at most alignment-MALLOC_ALIGNMENT bytes
3721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    size_t size = (alignment-MALLOC_ALIGNMENT) + bytes;
3737f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang    if (size < bytes) { // Overflow.
3747f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang        return NULL;
3757f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang    }
3767f5aa4f35e23fd37425b3a5041737cdf58f87385Xi Wang
3771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    void* base = leak_malloc(size);
3781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    if (base != NULL) {
379c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        intptr_t ptr = reinterpret_cast<intptr_t>(base);
380c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        if ((ptr % alignment) == 0) {
3811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project            return base;
382c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        }
3831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        // align the pointer
3851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        ptr += ((-ptr) % alignment);
386b74ceb25aae555570df64fa4d4076272733a9a20Vladimir Chtchetkine
3871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        // there is always enough space for the base pointer and the guard
388c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        reinterpret_cast<void**>(ptr)[-1] = MEMALIGN_GUARD;
389c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        reinterpret_cast<void**>(ptr)[-2] = base;
3901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
391c4d1fecc105063e68a5090a6900b63d1b9a24287Elliott Hughes        return reinterpret_cast<void*>(ptr);
3921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    }
3931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    return base;
3941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
395