Skip to content

Commit 21035c8

Browse files
committed
Handle mutating of array passed to Set.new during iteration
This avoids a heap-use-after-free. Fixes [Bug #21306]
1 parent be665cf commit 21035c8

File tree

2 files changed

+12
-12
lines changed

2 files changed

+12
-12
lines changed

set.c

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -494,18 +494,13 @@ set_i_initialize(int argc, VALUE *argv, VALUE set)
494494

495495
if (argc > 0 && (other = argv[0]) != Qnil) {
496496
if (RB_TYPE_P(other, T_ARRAY)) {
497-
long len = RARRAY_LEN(other);
498-
if (RARRAY_LEN(other) != 0) {
499-
set_table *into = RSET_TABLE(set);
500-
VALUE key;
501-
int block_given = rb_block_given_p();
502-
RARRAY_PTR_USE(other, ptr, {
503-
for(; len > 0; len--, ptr++) {
504-
key = *ptr;
505-
if (block_given) key = rb_yield(key);
506-
set_table_insert_wb(into, set, key, NULL);
507-
}
508-
});
497+
long i;
498+
int block_given = rb_block_given_p();
499+
set_table *into = RSET_TABLE(set);
500+
for (i=0; i<RARRAY_LEN(other); i++) {
501+
VALUE key = RARRAY_AREF(other, i);
502+
if (block_given) key = rb_yield(key);
503+
set_table_insert_wb(into, set, key, NULL);
509504
}
510505
}
511506
else {

test/ruby/test_set.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,11 @@ def test_merge_mutating_hash_bug_21305
643643
assert_equal([o], Set.new.merge(a).to_a)
644644
end
645645

646+
def test_initialize_mutating_array_bug_21306
647+
a = (1..100).to_a
648+
assert_equal(Set[0], Set.new(a){a.clear; 0})
649+
end
650+
646651
def test_subtract
647652
set = Set[1,2,3]
648653

0 commit comments

Comments
 (0)