From c0ee2d78d739c27891d4e230ef6ebc691806a03a Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 12 Apr 2024 17:54:51 +0200 Subject: [PATCH] DEBUG: pools: report the data around the offending area in case of mismatch When the integrity check fails, it's useful to get a dump of the area around the first faulty byte. That's what this patch does. For example it now shows this before reporting info about the tag itself: Contents around first corrupted address relative to pool item:. Contents around address 0xe4febc0792c0+40=0xe4febc0792e8: 0xe4febc0792c8 [80 75 56 d8 fe e4 00 00] [.uV.....] 0xe4febc0792d0 [a0 f7 23 a4 fe e4 00 00] [..#.....] 0xe4febc0792d8 [90 75 56 d8 fe e4 00 00] [.uV.....] 0xe4febc0792e0 [d9 93 fb ff fd ff ff ff] [........] 0xe4febc0792e8 [d9 93 fb ff ff ff ff ff] [........] 0xe4febc0792f0 [d9 93 fb ff ff ff ff ff] [........] 0xe4febc0792f8 [d9 93 fb ff ff ff ff ff] [........] 0xe4febc079300 [d9 93 fb ff ff ff ff ff] [........] This may be backported to 2.9 and maybe even 2.8 as it does help spot the cause of the memory corruption. --- include/haproxy/pool.h | 4 ++-- src/pool.c | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/include/haproxy/pool.h b/include/haproxy/pool.h index bf7cb8d01..66ad2927e 100644 --- a/include/haproxy/pool.h +++ b/include/haproxy/pool.h @@ -77,7 +77,7 @@ if (likely(!(pool_debugging & POOL_DBG_TAG))) \ break; \ if (*(typeof(pool)*)(((char *)__i) + __p->size) != __p) { \ - pool_inspect_item("tag mismatch on free()", pool, item, caller); \ + pool_inspect_item("tag mismatch on free()", __p, __i, caller, -1); \ ABORT_NOW(); \ } \ } while (0) @@ -126,7 +126,7 @@ void *pool_destroy(struct pool_head *pool); void pool_destroy_all(void); void *__pool_alloc(struct pool_head *pool, unsigned int flags); void __pool_free(struct pool_head *pool, void *ptr); -void pool_inspect_item(const char *msg, struct pool_head *pool, const void *item, const void *caller); +void pool_inspect_item(const char *msg, struct pool_head *pool, const void *item, const void *caller, ssize_t ofs); /****************** Thread-local cache management ******************/ diff --git a/src/pool.c b/src/pool.c index cc85faff3..1fbbe5079 100644 --- a/src/pool.c +++ b/src/pool.c @@ -496,7 +496,7 @@ void pool_check_pattern(struct pool_cache_head *pch, struct pool_head *pool, str u = ptr[ofs++]; while (ofs < size / sizeof(*ptr)) { if (unlikely(ptr[ofs] != u)) { - pool_inspect_item("cache corruption detected", pool, item, caller); + pool_inspect_item("cache corruption detected", pool, item, caller, ofs * sizeof(*ptr)); ABORT_NOW(); } ofs++; @@ -961,8 +961,12 @@ void pool_destroy_all() } } -/* carefully inspects an item upon fatal error and emit diagnostics */ -void pool_inspect_item(const char *msg, struct pool_head *pool, const void *item, const void *caller) +/* carefully inspects an item upon fatal error and emit diagnostics. + * If ofs < 0, no hint is provided regarding the content location. However if + * ofs >= 0, then we also try to inspect around that place where corruption + * was detected. + */ +void pool_inspect_item(const char *msg, struct pool_head *pool, const void *item, const void *caller, ssize_t ofs) { const struct pool_head *the_pool = NULL; @@ -979,6 +983,11 @@ void pool_inspect_item(const char *msg, struct pool_head *pool, const void *item " pool: %p ('%s', size %u, real %u, users %u)\n", item, pool, pool->name, pool->size, pool->alloc_sz, pool->users); + if (ofs >= 0) { + chunk_printf(&trash, "Contents around first corrupted address relative to pool item:.\n"); + dump_area_with_syms(&trash, item, item + ofs, NULL, NULL, NULL); + } + if (pool_debugging & POOL_DBG_TAG) { const void **pool_mark; struct pool_head *ph;