aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--array.c5
-rw-r--r--test/ruby/test_array.rb4
-rw-r--r--tool/lib/envutil.rb9
3 files changed, 17 insertions, 1 deletions
diff --git a/array.c b/array.c
index b44c0c2ade..a9f4990462 100644
--- a/array.c
+++ b/array.c
@@ -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));
diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb
index 6c0db0832b..838ef15b91 100644
--- a/test/ruby/test_array.rb
+++ b/test/ruby/test_array.rb
@@ -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))
diff --git a/tool/lib/envutil.rb b/tool/lib/envutil.rb
index 1ca76d17a7..e47523a24b 100644
--- a/tool/lib/envutil.rb
+++ b/tool/lib/envutil.rb
@@ -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