glibc: Patch for better Analysis of malloc issue The function __malloc_tcache_walk added in this patch provides information of entire heap memory chunk in the core file. This patch provides address and value of the memory chunk illegally written, which can help to understand and debug the issue. Used below CPP code for testing purpose. ============================================================================ typedef std::size_t Item; const std::size_t nItemsWanted = 64 / sizeof (Item); Item *const paItems1 = new Item [nItemsWanted]; { std::fill (paItems1, paItems1 + nItemsWanted, Item (0x8899AABBCCDDEEFF)); } delete [] paItems1; paItems1 [0] = 0x00214E414D544142; Item *const paItems3 = new Item [nItemsWanted]; Item *const paItems4 = new Item [nItemsWanted]; ============================================================================ This code fails and produce coredump below is the log of backtrace Without proposed patch: (gdb) bt #0 0x00007ff12b8f8407 in _GI__libc_malloc (bytes=64) at /usr/src/debug/glibc/2.27-r0/git/malloc/malloc.c:3068 #1 0x00007ff12c261b48 in operator new(unsigned long) () from /usr/lib/libstdc++.so.6 #2 0x000055c2db586645 in main () at /usr/src/debug/qtbase/5.6.2+gitAUTOINC+b4ada3f0d8-r0/Example-of-Buggy-Program-v2.cpp:22 (gdb) x/8gx e Value can't be converted to integer. With proposed patch: (gdb) bt #0 __malloc_tcache_walk (ptcache=0x55b28b3d0010, tc_idx=tc_idx@entry=3, e=e@entry=0x55b28b3e1e70) at /usr/src/debug/glibc/2.27-r0/git/malloc/malloc.c:2949 #1 0x00007f90e5abc53a in tcache_get (tc_idx=3) at /usr/src/debug/glibc/2.27-r0/git/malloc/malloc.c:2984 #2 _GI__libc_malloc (bytes=64) at /usr/src/debug/glibc/2.27-r0/git/malloc/malloc.c:3096 #3 0x00007f90e6425b48 in operator new(unsigned long) () from /usr/lib/libstdc++.so.6 #4 0x000055b28a44263b in main () at /usr/src/debug/qtbase/5.6.2+gitAUTOINC+b4ada3f0d8-r0/Example-of-Buggy-Program-v2.cpp:21 (gdb) x/8gx e 0x55b28b3e1e70: 0x00214e414d544142 0x000055b28b3d0010 0x55b28b3e1e80: 0x8899aabbccddeeff 0x8899aabbccddeeff 0x55b28b3e1e90: 0x8899aabbccddeeff 0x8899aabbccddeeff 0x55b28b3e1ea0: 0x8899aabbccddeeff 0x8899aabbccddeeff Signed-off-by: Bogdan Dragu Signed-off-by: Akash Hadke Upstream-Status: Pending --- --- a/malloc/malloc.c 2021-01-19 14:42:22.263863000 +0530 +++ b/malloc/malloc.c 2021-01-19 15:01:42.291811660 +0530 @@ -2924,6 +2924,25 @@ static __thread bool tcache_shutting_down = false; static __thread tcache_perthread_struct *tcache = NULL; +__thread size_t __malloc_tcache_t_dummy_count; + +const tcache_entry * +__malloc_tcache_walk +(const tcache_perthread_struct *ptcache, size_t tc_idx, const tcache_entry *e) +{ + const tcache_entry *const p0 = e->next; + + const tcache_entry * p = p0; + { + for (size_t i = 0; p && i < 4; ++i) + p = p->next; + } + + ++__malloc_tcache_t_dummy_count; + + return p0; +} + /* Caller must ensure that we know tc_idx is valid and there's room for more chunks. */ static __always_inline void @@ -2946,10 +2965,14 @@ static __always_inline void * tcache_get (size_t tc_idx) { - tcache_entry *e = tcache->entries[tc_idx]; assert (tc_idx < TCACHE_MAX_BINS); - assert (tcache->entries[tc_idx] > 0); - tcache->entries[tc_idx] = e->next; + tcache_entry *const e = tcache->entries[tc_idx]; + + tcache_entry *const e_next = (tcache_entry *) __malloc_tcache_walk (tcache, tc_idx, e); + assert (e_next == e->next); + + tcache->entries[tc_idx] = e_next; + --(tcache->counts[tc_idx]); e->key = NULL; return (void *) e;