From 1e26d35193efbb29239c710a4c46a64708643320 Mon Sep 17 00:00:00 2001 From: Carlos O'Donell Date: Thu, 28 Sep 2017 11:05:18 -0600 Subject: malloc: Fix tcache leak after thread destruction [BZ #22111] The malloc tcache added in 2.26 will leak all of the elements remaining in the cache and the cache structure itself when a thread exits. The defect is that we do not set tcache_shutting_down early enough, and the thread simply recreates the tcache and places the elements back onto a new tcache which is subsequently lost as the thread exits (unfreed memory). The fix is relatively simple, move the setting of tcache_shutting_down earlier in tcache_thread_freeres. We add a test case which uses mallinfo and some heuristics to look for unaccounted for memory usage between the start and end of a thread start/join loop. It is very reliable at detecting that there is a leak given the number of iterations. Without the fix the test will consume 122MiB of leaked memory. --- malloc/malloc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'malloc/malloc.c') diff --git a/malloc/malloc.c b/malloc/malloc.c index 1c2a0b0..d3fcadd 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -2916,7 +2916,7 @@ typedef struct tcache_perthread_struct tcache_entry *entries[TCACHE_MAX_BINS]; } tcache_perthread_struct; -static __thread char tcache_shutting_down = 0; +static __thread bool tcache_shutting_down = false; static __thread tcache_perthread_struct *tcache = NULL; /* Caller must ensure that we know tc_idx is valid and there's room @@ -2953,8 +2953,12 @@ tcache_thread_freeres (void) if (!tcache) return; + /* Disable the tcache and prevent it from being reinitialized. */ tcache = NULL; + tcache_shutting_down = true; + /* Free all of the entries and the tcache itself back to the arena + heap for coalescing. */ for (i = 0; i < TCACHE_MAX_BINS; ++i) { while (tcache_tmp->entries[i]) @@ -2966,8 +2970,6 @@ tcache_thread_freeres (void) } __libc_free (tcache_tmp); - - tcache_shutting_down = 1; } text_set_element (__libc_thread_subfreeres, tcache_thread_freeres); -- cgit v1.1