summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Zhu <[email protected]>2023-12-18 20:55:59 -0500
committerPeter Zhu <[email protected]>2023-12-21 10:39:03 -0500
commite191bf42d2077a025c21888573f8b81688e5ea28 (patch)
tree69e009c2b48a2da585672c04b6dfc59b864ef377
parentfd4735130e5fdc0a11f970092d5900847a3ce4cf (diff)
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
-rw-r--r--array.c7
-rw-r--r--test/ruby/test_array.rb4
2 files changed, 10 insertions, 1 deletions
diff --git a/array.c b/array.c
index e8a4aba3c7..0f274cb093 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 558e1c2042..97e2fa3de8 100644
--- a/test/ruby/test_array.rb
+++ b/test/ruby/test_array.rb
@@ -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!