Check whether object is valid in allocation_info_tracer_compact
When reference updating ObjectSpace.trace_object_allocations, we need to check whether the object is valid or not because it does not mark the object so the object may be dead. This can cause a segmentation fault if the object is on a free heap page. For example, the following script crashes: require "objspace" objs = [] ObjectSpace.trace_object_allocations do 1_000_000.times do objs << Object.new end end objs = nil # Free pages that the objs were on GC.start # Run compaction and check that it doesn't crash GC.compact
This commit is contained in:
parent
960f971ac8
commit
516a6cd1ad
Notes:
git
2024-12-16 17:24:43 +00:00
@ -194,6 +194,10 @@ allocation_info_tracer_compact_update_object_table_i(st_data_t key, st_data_t va
|
||||
{
|
||||
st_table *table = (st_table *)data;
|
||||
|
||||
if (!rb_gc_pointer_to_heap_p(key)) {
|
||||
return ST_DELETE;
|
||||
}
|
||||
|
||||
if (key != rb_gc_location(key)) {
|
||||
DURING_GC_COULD_MALLOC_REGION_START();
|
||||
{
|
||||
|
6
gc.c
6
gc.c
@ -1724,6 +1724,12 @@ rb_objspace_garbage_object_p(VALUE obj)
|
||||
return rb_gc_impl_garbage_object_p(rb_gc_get_objspace(), obj);
|
||||
}
|
||||
|
||||
bool
|
||||
rb_gc_pointer_to_heap_p(VALUE obj)
|
||||
{
|
||||
return rb_gc_impl_pointer_to_heap_p(rb_gc_get_objspace(), (void *)obj);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* ObjectSpace._id2ref(object_id) -> an_object
|
||||
|
@ -227,6 +227,7 @@ void rb_objspace_reachable_objects_from(VALUE obj, void (func)(VALUE, void *), v
|
||||
void rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE, void *), void *data);
|
||||
int rb_objspace_internal_object_p(VALUE obj);
|
||||
int rb_objspace_garbage_object_p(VALUE obj);
|
||||
bool rb_gc_pointer_to_heap_p(VALUE obj);
|
||||
|
||||
void rb_objspace_each_objects(
|
||||
int (*callback)(void *start, void *end, size_t stride, void *data),
|
||||
|
@ -305,6 +305,29 @@ class TestObjSpace < Test::Unit::TestCase
|
||||
RUBY
|
||||
end
|
||||
|
||||
def test_trace_object_allocations_compaction_freed_pages
|
||||
omit "compaction is not supported on this platform" unless GC.respond_to?(:compact)
|
||||
|
||||
assert_normal_exit(<<~RUBY)
|
||||
require "objspace"
|
||||
|
||||
objs = []
|
||||
ObjectSpace.trace_object_allocations do
|
||||
1_000_000.times do
|
||||
objs << Object.new
|
||||
end
|
||||
end
|
||||
|
||||
objs = nil
|
||||
|
||||
# Free pages that the objs were on
|
||||
GC.start
|
||||
|
||||
# Run compaction and check that it doesn't crash
|
||||
GC.compact
|
||||
RUBY
|
||||
end
|
||||
|
||||
def test_dump_flags
|
||||
# Ensure that the fstring is promoted to old generation
|
||||
4.times { GC.start }
|
||||
|
Loading…
x
Reference in New Issue
Block a user