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;
|
st_table *table = (st_table *)data;
|
||||||
|
|
||||||
|
if (!rb_gc_pointer_to_heap_p(key)) {
|
||||||
|
return ST_DELETE;
|
||||||
|
}
|
||||||
|
|
||||||
if (key != rb_gc_location(key)) {
|
if (key != rb_gc_location(key)) {
|
||||||
DURING_GC_COULD_MALLOC_REGION_START();
|
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);
|
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:
|
* call-seq:
|
||||||
* ObjectSpace._id2ref(object_id) -> an_object
|
* 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);
|
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_internal_object_p(VALUE obj);
|
||||||
int rb_objspace_garbage_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(
|
void rb_objspace_each_objects(
|
||||||
int (*callback)(void *start, void *end, size_t stride, void *data),
|
int (*callback)(void *start, void *end, size_t stride, void *data),
|
||||||
|
@ -305,6 +305,29 @@ class TestObjSpace < Test::Unit::TestCase
|
|||||||
RUBY
|
RUBY
|
||||||
end
|
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
|
def test_dump_flags
|
||||||
# Ensure that the fstring is promoted to old generation
|
# Ensure that the fstring is promoted to old generation
|
||||||
4.times { GC.start }
|
4.times { GC.start }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user