summaryrefslogtreecommitdiff
path: root/gc.c
diff options
context:
space:
mode:
authorPeter Zhu <peter@peterzhu.ca>2021-08-27 09:37:51 -0400
committerPeter Zhu <peter@peterzhu.ca>2021-08-27 10:13:32 -0400
commited31bdfeee3396bd703ba432630bc31933a08feb (patch)
tree776ee683f63297c5466910fa25b74d89355e1c3c /gc.c
parent3562c7ba332009ff9b0bd559ff8a65fe1bef2781 (diff)
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.
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/4786
Diffstat (limited to 'gc.c')
-rw-r--r--gc.c50
1 files changed, 27 insertions, 23 deletions
diff --git a/gc.c b/gc.c
index f7ce094669..7764daa18c 100644
--- a/gc.c
+++ b/gc.c
@@ -5535,6 +5535,30 @@ gc_mode_transition(rb_objspace_t *objspace, enum gc_mode 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)
{
heap->sweeping_page = list_top(&heap->pages, struct heap_page, page_node);
@@ -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;