Unpoison page->freelist before trying to assert on it

Otherwise trying to deref the pointer can cause an ASAN crash, even
though the only reason we're dereferencing it is so that we can assert
on it.
This commit is contained in:
KJ Tsanaktsidis 2024-09-21 21:11:27 +10:00
parent 95d26ee41e
commit 02b36f7572
Notes: git 2024-09-23 00:12:11 +00:00
2 changed files with 32 additions and 7 deletions

View File

@ -788,7 +788,9 @@ heap_page_in_global_empty_pages_pool(rb_objspace_t *objspace, struct heap_page *
GC_ASSERT(page->slot_size == 0);
GC_ASSERT(page->size_pool == NULL);
GC_ASSERT(page->free_slots == 0);
GC_ASSERT(page->freelist == NULL);
asan_unpoisoning_memory_region(&page->freelist, sizeof(&page->freelist)) {
GC_ASSERT(page->freelist == NULL);
}
return true;
}
@ -1177,12 +1179,6 @@ tick(void)
#define MEASURE_LINE(expr) expr
#endif /* USE_TICK_T */
#define asan_unpoisoning_object(obj) \
for (void *poisoned = asan_unpoison_object_temporary(obj), \
*unpoisoning = &poisoned; /* flag to loop just once */ \
unpoisoning; \
unpoisoning = asan_poison_object_restore(obj, poisoned))
#define FL_CHECK2(name, x, pred) \
((RGENGC_CHECK_MODE && SPECIAL_CONST_P(x)) ? \
(rb_bug(name": SPECIAL_CONST (%p)", (void *)(x)), 0) : (pred))

View File

@ -206,6 +206,35 @@ asan_poison_object_restore(VALUE obj, void *ptr)
return NULL;
}
#define asan_unpoisoning_object(obj) \
for (void *poisoned = asan_unpoison_object_temporary(obj), \
*unpoisoning = &poisoned; /* flag to loop just once */ \
unpoisoning; \
unpoisoning = asan_poison_object_restore(obj, poisoned))
static inline void *
asan_unpoison_memory_region_temporary(void *ptr, size_t len)
{
void *poisoned_ptr = __asan_region_is_poisoned(ptr, len);
asan_unpoison_memory_region(ptr, len, false);
return poisoned_ptr;
}
static inline void *
asan_poison_memory_region_restore(void *ptr, size_t len, void *poisoned_ptr)
{
if (poisoned_ptr) {
asan_poison_memory_region(ptr, len);
}
return NULL;
}
#define asan_unpoisoning_memory_region(ptr, len) \
for (void *poisoned = asan_unpoison_memory_region_temporary(ptr, len), \
*unpoisoning = &poisoned; /* flag to loop just once */ \
unpoisoning; \
unpoisoning = asan_poison_memory_region_restore(ptr, len, poisoned))
/**
* Checks if the given pointer is on an ASAN fake stack. If so, it returns the