From 68dbd2426b738a32324c225a543a12908dafaf43 Mon Sep 17 00:00:00 2001 From: Paulo Andrade Date: Fri, 2 Oct 2015 11:10:04 -0300 Subject: [PATCH] Avoid corruption of free_list When a thread leaves, arena_thread_freeres is called, the malloc arena associated with the thread is added to the head of free_list, and free_list set to the arena of the exiting thread. A common problem can be described as: 1. thread "t1" uses arena "a" 2. thread "t2" uses arena "a" 3. "t1" exit, making: a->next_free = free_list; free_list = a; 4. "t2" exits, but since free_list == a, it ends with free_list->next_free = free_list; When a program has several short lived threads, and most commonly when there are more threads than arenas, one arena will end up being used by most threads, causing significant contention. --- malloc/arena.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/malloc/arena.c b/malloc/arena.c index b44e307..afe775b 100644 --- a/malloc/arena.c +++ b/malloc/arena.c @@ -935,8 +935,26 @@ arena_thread_freeres (void) if (a != NULL) { (void) mutex_lock (&list_lock); - a->next_free = free_list; - free_list = a; + /* Use other arenas before "a". */ + if (a == free_list) + free_list = free_list->next_free; + /* Insert "a" last in free_list. */ + if (free_list != NULL) + { + mstate b = free_list; + while (b->next_free != NULL) + { + /* Make sure to check if "a" is already in free_list. */ + if (b->next_free == a) + b->next_free = a->next_free; + else + b = b->next_free; + } + b->next_free = a; + } + else + free_list = a; + a->next_free = NULL; (void) mutex_unlock (&list_lock); } } -- 1.8.3.1