From e191bf42d2077a025c21888573f8b81688e5ea28 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Mon, 18 Dec 2023 20:55:59 -0500 Subject: [PATCH] Fix ary_make_partial_step for compaction ary could change embeddedness due to compaction, so we should only get the pointer after allocations. The included test was crashing with: TestArray#test_slice_gc_compact_stress ruby/lib/pp.rb:192: [BUG] Segmentation fault at 0x0000000000000038 --- array.c | 7 ++++++- test/ruby/test_array.rb | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/array.c b/array.c index e8a4aba3c73ecf..0f274cb093eaa8 100644 --- a/array.c +++ b/array.c @@ -1231,12 +1231,13 @@ ary_make_partial_step(VALUE ary, VALUE klass, long offset, long len, long step) assert(offset+len <= RARRAY_LEN(ary)); assert(step != 0); - const VALUE *values = RARRAY_CONST_PTR(ary); const long orig_len = len; if (step > 0 && step >= len) { VALUE result = ary_new(klass, 1); VALUE *ptr = (VALUE *)ARY_EMBED_PTR(result); + const VALUE *values = RARRAY_CONST_PTR(ary); + RB_OBJ_WRITE(result, ptr, values[offset]); ARY_SET_EMBED_LEN(result, 1); return result; @@ -1254,6 +1255,8 @@ ary_make_partial_step(VALUE ary, VALUE klass, long offset, long len, long step) VALUE result = ary_new(klass, len); if (ARY_EMBED_P(result)) { VALUE *ptr = (VALUE *)ARY_EMBED_PTR(result); + const VALUE *values = RARRAY_CONST_PTR(ary); + for (i = 0; i < len; ++i) { RB_OBJ_WRITE(result, ptr+i, values[j]); j += step; @@ -1261,6 +1264,8 @@ ary_make_partial_step(VALUE ary, VALUE klass, long offset, long len, long step) ARY_SET_EMBED_LEN(result, len); } else { + const VALUE *values = RARRAY_CONST_PTR(ary); + RARRAY_PTR_USE(result, ptr, { for (i = 0; i < len; ++i) { RB_OBJ_WRITE(result, ptr+i, values[j]); diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb index 558e1c2042cb91..97e2fa3de85883 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -1704,6 +1704,10 @@ def test_slice_out_of_range def test_slice_gc_compact_stress EnvUtil.under_gc_compact_stress { assert_equal([1, 2, 3, 4, 5], (0..10).to_a[1, 5]) } + EnvUtil.under_gc_compact_stress do + a = [0, 1, 2, 3, 4, 5] + assert_equal([2, 1, 0], a.slice((2..).step(-1))) + end end def test_slice!