mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
Fix frozen status loss when moving objects
[Bug #19536] When objects are moved between size pools, their frozen status is lost in the shape. This will cause the frozen check to be bypassed when there is an inline cache. For example, the following script should raise a FrozenError, but doesn't on Ruby 3.2 and master. class A def add_ivars @a = @b = @c = @d = 1 end def set_a @a = 10 end end a = A.new a.add_ivars a.freeze b = A.new b.add_ivars b.set_a # Set the inline cache in set_a GC.verify_compaction_references(expand_heap: true, toward: :empty) a.set_a
This commit is contained in:
parent
dc28ccbb6d
commit
cb22d78354
Notes:
git
2023-03-18 13:07:32 +00:00
2 changed files with 29 additions and 1 deletions
2
shape.c
2
shape.c
|
@ -451,6 +451,7 @@ rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *dest_shap
|
|||
|
||||
switch ((enum shape_type)dest_shape->type) {
|
||||
case SHAPE_IVAR:
|
||||
case SHAPE_FROZEN:
|
||||
if (!next_shape->edges) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -464,7 +465,6 @@ rb_shape_traverse_from_new_root(rb_shape_t *initial_shape, rb_shape_t *dest_shap
|
|||
}
|
||||
break;
|
||||
case SHAPE_ROOT:
|
||||
case SHAPE_FROZEN:
|
||||
case SHAPE_CAPACITY_CHANGE:
|
||||
case SHAPE_INITIAL_CAPACITY:
|
||||
case SHAPE_T_OBJECT:
|
||||
|
|
|
@ -416,4 +416,32 @@ class TestGCCompact < Test::Unit::TestCase
|
|||
assert_include(ObjectSpace.dump(ary[0]), '"embedded":true')
|
||||
end;
|
||||
end
|
||||
|
||||
def test_moving_objects_between_size_pools_keeps_shape_frozen_status
|
||||
# [Bug #19536]
|
||||
assert_separately([], "#{<<~"begin;"}\n#{<<~"end;"}")
|
||||
begin;
|
||||
class A
|
||||
def add_ivars
|
||||
@a = @b = @c = @d = 1
|
||||
end
|
||||
|
||||
def set_a
|
||||
@a = 10
|
||||
end
|
||||
end
|
||||
|
||||
a = A.new
|
||||
a.add_ivars
|
||||
a.freeze
|
||||
|
||||
b = A.new
|
||||
b.add_ivars
|
||||
b.set_a # Set the inline cache in set_a
|
||||
|
||||
GC.verify_compaction_references(expand_heap: true, toward: :empty)
|
||||
|
||||
assert_raise(FrozenError) { a.set_a }
|
||||
end;
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue