From b0c5665f15c8539fc0c9d1ebdb605e83dd6c79ce Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 19 Oct 2017 15:59:04 +0800 Subject: [PATCH] heap: Fix race condition causing malloc() to fail under some conditions During a call to multi_heap_malloc(), if both these conditions were true: - That heap only has one block large enough for the allocation (this is always the case if the heap is unfragmented). - Another allocation is simultaneously occurring in the same heap. ... multi_heap_malloc() could incorrectly return NULL. This caused IDF heap_caps_malloc() and malloc() to also fail, particularly often if only one or two heaps had space for the allocation (otherwise heap_caps_malloc() fails over to the next heap). --- components/heap/multi_heap.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/components/heap/multi_heap.c b/components/heap/multi_heap.c index b0452f4c4e..cc621c0d88 100644 --- a/components/heap/multi_heap.c +++ b/components/heap/multi_heap.c @@ -337,12 +337,22 @@ void *multi_heap_malloc_impl(multi_heap_handle_t heap, size_t size) size_t best_size = SIZE_MAX; size = ALIGN_UP(size); - if (size == 0 || heap == NULL || heap->free_bytes < size) { + if (size == 0 || heap == NULL) { return NULL; } MULTI_HEAP_LOCK(heap->lock); + /* Note: this check must be done while holding the lock as both + malloc & realloc may temporarily shrink the free_bytes value + before they split a large block. This can result in false negatives, + especially if the heap is unfragmented. + */ + if (heap->free_bytes < size) { + MULTI_HEAP_UNLOCK(heap->lock); + return NULL; + } + /* Find best free block to perform the allocation in */ prev = &heap->first_block; for (heap_block_t *b = heap->first_block.next_free; b != NULL; b = b->next_free) {