Handle mutating of array passed to Set.new during iteration

This avoids a heap-use-after-free.

Fixes [Bug #21306]
This commit is contained in:
Jeremy Evans 2025-05-03 11:20:23 -07:00
parent be665cf855
commit 21035c826d
Notes: git 2025-05-03 19:11:32 +00:00
2 changed files with 12 additions and 12 deletions

19
set.c
View File

@ -494,18 +494,13 @@ set_i_initialize(int argc, VALUE *argv, VALUE set)
if (argc > 0 && (other = argv[0]) != Qnil) { if (argc > 0 && (other = argv[0]) != Qnil) {
if (RB_TYPE_P(other, T_ARRAY)) { if (RB_TYPE_P(other, T_ARRAY)) {
long len = RARRAY_LEN(other); long i;
if (RARRAY_LEN(other) != 0) { int block_given = rb_block_given_p();
set_table *into = RSET_TABLE(set); set_table *into = RSET_TABLE(set);
VALUE key; for (i=0; i<RARRAY_LEN(other); i++) {
int block_given = rb_block_given_p(); VALUE key = RARRAY_AREF(other, i);
RARRAY_PTR_USE(other, ptr, { if (block_given) key = rb_yield(key);
for(; len > 0; len--, ptr++) { set_table_insert_wb(into, set, key, NULL);
key = *ptr;
if (block_given) key = rb_yield(key);
set_table_insert_wb(into, set, key, NULL);
}
});
} }
} }
else { else {

View File

@ -643,6 +643,11 @@ class TC_Set < Test::Unit::TestCase
assert_equal([o], Set.new.merge(a).to_a) assert_equal([o], Set.new.merge(a).to_a)
end end
def test_initialize_mutating_array_bug_21306
a = (1..100).to_a
assert_equal(Set[0], Set.new(a){a.clear; 0})
end
def test_subtract def test_subtract
set = Set[1,2,3] set = Set[1,2,3]