Skip to content

Commit be665cf

Browse files
committed
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]
1 parent f3246cc commit be665cf

File tree

2 files changed

+15
-8
lines changed

2 files changed

+15
-8
lines changed

set.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,14 +1120,10 @@ set_merge_enum_into(VALUE set, VALUE arg)
11201120
set_iter(arg, set_merge_i, (st_data_t)&args);
11211121
}
11221122
else if (RB_TYPE_P(arg, T_ARRAY)) {
1123-
long len = RARRAY_LEN(arg);
1124-
if (RARRAY_LEN(arg) != 0) {
1125-
set_table *into = RSET_TABLE(set);
1126-
RARRAY_PTR_USE(arg, ptr, {
1127-
for(; len > 0; len--, ptr++) {
1128-
set_table_insert_wb(into, set, *ptr, NULL);
1129-
}
1130-
});
1123+
long i;
1124+
set_table *into = RSET_TABLE(set);
1125+
for (i=0; i<RARRAY_LEN(arg); i++) {
1126+
set_table_insert_wb(into, set, RARRAY_AREF(arg, i), NULL);
11311127
}
11321128
}
11331129
else {

test/ruby/test_set.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,17 @@ def test_merge
632632
}
633633
end
634634

635+
def test_merge_mutating_hash_bug_21305
636+
a = (1..100).to_a
637+
o = Object.new
638+
o.define_singleton_method(:hash) do
639+
a.clear
640+
0
641+
end
642+
a.unshift o
643+
assert_equal([o], Set.new.merge(a).to_a)
644+
end
645+
635646
def test_subtract
636647
set = Set[1,2,3]
637648

0 commit comments

Comments
 (0)