Fix gc_page_sweep when last bitmap plane is not used

Depending on alignment, the last bitmap plane may not used. Then it will
appear as if all of the objects on that plane is unmarked, which will
cause a buffer overrun when we try to free the object. This commit
changes the loop to calculate the number of planes used
(bitmap_plane_count).
This commit is contained in:
Peter Zhu 2022-05-04 09:50:48 -04:00
Родитель a41fbc2c95
Коммит 033e58cf2c
1 изменённых файлов: 8 добавлений и 3 удалений

11
gc.c
Просмотреть файл

@ -5405,8 +5405,6 @@ gc_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct gc_sweep_context
{ {
struct heap_page *sweep_page = ctx->page; struct heap_page *sweep_page = ctx->page;
int i;
uintptr_t p; uintptr_t p;
bits_t *bits, bitset; bits_t *bits, bitset;
@ -5429,6 +5427,13 @@ gc_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct gc_sweep_context
bits[BITMAP_INDEX(p) + page_rvalue_count / BITS_BITLENGTH] |= ~(((bits_t)1 << out_of_range_bits) - 1); bits[BITMAP_INDEX(p) + page_rvalue_count / BITS_BITLENGTH] |= ~(((bits_t)1 << out_of_range_bits) - 1);
} }
/* The last bitmap plane may not be used if the last plane does not have
* have enough space for the slot_size. In that case, the last plane must
* be skipped since none of the bits will be set. */
int bitmap_plane_count = CEILDIV(NUM_IN_PAGE(p) + page_rvalue_count, BITS_BITLENGTH);
GC_ASSERT(bitmap_plane_count == HEAP_PAGE_BITMAP_LIMIT - 1 ||
bitmap_plane_count == HEAP_PAGE_BITMAP_LIMIT);
// Skip out of range slots at the head of the page // Skip out of range slots at the head of the page
bitset = ~bits[0]; bitset = ~bits[0];
bitset >>= NUM_IN_PAGE(p); bitset >>= NUM_IN_PAGE(p);
@ -5437,7 +5442,7 @@ gc_sweep_page(rb_objspace_t *objspace, rb_heap_t *heap, struct gc_sweep_context
} }
p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE; p += (BITS_BITLENGTH - NUM_IN_PAGE(p)) * BASE_SLOT_SIZE;
for (i=1; i < HEAP_PAGE_BITMAP_LIMIT; i++) { for (int i = 1; i < bitmap_plane_count; i++) {
bitset = ~bits[i]; bitset = ~bits[i];
if (bitset) { if (bitset) {
gc_sweep_plane(objspace, heap, p, bitset, ctx); gc_sweep_plane(objspace, heap, p, bitset, ctx);