This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: The direction of malloc?
- From: "Maciej W. Rozycki" <macro at codesourcery dot com>
- To: Jeff Law <law at redhat dot com>
- Cc: Carlos O'Donell <carlos at redhat dot com>, GNU C Library <libc-alpha at sourceware dot org>, Roland McGrath <roland at hack dot frob dot com>, Andreas Jaeger <aj at suse dot com>, "Joseph S. Myers" <joseph at codesourcery dot com>, Andreas Schwab <schwab at suse dot de>, Ondřej Bílka <neleai at seznam dot cz>, Siddhesh Poyarekar <siddhesh at redhat dot com>
- Date: Tue, 10 Dec 2013 22:21:52 +0000
- Subject: Re: The direction of malloc?
- Authentication-results: sourceware.org; auth=none
- References: <52A6A0DA dot 1080109 at redhat dot com> <52A6AC38 dot 6000008 at redhat dot com>
On Tue, 10 Dec 2013, Jeff Law wrote:
> The other thing that I've been asked about a few times would be to fix the
> thread safety issues around the hooks, which IIRC requires some redesign.
A starting point could be an implementation I made a while ago, presented
below. This was based on 2.8 and intended to make its way into 2.10, but
regrettably that has never happened. The change looks extensive, but this
is due to code shuffling resulting from adding wrappers that separate
calls to hooks (both the preexisting and the new ones) from actual
allocation implementation, that may call into itself too.
This also changes the semantics of the preexisting hooks a bit, in
particular internal calls into itself do not call any of the hooks anymore
such as in the case of _do_realloc (nee public_rEALLOc) calling into
_do_malloc (nee public_mALLOc). This may require further consideration.
Formatting follows that of current malloc code and would require updating
as being discussed here too.
The original description I made for an internal review follows.
--------------------------------------------------------------------------
Here is an implementation of the revised malloc hook API. I have
designed it with thread safety in mind. Under such an assumption
recursive calls via the existing hooks by substituting the value of the
appropriate variable are infeasible and the hooks are called too early for
the return value of the respective call (if applicable) to be supplied
under a revised API.
Therefore I have introduced a set of new hooks. They all are called at
the conclusion of the respective function, when all the data to be
gathered has already been obtained. For this to happen the structure of
malloc.c code had to be modified slightly, introducing an intermediate
function level with all the hooks moved to the new outermost one. This
has made source code a little bit clearer and as a side-effect fixed a bug
in public_vALLOc() and public_pVALLOc() aka valloc() and pvalloc() where
the arena would get initialised before calling the __memalign_hook() hook.
The drawback is there is some performance impact.
2008-12-13 Maciej W. Rozycki <macro@codesourcery.com>
* malloc/malloc.c (realloc_hook_ini): Rename ptr to oldptr.
(__realloc_hook): Likewise.
(__free_hook): Likewise.
(__malloc_trace): New hook variable.
(__free_trace): Likewise.
(__realloc_trace): Likewise.
(__memalign_trace): Likewise.
(public_mALLOc): Add the new hook. Move all the body but the old
hook over to...
(_do_malloc): ... here.
(public_fREe): Likewise to...
(_do_free): ... here.
(public_mEMALIGn): Likewise to...
(_do_memalign): ... here.
(public_vALLOc): Likewise to...
(_do_valloc): ... here.
(public_pVALLOc): Likewise to...
(_do_pvalloc): ... here.
(public_cALLOc): Likewise to...
(_do_calloc): ... here.
(public_rEALLOc): Restructure to call the realloc(), malloc() or
free() hooks as appropriate. Add the new hooks. Move all the
genuine realloc() processing over to...
(_do_realloc): ... here.
(__posix_memalign): Add the new hook. Call _do_memalign() rather
than public_mEMALIGn().
* malloc/malloc.h (__realloc_hook): Rename ptr to oldptr.
(__free_hook): Likewise.
(__malloc_trace): New declaration.
(__free_trace): Likewise.
(__realloc_trace): Likewise.
(__memalign_trace): Likewise.
* Versions.def [libc] (GLIBC_2.10): New version.
* malloc/Versions [libc] (GLIBC_2.10): Add __malloc_trace,
__free_trace, __realloc_trace and __memalign_trace.
* manual/memory.texi (Hooks for Malloc): Document __malloc_trace,
__free_trace, __realloc_trace and __memalign_trace.
Maciej
glibc-2.8-malloc-hooks-13.patch
Index: malloc/malloc.c
===================================================================
--- malloc/malloc.c (revision 226481)
+++ malloc/malloc.c (working copy)
@@ -1592,6 +1592,13 @@ static Void_t* _int_pvalloc(mstate, siz
static Void_t** _int_icalloc(mstate, size_t, size_t, Void_t**);
static Void_t** _int_icomalloc(mstate, size_t, size_t*, Void_t**);
#endif
+static Void_t* _do_malloc(size_t);
+static void _do_free(Void_t*);
+static Void_t* _do_realloc(Void_t*, size_t);
+static Void_t* _do_memalign(size_t, size_t);
+static Void_t* _do_valloc(size_t);
+static Void_t* _do_pvalloc(size_t);
+static Void_t* _do_calloc(INTERNAL_SIZE_T);
static int mTRIm(mstate, size_t);
static size_t mUSABLe(Void_t*);
static void mSTATs(void);
@@ -1641,6 +1648,13 @@ Void_t* _int_pvalloc();
/*static Void_t* cALLOc();*/
static Void_t** _int_icalloc();
static Void_t** _int_icomalloc();
+static Void_t* _do_malloc();
+static void _do_free();
+static Void_t* _do_realloc();
+static Void_t* _do_memalign();
+static Void_t* _do_valloc();
+static Void_t* _do_pvalloc();
+static Void_t* _do_calloc();
static int mTRIm();
static size_t mUSABLe();
static void mSTATs();
@@ -2466,24 +2480,34 @@ static Void_t** iALLOc();
/* Forward declarations. */
static Void_t* malloc_hook_ini __MALLOC_P ((size_t sz,
const __malloc_ptr_t caller));
-static Void_t* realloc_hook_ini __MALLOC_P ((Void_t* ptr, size_t sz,
+static Void_t* realloc_hook_ini __MALLOC_P ((Void_t* oldptr, size_t sz,
const __malloc_ptr_t caller));
static Void_t* memalign_hook_ini __MALLOC_P ((size_t alignment, size_t sz,
const __malloc_ptr_t caller));
void weak_variable (*__malloc_initialize_hook) (void) = NULL;
-void weak_variable (*__free_hook) (__malloc_ptr_t __ptr,
+void weak_variable (*__free_hook) (__malloc_ptr_t __oldptr,
const __malloc_ptr_t) = NULL;
__malloc_ptr_t weak_variable (*__malloc_hook)
(size_t __size, const __malloc_ptr_t) = malloc_hook_ini;
__malloc_ptr_t weak_variable (*__realloc_hook)
- (__malloc_ptr_t __ptr, size_t __size, const __malloc_ptr_t)
+ (__malloc_ptr_t __oldptr, size_t __size, const __malloc_ptr_t)
= realloc_hook_ini;
__malloc_ptr_t weak_variable (*__memalign_hook)
(size_t __alignment, size_t __size, const __malloc_ptr_t)
= memalign_hook_ini;
void weak_variable (*__after_morecore_hook) (void) = NULL;
+void weak_variable (*__free_trace) (__malloc_ptr_t __oldptr,
+ const __malloc_ptr_t) = NULL;
+void weak_variable (*__malloc_trace) (size_t __size, const __malloc_ptr_t,
+ __malloc_ptr_t __ptr) = NULL;
+void weak_variable (*__realloc_trace) (__malloc_ptr_t __oldptr, size_t __size,
+ const __malloc_ptr_t,
+ __malloc_ptr_t __ptr) = NULL;
+void weak_variable (*__memalign_trace) (size_t __alignment, size_t __size,
+ const __malloc_ptr_t,
+ __malloc_ptr_t __ptr) = NULL;
/* ---------------- Error behavior ------------------------------------ */
@@ -3538,13 +3562,333 @@ mremap_chunk(p, new_size) mchunkptr p; s
Void_t*
public_mALLOc(size_t bytes)
{
- mstate ar_ptr;
- Void_t *victim;
+ __malloc_ptr_t (*hook) (size_t, __const __malloc_ptr_t);
+ void (*trace) (size_t, __const __malloc_ptr_t, __malloc_ptr_t);
+ Void_t *mem;
- __malloc_ptr_t (*hook) (size_t, __const __malloc_ptr_t) = __malloc_hook;
+ hook = __malloc_hook;
if (hook != NULL)
return (*hook)(bytes, RETURN_ADDRESS (0));
+ mem = _do_malloc(bytes);
+
+ trace = __malloc_trace;
+ if (trace != NULL)
+ (*trace)(bytes, RETURN_ADDRESS (0), mem);
+
+ return mem;
+}
+#ifdef libc_hidden_def
+libc_hidden_def(public_mALLOc)
+#endif
+
+void
+public_fREe(Void_t* mem)
+{
+ void (*hook) (__malloc_ptr_t, __const __malloc_ptr_t);
+ void (*trace) (__malloc_ptr_t, __const __malloc_ptr_t);
+
+ hook = __free_hook;
+ if (hook != NULL) {
+ (*hook)(mem, RETURN_ADDRESS (0));
+ return;
+ }
+
+ _do_free(mem);
+
+ trace = __free_trace;
+ if (trace != NULL)
+ (*trace)(mem, RETURN_ADDRESS (0));
+}
+#ifdef libc_hidden_def
+libc_hidden_def (public_fREe)
+#endif
+
+Void_t*
+public_rEALLOc(Void_t* oldmem, size_t bytes)
+{
+ __malloc_ptr_t (*hook) (__malloc_ptr_t, size_t, __const __malloc_ptr_t);
+ void (*trace) (__malloc_ptr_t, size_t, const __malloc_ptr_t, __malloc_ptr_t);
+ Void_t *mem;
+
+ hook = __realloc_hook;
+ if (hook != NULL)
+ return (*hook)(oldmem, bytes, RETURN_ADDRESS (0));
+
+#if REALLOC_ZERO_BYTES_FREES
+ if (bytes == 0 && oldmem != NULL) {
+ void (*free_hook) (__malloc_ptr_t, __const __malloc_ptr_t);
+ void (*free_trace) (__malloc_ptr_t, __const __malloc_ptr_t);
+
+ free_hook = __free_hook;
+ if (free_hook != NULL) {
+ (*free_hook)(oldmem, RETURN_ADDRESS (0));
+ return 0;
+ }
+
+ _do_free(oldmem);
+
+ free_trace = __free_trace;
+ if (free_trace != NULL)
+ (*free_trace)(oldmem, RETURN_ADDRESS (0));
+
+ return 0;
+ }
+#endif
+
+ /* realloc of null is supposed to be same as malloc */
+ if (oldmem == 0) {
+ __malloc_ptr_t (*malloc_hook) (size_t, __const __malloc_ptr_t);
+ void (*malloc_trace) (size_t, __const __malloc_ptr_t, __malloc_ptr_t);
+
+ malloc_hook = __malloc_hook;
+ if (malloc_hook != NULL)
+ return (*malloc_hook)(bytes, RETURN_ADDRESS (0));
+
+ mem = _do_malloc(bytes);
+
+ malloc_trace = __malloc_trace;
+ if (malloc_trace != NULL)
+ (*malloc_trace)(bytes, RETURN_ADDRESS (0), mem);
+
+ return mem;
+ }
+
+ mem = _do_realloc(oldmem, bytes);
+
+ trace = __realloc_trace;
+ if (trace != NULL)
+ (*trace)(oldmem, bytes, RETURN_ADDRESS (0), mem);
+
+ return mem;
+}
+#ifdef libc_hidden_def
+libc_hidden_def (public_rEALLOc)
+#endif
+
+Void_t*
+public_mEMALIGn(size_t alignment, size_t bytes)
+{
+ __malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, size_t,
+ __const __malloc_ptr_t));
+ void (*trace) __MALLOC_PMT ((size_t, size_t,
+ __const __malloc_ptr_t, __malloc_ptr_t));
+ Void_t *mem;
+
+ hook = __memalign_hook;
+ if (hook != NULL)
+ return (*hook)(alignment, bytes, RETURN_ADDRESS (0));
+
+ mem = _do_memalign(alignment, bytes);
+
+ trace = __memalign_trace;
+ if (trace != NULL)
+ (*trace)(alignment, bytes, RETURN_ADDRESS (0), mem);
+
+ return mem;
+}
+#ifdef libc_hidden_def
+libc_hidden_def (public_mEMALIGn)
+#endif
+
+Void_t*
+public_vALLOc(size_t bytes)
+{
+ __malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, size_t,
+ __const __malloc_ptr_t));
+ void (*trace) __MALLOC_PMT ((size_t, size_t,
+ __const __malloc_ptr_t, __malloc_ptr_t));
+ Void_t *mem;
+
+ hook = __memalign_hook;
+ if (hook != NULL)
+ return (*hook)(mp_.pagesize, bytes, RETURN_ADDRESS (0));
+
+ mem = _do_valloc(bytes);
+
+ trace = __memalign_trace;
+ if (trace != NULL)
+ (*trace)(mp_.pagesize, bytes, RETURN_ADDRESS (0), mem);
+
+ return mem;
+}
+
+Void_t*
+public_pVALLOc(size_t bytes)
+{
+ __malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, size_t,
+ __const __malloc_ptr_t));
+ void (*trace) __MALLOC_PMT ((size_t, size_t,
+ __const __malloc_ptr_t, __malloc_ptr_t));
+ Void_t *mem;
+
+ hook = __memalign_hook;
+ if (hook != NULL)
+ return (*hook)(mp_.pagesize,
+ (bytes + mp_.pagesize - 1) & ~(mp_.pagesize - 1),
+ RETURN_ADDRESS (0));
+
+ mem = _do_pvalloc(bytes);
+
+ trace = __memalign_trace;
+ if (trace != NULL)
+ (*trace)(mp_.pagesize, (bytes + mp_.pagesize - 1) & ~(mp_.pagesize - 1),
+ RETURN_ADDRESS (0), mem);
+
+ return mem;
+}
+
+Void_t*
+public_cALLOc(size_t n, size_t elem_size)
+{
+ __malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, __const __malloc_ptr_t));
+ void (*trace) (size_t, __const __malloc_ptr_t, __malloc_ptr_t);
+ INTERNAL_SIZE_T bytes;
+ Void_t* mem;
+
+ /* size_t is unsigned so the behavior on overflow is defined. */
+ bytes = n * elem_size;
+#define HALF_INTERNAL_SIZE_T \
+ (((INTERNAL_SIZE_T) 1) << (8 * sizeof (INTERNAL_SIZE_T) / 2))
+ if (__builtin_expect ((n | elem_size) >= HALF_INTERNAL_SIZE_T, 0)) {
+ if (elem_size != 0 && bytes / elem_size != n) {
+ MALLOC_FAILURE_ACTION;
+ return 0;
+ }
+ }
+
+ hook = __malloc_hook;
+ if (hook != NULL) {
+ mem = (*hook)(bytes, RETURN_ADDRESS (0));
+ if(mem == 0)
+ return 0;
+#ifdef HAVE_MEMCPY
+ return memset(mem, 0, bytes);
+#else
+ while(bytes > 0) ((char*)mem)[--bytes] = 0; /* rather inefficient */
+ return mem;
+#endif
+ }
+
+ mem = _do_calloc(bytes);
+
+ trace = __malloc_trace;
+ if (trace != NULL)
+ (*trace)(bytes, RETURN_ADDRESS (0), mem);
+
+ return mem;
+}
+
+#ifndef _LIBC
+
+Void_t**
+public_iCALLOc(size_t n, size_t elem_size, Void_t** chunks)
+{
+ mstate ar_ptr;
+ Void_t** m;
+
+ arena_get(ar_ptr, n*elem_size);
+ if(!ar_ptr)
+ return 0;
+
+ m = _int_icalloc(ar_ptr, n, elem_size, chunks);
+ (void)mutex_unlock(&ar_ptr->mutex);
+ return m;
+}
+
+Void_t**
+public_iCOMALLOc(size_t n, size_t sizes[], Void_t** chunks)
+{
+ mstate ar_ptr;
+ Void_t** m;
+
+ arena_get(ar_ptr, 0);
+ if(!ar_ptr)
+ return 0;
+
+ m = _int_icomalloc(ar_ptr, n, sizes, chunks);
+ (void)mutex_unlock(&ar_ptr->mutex);
+ return m;
+}
+
+void
+public_cFREe(Void_t* m)
+{
+ public_fREe(m);
+}
+
+#endif /* _LIBC */
+
+int
+public_mTRIm(size_t s)
+{
+ int result = 0;
+
+ if(__malloc_initialized < 0)
+ ptmalloc_init ();
+
+ mstate ar_ptr = &main_arena;
+ do
+ {
+ (void) mutex_lock (&ar_ptr->mutex);
+ result |= mTRIm (ar_ptr, s);
+ (void) mutex_unlock (&ar_ptr->mutex);
+
+ ar_ptr = ar_ptr->next;
+ }
+ while (ar_ptr != &main_arena);
+
+ return result;
+}
+
+size_t
+public_mUSABLe(Void_t* m)
+{
+ size_t result;
+
+ result = mUSABLe(m);
+ return result;
+}
+
+void
+public_mSTATs()
+{
+ mSTATs();
+}
+
+struct mallinfo public_mALLINFo()
+{
+ struct mallinfo m;
+
+ if(__malloc_initialized < 0)
+ ptmalloc_init ();
+ (void)mutex_lock(&main_arena.mutex);
+ m = mALLINFo(&main_arena);
+ (void)mutex_unlock(&main_arena.mutex);
+ return m;
+}
+
+int
+public_mALLOPt(int p, int v)
+{
+ int result;
+ result = mALLOPt(p, v);
+ return result;
+}
+
+/*------------------------ Intermediate helpers. ---------------------------*/
+
+static Void_t*
+#if __STD_C
+_do_malloc(size_t bytes)
+#else
+_do_malloc(bytes)
+size_t bytes;
+#endif
+{
+ mstate ar_ptr;
+ Void_t *victim;
+
arena_get(ar_ptr, bytes);
if(!ar_ptr)
return 0;
@@ -3574,22 +3918,18 @@ public_mALLOc(size_t bytes)
ar_ptr == arena_for_chunk(mem2chunk(victim)));
return victim;
}
-#ifdef libc_hidden_def
-libc_hidden_def(public_mALLOc)
-#endif
-void
-public_fREe(Void_t* mem)
+static void
+#if __STD_C
+_do_free(Void_t* mem)
+#else
+_do_free(mem)
+Void_t* mem;
+#endif
{
mstate ar_ptr;
mchunkptr p; /* chunk corresponding to mem */
- void (*hook) (__malloc_ptr_t, __const __malloc_ptr_t) = __free_hook;
- if (hook != NULL) {
- (*hook)(mem, RETURN_ADDRESS (0));
- return;
- }
-
if (mem == 0) /* free(0) has no effect */
return;
@@ -3625,12 +3965,14 @@ public_fREe(Void_t* mem)
_int_free(ar_ptr, mem);
(void)mutex_unlock(&ar_ptr->mutex);
}
-#ifdef libc_hidden_def
-libc_hidden_def (public_fREe)
-#endif
-Void_t*
-public_rEALLOc(Void_t* oldmem, size_t bytes)
+static Void_t*
+#if __STD_C
+_do_realloc(Void_t* oldmem, size_t bytes)
+#else
+_do_realloc(oldmem, bytes)
+Void_t* oldmem; size_t bytes;
+#endif
{
mstate ar_ptr;
INTERNAL_SIZE_T nb; /* padded request size */
@@ -3640,18 +3982,6 @@ public_rEALLOc(Void_t* oldmem, size_t by
Void_t* newp; /* chunk to return */
- __malloc_ptr_t (*hook) (__malloc_ptr_t, size_t, __const __malloc_ptr_t) =
- __realloc_hook;
- if (hook != NULL)
- return (*hook)(oldmem, bytes, RETURN_ADDRESS (0));
-
-#if REALLOC_ZERO_BYTES_FREES
- if (bytes == 0 && oldmem != NULL) { public_fREe(oldmem); return 0; }
-#endif
-
- /* realloc of null is supposed to be same as malloc */
- if (oldmem == 0) return public_mALLOc(bytes);
-
oldp = mem2chunk(oldmem);
oldsize = chunksize(oldp);
@@ -3680,7 +4010,7 @@ public_rEALLOc(Void_t* oldmem, size_t by
/* Note the extra SIZE_SZ overhead. */
if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */
/* Must alloc, copy, free. */
- newmem = public_mALLOc(bytes);
+ newmem = _do_malloc(bytes);
if (newmem == 0) return 0; /* propagate failure */
MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
munmap_chunk(oldp);
@@ -3714,7 +4044,7 @@ public_rEALLOc(Void_t* oldmem, size_t by
if (newp == NULL)
{
/* Try harder to allocate memory in other arenas. */
- newp = public_mALLOc(bytes);
+ newp = _do_malloc(bytes);
if (newp != NULL)
{
MALLOC_COPY (newp, oldmem, oldsize - 2 * SIZE_SZ);
@@ -3735,24 +4065,20 @@ public_rEALLOc(Void_t* oldmem, size_t by
return newp;
}
-#ifdef libc_hidden_def
-libc_hidden_def (public_rEALLOc)
-#endif
-Void_t*
-public_mEMALIGn(size_t alignment, size_t bytes)
+static Void_t*
+#if __STD_C
+_do_memalign(size_t alignment, size_t bytes)
+#else
+_do_memalign(alignment, bytes)
+size_t alignment; size_t bytes;
+#endif
{
mstate ar_ptr;
Void_t *p;
- __malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, size_t,
- __const __malloc_ptr_t)) =
- __memalign_hook;
- if (hook != NULL)
- return (*hook)(alignment, bytes, RETURN_ADDRESS (0));
-
/* If need less alignment than we give anyway, just relay to malloc */
- if (alignment <= MALLOC_ALIGNMENT) return public_mALLOc(bytes);
+ if (alignment <= MALLOC_ALIGNMENT) return _do_malloc(bytes);
/* Otherwise, ensure that it is at least a minimum chunk size */
if (alignment < MINSIZE) alignment = MINSIZE;
@@ -3787,12 +4113,14 @@ public_mEMALIGn(size_t alignment, size_t
ar_ptr == arena_for_chunk(mem2chunk(p)));
return p;
}
-#ifdef libc_hidden_def
-libc_hidden_def (public_mEMALIGn)
-#endif
-Void_t*
-public_vALLOc(size_t bytes)
+static Void_t*
+#if __STD_C
+_do_valloc(size_t bytes)
+#else
+_do_valloc(bytes)
+size_t bytes;
+#endif
{
mstate ar_ptr;
Void_t *p;
@@ -3800,12 +4128,6 @@ public_vALLOc(size_t bytes)
if(__malloc_initialized < 0)
ptmalloc_init ();
- __malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, size_t,
- __const __malloc_ptr_t)) =
- __memalign_hook;
- if (hook != NULL)
- return (*hook)(mp_.pagesize, bytes, RETURN_ADDRESS (0));
-
arena_get(ar_ptr, bytes + mp_.pagesize + MINSIZE);
if(!ar_ptr)
return 0;
@@ -3814,8 +4136,13 @@ public_vALLOc(size_t bytes)
return p;
}
-Void_t*
-public_pVALLOc(size_t bytes)
+static Void_t*
+#if __STD_C
+_do_pvalloc(size_t bytes)
+#else
+_do_pvalloc(bytes)
+size_t bytes;
+#endif
{
mstate ar_ptr;
Void_t *p;
@@ -3823,56 +4150,27 @@ public_pVALLOc(size_t bytes)
if(__malloc_initialized < 0)
ptmalloc_init ();
- __malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, size_t,
- __const __malloc_ptr_t)) =
- __memalign_hook;
- if (hook != NULL)
- return (*hook)(mp_.pagesize,
- (bytes + mp_.pagesize - 1) & ~(mp_.pagesize - 1),
- RETURN_ADDRESS (0));
-
arena_get(ar_ptr, bytes + 2*mp_.pagesize + MINSIZE);
p = _int_pvalloc(ar_ptr, bytes);
(void)mutex_unlock(&ar_ptr->mutex);
return p;
}
-Void_t*
-public_cALLOc(size_t n, size_t elem_size)
+static Void_t*
+#if __STD_C
+_do_calloc(INTERNAL_SIZE_T bytes)
+#else
+_do_calloc(bytes)
+INTERNAL_SIZE_T bytes;
+#endif
{
mstate av;
mchunkptr oldtop, p;
- INTERNAL_SIZE_T bytes, sz, csz, oldtopsize;
+ INTERNAL_SIZE_T sz, csz, oldtopsize;
Void_t* mem;
unsigned long clearsize;
unsigned long nclears;
INTERNAL_SIZE_T* d;
- __malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, __const __malloc_ptr_t)) =
- __malloc_hook;
-
- /* size_t is unsigned so the behavior on overflow is defined. */
- bytes = n * elem_size;
-#define HALF_INTERNAL_SIZE_T \
- (((INTERNAL_SIZE_T) 1) << (8 * sizeof (INTERNAL_SIZE_T) / 2))
- if (__builtin_expect ((n | elem_size) >= HALF_INTERNAL_SIZE_T, 0)) {
- if (elem_size != 0 && bytes / elem_size != n) {
- MALLOC_FAILURE_ACTION;
- return 0;
- }
- }
-
- if (hook != NULL) {
- sz = bytes;
- mem = (*hook)(sz, RETURN_ADDRESS (0));
- if(mem == 0)
- return 0;
-#ifdef HAVE_MEMCPY
- return memset(mem, 0, sz);
-#else
- while(sz > 0) ((char*)mem)[--sz] = 0; /* rather inefficient */
- return mem;
-#endif
- }
sz = bytes;
@@ -3978,104 +4276,6 @@ public_cALLOc(size_t n, size_t elem_size
return mem;
}
-
-#ifndef _LIBC
-
-Void_t**
-public_iCALLOc(size_t n, size_t elem_size, Void_t** chunks)
-{
- mstate ar_ptr;
- Void_t** m;
-
- arena_get(ar_ptr, n*elem_size);
- if(!ar_ptr)
- return 0;
-
- m = _int_icalloc(ar_ptr, n, elem_size, chunks);
- (void)mutex_unlock(&ar_ptr->mutex);
- return m;
-}
-
-Void_t**
-public_iCOMALLOc(size_t n, size_t sizes[], Void_t** chunks)
-{
- mstate ar_ptr;
- Void_t** m;
-
- arena_get(ar_ptr, 0);
- if(!ar_ptr)
- return 0;
-
- m = _int_icomalloc(ar_ptr, n, sizes, chunks);
- (void)mutex_unlock(&ar_ptr->mutex);
- return m;
-}
-
-void
-public_cFREe(Void_t* m)
-{
- public_fREe(m);
-}
-
-#endif /* _LIBC */
-
-int
-public_mTRIm(size_t s)
-{
- int result = 0;
-
- if(__malloc_initialized < 0)
- ptmalloc_init ();
-
- mstate ar_ptr = &main_arena;
- do
- {
- (void) mutex_lock (&ar_ptr->mutex);
- result |= mTRIm (ar_ptr, s);
- (void) mutex_unlock (&ar_ptr->mutex);
-
- ar_ptr = ar_ptr->next;
- }
- while (ar_ptr != &main_arena);
-
- return result;
-}
-
-size_t
-public_mUSABLe(Void_t* m)
-{
- size_t result;
-
- result = mUSABLe(m);
- return result;
-}
-
-void
-public_mSTATs()
-{
- mSTATs();
-}
-
-struct mallinfo public_mALLINFo()
-{
- struct mallinfo m;
-
- if(__malloc_initialized < 0)
- ptmalloc_init ();
- (void)mutex_lock(&main_arena.mutex);
- m = mALLINFo(&main_arena);
- (void)mutex_unlock(&main_arena.mutex);
- return m;
-}
-
-int
-public_mALLOPt(int p, int v)
-{
- int result;
- result = mALLOPt(p, v);
- return result;
-}
-
/*
------------------------------ malloc ------------------------------
*/
@@ -5963,8 +6163,9 @@ __posix_memalign (void **memptr, size_t
{
void *mem;
__malloc_ptr_t (*hook) __MALLOC_PMT ((size_t, size_t,
- __const __malloc_ptr_t)) =
- __memalign_hook;
+ __const __malloc_ptr_t));
+ void (*trace) __MALLOC_PMT ((size_t, size_t,
+ __const __malloc_ptr_t, __malloc_ptr_t));
/* Test whether the SIZE argument is valid. It must be a power of
two multiple of sizeof (void *). */
@@ -5973,12 +6174,16 @@ __posix_memalign (void **memptr, size_t
|| alignment == 0)
return EINVAL;
- /* Call the hook here, so that caller is posix_memalign's caller
- and not posix_memalign itself. */
+ hook = __memalign_hook;
if (hook != NULL)
mem = (*hook)(alignment, size, RETURN_ADDRESS (0));
- else
- mem = public_mEMALIGn (alignment, size);
+ else {
+ mem = _do_memalign (alignment, size);
+
+ trace = __memalign_trace;
+ if (trace != NULL)
+ (*trace)(alignment, size, RETURN_ADDRESS (0), mem);
+ }
if (mem != NULL) {
*memptr = mem;
Index: malloc/malloc.h
===================================================================
--- malloc/malloc.h (revision 226481)
+++ malloc/malloc.h (working copy)
@@ -153,18 +153,33 @@ extern int malloc_set_state __MALLOC_P (
the application provides the preferred way to set up the hook
pointers. */
extern void (*__malloc_initialize_hook) __MALLOC_PMT ((void));
+
/* Hooks for debugging and user-defined versions. */
-extern void (*__free_hook) __MALLOC_PMT ((void *__ptr,
+extern void (*__free_hook) __MALLOC_PMT ((void *__oldptr,
__const __malloc_ptr_t));
extern void *(*__malloc_hook) __MALLOC_PMT ((size_t __size,
__const __malloc_ptr_t));
-extern void *(*__realloc_hook) __MALLOC_PMT ((void *__ptr, size_t __size,
+extern void *(*__realloc_hook) __MALLOC_PMT ((void *__oldptr, size_t __size,
__const __malloc_ptr_t));
extern void *(*__memalign_hook) __MALLOC_PMT ((size_t __alignment,
size_t __size,
__const __malloc_ptr_t));
extern void (*__after_morecore_hook) __MALLOC_PMT ((void));
+/* Additional post-processing hooks. */
+extern void (*__free_trace) __MALLOC_PMT ((void *__oldptr,
+ __const __malloc_ptr_t));
+extern void (*__malloc_trace) __MALLOC_PMT ((size_t __size,
+ __const __malloc_ptr_t,
+ void *__ptr));
+extern void (*__realloc_trace) __MALLOC_PMT ((void *__oldptr, size_t __size,
+ __const __malloc_ptr_t,
+ void *__ptr));
+extern void (*__memalign_trace) __MALLOC_PMT ((size_t __alignment,
+ size_t __size,
+ __const __malloc_ptr_t,
+ void *__ptr));
+
/* Activate a standard set of debugging hooks. */
extern void __malloc_check_init __MALLOC_P ((void));
Index: malloc/Versions
===================================================================
--- malloc/Versions (revision 226481)
+++ malloc/Versions (working copy)
@@ -55,6 +55,10 @@ libc {
# p*
posix_memalign;
}
+ GLIBC_2.10 {
+ # interface of malloc functions
+ __free_trace; __malloc_trace; __realloc_trace; __memalign_trace;
+ }
GLIBC_PRIVATE {
# Internal startup hook for libpthread.
__libc_malloc_pthread_startup;
Index: Versions.def
===================================================================
--- Versions.def (revision 226481)
+++ Versions.def (working copy)
@@ -25,6 +25,7 @@ libc {
GLIBC_2.6
GLIBC_2.7
GLIBC_2.8
+ GLIBC_2.10
%ifdef USE_IN_LIBIO
HURD_CTHREADS_0.3
%endif
Index: manual/memory.texi
===================================================================
--- manual/memory.texi (revision 226481)
+++ manual/memory.texi (working copy)
@@ -855,6 +855,24 @@ the memory consumption of the program.
@comment malloc.h
@comment GNU
+@defvar __malloc_trace
+The value of this variable is a pointer to the function that
+@code{malloc} calls at the conclusion whenever it is called. You should
+define this function to look like @code{malloc} with additional two
+arguments; that is, like:
+
+@smallexample
+void *@var{function} (size_t @var{size}, const void *@var{caller}, void *@var{ptr})
+@end smallexample
+
+The value of @var{caller} is the return address found on the stack when
+the @code{malloc} function was called. The value of @var{ptr} is one
+@code{malloc} will return. This hook lets you trace @code{malloc} calls
+in a thread-safe manner.
+@end defvar
+
+@comment malloc.h
+@comment GNU
@defvar __realloc_hook
The value of this variable is a pointer to function that @code{realloc}
uses whenever it is called. You should define this function to look
@@ -871,6 +889,26 @@ memory consumption of the program.
@comment malloc.h
@comment GNU
+@defvar __realloc_trace
+The value of this variable is a pointer to function that @code{realloc}
+calls at the conclusion whenever it is called (note however, that if the
+arguments passed to @code{realloc} imply the semantics of @code{malloc}
+or @code{free}, then @code{__malloc_trace} or @code{__free_trace}
+respectively is called instead). You should define this function to look
+like @code{realloc} with additional two arguments; that is, like:
+
+@smallexample
+void *@var{function} (void *@var{oldptr}, size_t @var{size}, const void *@var{caller}, void *@var{ptr})
+@end smallexample
+
+The value of @var{caller} is the return address found on the stack when
+the @code{realloc} function was called. The value of @var{ptr} is one
+@code{realloc} will return. This hook lets you trace @code{malloc} calls
+in a thread-safe manner.
+@end defvar
+
+@comment malloc.h
+@comment GNU
@defvar __free_hook
The value of this variable is a pointer to function that @code{free}
uses whenever it is called. You should define this function to look
@@ -887,6 +925,23 @@ memory consumption of the program.
@comment malloc.h
@comment GNU
+@defvar __free_trace
+The value of this variable is a pointer to function that @code{free}
+calls at the conclusion whenever it is called. You should define this
+function to look like @code{free} with an additional argument; that is,
+like:
+
+@smallexample
+void @var{function} (void *@var{oldptr}, const void *@var{caller})
+@end smallexample
+
+The value of @var{caller} is the return address found on the stack when
+the @code{free} function was called. This hook lets you trace @code{free}
+calls in a thread-safe manner.
+@end defvar
+
+@comment malloc.h
+@comment GNU
@defvar __memalign_hook
The value of this variable is a pointer to function that @code{memalign}
uses whenever it is called. You should define this function to look
@@ -901,6 +956,24 @@ the @code{memalign} function was called.
memory consumption of the program.
@end defvar
+@comment malloc.h
+@comment GNU
+@defvar __memalign_trace
+The value of this variable is a pointer to function that @code{memalign}
+calls at the conclusion whenever it is called. You should define this
+function to look like @code{memalign} with additional two arguments; that
+is, like:
+
+@smallexample
+void *@var{function} (size_t @var{alignment}, size_t @var{size}, const void *@var{caller}, void *@var{ptr})
+@end smallexample
+
+The value of @var{caller} is the return address found on the stack when
+the @code{memalign} function was called. The value of @var{ptr} is one
+@code{memalign} will return. This hook lets you trace @code{memalign}
+calls in a thread-safe manner.
+@end defvar
+
You must make sure that the function you install as a hook for one of
these functions does not call that function recursively without restoring
the old value of the hook first! Otherwise, your program will get stuck