From: Willy Tarreau Date: Wed, 28 Oct 2015 14:23:51 +0000 (+0100) Subject: DEBUG/MEDIUM: memory: add optional control pool memory operations X-Git-Tag: v1.7-dev1~67 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=de30a684cab39db61de1101506b8676479dcd85a;p=thirdparty%2Fhaproxy.git DEBUG/MEDIUM: memory: add optional control pool memory operations When DEBUG_MEMORY_POOLS is used, we now use the link pointer at the end of the pool to store a pointer to the pool, and to control it during pool_free2() in order to serve four purposes : - at any instant we can know what pool an object was allocated from when examining memory, hence how we should possibly decode it ; - it serves to detect double free when they happen, as the pointer cannot be valid after the element is linked into the pool ; - it serves to detect if an element is released in the wrong pool ; - it serves as a canary, to detect if some buffers experienced an overflow before being release. All these elements will definitely help better troubleshoot strange situations, or at least confirm that certain conditions did not happen. --- diff --git a/include/common/memory.h b/include/common/memory.h index bbac58d49a..410c97ffcf 100644 --- a/include/common/memory.h +++ b/include/common/memory.h @@ -124,6 +124,10 @@ static inline void *pool_get_first(struct pool_head *pool) if ((p = pool->free_list) != NULL) { pool->free_list = *POOL_LINK(pool, p); pool->used++; +#ifdef DEBUG_MEMORY_POOLS + /* keep track of where the element was allocated from */ + *POOL_LINK(pool, p) = (void *)pool; +#endif } return p; } @@ -154,8 +158,16 @@ static inline void *pool_alloc2(struct pool_head *pool) void *p; p = pool_alloc_dirty(pool); - if (p && mem_poison_byte >= 0) +#ifdef DEBUG_MEMORY_POOLS + if (p) { + /* keep track of where the element was allocated from */ + *POOL_LINK(pool, p) = (void *)pool; + } +#endif + if (p && mem_poison_byte >= 0) { memset(p, mem_poison_byte, pool->size); + } + return p; } @@ -171,6 +183,11 @@ static inline void *pool_alloc2(struct pool_head *pool) static inline void pool_free2(struct pool_head *pool, void *ptr) { if (likely(ptr != NULL)) { +#ifdef DEBUG_MEMORY_POOLS + /* we'll get late corruption if we refill to the wrong pool or double-free */ + if (*POOL_LINK(pool, ptr) != (void *)pool) + *(int *)0 = 0; +#endif *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 0363f36d8f..691e1e34a3 100644 --- a/src/memory.c +++ b/src/memory.c @@ -116,6 +116,10 @@ void *pool_refill_alloc(struct pool_head *pool, unsigned int avail) pool->free_list = ptr; } pool->used++; +#ifdef DEBUG_MEMORY_POOLS + /* keep track of where the element was allocated from */ + *POOL_LINK(pool, ptr) = (void *)pool; +#endif return ptr; }