From ed31bdfeee3396bd703ba432630bc31933a08feb Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Fri, 27 Aug 2021 09:37:51 -0400 Subject: [PATCH] Fix memory leak in Variable Width Allocation Force recycled objects could create a freelist for the page. At the start of sweeping we should append to the freelist to avoid permanently losing the slots on the freelist. --- gc.c | 50 +++++++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/gc.c b/gc.c index f7ce094669..7764daa18c 100644 --- a/gc.c +++ b/gc.c @@ -5534,6 +5534,30 @@ gc_mode_transition(rb_objspace_t *objspace, enum gc_mode mode) gc_mode_set(objspace, mode); } +static void +heap_page_freelist_append(struct heap_page *page, RVALUE *freelist) +{ + if (freelist) { + asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); + if (page->freelist) { + RVALUE *p = page->freelist; + asan_unpoison_object((VALUE)p, false); + while (p->as.free.next) { + RVALUE *prev = p; + p = p->as.free.next; + asan_poison_object((VALUE)prev); + asan_unpoison_object((VALUE)p, false); + } + p->as.free.next = freelist; + asan_poison_object((VALUE)p); + } + else { + page->freelist = freelist; + } + asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); + } +} + static void gc_sweep_start_heap(rb_objspace_t *objspace, rb_heap_t *heap) { @@ -5560,12 +5584,10 @@ gc_sweep_start(rb_objspace_t *objspace) rb_size_pool_t *size_pool = &size_pools[i]; #if USE_RVARGC - if (size_pool->freelist) { - size_pool->using_page->freelist = (RVALUE *)size_pool->freelist; - size_pool->freelist = 0; - } + heap_page_freelist_append(size_pool->using_page, size_pool->freelist); size_pool->using_page = NULL; + size_pool->freelist = NULL; #endif gc_sweep_start_heap(objspace, SIZE_POOL_EDEN_HEAP(size_pool)); @@ -8713,25 +8735,7 @@ rb_gc_ractor_newobj_cache_clear(rb_ractor_newobj_cache_t *newobj_cache) RVALUE *freelist = newobj_cache->freelist; RUBY_DEBUG_LOG("ractor using_page:%p freelist:%p", page, freelist); - if (page && freelist) { - asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); - if (page->freelist) { - RVALUE *p = page->freelist; - asan_unpoison_object((VALUE)p, false); - while (p->as.free.next) { - RVALUE *prev = p; - p = p->as.free.next; - asan_poison_object((VALUE)prev); - asan_unpoison_object((VALUE)p, false); - } - p->as.free.next = freelist; - asan_poison_object((VALUE)p); - } - else { - page->freelist = freelist; - } - asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); - } + heap_page_freelist_append(page, freelist); newobj_cache->using_page = NULL; newobj_cache->freelist = NULL;