ruby-changes:55209
From: tenderlove <ko1@a...>
Date: Wed, 3 Apr 2019 04:13:18 +0900 (JST)
Subject: [ruby-changes:55209] tenderlove:r67416 (trunk): Poison / verify the freelist
tenderlove 2019-04-03 04:13:07 +0900 (Wed, 03 Apr 2019) New Revision: 67416 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=67416 Log: Poison / verify the freelist This commit just adds poisoning around the freelist to help debugging. Also verify that the freelist only contains T_NONE objects when checking the heap integrity Modified files: trunk/gc.c Index: gc.c =================================================================== --- gc.c (revision 67415) +++ gc.c (revision 67416) @@ -1425,9 +1425,12 @@ static inline void https://github.com/ruby/ruby/blob/trunk/gc.c#L1425 heap_page_add_freeobj(rb_objspace_t *objspace, struct heap_page *page, VALUE obj) { RVALUE *p = (RVALUE *)obj; + unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); + p->as.free.flags = 0; p->as.free.next = page->freelist; page->freelist = p; + __asan_poison_memory_region(&page->freelist, sizeof(RVALUE*)); if (RGENGC_CHECK_MODE && !is_pointer_to_heap(objspace, p)) { rb_bug("heap_page_add_freeobj: %p is not rvalue.", (void *)p); @@ -1440,23 +1443,30 @@ heap_page_add_freeobj(rb_objspace_t *obj https://github.com/ruby/ruby/blob/trunk/gc.c#L1443 static inline void heap_add_freepage(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page) { + unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); if (page->freelist) { page->free_next = heap->free_pages; heap->free_pages = page; } + poison_memory_region(&page->freelist, sizeof(RVALUE*)); } #if GC_ENABLE_INCREMENTAL_MARK static inline int heap_add_poolpage(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *page) { + unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); if (page->freelist) { page->free_next = heap->pooled_pages; heap->pooled_pages = page; objspace->rincgc.pooled_slots += page->free_slots; + poison_memory_region(&page->freelist, sizeof(RVALUE*)); + return TRUE; } else { + poison_memory_region(&page->freelist, sizeof(RVALUE*)); + return FALSE; } } @@ -1585,6 +1595,7 @@ heap_page_allocate(rb_objspace_t *objspa https://github.com/ruby/ruby/blob/trunk/gc.c#L1595 } page->free_slots = limit; + poison_memory_region(&page->freelist, sizeof(RVALUE*)); return page; } @@ -1594,8 +1605,10 @@ heap_page_resurrect(rb_objspace_t *objsp https://github.com/ruby/ruby/blob/trunk/gc.c#L1605 struct heap_page *page = 0, *next; list_for_each_safe(&heap_tomb->pages, page, next, page_node) { + unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); if (page->freelist != NULL) { heap_unlink_page(objspace, heap_tomb, page); + poison_memory_region(&page->freelist, sizeof(RVALUE*)); return page; } } @@ -1754,8 +1767,10 @@ heap_get_freeobj_from_next_freepage(rb_o https://github.com/ruby/ruby/blob/trunk/gc.c#L1767 heap->using_page = page; GC_ASSERT(page->free_slots != 0); + unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); p = page->freelist; page->freelist = NULL; + poison_memory_region(&page->freelist, sizeof(RVALUE*)); page->free_slots = 0; unpoison_object((VALUE)p, true); return p; @@ -3745,11 +3760,15 @@ gc_sweep_start_heap(rb_objspace_t *objsp https://github.com/ruby/ruby/blob/trunk/gc.c#L3760 objspace->rincgc.pooled_slots = 0; #endif if (heap->using_page) { - RVALUE **p = &heap->using_page->freelist; + struct heap_page *page = heap->using_page; + unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); + + RVALUE **p = &page->freelist; while (*p) { p = &(*p)->as.free.next; } *p = heap->freelist; + poison_memory_region(&page->freelist, sizeof(RVALUE*)); heap->using_page = NULL; } heap->freelist = NULL; @@ -5445,6 +5464,19 @@ gc_verify_heap_pages_(rb_objspace_t *obj https://github.com/ruby/ruby/blob/trunk/gc.c#L5464 struct heap_page *page = 0; list_for_each(head, page, page_node) { + unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false); + RVALUE *p = page->freelist; + while(p) { + RVALUE *prev = p; + unpoison_object(p, false); + if (BUILTIN_TYPE(p) != T_NONE) { + fprintf(stderr, "freelist slot expected to be T_NONE but was: %s\n", obj_info((VALUE)p)); + } + p = p->as.free.next; + poison_object(prev); + } + poison_memory_region(&page->freelist, sizeof(RVALUE*)); + if (page->flags.has_remembered_objects == FALSE) { remembered_old_objects += gc_verify_heap_page(objspace, page, Qfalse); } -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/