summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Wu <XrXr@users.noreply.github.com>2022-04-27 12:23:52 -0400
committerAlan Wu <XrXr@users.noreply.github.com>2022-04-28 11:31:22 -0400
commitc416dbb3c700173d62c2d8381e3680b8aa4482ae (patch)
tree3a8a256a139cc4aeb54018a270eef2e4914131a6
parent0626e6f959ed740508ff2ec1f2ff4b7188fa821d (diff)
downloadruby-c416dbb3c700173d62c2d8381e3680b8aa4482ae.tar.gz
Add missing write barriers to Array#replace
Previously it made object references without using write barriers, creating GC inconsistencies. See: http://ci.rvm.jp/results/trunk-gc-asserts@phosphorus-docker/3925529
-rw-r--r--array.c6
-rw-r--r--test/ruby/test_array.rb8
2 files changed, 12 insertions, 2 deletions
diff --git a/array.c b/array.c
index 9bb767d79f..7b3f5bd0b0 100644
--- a/array.c
+++ b/array.c
@@ -4680,14 +4680,16 @@ rb_ary_replace(VALUE copy, VALUE orig)
* contents of orig. */
else if (ARY_EMBED_P(orig)) {
long len = ARY_EMBED_LEN(orig);
-
VALUE *ptr = ary_heap_alloc(copy, len);
- MEMCPY(ptr, ARY_EMBED_PTR(orig), VALUE, len);
FL_UNSET_EMBED(copy);
ARY_SET_PTR(copy, ptr);
ARY_SET_LEN(copy, len);
ARY_SET_CAPA(copy, len);
+
+ // No allocation and exception expected that could leave `copy` in a
+ // bad state from the edits above.
+ ary_memcpy(copy, 0, len, RARRAY_CONST_PTR_TRANSIENT(orig));
}
#endif
/* Otherwise, orig is on heap and copy does not have enough space to embed
diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb
index b100cf334c..e376d76a16 100644
--- a/test/ruby/test_array.rb
+++ b/test/ruby/test_array.rb
@@ -1439,6 +1439,14 @@ class TestArray < Test::Unit::TestCase
assert_raise(FrozenError) { fa.replace(42) }
end
+ def test_replace_wb_variable_width_alloc
+ small_embed = []
+ 4.times { GC.start } # age small_embed
+ large_embed = [1, 2, 3, 4, 5, Array.new] # new young object
+ small_embed.replace(large_embed) # adds old to young reference
+ GC.verify_internal_consistency
+ end
+
def test_reverse
a = @cls[*%w( dog cat bee ant )]
assert_equal(@cls[*%w(ant bee cat dog)], a.reverse)