From ac421118db064273a71d5f94929c984a96425a54 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Wed, 28 Oct 2015 15:09:29 +0100 Subject: [PATCH] DEBUG/MEDIUM: memory: optionally protect free data in pools When debugging a core file, it's sometimes convenient to be able to visit the released entries in the pools (typically last released session). Unfortunately the first bytes of these entries are destroyed by the link elements of the pool. And of course, most structures have their most accessed elements at the beginning of the structure (typically flags). Let's add a build-time option DEBUG_MEMORY_POOLS which allocates an extra pointer in each pool to put the link at the end of each pool item instead of the beginning. --- include/common/memory.h | 13 +++++++++++-- src/memory.c | 14 ++++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/include/common/memory.h b/include/common/memory.h index af4e6534b..bbac58d49 100644 --- a/include/common/memory.h +++ b/include/common/memory.h @@ -34,6 +34,15 @@ #define MEM_F_SHARED 0 #endif +/* reserve an extra void* at the end of a pool for linking */ +#ifdef DEBUG_MEMORY_POOLS +#define POOL_EXTRA (sizeof(void *)) +#define POOL_LINK(pool, item) (void **)(((char *)item) + (pool->size)) +#else +#define POOL_EXTRA (0) +#define POOL_LINK(pool, item) ((void **)(item)) +#endif + struct pool_head { void **free_list; struct list list; /* list of all known pools */ @@ -113,7 +122,7 @@ static inline void *pool_get_first(struct pool_head *pool) void *p; if ((p = pool->free_list) != NULL) { - pool->free_list = *(void **)pool->free_list; + pool->free_list = *POOL_LINK(pool, p); pool->used++; } return p; @@ -162,7 +171,7 @@ static inline void *pool_alloc2(struct pool_head *pool) static inline void pool_free2(struct pool_head *pool, void *ptr) { if (likely(ptr != NULL)) { - *(void **)ptr= (void *)pool->free_list; + *POOL_LINK(pool, ptr) = (void *)pool->free_list; pool->free_list = (void *)ptr; pool->used--; } diff --git a/src/memory.c b/src/memory.c index d9cef64b6..0363f36d8 100644 --- a/src/memory.c +++ b/src/memory.c @@ -33,14 +33,16 @@ struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags) struct list *start; unsigned int align; - /* We need to store at least a (void *) in the chunks. Since we know + /* We need to store a (void *) at the end of the chunks. Since we know * that the malloc() function will never return such a small size, * let's round the size up to something slightly bigger, in order to * ease merging of entries. Note that the rounding is a power of two. + * This extra (void *) is not accounted for in the size computation + * so that the visible parts outside are not affected. */ align = 16; - size = (size + align - 1) & -align; + size = ((size + POOL_EXTRA + align - 1) & -align) - POOL_EXTRA; start = &pools; pool = NULL; @@ -99,7 +101,7 @@ void *pool_refill_alloc(struct pool_head *pool, unsigned int avail) if (pool->limit && pool->allocated >= pool->limit) return NULL; - ptr = MALLOC(pool->size); + ptr = MALLOC(pool->size + POOL_EXTRA); if (!ptr) { if (failed) return NULL; @@ -110,7 +112,7 @@ void *pool_refill_alloc(struct pool_head *pool, unsigned int avail) if (++pool->allocated > avail) break; - *(void **)ptr = (void *)pool->free_list; + *POOL_LINK(pool, ptr) = (void *)pool->free_list; pool->free_list = ptr; } pool->used++; @@ -129,7 +131,7 @@ void pool_flush2(struct pool_head *pool) next = pool->free_list; while (next) { temp = next; - next = *(void **)temp; + next = *POOL_LINK(pool, temp); pool->allocated--; FREE(temp); } @@ -158,7 +160,7 @@ void pool_gc2() while (next && (int)(entry->allocated - entry->used) > (int)entry->minavail) { temp = next; - next = *(void **)temp; + next = *POOL_LINK(entry, temp); entry->allocated--; FREE(temp); }