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
This commit is contained in:
Peter Zhu 2023-12-18 20:55:59 -05:00
parent fd4735130e
commit e191bf42d2
2 changed files with 10 additions and 1 deletions

View File

@ -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]);

View File

@ -1704,6 +1704,10 @@ class TestArray < Test::Unit::TestCase
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!