]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
DEBUG/MEDIUM: memory: add optional control pool memory operations
authorWilly Tarreau <w@1wt.eu>
Wed, 28 Oct 2015 14:23:51 +0000 (15:23 +0100)
committerWilly Tarreau <w@1wt.eu>
Wed, 28 Oct 2015 14:28:05 +0000 (15:28 +0100)
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.

include/common/memory.h
src/memory.c

index bbac58d49a111cc3a78b584592443ca2d0caa2fb..410c97ffcfcb4fe0a4cf54bd1d9053b7b70c7633 100644 (file)
@@ -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--;
index 0363f36d8fb965497df6cb71d3f67b04f68f98f5..691e1e34a362857ac2bc8785fb1b1bba5908ff8e 100644 (file)
@@ -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;
 }