2009-03-04 04:28:35 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2008 The Android Open Source Project
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* * Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
|
|
|
* distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
2012-03-14 07:48:39 +01:00
|
|
|
|
2012-10-12 01:08:51 +02:00
|
|
|
#include <arpa/inet.h>
|
2012-03-14 07:48:39 +01:00
|
|
|
#include <dlfcn.h>
|
2009-03-04 04:28:35 +01:00
|
|
|
#include <errno.h>
|
2012-03-14 07:48:39 +01:00
|
|
|
#include <fcntl.h>
|
2009-03-04 04:28:35 +01:00
|
|
|
#include <pthread.h>
|
2012-03-14 07:48:39 +01:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdint.h>
|
2009-03-04 04:28:35 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2014-06-13 22:57:51 +02:00
|
|
|
#include <sys/param.h>
|
2009-03-04 04:28:35 +01:00
|
|
|
#include <sys/select.h>
|
2012-03-14 07:48:39 +01:00
|
|
|
#include <sys/socket.h>
|
2009-03-04 04:28:35 +01:00
|
|
|
#include <sys/system_properties.h>
|
2012-03-14 07:48:39 +01:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/un.h>
|
2012-10-12 01:08:51 +02:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <unwind.h>
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2013-01-18 03:36:06 +01:00
|
|
|
#include "debug_stacktrace.h"
|
2014-08-08 01:21:21 +02:00
|
|
|
#include "malloc_debug_backtrace.h"
|
2009-11-17 23:13:38 +01:00
|
|
|
#include "malloc_debug_common.h"
|
2014-07-25 02:52:23 +02:00
|
|
|
#include "malloc_debug_disable.h"
|
2013-10-10 00:50:50 +02:00
|
|
|
|
2014-06-13 22:57:51 +02:00
|
|
|
#include "private/bionic_macros.h"
|
2013-10-10 00:50:50 +02:00
|
|
|
#include "private/libc_logging.h"
|
|
|
|
#include "private/ScopedPthreadMutexLocker.h"
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2009-11-17 23:13:38 +01:00
|
|
|
// This file should be included into the build only when
|
|
|
|
// MALLOC_LEAK_CHECK, or MALLOC_QEMU_INSTRUMENT, or both
|
|
|
|
// macros are defined.
|
|
|
|
#ifndef MALLOC_LEAK_CHECK
|
|
|
|
#error MALLOC_LEAK_CHECK is not defined.
|
|
|
|
#endif // !MALLOC_LEAK_CHECK
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2009-11-17 23:13:38 +01:00
|
|
|
extern int gMallocLeakZygoteChild;
|
2014-06-04 21:07:11 +02:00
|
|
|
extern HashTable* g_hash_table;
|
2014-07-10 02:16:07 +02:00
|
|
|
extern const MallocDebug* g_malloc_dispatch;
|
2009-03-04 04:28:35 +01:00
|
|
|
|
|
|
|
// =============================================================================
|
bionic: import heaptracker as chk_malloc
This patch is a rewrite of libc.debug.malloc = 10 (chk_malloc). It provides
the same features as the original (poison freed memory, detect heap overruns
and underruns), except that it provides more debugging information whenever it
detects a problem.
In addition to the original features, the new chk_malloc() implementation
detects multiple frees within a given range of the last N allocations, N being
configurable via the system property libc.debug.malloc.backlog.
Finally, this patch keeps track of all outstanding memory allocations. On
program exit, we walk that list and report each outstanding allocation.
(There is support (not enabled) for a scanner thread periodically walks over
the list of outstanding allocations as well as the backlog of recently-freed
allocations, checking for heap-usage errors.)
Feature overview:
1) memory leaks
2) multiple frees
3) use after free
4) overrun
Implementation:
-- for each allocation, there is a:
1) stack trace at the time the allocation is made
2) if the memory is freed, there is also a stack trace at the point
3) a front and rear guard (fence)
4) the stack traces are kept together with the allocation
-- the following lists and maintained
1) all outstanding memory allocations
3) a backlog of allocations what are freed; when you call free(), instead of
actually freed, the allocation is moved to this backlog;
4) when the backlog of allocations gets full, the oldest entry gets evicted
from it; at that point, the allocation is checked for overruns or
use-after-free errors, and then actually freed.
5) when the program exits, the list of outstanding allocations and the
backlog are inspected for errors, then freed;
To use this, set the following system properties before running the process or
processes you want to inspect:
libc.malloc.debug.backlog # defaults to 100
libc.malloc.debug 10
When a problem is detected, you will see the following on logcat for a multiple
free:
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 BYTES MULTIPLY FREED!
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 4009647c /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 FIRST FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096490 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 NOW BEING FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c6ac /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964a0 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
The following for a heap overrun and underrun:
E/libc ( 7233): +++ REAR GUARD MISMATCH [10, 11)
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 HAS A CORRUPTED REAR GUARD
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096438 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096462 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 HAS A CORRUPTED FRONT GUARD
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964ba /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964e4 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
The following for a memory leak:
E/libc ( 7233): +++ THERE ARE 1 LEAKED ALLOCATIONS
E/libc ( 7233): +++ DELETING 4096 BYTES OF LEAKED MEMORY AT 0x404b95e8 (1 REMAINING)
E/libc ( 7233): +++ ALLOCATION 0x404b95e8 SIZE 4096 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 0001bc94 /system/lib/libc.so
E/libc ( 7233): #04 pc 0001edf6 /system/lib/libc.so
E/libc ( 7233): #05 pc 0001b80a /system/lib/libc.so
E/libc ( 7233): #06 pc 0001c086 /system/lib/libc.so
E/libc ( 7233): #07 pc 40096402 /system/bin/malloctest
E/libc ( 7233): #08 pc 00016f24 /system/lib/libc.so
Change-Id: Ic440e9d05a01e2ea86b25e8998714e88bc2d16e0
Signed-off-by: Iliyan Malchev <malchev@google.com>
2012-05-29 23:22:42 +02:00
|
|
|
// stack trace functions
|
2009-07-22 00:25:23 +02:00
|
|
|
// =============================================================================
|
|
|
|
|
2009-03-04 04:28:35 +01:00
|
|
|
#define GUARD 0x48151642
|
|
|
|
#define DEBUG 0
|
|
|
|
|
|
|
|
// =============================================================================
|
|
|
|
// Structures
|
|
|
|
// =============================================================================
|
2012-08-28 23:15:04 +02:00
|
|
|
|
2009-03-04 04:28:35 +01:00
|
|
|
struct AllocationEntry {
|
|
|
|
HashEntry* entry;
|
|
|
|
uint32_t guard;
|
2013-05-22 02:48:01 +02:00
|
|
|
} __attribute__((aligned(MALLOC_ALIGNMENT)));
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2013-05-22 02:48:01 +02:00
|
|
|
static inline AllocationEntry* to_header(void* mem) {
|
2012-08-28 23:15:04 +02:00
|
|
|
return reinterpret_cast<AllocationEntry*>(mem) - 1;
|
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2013-05-22 02:48:01 +02:00
|
|
|
static inline const AllocationEntry* const_to_header(const void* mem) {
|
|
|
|
return reinterpret_cast<const AllocationEntry*>(mem) - 1;
|
|
|
|
}
|
|
|
|
|
2009-03-04 04:28:35 +01:00
|
|
|
// =============================================================================
|
|
|
|
// Hash Table functions
|
|
|
|
// =============================================================================
|
2012-08-28 23:15:04 +02:00
|
|
|
|
2013-01-26 02:13:45 +01:00
|
|
|
static uint32_t get_hash(uintptr_t* backtrace, size_t numEntries) {
|
2009-03-04 04:28:35 +01:00
|
|
|
if (backtrace == NULL) return 0;
|
|
|
|
|
|
|
|
int hash = 0;
|
|
|
|
size_t i;
|
|
|
|
for (i = 0 ; i < numEntries ; i++) {
|
|
|
|
hash = (hash * 33) + (backtrace[i] >> 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
return hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HashEntry* find_entry(HashTable* table, int slot,
|
2013-01-26 02:13:45 +01:00
|
|
|
uintptr_t* backtrace, size_t numEntries, size_t size) {
|
2009-03-04 04:28:35 +01:00
|
|
|
HashEntry* entry = table->slots[slot];
|
|
|
|
while (entry != NULL) {
|
|
|
|
//debug_log("backtrace: %p, entry: %p entry->backtrace: %p\n",
|
|
|
|
// backtrace, entry, (entry != NULL) ? entry->backtrace : NULL);
|
|
|
|
/*
|
|
|
|
* See if the entry matches exactly. We compare the "size" field,
|
|
|
|
* including the flag bits.
|
|
|
|
*/
|
|
|
|
if (entry->size == size && entry->numEntries == numEntries &&
|
2013-01-26 02:13:45 +01:00
|
|
|
!memcmp(backtrace, entry->backtrace, numEntries * sizeof(uintptr_t))) {
|
2009-03-04 04:28:35 +01:00
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry = entry->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-01-26 02:13:45 +01:00
|
|
|
static HashEntry* record_backtrace(uintptr_t* backtrace, size_t numEntries, size_t size) {
|
2009-03-04 04:28:35 +01:00
|
|
|
size_t hash = get_hash(backtrace, numEntries);
|
|
|
|
size_t slot = hash % HASHTABLE_SIZE;
|
|
|
|
|
|
|
|
if (size & SIZE_FLAG_MASK) {
|
|
|
|
debug_log("malloc_debug: allocation %zx exceeds bit width\n", size);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
if (gMallocLeakZygoteChild) {
|
2009-03-04 04:28:35 +01:00
|
|
|
size |= SIZE_FLAG_ZYGOTE_CHILD;
|
2012-08-28 23:15:04 +02:00
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2014-06-04 21:07:11 +02:00
|
|
|
HashEntry* entry = find_entry(g_hash_table, slot, backtrace, numEntries, size);
|
2009-03-04 04:28:35 +01:00
|
|
|
|
|
|
|
if (entry != NULL) {
|
|
|
|
entry->allocations++;
|
|
|
|
} else {
|
|
|
|
// create a new entry
|
2014-07-10 02:16:07 +02:00
|
|
|
entry = static_cast<HashEntry*>(g_malloc_dispatch->malloc(sizeof(HashEntry) + numEntries*sizeof(uintptr_t)));
|
2012-08-28 23:15:04 +02:00
|
|
|
if (!entry) {
|
2010-02-05 19:03:09 +01:00
|
|
|
return NULL;
|
2012-08-28 23:15:04 +02:00
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
entry->allocations = 1;
|
|
|
|
entry->slot = slot;
|
|
|
|
entry->prev = NULL;
|
2014-06-04 21:07:11 +02:00
|
|
|
entry->next = g_hash_table->slots[slot];
|
2009-03-04 04:28:35 +01:00
|
|
|
entry->numEntries = numEntries;
|
|
|
|
entry->size = size;
|
|
|
|
|
2013-01-26 02:13:45 +01:00
|
|
|
memcpy(entry->backtrace, backtrace, numEntries * sizeof(uintptr_t));
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2014-06-04 21:07:11 +02:00
|
|
|
g_hash_table->slots[slot] = entry;
|
2009-03-04 04:28:35 +01:00
|
|
|
|
|
|
|
if (entry->next != NULL) {
|
|
|
|
entry->next->prev = entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
// we just added an entry, increase the size of the hashtable
|
2014-06-04 21:07:11 +02:00
|
|
|
g_hash_table->count++;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
static int is_valid_entry(HashEntry* entry) {
|
2014-06-04 21:07:11 +02:00
|
|
|
if (entry != NULL) {
|
|
|
|
for (size_t i = 0; i < HASHTABLE_SIZE; ++i) {
|
|
|
|
HashEntry* e1 = g_hash_table->slots[i];
|
|
|
|
while (e1 != NULL) {
|
|
|
|
if (e1 == entry) {
|
|
|
|
return 1;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
2014-06-04 21:07:11 +02:00
|
|
|
e1 = e1->next;
|
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
2014-06-04 21:07:11 +02:00
|
|
|
}
|
|
|
|
return 0;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
static void remove_entry(HashEntry* entry) {
|
2014-06-04 21:07:11 +02:00
|
|
|
HashEntry* prev = entry->prev;
|
|
|
|
HashEntry* next = entry->next;
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2014-06-04 21:07:11 +02:00
|
|
|
if (prev != NULL) entry->prev->next = next;
|
|
|
|
if (next != NULL) entry->next->prev = prev;
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2014-06-04 21:07:11 +02:00
|
|
|
if (prev == NULL) {
|
|
|
|
// we are the head of the list. set the head to be next
|
|
|
|
g_hash_table->slots[entry->slot] = entry->next;
|
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2014-06-04 21:07:11 +02:00
|
|
|
// we just removed and entry, decrease the size of the hashtable
|
|
|
|
g_hash_table->count--;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// =============================================================================
|
bionic: import heaptracker as chk_malloc
This patch is a rewrite of libc.debug.malloc = 10 (chk_malloc). It provides
the same features as the original (poison freed memory, detect heap overruns
and underruns), except that it provides more debugging information whenever it
detects a problem.
In addition to the original features, the new chk_malloc() implementation
detects multiple frees within a given range of the last N allocations, N being
configurable via the system property libc.debug.malloc.backlog.
Finally, this patch keeps track of all outstanding memory allocations. On
program exit, we walk that list and report each outstanding allocation.
(There is support (not enabled) for a scanner thread periodically walks over
the list of outstanding allocations as well as the backlog of recently-freed
allocations, checking for heap-usage errors.)
Feature overview:
1) memory leaks
2) multiple frees
3) use after free
4) overrun
Implementation:
-- for each allocation, there is a:
1) stack trace at the time the allocation is made
2) if the memory is freed, there is also a stack trace at the point
3) a front and rear guard (fence)
4) the stack traces are kept together with the allocation
-- the following lists and maintained
1) all outstanding memory allocations
3) a backlog of allocations what are freed; when you call free(), instead of
actually freed, the allocation is moved to this backlog;
4) when the backlog of allocations gets full, the oldest entry gets evicted
from it; at that point, the allocation is checked for overruns or
use-after-free errors, and then actually freed.
5) when the program exits, the list of outstanding allocations and the
backlog are inspected for errors, then freed;
To use this, set the following system properties before running the process or
processes you want to inspect:
libc.malloc.debug.backlog # defaults to 100
libc.malloc.debug 10
When a problem is detected, you will see the following on logcat for a multiple
free:
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 BYTES MULTIPLY FREED!
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 4009647c /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 FIRST FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096490 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 NOW BEING FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c6ac /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964a0 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
The following for a heap overrun and underrun:
E/libc ( 7233): +++ REAR GUARD MISMATCH [10, 11)
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 HAS A CORRUPTED REAR GUARD
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096438 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096462 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 HAS A CORRUPTED FRONT GUARD
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964ba /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964e4 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
The following for a memory leak:
E/libc ( 7233): +++ THERE ARE 1 LEAKED ALLOCATIONS
E/libc ( 7233): +++ DELETING 4096 BYTES OF LEAKED MEMORY AT 0x404b95e8 (1 REMAINING)
E/libc ( 7233): +++ ALLOCATION 0x404b95e8 SIZE 4096 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 0001bc94 /system/lib/libc.so
E/libc ( 7233): #04 pc 0001edf6 /system/lib/libc.so
E/libc ( 7233): #05 pc 0001b80a /system/lib/libc.so
E/libc ( 7233): #06 pc 0001c086 /system/lib/libc.so
E/libc ( 7233): #07 pc 40096402 /system/bin/malloctest
E/libc ( 7233): #08 pc 00016f24 /system/lib/libc.so
Change-Id: Ic440e9d05a01e2ea86b25e8998714e88bc2d16e0
Signed-off-by: Iliyan Malchev <malchev@google.com>
2012-05-29 23:22:42 +02:00
|
|
|
// malloc fill functions
|
2009-03-04 04:28:35 +01:00
|
|
|
// =============================================================================
|
|
|
|
|
|
|
|
#define CHK_FILL_FREE 0xef
|
2012-08-28 23:15:04 +02:00
|
|
|
#define CHK_SENTINEL_VALUE 0xeb
|
|
|
|
|
|
|
|
extern "C" void* fill_calloc(size_t n_elements, size_t elem_size) {
|
2014-07-10 02:16:07 +02:00
|
|
|
return g_malloc_dispatch->calloc(n_elements, elem_size);
|
2012-08-28 23:15:04 +02:00
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
extern "C" void* fill_malloc(size_t bytes) {
|
2014-07-10 02:16:07 +02:00
|
|
|
void* buffer = g_malloc_dispatch->malloc(bytes);
|
2009-03-04 04:28:35 +01:00
|
|
|
if (buffer) {
|
|
|
|
memset(buffer, CHK_SENTINEL_VALUE, bytes);
|
|
|
|
}
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
extern "C" void fill_free(void* mem) {
|
2014-07-10 02:16:07 +02:00
|
|
|
size_t bytes = g_malloc_dispatch->malloc_usable_size(mem);
|
2009-03-04 04:28:35 +01:00
|
|
|
memset(mem, CHK_FILL_FREE, bytes);
|
2014-07-10 02:16:07 +02:00
|
|
|
g_malloc_dispatch->free(mem);
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
extern "C" void* fill_realloc(void* mem, size_t bytes) {
|
2014-07-10 02:16:07 +02:00
|
|
|
size_t oldSize = g_malloc_dispatch->malloc_usable_size(mem);
|
|
|
|
void* newMem = g_malloc_dispatch->realloc(mem, bytes);
|
2013-05-22 02:48:01 +02:00
|
|
|
if (newMem) {
|
|
|
|
// If this is larger than before, fill the extra with our pattern.
|
2014-07-10 02:16:07 +02:00
|
|
|
size_t newSize = g_malloc_dispatch->malloc_usable_size(newMem);
|
2013-05-22 02:48:01 +02:00
|
|
|
if (newSize > oldSize) {
|
|
|
|
memset(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(newMem)+oldSize), CHK_FILL_FREE, newSize-oldSize);
|
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
2013-05-22 02:48:01 +02:00
|
|
|
return newMem;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
extern "C" void* fill_memalign(size_t alignment, size_t bytes) {
|
2014-07-10 02:16:07 +02:00
|
|
|
void* buffer = g_malloc_dispatch->memalign(alignment, bytes);
|
2009-03-04 04:28:35 +01:00
|
|
|
if (buffer) {
|
|
|
|
memset(buffer, CHK_SENTINEL_VALUE, bytes);
|
|
|
|
}
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
2013-05-22 02:48:01 +02:00
|
|
|
extern "C" size_t fill_malloc_usable_size(const void* mem) {
|
|
|
|
// Since we didn't allocate extra bytes before or after, we can
|
|
|
|
// report the normal usable size here.
|
2014-07-10 02:16:07 +02:00
|
|
|
return g_malloc_dispatch->malloc_usable_size(mem);
|
2013-05-22 02:48:01 +02:00
|
|
|
}
|
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
extern "C" struct mallinfo fill_mallinfo() {
|
2014-07-10 02:16:07 +02:00
|
|
|
return g_malloc_dispatch->mallinfo();
|
2014-06-10 04:14:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" int fill_posix_memalign(void** memptr, size_t alignment, size_t size) {
|
2014-06-13 22:57:51 +02:00
|
|
|
if (!powerof2(alignment)) {
|
2014-06-10 04:14:11 +02:00
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
int saved_errno = errno;
|
|
|
|
*memptr = fill_memalign(alignment, size);
|
|
|
|
errno = saved_errno;
|
|
|
|
return (*memptr != NULL) ? 0 : ENOMEM;
|
|
|
|
}
|
|
|
|
|
2014-07-25 02:52:23 +02:00
|
|
|
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
|
2014-06-10 04:14:11 +02:00
|
|
|
extern "C" void* fill_pvalloc(size_t bytes) {
|
2014-07-10 21:34:23 +02:00
|
|
|
size_t pagesize = getpagesize();
|
2014-06-13 22:57:51 +02:00
|
|
|
size_t size = BIONIC_ALIGN(bytes, pagesize);
|
2014-06-10 04:14:11 +02:00
|
|
|
if (size < bytes) { // Overflow
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return fill_memalign(pagesize, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" void* fill_valloc(size_t size) {
|
2014-07-10 21:34:23 +02:00
|
|
|
return fill_memalign(getpagesize(), size);
|
2014-06-10 04:14:11 +02:00
|
|
|
}
|
2014-07-25 02:52:23 +02:00
|
|
|
#endif
|
2014-06-10 04:14:11 +02:00
|
|
|
|
2009-03-04 04:28:35 +01:00
|
|
|
// =============================================================================
|
|
|
|
// malloc leak functions
|
|
|
|
// =============================================================================
|
|
|
|
|
2013-05-22 02:48:01 +02:00
|
|
|
static uint32_t MEMALIGN_GUARD = 0xA1A41520;
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
extern "C" void* leak_malloc(size_t bytes) {
|
2014-07-25 02:52:23 +02:00
|
|
|
if (DebugCallsDisabled()) {
|
|
|
|
return g_malloc_dispatch->malloc(bytes);
|
|
|
|
}
|
|
|
|
|
2009-03-04 04:28:35 +01:00
|
|
|
// allocate enough space infront of the allocation to store the pointer for
|
|
|
|
// the alloc structure. This will making free'ing the structer really fast!
|
|
|
|
|
|
|
|
// 1. allocate enough memory and include our header
|
|
|
|
// 2. set the base pointer to be right after our header
|
|
|
|
|
2012-03-14 07:48:39 +01:00
|
|
|
size_t size = bytes + sizeof(AllocationEntry);
|
|
|
|
if (size < bytes) { // Overflow.
|
2014-06-10 04:14:11 +02:00
|
|
|
errno = ENOMEM;
|
2012-03-14 07:48:39 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-07-10 02:16:07 +02:00
|
|
|
void* base = g_malloc_dispatch->malloc(size);
|
2009-03-04 04:28:35 +01:00
|
|
|
if (base != NULL) {
|
2014-06-04 21:07:11 +02:00
|
|
|
ScopedPthreadMutexLocker locker(&g_hash_table->lock);
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2013-01-26 02:13:45 +01:00
|
|
|
uintptr_t backtrace[BACKTRACE_SIZE];
|
2014-08-08 01:21:21 +02:00
|
|
|
size_t numEntries = GET_BACKTRACE(backtrace, BACKTRACE_SIZE);
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
AllocationEntry* header = reinterpret_cast<AllocationEntry*>(base);
|
|
|
|
header->entry = record_backtrace(backtrace, numEntries, bytes);
|
|
|
|
header->guard = GUARD;
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
// now increment base to point to after our header.
|
|
|
|
// this should just work since our header is 8 bytes.
|
|
|
|
base = reinterpret_cast<AllocationEntry*>(base) + 1;
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return base;
|
|
|
|
}
|
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
extern "C" void leak_free(void* mem) {
|
2014-07-25 02:52:23 +02:00
|
|
|
if (DebugCallsDisabled()) {
|
|
|
|
return g_malloc_dispatch->free(mem);
|
|
|
|
}
|
|
|
|
|
2014-06-04 21:07:11 +02:00
|
|
|
if (mem == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2014-06-04 21:07:11 +02:00
|
|
|
ScopedPthreadMutexLocker locker(&g_hash_table->lock);
|
|
|
|
|
|
|
|
// check the guard to make sure it is valid
|
|
|
|
AllocationEntry* header = to_header(mem);
|
|
|
|
|
|
|
|
if (header->guard != GUARD) {
|
|
|
|
// could be a memaligned block
|
|
|
|
if (header->guard == MEMALIGN_GUARD) {
|
|
|
|
// For memaligned blocks, header->entry points to the memory
|
|
|
|
// allocated through leak_malloc.
|
|
|
|
header = to_header(header->entry);
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
2014-06-04 21:07:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (header->guard == GUARD || is_valid_entry(header->entry)) {
|
|
|
|
// decrement the allocations
|
|
|
|
HashEntry* entry = header->entry;
|
|
|
|
entry->allocations--;
|
|
|
|
if (entry->allocations <= 0) {
|
|
|
|
remove_entry(entry);
|
2014-07-10 02:16:07 +02:00
|
|
|
g_malloc_dispatch->free(entry);
|
2014-06-04 21:07:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// now free the memory!
|
2014-07-10 02:16:07 +02:00
|
|
|
g_malloc_dispatch->free(header);
|
2014-06-04 21:07:11 +02:00
|
|
|
} else {
|
|
|
|
debug_log("WARNING bad header guard: '0x%x'! and invalid entry: %p\n",
|
|
|
|
header->guard, header->entry);
|
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
extern "C" void* leak_calloc(size_t n_elements, size_t elem_size) {
|
2014-07-25 02:52:23 +02:00
|
|
|
if (DebugCallsDisabled()) {
|
|
|
|
return g_malloc_dispatch->calloc(n_elements, elem_size);
|
|
|
|
}
|
|
|
|
|
2014-06-04 21:07:11 +02:00
|
|
|
// Fail on overflow - just to be safe even though this code runs only
|
|
|
|
// within the debugging C library, not the production one.
|
|
|
|
if (n_elements && SIZE_MAX / n_elements < elem_size) {
|
2014-06-10 04:14:11 +02:00
|
|
|
errno = ENOMEM;
|
2009-03-04 04:28:35 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
2012-08-28 23:15:04 +02:00
|
|
|
size_t size = n_elements * elem_size;
|
|
|
|
void* ptr = leak_malloc(size);
|
2009-03-04 04:28:35 +01:00
|
|
|
if (ptr != NULL) {
|
|
|
|
memset(ptr, 0, size);
|
|
|
|
}
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2014-08-16 03:42:58 +02:00
|
|
|
extern "C" size_t leak_malloc_usable_size(const void* mem) {
|
|
|
|
if (DebugCallsDisabled()) {
|
|
|
|
return g_malloc_dispatch->malloc_usable_size(mem);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mem == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the guard to make sure it is valid.
|
|
|
|
const AllocationEntry* header = const_to_header(mem);
|
|
|
|
|
|
|
|
if (header->guard == MEMALIGN_GUARD) {
|
|
|
|
// If this is a memalign'd pointer, then grab the header from
|
|
|
|
// entry.
|
|
|
|
header = const_to_header(header->entry);
|
|
|
|
} else if (header->guard != GUARD) {
|
|
|
|
debug_log("WARNING bad header guard: '0x%x'! and invalid entry: %p\n",
|
|
|
|
header->guard, header->entry);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t ret = g_malloc_dispatch->malloc_usable_size(header);
|
|
|
|
if (ret != 0) {
|
|
|
|
// The usable area starts at 'mem' and stops at 'header+ret'.
|
|
|
|
return reinterpret_cast<uintptr_t>(header) + ret - reinterpret_cast<uintptr_t>(mem);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
extern "C" void* leak_realloc(void* oldMem, size_t bytes) {
|
2014-07-25 02:52:23 +02:00
|
|
|
if (DebugCallsDisabled()) {
|
|
|
|
return g_malloc_dispatch->realloc(oldMem, bytes);
|
|
|
|
}
|
|
|
|
|
2009-03-04 04:28:35 +01:00
|
|
|
if (oldMem == NULL) {
|
|
|
|
return leak_malloc(bytes);
|
|
|
|
}
|
2013-05-22 02:48:01 +02:00
|
|
|
|
2009-03-04 04:28:35 +01:00
|
|
|
void* newMem = NULL;
|
2012-08-28 23:15:04 +02:00
|
|
|
AllocationEntry* header = to_header(oldMem);
|
2013-05-22 02:48:01 +02:00
|
|
|
if (header->guard == MEMALIGN_GUARD) {
|
|
|
|
// Get the real header.
|
|
|
|
header = to_header(header->entry);
|
|
|
|
} else if (header->guard != GUARD) {
|
|
|
|
debug_log("WARNING bad header guard: '0x%x'! and invalid entry: %p\n",
|
|
|
|
header->guard, header->entry);
|
2014-06-10 04:14:11 +02:00
|
|
|
errno = ENOMEM;
|
2013-05-22 02:48:01 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
newMem = leak_malloc(bytes);
|
|
|
|
if (newMem != NULL) {
|
2014-08-16 03:42:58 +02:00
|
|
|
size_t oldSize = leak_malloc_usable_size(oldMem);
|
2013-05-22 02:48:01 +02:00
|
|
|
size_t copySize = (oldSize <= bytes) ? oldSize : bytes;
|
|
|
|
memcpy(newMem, oldMem, copySize);
|
2014-06-10 04:14:11 +02:00
|
|
|
leak_free(oldMem);
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
2013-05-22 02:48:01 +02:00
|
|
|
|
2009-03-04 04:28:35 +01:00
|
|
|
return newMem;
|
|
|
|
}
|
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
extern "C" void* leak_memalign(size_t alignment, size_t bytes) {
|
2014-07-25 02:52:23 +02:00
|
|
|
if (DebugCallsDisabled()) {
|
|
|
|
return g_malloc_dispatch->memalign(alignment, bytes);
|
|
|
|
}
|
|
|
|
|
2009-03-04 04:28:35 +01:00
|
|
|
// we can just use malloc
|
2012-08-28 23:15:04 +02:00
|
|
|
if (alignment <= MALLOC_ALIGNMENT) {
|
2009-03-04 04:28:35 +01:00
|
|
|
return leak_malloc(bytes);
|
2012-08-28 23:15:04 +02:00
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
|
|
|
|
// need to make sure it's a power of two
|
2014-06-13 22:57:51 +02:00
|
|
|
if (!powerof2(alignment)) {
|
|
|
|
alignment = BIONIC_ROUND_UP_POWER_OF_2(alignment);
|
2012-08-28 23:15:04 +02:00
|
|
|
}
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2012-10-10 02:23:09 +02:00
|
|
|
// here, alignment is at least MALLOC_ALIGNMENT<<1 bytes
|
2009-03-04 04:28:35 +01:00
|
|
|
// we will align by at least MALLOC_ALIGNMENT bytes
|
|
|
|
// and at most alignment-MALLOC_ALIGNMENT bytes
|
|
|
|
size_t size = (alignment-MALLOC_ALIGNMENT) + bytes;
|
2012-03-14 07:48:39 +01:00
|
|
|
if (size < bytes) { // Overflow.
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-03-04 04:28:35 +01:00
|
|
|
void* base = leak_malloc(size);
|
|
|
|
if (base != NULL) {
|
2013-05-22 02:48:01 +02:00
|
|
|
uintptr_t ptr = reinterpret_cast<uintptr_t>(base);
|
2012-08-28 23:15:04 +02:00
|
|
|
if ((ptr % alignment) == 0) {
|
2009-03-04 04:28:35 +01:00
|
|
|
return base;
|
2012-08-28 23:15:04 +02:00
|
|
|
}
|
2009-03-04 04:28:35 +01:00
|
|
|
|
|
|
|
// align the pointer
|
|
|
|
ptr += ((-ptr) % alignment);
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2013-05-22 02:48:01 +02:00
|
|
|
// Already allocated enough space for the header. This assumes
|
|
|
|
// that the malloc alignment is at least 8, otherwise, this is
|
|
|
|
// not guaranteed to have the space for the header.
|
|
|
|
AllocationEntry* header = to_header(reinterpret_cast<void*>(ptr));
|
|
|
|
header->guard = MEMALIGN_GUARD;
|
|
|
|
header->entry = reinterpret_cast<HashEntry*>(base);
|
2009-03-04 04:28:35 +01:00
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
return reinterpret_cast<void*>(ptr);
|
2009-03-04 04:28:35 +01:00
|
|
|
}
|
|
|
|
return base;
|
|
|
|
}
|
2013-05-22 02:48:01 +02:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
extern "C" struct mallinfo leak_mallinfo() {
|
2014-07-10 02:16:07 +02:00
|
|
|
return g_malloc_dispatch->mallinfo();
|
2014-06-10 04:14:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" int leak_posix_memalign(void** memptr, size_t alignment, size_t size) {
|
2014-07-25 02:52:23 +02:00
|
|
|
if (DebugCallsDisabled()) {
|
|
|
|
return g_malloc_dispatch->posix_memalign(memptr, alignment, size);
|
|
|
|
}
|
|
|
|
|
2014-06-13 22:57:51 +02:00
|
|
|
if (!powerof2(alignment)) {
|
2014-06-10 04:14:11 +02:00
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
int saved_errno = errno;
|
|
|
|
*memptr = leak_memalign(alignment, size);
|
|
|
|
errno = saved_errno;
|
|
|
|
return (*memptr != NULL) ? 0 : ENOMEM;
|
|
|
|
}
|
|
|
|
|
2014-07-25 02:52:23 +02:00
|
|
|
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
|
2014-06-10 04:14:11 +02:00
|
|
|
extern "C" void* leak_pvalloc(size_t bytes) {
|
2014-07-25 02:52:23 +02:00
|
|
|
if (DebugCallsDisabled()) {
|
|
|
|
return g_malloc_dispatch->pvalloc(bytes);
|
|
|
|
}
|
|
|
|
|
2014-07-10 21:34:23 +02:00
|
|
|
size_t pagesize = getpagesize();
|
2014-06-13 22:57:51 +02:00
|
|
|
size_t size = BIONIC_ALIGN(bytes, pagesize);
|
2014-06-10 04:14:11 +02:00
|
|
|
if (size < bytes) { // Overflow
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return leak_memalign(pagesize, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" void* leak_valloc(size_t size) {
|
2014-07-25 02:52:23 +02:00
|
|
|
if (DebugCallsDisabled()) {
|
|
|
|
return g_malloc_dispatch->valloc(size);
|
|
|
|
}
|
|
|
|
|
2014-07-10 21:34:23 +02:00
|
|
|
return leak_memalign(getpagesize(), size);
|
2014-06-10 04:14:11 +02:00
|
|
|
}
|
2014-07-25 02:52:23 +02:00
|
|
|
#endif
|