]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
DEBUG: pools: report the data around the offending area in case of mismatch
authorWilly Tarreau <w@1wt.eu>
Fri, 12 Apr 2024 15:54:51 +0000 (17:54 +0200)
committerWilly Tarreau <w@1wt.eu>
Fri, 12 Apr 2024 16:01:55 +0000 (18:01 +0200)
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
src/pool.c

index bf7cb8d012811daf63d478f2fdbd93270ea5a9f6..66ad2927ed956aeb1fbf229298d01fbefd998981 100644 (file)
@@ -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 ******************/
index cc85faff317e7ef3ffadb4b69711c95c192fd07b..1fbbe5079c07169ea5c601de66b72039bb16bdf2 100644 (file)
@@ -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;