Skip to content

Commit

Permalink
Add missing write barriers to Array#replace
Browse files Browse the repository at this point in the history
Previously it made object references without using write barriers,
creating GC inconsistencies.

See: http://ci.rvm.jp/results/trunk-gc-asserts@phosphorus-docker/3925529
  • Loading branch information
XrXr committed Apr 28, 2022
1 parent 0626e6f commit c416dbb
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 2 deletions.
6 changes: 4 additions & 2 deletions array.c
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions test/ruby/test_array.rb
Expand Up @@ -1439,6 +1439,14 @@ def test_replace
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)
Expand Down

0 comments on commit c416dbb

Please sign in to comment.