array.c (mrb_ary_sort_bang): check if array is modified in blocks

This address at least part of #6326. CRuby copied the array internally,
but mruby avoid copying to reserve memory.
This commit is contained in:
Yukihiro "Matz" Matsumoto
2024-08-21 18:31:46 +09:00
parent 4b9f567821
commit 752ebe6b7f
+11 -7
View File
@@ -1583,7 +1583,7 @@ mrb_ary_delete(mrb_state *mrb, mrb_value self)
}
static mrb_bool
sort_cmp(mrb_state *mrb, mrb_value *p, mrb_int a, mrb_int b, mrb_value blk)
sort_cmp(mrb_state *mrb, mrb_value ary, mrb_value *p, mrb_int a, mrb_int b, mrb_value blk)
{
mrb_int cmp;
@@ -1592,6 +1592,10 @@ sort_cmp(mrb_state *mrb, mrb_value *p, mrb_int a, mrb_int b, mrb_value blk)
}
else {
mrb_value c = mrb_funcall_id(mrb, blk, MRB_SYM(call), 2, p[a], p[b]);
mrb_int size = RARRAY_LEN(ary);
if (RARRAY_PTR(ary) != p || size < a || size < b) {
mrb_raise(mrb, E_RUNTIME_ERROR, "array modified during sort");
}
if (mrb_nil_p(c) || !mrb_fixnum_p(c)) {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "comparison of %!v and %!v failed", p[a], p[b]);
}
@@ -1601,22 +1605,22 @@ sort_cmp(mrb_state *mrb, mrb_value *p, mrb_int a, mrb_int b, mrb_value blk)
}
static void
heapify(mrb_state *mrb, mrb_value *a, mrb_int index, mrb_int size, mrb_value blk)
heapify(mrb_state *mrb, mrb_value ary, mrb_value *a, mrb_int index, mrb_int size, mrb_value blk)
{
mrb_int max = index;
mrb_int left_index = 2 * index + 1;
mrb_int right_index = left_index + 1;
if (left_index < size && sort_cmp(mrb, a, left_index, max, blk)) {
if (left_index < size && sort_cmp(mrb, ary, a, left_index, max, blk)) {
max = left_index;
}
if (right_index < size && sort_cmp(mrb, a, right_index, max, blk)) {
if (right_index < size && sort_cmp(mrb, ary, a, right_index, max, blk)) {
max = right_index;
}
if (max != index) {
mrb_value tmp = a[max];
a[max] = a[index];
a[index] = tmp;
heapify(mrb, a, max, size, blk);
heapify(mrb, ary, a, max, size, blk);
}
}
@@ -1641,13 +1645,13 @@ mrb_ary_sort_bang(mrb_state *mrb, mrb_value ary)
mrb_value *a = RARRAY_PTR(ary);
for (mrb_int i = n / 2 - 1; i > -1; i--) {
heapify(mrb, a, i, n, blk);
heapify(mrb, ary, a, i, n, blk);
}
for (mrb_int i = n - 1; i > 0; i--) {
mrb_value tmp = a[0];
a[0] = a[i];
a[i] = tmp;
heapify(mrb, a, 0, i, blk);
heapify(mrb, ary, a, 0, i, blk);
}
return ary;
}