Fix compaction during ary_make_partial

The ary_make_shared call may allocate, which can trigger a GC
compaction. This can cause the array to be embedded because it has a
length of 0.
This commit is contained in:
Peter Zhu 2023-11-27 11:30:47 -05:00
parent 3af56e87ca
commit 150ed44d87
3 changed files with 17 additions and 1 deletions

View File

@ -1204,7 +1204,10 @@ ary_make_partial(VALUE ary, VALUE klass, long offset, long len)
else {
VALUE shared = ary_make_shared(ary);
assert(!ARY_EMBED_P(result));
/* The ary_make_shared call may allocate, which can trigger a GC
* compaction. This can cause the array to be embedded because it has
* a length of 0. */
FL_UNSET_EMBED(result);
ARY_SET_PTR(result, RARRAY_CONST_PTR(ary));
ARY_SET_LEN(result, RARRAY_LEN(ary));

View File

@ -1693,6 +1693,10 @@ class TestArray < Test::Unit::TestCase
assert_equal([100], a.slice(-1, 1_000_000_000))
end
def test_slice_gc_compact_stress
EnvUtil.under_gc_compact_stress { assert_equal([1, 2, 3, 4, 5], (0..10).to_a[1, 5]) }
end
def test_slice!
a = @cls[1, 2, 3, 4, 5]
assert_equal(3, a.slice!(2))

View File

@ -245,6 +245,15 @@ module EnvUtil
end
module_function :under_gc_stress
def under_gc_compact_stress(&block)
auto_compact = GC.auto_compact
GC.auto_compact = true
under_gc_stress(&block)
ensure
GC.auto_compact = auto_compact
end
module_function :under_gc_compact_stress
def with_default_external(enc)
suppress_warning { Encoding.default_external = enc }
yield