am 011076b7: Merge "Support for jemalloc to replace dlmalloc."

* commit '011076b720b0809a6b94703780e768cd7b877c68':
  Support for jemalloc to replace dlmalloc.
This commit is contained in:
Christopher Ferris 2014-05-21 18:16:41 +00:00 committed by Android Git Automerger
commit c1be1eccbb
13 changed files with 206 additions and 80 deletions

View File

@ -498,6 +498,16 @@ ifeq ($(strip $(DEBUG_BIONIC_LIBC)),true)
libc_common_cflags += -DDEBUG
endif
ifeq ($(MALLOC_IMPL),jemalloc)
libc_common_cflags += -DUSE_JEMALLOC
libc_malloc_src := bionic/jemalloc.cpp
else
libc_common_cflags += -DUSE_DLMALLOC
libc_malloc_src := bionic/dlmalloc.cpp
endif
# To customize dlmalloc's alignment, set BOARD_MALLOC_ALIGNMENT in
# the appropriate BoardConfig.mk file.
#
@ -526,6 +536,10 @@ libc_common_c_includes := \
$(LOCAL_PATH)/stdlib \
$(LOCAL_PATH)/stdio \
ifeq ($(MALLOC_IMPL),jemalloc)
libc_common_c_includes += external/jemalloc/include
endif
# ========================================================
# Add in the arch-specific flags.
# Must be called with $(eval).
@ -812,6 +826,11 @@ LOCAL_WHOLE_STATIC_LIBRARIES := \
libc_syscalls \
libc_tzcode \
ifeq ($(MALLOC_IMPL),jemalloc)
LOCAL_WHOLE_STATIC_LIBRARIES += \
libjemalloc
endif
LOCAL_SYSTEM_SHARED_LIBRARIES :=
# TODO: split out the asflags.
@ -866,7 +885,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(libc_arch_static_src_files) \
$(libc_static_common_src_files) \
bionic/dlmalloc.c \
$(libc_malloc_src) \
bionic/malloc_debug_common.cpp \
bionic/libc_init_static.cpp \
@ -896,11 +915,10 @@ LOCAL_CFLAGS := $(libc_common_cflags) -Werror
LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
LOCAL_CPPFLAGS := $(libc_common_cppflags)
LOCAL_C_INCLUDES := $(libc_common_c_includes)
LOCAL_SRC_FILES := \
$(libc_arch_dynamic_src_files) \
$(libc_static_common_src_files) \
bionic/dlmalloc.c \
$(libc_malloc_src) \
bionic/malloc_debug_common.cpp \
bionic/debug_mapinfo.cpp \
bionic/debug_stacktrace.cpp \

View File

@ -30,7 +30,13 @@
#include <string.h>
#include <stdlib.h>
#ifdef USE_JEMALLOC
#include "jemalloc.h"
#define Malloc(function) je_ ## function
#else
#include "dlmalloc.h"
#define Malloc(function) dl ## function
#endif
#include "debug_mapinfo.h"
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
@ -46,7 +52,7 @@ static mapinfo_t* parse_maps_line(char* line) {
if (len < 50) return 0;
if (line[20] != 'x') return 0;
mapinfo_t* mi = static_cast<mapinfo_t*>(dlmalloc(sizeof(mapinfo_t) + (len - 47)));
mapinfo_t* mi = static_cast<mapinfo_t*>(Malloc(malloc)(sizeof(mapinfo_t) + (len - 47)));
if (mi == 0) return 0;
mi->start = strtoul(line, 0, 16);
@ -79,7 +85,7 @@ __LIBC_HIDDEN__ void mapinfo_destroy(mapinfo_t* mi) {
while (mi != NULL) {
mapinfo_t* del = mi;
mi = mi->next;
dlfree(del);
Malloc(free)(del);
}
}

44
libc/bionic/jemalloc.cpp Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <unistd.h>
#include "jemalloc.h"
void* je_pvalloc(size_t bytes) {
size_t pagesize = sysconf(_SC_PAGESIZE);
return je_memalign(pagesize, (bytes + pagesize - 1) & ~(pagesize - 1));
}
#ifdef je_memalign
#undef je_memalign
#endif
// The man page for memalign says it fails if boundary is not a power of 2,
// but this is not true. Both glibc and dlmalloc round up to the next power
// of 2, so we'll do the same.
void* je_memalign_round_up_boundary(size_t boundary, size_t size) {
unsigned int power_of_2 = static_cast<unsigned int>(boundary);
if (power_of_2 != 0) {
power_of_2 = 1UL << (sizeof(unsigned int)*8 - 1 - __builtin_clz(power_of_2));
if (power_of_2 != boundary) {
boundary = power_of_2 << 1;
}
} else {
boundary = 1;
}
return je_memalign(boundary, size);
}

33
libc/bionic/jemalloc.h Normal file
View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef LIBC_BIONIC_JEMALLOC_H_
#define LIBC_BIONIC_JEMALLOC_H_
#include <jemalloc/jemalloc.h>
// Need to wrap memalign since je_memalign fails on non-power of 2 alignments.
#define je_memalign je_memalign_round_up_boundary
__BEGIN_DECLS
struct mallinfo je_mallinfo();
void* je_memalign_round_up_boundary(size_t, size_t);
void* je_pvalloc(size_t);
__END_DECLS
#endif // LIBC_BIONIC_DLMALLOC_H_

View File

@ -47,7 +47,6 @@
#include "debug_mapinfo.h"
#include "debug_stacktrace.h"
#include "dlmalloc.h"
#include "private/libc_logging.h"
#include "malloc_debug_common.h"
#include "private/ScopedPthreadMutexLocker.h"
@ -74,7 +73,7 @@ static void log_message(const char* format, ...) {
struct hdr_t {
uint32_t tag;
void* base; // Always points to the memory allocated using dlmalloc.
void* base; // Always points to the memory allocated using malloc.
// For memory allocated in chk_memalign, this value will
// not be the same as the location of the start of this
// structure.
@ -321,14 +320,14 @@ static inline void add_to_backlog(hdr_t* hdr) {
while (backlog_num > g_malloc_debug_backlog) {
hdr_t* gone = backlog_tail;
del_from_backlog_locked(gone);
dlfree(gone->base);
Malloc(free)(gone->base);
}
}
extern "C" void* chk_malloc(size_t size) {
// log_message("%s: %s\n", __FILE__, __FUNCTION__);
hdr_t* hdr = static_cast<hdr_t*>(dlmalloc(sizeof(hdr_t) + size + sizeof(ftr_t)));
hdr_t* hdr = static_cast<hdr_t*>(Malloc(malloc)(sizeof(hdr_t) + size + sizeof(ftr_t)));
if (hdr) {
hdr->base = hdr;
hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH);
@ -356,7 +355,7 @@ extern "C" void* chk_memalign(size_t alignment, size_t bytes) {
return NULL;
}
void* base = dlmalloc(sizeof(hdr_t) + size + sizeof(ftr_t));
void* base = Malloc(malloc)(sizeof(hdr_t) + size + sizeof(ftr_t));
if (base != NULL) {
// Check that the actual pointer that will be returned is aligned
// properly.
@ -453,25 +452,25 @@ extern "C" void* chk_realloc(void* ptr, size_t size) {
user(hdr), size);
log_backtrace(bt, depth);
// just get a whole new allocation and leak the old one
return dlrealloc(0, size);
// return dlrealloc(user(hdr), size); // assuming it was allocated externally
return Malloc(realloc)(0, size);
// return realloc(user(hdr), size); // assuming it was allocated externally
}
}
if (hdr->base != hdr) {
// An allocation from memalign, so create another allocation and
// copy the data out.
void* newMem = dlmalloc(sizeof(hdr_t) + size + sizeof(ftr_t));
void* newMem = Malloc(malloc)(sizeof(hdr_t) + size + sizeof(ftr_t));
if (newMem) {
memcpy(newMem, hdr, sizeof(hdr_t) + hdr->size);
dlfree(hdr->base);
Malloc(free)(hdr->base);
hdr = static_cast<hdr_t*>(newMem);
} else {
dlfree(hdr->base);
Malloc(free)(hdr->base);
hdr = NULL;
}
} else {
hdr = static_cast<hdr_t*>(dlrealloc(hdr, sizeof(hdr_t) + size + sizeof(ftr_t)));
hdr = static_cast<hdr_t*>(Malloc(realloc)(hdr, sizeof(hdr_t) + size + sizeof(ftr_t)));
}
if (hdr) {
hdr->base = hdr;
@ -486,7 +485,7 @@ extern "C" void* chk_realloc(void* ptr, size_t size) {
extern "C" void* chk_calloc(int nmemb, size_t size) {
// log_message("%s: %s\n", __FILE__, __FUNCTION__);
size_t total_size = nmemb * size;
hdr_t* hdr = static_cast<hdr_t*>(dlcalloc(1, sizeof(hdr_t) + total_size + sizeof(ftr_t)));
hdr_t* hdr = static_cast<hdr_t*>(Malloc(calloc)(1, sizeof(hdr_t) + total_size + sizeof(ftr_t)));
if (hdr) {
hdr->base = hdr;
hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH);
@ -497,7 +496,7 @@ extern "C" void* chk_calloc(int nmemb, size_t size) {
}
extern "C" size_t chk_malloc_usable_size(const void* ptr) {
// dlmalloc_usable_size returns 0 for NULL and unknown blocks.
// malloc_usable_size returns 0 for NULL and unknown blocks.
if (ptr == NULL)
return 0;

View File

@ -46,7 +46,6 @@
#include <stdlib.h>
#include <unistd.h>
#include "dlmalloc.h"
#include "private/ScopedPthreadMutexLocker.h"
/*
@ -134,7 +133,7 @@ extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
return;
}
HashEntry** list = static_cast<HashEntry**>(dlmalloc(sizeof(void*) * g_hash_table.count));
HashEntry** list = static_cast<HashEntry**>(Malloc(malloc)(sizeof(void*) * g_hash_table.count));
// get the entries into an array to be sorted
int index = 0;
@ -155,11 +154,11 @@ extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
*backtraceSize = BACKTRACE_SIZE;
// now get a byte array big enough for this
*info = static_cast<uint8_t*>(dlmalloc(*overallSize));
*info = static_cast<uint8_t*>(Malloc(malloc)(*overallSize));
if (*info == NULL) {
*overallSize = 0;
dlfree(list);
Malloc(free)(list);
return;
}
@ -181,42 +180,36 @@ extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
head += *infoSize;
}
dlfree(list);
Malloc(free)(list);
}
// Exported for use by ddms.
extern "C" void free_malloc_leak_info(uint8_t* info) {
dlfree(info);
Malloc(free)(info);
}
extern "C" struct mallinfo mallinfo() {
return dlmallinfo();
return Malloc(mallinfo)();
}
extern "C" void* valloc(size_t bytes) {
return dlvalloc(bytes);
return Malloc(valloc)(bytes);
}
extern "C" void* pvalloc(size_t bytes) {
return dlpvalloc(bytes);
return Malloc(pvalloc)(bytes);
}
extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size) {
return dlposix_memalign(memptr, alignment, size);
return Malloc(posix_memalign)(memptr, alignment, size);
}
/* Support for malloc debugging.
* Note that if USE_DL_PREFIX is not defined, it's assumed that memory
* allocation routines are implemented somewhere else, so all our custom
* malloc routines should not be compiled at all.
*/
#ifdef USE_DL_PREFIX
/* Table for dispatching malloc calls, initialized with default dispatchers. */
// Support for malloc debugging.
// Table for dispatching malloc calls, initialized with default dispatchers.
extern const MallocDebug __libc_malloc_default_dispatch;
const MallocDebug __libc_malloc_default_dispatch __attribute__((aligned(32))) =
{
dlmalloc, dlfree, dlcalloc, dlrealloc, dlmemalign, dlmalloc_usable_size,
Malloc(malloc), Malloc(free), Malloc(calloc), Malloc(realloc), Malloc(memalign), Malloc(malloc_usable_size),
};
/* Selector of dispatch table to use for dispatching malloc calls. */
@ -257,7 +250,7 @@ extern "C" size_t malloc_usable_size(const void* mem) {
/* Table for dispatching malloc calls, depending on environment. */
static MallocDebug g_malloc_dispatch_table __attribute__((aligned(32))) = {
dlmalloc, dlfree, dlcalloc, dlrealloc, dlmemalign, dlmalloc_usable_size
Malloc(malloc), Malloc(free), Malloc(calloc), Malloc(realloc), Malloc(memalign), Malloc(malloc_usable_size)
};
extern const char* __progname;
@ -347,8 +340,7 @@ static void malloc_init_impl() {
g_malloc_debug_level = atoi(env);
}
/* Debug level 0 means that we should use dlxxx allocation
* routines (default). */
/* Debug level 0 means that we should use default allocation routines. */
if (g_malloc_debug_level == 0) {
return;
}
@ -504,7 +496,6 @@ static pthread_once_t malloc_init_once_ctl = PTHREAD_ONCE_INIT;
static pthread_once_t malloc_fini_once_ctl = PTHREAD_ONCE_INIT;
#endif // !LIBC_STATIC
#endif // USE_DL_PREFIX
/* Initializes memory allocation framework.
* This routine is called from __libc_init routines implemented

View File

@ -45,11 +45,22 @@
#define MAX_SIZE_T (~(size_t)0)
// This must match the alignment used by dlmalloc.
// This must match the alignment used by the malloc implementation.
#ifndef MALLOC_ALIGNMENT
#define MALLOC_ALIGNMENT ((size_t)(2 * sizeof(void *)))
#endif
#ifdef USE_JEMALLOC
#include "jemalloc.h"
#define Malloc(function) je_ ## function
#else
#ifndef USE_DLMALLOC
#error "Either one of USE_DLMALLOC or USE_JEMALLOC must be defined."
#endif
#include "dlmalloc.h"
#define Malloc(function) dl ## function
#endif
// =============================================================================
// Structures
// =============================================================================

View File

@ -46,7 +46,6 @@
#include <unwind.h>
#include "debug_stacktrace.h"
#include "dlmalloc.h"
#include "malloc_debug_common.h"
#include "private/libc_logging.h"
@ -144,7 +143,7 @@ static HashEntry* record_backtrace(uintptr_t* backtrace, size_t numEntries, size
entry->allocations++;
} else {
// create a new entry
entry = static_cast<HashEntry*>(dlmalloc(sizeof(HashEntry) + numEntries*sizeof(uintptr_t)));
entry = static_cast<HashEntry*>(Malloc(malloc)(sizeof(HashEntry) + numEntries*sizeof(uintptr_t)));
if (!entry) {
return NULL;
}
@ -213,11 +212,11 @@ static void remove_entry(HashEntry* entry) {
#define CHK_SENTINEL_VALUE 0xeb
extern "C" void* fill_calloc(size_t n_elements, size_t elem_size) {
return dlcalloc(n_elements, elem_size);
return Malloc(calloc)(n_elements, elem_size);
}
extern "C" void* fill_malloc(size_t bytes) {
void* buffer = dlmalloc(bytes);
void* buffer = Malloc(malloc)(bytes);
if (buffer) {
memset(buffer, CHK_SENTINEL_VALUE, bytes);
}
@ -225,17 +224,17 @@ extern "C" void* fill_malloc(size_t bytes) {
}
extern "C" void fill_free(void* mem) {
size_t bytes = dlmalloc_usable_size(mem);
size_t bytes = Malloc(malloc_usable_size)(mem);
memset(mem, CHK_FILL_FREE, bytes);
dlfree(mem);
Malloc(free)(mem);
}
extern "C" void* fill_realloc(void* mem, size_t bytes) {
size_t oldSize = dlmalloc_usable_size(mem);
void* newMem = dlrealloc(mem, bytes);
size_t oldSize = Malloc(malloc_usable_size)(mem);
void* newMem = Malloc(realloc)(mem, bytes);
if (newMem) {
// If this is larger than before, fill the extra with our pattern.
size_t newSize = dlmalloc_usable_size(newMem);
size_t newSize = Malloc(malloc_usable_size)(newMem);
if (newSize > oldSize) {
memset(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(newMem)+oldSize), CHK_FILL_FREE, newSize-oldSize);
}
@ -244,7 +243,7 @@ extern "C" void* fill_realloc(void* mem, size_t bytes) {
}
extern "C" void* fill_memalign(size_t alignment, size_t bytes) {
void* buffer = dlmemalign(alignment, bytes);
void* buffer = Malloc(memalign)(alignment, bytes);
if (buffer) {
memset(buffer, CHK_SENTINEL_VALUE, bytes);
}
@ -254,7 +253,7 @@ extern "C" void* fill_memalign(size_t alignment, size_t bytes) {
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.
return dlmalloc_usable_size(mem);
return Malloc(malloc_usable_size)(mem);
}
// =============================================================================
@ -275,7 +274,7 @@ extern "C" void* leak_malloc(size_t bytes) {
return NULL;
}
void* base = dlmalloc(size);
void* base = Malloc(malloc)(size);
if (base != NULL) {
ScopedPthreadMutexLocker locker(&g_allocations_mutex);
@ -316,11 +315,11 @@ extern "C" void leak_free(void* mem) {
entry->allocations--;
if (entry->allocations <= 0) {
remove_entry(entry);
dlfree(entry);
Malloc(free)(entry);
}
// now free the memory!
dlfree(header);
Malloc(free)(header);
} else {
debug_log("WARNING bad header guard: '0x%x'! and invalid entry: %p\n",
header->guard, header->entry);
@ -425,7 +424,7 @@ extern "C" size_t leak_malloc_usable_size(const void* mem) {
return 0;
}
size_t ret = dlmalloc_usable_size(header);
size_t ret = Malloc(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);

View File

@ -50,7 +50,6 @@
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include "dlmalloc.h"
#include "private/libc_logging.h"
#include "malloc_debug_common.h"
@ -344,7 +343,7 @@ static volatile void* qtrace = NULL;
* has been initialized. */
static uint32_t malloc_pid = 0;
/* Memory allocation alignment that is used in dlmalloc.
/* Memory allocation alignment that is used in the malloc implementation.
* This variable is updated by memcheck_initialize routine. */
static uint32_t malloc_alignment = 8;
@ -677,14 +676,14 @@ extern "C" int memcheck_initialize(int alignment, const char* memcheck_param) {
extern "C" void* qemu_instrumented_malloc(size_t bytes) {
MallocDesc desc;
/* Initialize block descriptor and allocate memory. Note that dlmalloc
/* Initialize block descriptor and allocate memory. Note that malloc
* returns a valid pointer on zero allocation. Lets mimic this behavior. */
desc.prefix_size = DEFAULT_PREFIX_SIZE;
desc.requested_bytes = bytes;
desc.suffix_size = DEFAULT_SUFFIX_SIZE;
desc.ptr = dlmalloc(mallocdesc_alloc_size(&desc));
desc.ptr = Malloc(malloc)(mallocdesc_alloc_size(&desc));
if (desc.ptr == NULL) {
qemu_error_log("<libc_pid=%03u, pid=%03u> malloc(%zd): dlmalloc(%u) failed.",
qemu_error_log("<libc_pid=%03u, pid=%03u> malloc(%zd): malloc(%u) failed.",
malloc_pid, getpid(), bytes, mallocdesc_alloc_size(&desc));
return NULL;
}
@ -693,7 +692,7 @@ extern "C" void* qemu_instrumented_malloc(size_t bytes) {
if (notify_qemu_malloc(&desc)) {
log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: malloc: notify_malloc failed for ",
malloc_pid, getpid());
dlfree(desc.ptr);
Malloc(free)(desc.ptr);
return NULL;
} else {
#if TEST_ACCESS_VIOLATIONS
@ -714,7 +713,7 @@ extern "C" void qemu_instrumented_free(void* mem) {
if (mem == NULL) {
// Just let go NULL free
dlfree(mem);
Malloc(free)(mem);
return;
}
@ -745,7 +744,7 @@ extern "C" void qemu_instrumented_free(void* mem) {
} else {
log_mdesc(info, &desc, "--- <libc_pid=%03u, pid=%03u> free(%p) -> ",
malloc_pid, getpid(), mem);
dlfree(desc.ptr);
Malloc(free)(desc.ptr);
}
}
@ -795,9 +794,9 @@ extern "C" void* qemu_instrumented_calloc(size_t n_elements, size_t elem_size) {
total_elements++;
desc.suffix_size += (elem_size - total_size);
}
desc.ptr = dlcalloc(total_elements, elem_size);
desc.ptr = Malloc(calloc)(total_elements, elem_size);
if (desc.ptr == NULL) {
error_log("<libc_pid=%03u, pid=%03u> calloc: dlcalloc(%zd(%zd), %zd) (prx=%u, sfx=%u) failed.",
error_log("<libc_pid=%03u, pid=%03u> calloc: calloc(%zd(%zd), %zd) (prx=%u, sfx=%u) failed.",
malloc_pid, getpid(), n_elements, total_elements, elem_size,
desc.prefix_size, desc.suffix_size);
return NULL;
@ -806,7 +805,7 @@ extern "C" void* qemu_instrumented_calloc(size_t n_elements, size_t elem_size) {
if (notify_qemu_malloc(&desc)) {
log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: calloc(%zd(%zd), %zd): notify_malloc failed for ",
malloc_pid, getpid(), n_elements, total_elements, elem_size);
dlfree(desc.ptr);
Malloc(free)(desc.ptr);
return NULL;
} else {
#if TEST_ACCESS_VIOLATIONS
@ -843,7 +842,7 @@ extern "C" void* qemu_instrumented_realloc(void* mem, size_t bytes) {
malloc_pid, getpid(), mem, bytes);
qemu_instrumented_free(mem);
// This is what dlrealloc does for a "free" realloc.
// This is what realloc does for a "free" realloc.
return NULL;
}
@ -877,9 +876,9 @@ extern "C" void* qemu_instrumented_realloc(void* mem, size_t bytes) {
new_desc.prefix_size = DEFAULT_PREFIX_SIZE;
new_desc.requested_bytes = bytes;
new_desc.suffix_size = DEFAULT_SUFFIX_SIZE;
new_desc.ptr = dlmalloc(mallocdesc_alloc_size(&new_desc));
new_desc.ptr = Malloc(malloc)(mallocdesc_alloc_size(&new_desc));
if (new_desc.ptr == NULL) {
log_mdesc(error, &cur_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %zd): dlmalloc(%u) failed on ",
log_mdesc(error, &cur_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %zd): malloc(%u) failed on ",
malloc_pid, getpid(), mem, bytes,
mallocdesc_alloc_size(&new_desc));
return NULL;
@ -898,7 +897,7 @@ extern "C" void* qemu_instrumented_realloc(void* mem, size_t bytes) {
log_mdesc(error, &new_desc, "<libc_pid=%03u, pid=%03u>: realloc(%p, %zd) notify_malloc failed -> ",
malloc_pid, getpid(), mem, bytes);
log_mdesc(error, &cur_desc, " <- ");
dlfree(new_desc.ptr);
Malloc(free)(new_desc.ptr);
return NULL;
}
@ -913,10 +912,10 @@ extern "C" void* qemu_instrumented_realloc(void* mem, size_t bytes) {
/* Since we registered new decriptor with the emulator, we need
* to unregister it before freeing newly allocated block. */
notify_qemu_free(mallocdesc_user_ptr(&new_desc));
dlfree(new_desc.ptr);
Malloc(free)(new_desc.ptr);
return NULL;
}
dlfree(cur_desc.ptr);
Malloc(free)(cur_desc.ptr);
log_mdesc(info, &new_desc, "=== <libc_pid=%03u, pid=%03u>: realloc(%p, %zd) -> ",
malloc_pid, getpid(), mem, bytes);
@ -946,9 +945,9 @@ extern "C" void* qemu_instrumented_memalign(size_t alignment, size_t bytes) {
DEFAULT_PREFIX_SIZE;
desc.requested_bytes = bytes;
desc.suffix_size = DEFAULT_SUFFIX_SIZE;
desc.ptr = dlmemalign(desc.prefix_size, mallocdesc_alloc_size(&desc));
desc.ptr = Malloc(memalign)(desc.prefix_size, mallocdesc_alloc_size(&desc));
if (desc.ptr == NULL) {
error_log("<libc_pid=%03u, pid=%03u> memalign(%zx, %zd): dlmalloc(%u) failed.",
error_log("<libc_pid=%03u, pid=%03u> memalign(%zx, %zd): malloc(%u) failed.",
malloc_pid, getpid(), alignment, bytes,
mallocdesc_alloc_size(&desc));
return NULL;
@ -956,7 +955,7 @@ extern "C" void* qemu_instrumented_memalign(size_t alignment, size_t bytes) {
if (notify_qemu_malloc(&desc)) {
log_mdesc(error, &desc, "<libc_pid=%03u, pid=%03u>: memalign(%zx, %zd): notify_malloc failed for ",
malloc_pid, getpid(), alignment, bytes);
dlfree(desc.ptr);
Malloc(free)(desc.ptr);
return NULL;
}

View File

@ -309,7 +309,7 @@ int sysconf(int name) {
return _POSIX_THREAD_DESTRUCTOR_ITERATIONS;
case _SC_THREAD_KEYS_MAX:
return (BIONIC_TLS_SLOTS - TLS_SLOT_FIRST_USER_SLOT - GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT);
return (BIONIC_TLS_SLOTS - TLS_SLOT_FIRST_USER_SLOT - BIONIC_TLS_RESERVED_SLOTS);
case _SC_THREAD_STACK_MIN: return PTHREAD_STACK_MIN;
case _SC_THREAD_THREADS_MAX: return SYSTEM_THREAD_THREADS_MAX;

View File

@ -82,6 +82,13 @@ enum {
*/
#define GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT 5
#if defined(USE_JEMALLOC)
/* jemalloc uses 5 keys for itself. */
#define BIONIC_TLS_RESERVED_SLOTS (GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT + 5)
#else
#define BIONIC_TLS_RESERVED_SLOTS GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT
#endif
#define BIONIC_ALIGN(x, a) (((x) + (a - 1)) & ~(a - 1))
/*
@ -89,7 +96,7 @@ enum {
* This includes space for pthread keys and our own internal slots.
* We need to round up to maintain stack alignment.
*/
#define BIONIC_TLS_SLOTS BIONIC_ALIGN(PTHREAD_KEYS_MAX + TLS_SLOT_FIRST_USER_SLOT + GLOBAL_INIT_THREAD_LOCAL_BUFFER_COUNT, 4)
#define BIONIC_TLS_SLOTS BIONIC_ALIGN(PTHREAD_KEYS_MAX + TLS_SLOT_FIRST_USER_SLOT + BIONIC_TLS_RESERVED_SLOTS, 4)
__END_DECLS

View File

@ -40,6 +40,10 @@ test_cflags = \
test_cflags += -D__STDC_LIMIT_MACROS # For glibc.
ifeq ($(MALLOC_IMPL),jemalloc)
test_cflags += -DUSE_JEMALLOC
endif
test_cppflags = \
-std=gnu++11 \

View File

@ -46,7 +46,7 @@ TEST(malloc, memalign_multiple) {
for (size_t i = 0; i <= 12; i++) {
for (size_t alignment = 1 << i; alignment < (1U << (i+1)); alignment++) {
char *ptr = (char*)memalign(alignment, 100);
ASSERT_TRUE(ptr != NULL);
ASSERT_TRUE(ptr != NULL) << alignment;
ASSERT_LE(100U, malloc_usable_size(ptr));
ASSERT_EQ(0, (intptr_t)ptr % (1 << i));
@ -233,3 +233,18 @@ TEST(malloc, calloc_multiple_realloc) {
free(ptr);
}
TEST(malloc, posix_memalign_non_power2) {
void* ptr;
ASSERT_EQ(EINVAL, posix_memalign(&ptr, 17, 1024));
}
TEST(malloc, memalign_non_power2) {
void* ptr;
for (size_t align = 0; align <= 256; align++) {
ptr = memalign(align, 1024);
ASSERT_TRUE(ptr != NULL) << "Failed at align " << align;
free(ptr);
}
}