Handle mutation of array being merged into set

Check length of array during every iteration, as a #hash method
could truncate the array, resulting in heap-use-after-free.

Fixes [Bug #21305]
This commit is contained in:
Jeremy Evans 2025-05-03 11:07:22 -07:00
parent f3246ccebb
commit be665cf855
Notes: git 2025-05-03 19:11:32 +00:00
2 changed files with 15 additions and 8 deletions

12
set.c
View File

@ -1120,14 +1120,10 @@ set_merge_enum_into(VALUE set, VALUE arg)
set_iter(arg, set_merge_i, (st_data_t)&args);
}
else if (RB_TYPE_P(arg, T_ARRAY)) {
long len = RARRAY_LEN(arg);
if (RARRAY_LEN(arg) != 0) {
set_table *into = RSET_TABLE(set);
RARRAY_PTR_USE(arg, ptr, {
for(; len > 0; len--, ptr++) {
set_table_insert_wb(into, set, *ptr, NULL);
}
});
long i;
set_table *into = RSET_TABLE(set);
for (i=0; i<RARRAY_LEN(arg); i++) {
set_table_insert_wb(into, set, RARRAY_AREF(arg, i), NULL);
}
}
else {

View File

@ -632,6 +632,17 @@ class TC_Set < Test::Unit::TestCase
}
end
def test_merge_mutating_hash_bug_21305
a = (1..100).to_a
o = Object.new
o.define_singleton_method(:hash) do
a.clear
0
end
a.unshift o
assert_equal([o], Set.new.merge(a).to_a)
end
def test_subtract
set = Set[1,2,3]