diff options
author | Jeremy Evans <code@jeremyevans.net> | 2021-05-21 18:33:56 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-21 18:33:56 -0700 |
commit | 8b00bfb7c2c33827490c78a16c44b102cb0d724b (patch) | |
tree | e8d06af25bd9504cf4984002f4bffaac42a777c8 /array.c | |
parent | b2fc592c3046e60fdfbb5692d52cc7cbf814b6d0 (diff) | |
download | ruby-8b00bfb7c2c33827490c78a16c44b102cb0d724b.tar.gz |
Do not allow array modifications after freeze inside sort!
If freezing an array inside sort!, previously the array could be
modified after the freeze. This checks whether the receiver is
frozen after every yield and potential call to #> or #<,
preventing modifications if the receiver is frozen inside the
block or by the #> or #< call.
Fixes [Bug #17739]
Diffstat (limited to 'array.c')
-rw-r--r-- | array.c | 15 |
1 files changed, 13 insertions, 2 deletions
@@ -3213,6 +3213,7 @@ rb_ary_rotate_m(int argc, VALUE *argv, VALUE ary) struct ary_sort_data { VALUE ary; + VALUE receiver; struct cmp_opt_data cmp_opt; }; @@ -3225,6 +3226,15 @@ sort_reentered(VALUE ary) return Qnil; } +static void +sort_returned(struct ary_sort_data *data) +{ + if (rb_obj_frozen_p(data->receiver)) { + rb_raise(rb_eFrozenError, "array frozen during sort"); + } + sort_reentered(data->ary); +} + static int sort_1(const void *ap, const void *bp, void *dummy) { @@ -3238,7 +3248,7 @@ sort_1(const void *ap, const void *bp, void *dummy) args[1] = b; retval = rb_yield_values2(2, args); n = rb_cmpint(retval, a, b); - sort_reentered(data->ary); + sort_returned(data); return n; } @@ -3264,7 +3274,7 @@ sort_2(const void *ap, const void *bp, void *dummy) retval = rb_funcallv(a, id_cmp, 1, &b); n = rb_cmpint(retval, a, b); - sort_reentered(data->ary); + sort_returned(data); return n; } @@ -3316,6 +3326,7 @@ rb_ary_sort_bang(VALUE ary) long len = RARRAY_LEN(ary); RBASIC_CLEAR_CLASS(tmp); data.ary = tmp; + data.receiver = ary; data.cmp_opt.opt_methods = 0; data.cmp_opt.opt_inited = 0; RARRAY_PTR_USE(tmp, ptr, { |