summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNARUSE, Yui <naruse@airemix.jp>2023-03-23 08:11:23 +0900
committerNARUSE, Yui <naruse@airemix.jp>2023-03-23 08:11:23 +0900
commit400ccb16eefe4e21c4e3eacab4fd0f208fc5e151 (patch)
tree020e8dbf831e7f4bb7900c7d212a06c978178738
parentad6fe84dfa6935bd6e2c3ef3ee36bed4e8627d0b (diff)
downloadruby-400ccb16eefe4e21c4e3eacab4fd0f208fc5e151.tar.gz
merge revision(s) cb22d78354e201ca74eba68a8b4edefb593e6754: [Backport #19536]
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 --- shape.c | 2 +- test/ruby/test_gc_compact.rb | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-)
-rw-r--r--shape.c2
-rw-r--r--test/ruby/test_gc_compact.rb28
-rw-r--r--version.h2
3 files changed, 30 insertions, 2 deletions
diff --git a/shape.c b/shape.c
index f3150127ff..1dc08dcb60 100644
--- a/shape.c
+++ b/shape.c
@@ -463,6 +463,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;
}
@@ -476,7 +477,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:
diff --git a/test/ruby/test_gc_compact.rb b/test/ruby/test_gc_compact.rb
index 4d7bb8f7ae..d53e61d252 100644
--- a/test/ruby/test_gc_compact.rb
+++ b/test/ruby/test_gc_compact.rb
@@ -415,4 +415,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
diff --git a/version.h b/version.h
index 8c22e9e7a4..5154d1c62f 100644
--- a/version.h
+++ b/version.h
@@ -11,7 +11,7 @@
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
#define RUBY_VERSION_TEENY 1
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
-#define RUBY_PATCHLEVEL 45
+#define RUBY_PATCHLEVEL 46
#include "ruby/version.h"
#include "ruby/internal/abi.h"