
Issue #21306 has been updated by mame (Yusuke Endoh). Assignee set to jeremyevans0 (Jeremy Evans) ---------------------------------------- Bug #21306: heap-use-after-free in set initialization via clearing the array while it’s being iterated https://bugs.ruby-lang.org/issues/21306#change-112876 * Author: cyruscyliu (Qiang Liu) * Status: Open * Assignee: jeremyevans0 (Jeremy Evans) * ruby -v: 3.5.0 * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN ---------------------------------------- Hi, we found a heap-use-after-free in set initialization via clearing the array while it’s being iterated. Here is the PoC. ``` $a = (1..100).to_a s = Set.new($a) { |x| $a.clear } ``` Initializing a Set with an array that has a block modifying the array causes memory corruption. In this case, the block clears $a while Set is being initialized, which can lead to inconsistent internal state and potential crashes. To reproduce, compile the recent Ruby with ASAN, and run the PoC. ``` $ git log | head -n3 commit 36c64b3be83f17992137d63ffd0b94f90e24424a Author: John Hawthorn <john@hawthorn.email> Date: Fri Apr 11 16:02:23 2025 -070 ./ruby set_initialize.rb `RubyGems' were not loaded. `error_highlight' was not loaded. `did_you_mean' was not loaded. `syntax_suggest' was not loaded. ================================================================= ==107246==ERROR: AddressSanitizer: heap-use-after-free on address 0x51900000dc88 at pc 0x5de0c6510d40 bp 0x7ffc82400690 sp 0x7ffc82400688 READ of size 8 at 0x51900000dc88 thread T0 #0 0x5de0c6510d3f in set_i_initialize /media/test/ruby/build/../set.c:502:17 #1 0x5de0c6658bb1 in vm_call0_cfunc_with_frame /media/test/ruby/build/../vm_eval.c:164:15 #2 0x5de0c6658bb1 in vm_call0_cfunc /media/test/ruby/build/../vm_eval.c:178:12 #3 0x5de0c6658bb1 in vm_call0_body /media/test/ruby/build/../vm_eval.c:229:15 #4 0x5de0c665c443 in vm_call0_cc /media/test/ruby/build/../vm_eval.c:101:12 #5 0x5de0c665c443 in rb_call0 /media/test/ruby/build/../vm_eval.c:554:12 #6 0x5de0c6613825 in rb_call /media/test/ruby/build/../vm_eval.c:873:12 #7 0x5de0c6613825 in rb_funcallv_kw /media/test/ruby/build/../vm_eval.c:1070:12 #8 0x5de0c63edc54 in rb_class_new_instance_pass_kw /media/test/ruby/build/../object.c:2203:5 #9 0x5de0c6646b3b in vm_call_cfunc_with_frame_ /media/test/ruby/build/../vm_insnhelper.c:3797:11 #10 0x5de0c662f4e3 in vm_call_method_each_type /media/test/ruby/build/../vm_insnhelper.c:4775:16 #11 0x5de0c662efd3 in vm_call_method /media/test/ruby/build/../vm_insnhelper.c #12 0x5de0c65f7f98 in vm_sendish /media/test/ruby/build/../vm_insnhelper.c:5972:15 #13 0x5de0c65f7f98 in vm_exec_core /media/test/ruby/build/../insns.def:851:11 #14 0x5de0c65eda47 in rb_vm_exec /media/test/ruby/build/../vm.c #15 0x5de0c62bfce0 in rb_ec_exec_node /media/test/ruby/build/../eval.c:281:9 #16 0x5de0c62bfce0 in ruby_run_node /media/test/ruby/build/../eval.c:319:30 #17 0x5de0c62bb3a0 in rb_main /media/test/ruby/build/../main.c:42:12 #18 0x5de0c62bb3a0 in main /media/test/ruby/build/../main.c:62:12 #19 0x77f098629d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 #20 0x77f098629e3f in __libc_start_main csu/../csu/libc-start.c:392:3 #21 0x5de0c61e3d54 in _start (/media/test/ruby/build/ruby+0x148d54) (BuildId: 58c97094e0527fad484552e230da980d80ffa516) 0x51900000dc88 is located 8 bytes inside of 1024-byte region [0x51900000dc80,0x51900000e080) freed by thread T0 here: #0 0x5de0c627e37c in realloc (/media/test/ruby/build/ruby+0x1e337c) (BuildId: 58c97094e0527fad484552e230da980d80ffa516) #1 0x5de0c6320acb in rb_gc_impl_realloc /media/test/ruby/build/../gc/default/default.c:8330:5 #2 0x5de0c62fdfd9 in ruby_sized_xrealloc2_body /media/test/ruby/build/../gc.c:4772:12 #3 0x5de0c62fdfd9 in ruby_sized_xrealloc2 /media/test/ruby/build/../gc.c:4765:34 #4 0x5de0c62fdfd9 in ruby_xrealloc2 /media/test/ruby/build/../gc.c:4778:12 #5 0x5de0c66add64 in ary_heap_realloc /media/test/ruby/build/../array.c:370:5 #6 0x5de0c66add64 in ary_resize_capa /media/test/ruby/build/../array.c:412:24 #7 0x5de0c66b5663 in rb_ary_clear /media/test/ruby/build/../array.c:4750:13 #8 0x5de0c6646b3b in vm_call_cfunc_with_frame_ /media/test/ruby/build/../vm_insnhelper.c:3797:11 #9 0x5de0c662f4e3 in vm_call_method_each_type /media/test/ruby/build/../vm_insnhelper.c:4775:16 #10 0x5de0c662efd3 in vm_call_method /media/test/ruby/build/../vm_insnhelper.c #11 0x5de0c65f51d8 in vm_sendish /media/test/ruby/build/../vm_insnhelper.c:5972:15 #12 0x5de0c65f51d8 in vm_exec_core /media/test/ruby/build/../insns.def:899:11 #13 0x5de0c65eda47 in rb_vm_exec /media/test/ruby/build/../vm.c #14 0x5de0c66607b6 in invoke_iseq_block_from_c /media/test/ruby/build/../vm.c:1648:12 #15 0x5de0c66607b6 in invoke_block_from_c_bh /media/test/ruby/build/../vm.c:1662:20 #16 0x5de0c661502a in vm_yield_with_cref /media/test/ruby/build/../vm.c:1699:12 #17 0x5de0c661502a in vm_yield /media/test/ruby/build/../vm.c:1707:12 #18 0x5de0c661502a in rb_yield_0 /media/test/ruby/build/../vm_eval.c:1344:12 #19 0x5de0c661502a in rb_yield /media/test/ruby/build/../vm_eval.c #20 0x5de0c6510aa4 in set_i_initialize /media/test/ruby/build/../set.c:502:17 #21 0x5de0c6658bb1 in vm_call0_cfunc_with_frame /media/test/ruby/build/../vm_eval.c:164:15 #22 0x5de0c6658bb1 in vm_call0_cfunc /media/test/ruby/build/../vm_eval.c:178:12 #23 0x5de0c6658bb1 in vm_call0_body /media/test/ruby/build/../vm_eval.c:229:15 #24 0x5de0c665c443 in vm_call0_cc /media/test/ruby/build/../vm_eval.c:101:12 #25 0x5de0c665c443 in rb_call0 /media/test/ruby/build/../vm_eval.c:554:12 #26 0x5de0c6613825 in rb_call /media/test/ruby/build/../vm_eval.c:873:12 #27 0x5de0c6613825 in rb_funcallv_kw /media/test/ruby/build/../vm_eval.c:1070:12 #28 0x5de0c63edc54 in rb_class_new_instance_pass_kw /media/test/ruby/build/../object.c:2203:5 #29 0x5de0c6646b3b in vm_call_cfunc_with_frame_ /media/test/ruby/build/../vm_insnhelper.c:3797:11 #30 0x5de0c662f4e3 in vm_call_method_each_type /media/test/ruby/build/../vm_insnhelper.c:4775:16 #31 0x5de0c662efd3 in vm_call_method /media/test/ruby/build/../vm_insnhelper.c #32 0x5de0c65f7f98 in vm_sendish /media/test/ruby/build/../vm_insnhelper.c:5972:15 #33 0x5de0c65f7f98 in vm_exec_core /media/test/ruby/build/../insns.def:851:11 #34 0x5de0c65eda47 in rb_vm_exec /media/test/ruby/build/../vm.c #35 0x5de0c62bfce0 in rb_ec_exec_node /media/test/ruby/build/../eval.c:281:9 #36 0x5de0c62bfce0 in ruby_run_node /media/test/ruby/build/../eval.c:319:30 #37 0x5de0c62bb3a0 in rb_main /media/test/ruby/build/../main.c:42:12 #38 0x5de0c62bb3a0 in main /media/test/ruby/build/../main.c:62:12 #39 0x77f098629d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 previously allocated by thread T0 here: #0 0x5de0c627e37c in realloc (/media/test/ruby/build/ruby+0x1e337c) (BuildId: 58c97094e0527fad484552e230da980d80ffa516) #1 0x5de0c6320acb in rb_gc_impl_realloc /media/test/ruby/build/../gc/default/default.c:8330:5 #2 0x5de0c62fdfd9 in ruby_sized_xrealloc2_body /media/test/ruby/build/../gc.c:4772:12 #3 0x5de0c62fdfd9 in ruby_sized_xrealloc2 /media/test/ruby/build/../gc.c:4765:34 #4 0x5de0c62fdfd9 in ruby_xrealloc2 /media/test/ruby/build/../gc.c:4778:12 #5 0x5de0c66add64 in ary_heap_realloc /media/test/ruby/build/../array.c:370:5 #6 0x5de0c66add64 in ary_resize_capa /media/test/ruby/build/../array.c:412:24 #7 0x5de0c66ad51b in ary_double_capa /media/test/ruby/build/../array.c:461:5 #8 0x5de0c66ad51b in ary_ensure_room_for_push /media/test/ruby/build/../array.c:620:9 #9 0x5de0c66ad0c4 in rb_ary_push /media/test/ruby/build/../array.c:1386:24 #10 0x5de0c68aceb9 in collect_all /media/test/ruby/build/../enum.c:636:5 #11 0x5de0c65e9803 in vm_yield_with_cfunc /media/test/ruby/build/../vm_insnhelper.c:5146:11 #12 0x5de0c66601f8 in invoke_block_from_c_bh /media/test/ruby/build/../vm.c:1667:16 #13 0x5de0c661502a in vm_yield_with_cref /media/test/ruby/build/../vm.c:1699:12 #14 0x5de0c661502a in vm_yield /media/test/ruby/build/../vm.c:1707:12 #15 0x5de0c661502a in rb_yield_0 /media/test/ruby/build/../vm_eval.c:1344:12 #16 0x5de0c661502a in rb_yield /media/test/ruby/build/../vm_eval.c #17 0x5de0c6444d87 in range_each_fixnum_loop /media/test/ruby/build/../range.c:1059:9 #18 0x5de0c6444d87 in range_each /media/test/ruby/build/../range.c:1096:16 #19 0x5de0c6658bb1 in vm_call0_cfunc_with_frame /media/test/ruby/build/../vm_eval.c:164:15 #20 0x5de0c6658bb1 in vm_call0_cfunc /media/test/ruby/build/../vm_eval.c:178:12 #21 0x5de0c6658bb1 in vm_call0_body /media/test/ruby/build/../vm_eval.c:229:15 #22 0x5de0c665c443 in vm_call0_cc /media/test/ruby/build/../vm_eval.c:101:12 #23 0x5de0c665c443 in rb_call0 /media/test/ruby/build/../vm_eval.c:554:12 #24 0x5de0c6616955 in rb_call /media/test/ruby/build/../vm_eval.c:873:12 #25 0x5de0c6616955 in iterate_method /media/test/ruby/build/../vm_eval.c:1528:12 #26 0x5de0c6616f55 in rb_iterate0 /media/test/ruby/build/../vm_eval.c:1470:18 #27 0x5de0c66167c9 in rb_iterate_internal /media/test/ruby/build/../vm_eval.c:1502:12 #28 0x5de0c66167c9 in rb_block_call_kw /media/test/ruby/build/../vm_eval.c:1551:12 #29 0x5de0c68a7b7b in enum_to_a /media/test/ruby/build/../enum.c:735:5 #30 0x5de0c6658bb1 in vm_call0_cfunc_with_frame /media/test/ruby/build/../vm_eval.c:164:15 #31 0x5de0c6658bb1 in vm_call0_cfunc /media/test/ruby/build/../vm_eval.c:178:12 #32 0x5de0c6658bb1 in vm_call0_body /media/test/ruby/build/../vm_eval.c:229:15 #33 0x5de0c6611076 in vm_call0_cc /media/test/ruby/build/../vm_eval.c:101:12 #34 0x5de0c6611076 in rb_vm_call0 /media/test/ruby/build/../vm_eval.c:61:12 #35 0x5de0c6611076 in rb_vm_call_kw /media/test/ruby/build/../vm_eval.c:326:12 #36 0x5de0c6611076 in vm_call_super /media/test/ruby/build/../vm_eval.c:350:12 #37 0x5de0c6611076 in rb_call_super_kw /media/test/ruby/build/../vm_eval.c:358:12 #38 0x5de0c6646b3b in vm_call_cfunc_with_frame_ /media/test/ruby/build/../vm_insnhelper.c:3797:11 #39 0x5de0c662f4e3 in vm_call_method_each_type /media/test/ruby/build/../vm_insnhelper.c:4775:16 #40 0x5de0c662efd3 in vm_call_method /media/test/ruby/build/../vm_insnhelper.c #41 0x5de0c65f51d8 in vm_sendish /media/test/ruby/build/../vm_insnhelper.c:5972:15 #42 0x5de0c65f51d8 in vm_exec_core /media/test/ruby/build/../insns.def:899:11 #43 0x5de0c65eda47 in rb_vm_exec /media/test/ruby/build/../vm.c #44 0x5de0c62bfce0 in rb_ec_exec_node /media/test/ruby/build/../eval.c:281:9 #45 0x5de0c62bfce0 in ruby_run_node /media/test/ruby/build/../eval.c:319:30 #46 0x5de0c62bb3a0 in rb_main /media/test/ruby/build/../main.c:42:12 #47 0x5de0c62bb3a0 in main /media/test/ruby/build/../main.c:62:12 #48 0x77f098629d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 SUMMARY: AddressSanitizer: heap-use-after-free /media/test/ruby/build/../set.c:502:17 in set_i_initialize Shadow bytes around the buggy address: 0x51900000da00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x51900000da80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x51900000db00: 00 00 00 00 00 00 00 00 00 fa fa fa fa fa fa fa 0x51900000db80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x51900000dc00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x51900000dc80: fd[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x51900000dd00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x51900000dd80: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x51900000de00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x51900000de80: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x51900000df00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==107246==ABORTING ../triaged/set_initialize.rb:3: [BUG] ASAN error ruby 3.5.0dev (2025-05-02T21:28:25Z master 36c64b3be8) +PRISM [x86_64-linux] -- Control frame information ----------------------------------------------- c:0004 p:---- s:0015 e:000014 CFUNC :initialize c:0003 p:---- s:0012 e:000011 CFUNC :new c:0002 p:0013 s:0007 E:000c48 EVAL ../triaged/set_initialize.rb:3 [FINISH] c:0001 p:0000 s:0003 E:000540 DUMMY [FINISH] -- Ruby level backtrace information ---------------------------------------- ../triaged/set_initialize.rb:3:in '<main>' ../triaged/set_initialize.rb:3:in 'new' ../triaged/set_initialize.rb:3:in 'initialize' -- Threading information --------------------------------------------------- Total ractor count: 1 Ruby thread count for this ractor: 1 -- C level backtrace information ------------------------------------------- ./ruby(___interceptor_backtrace) [0x5de0c6228006] /media/test/ruby/build/ruby(rb_print_backtrace+0x14) [0x5de0c6976337] /media/test/ruby/build/../vm_dump.c:839 /media/test/ruby/build/ruby(rb_vm_bugreport) /media/test/ruby/build/../vm_dump.c:1171 /media/test/ruby/build/ruby(rb_bug_without_die_internal+0x23c) [0x5de0c68ca76c] /media/test/ruby/build/../error.c:1097 /media/test/ruby/build/ruby(rb_bug_without_die+0x127) [0x5de0c68ca487] /media/test/ruby/build/../error.c:1106 ./ruby(0x5de0c62a1bc6) [0x5de0c62a1bc6] ./ruby(0x5de0c6282c9f) [0x5de0c6282c9f] ./ruby(0x5de0c6285ce5) [0x5de0c6285ce5] ./ruby(__asan_report_load8) [0x5de0c6286988] /media/test/ruby/build/ruby(set_i_initialize+0x4c0) [0x5de0c6510d40] /media/test/ruby/build/../set.c:502 /media/test/ruby/build/ruby(vm_call0_cfunc_with_frame+0x280) [0x5de0c6658bb2] ../vm_eval.c:164 /media/test/ruby/build/ruby(vm_call0_cfunc) ../vm_eval.c:178 /media/test/ruby/build/ruby(vm_call0_body) ../vm_eval.c:229 /media/test/ruby/build/ruby(vm_call0_cc+0x141) [0x5de0c665c444] ../vm_eval.c:101 /media/test/ruby/build/ruby(rb_call0) ../vm_eval.c:554 /media/test/ruby/build/ruby(rb_funcallv_kw+0x86) [0x5de0c6613826] ../vm_eval.c:873 /media/test/ruby/build/ruby(rb_class_new_instance_pass_kw+0x35) [0x5de0c63edc55] /media/test/ruby/build/../object.c:2203 /media/test/ruby/build/ruby(vm_cfp_consistent_p+0x0) [0x5de0c6646b3c] ../vm_insnhelper.c:3797 /media/test/ruby/build/ruby(vm_call_cfunc_with_frame_) ../vm_insnhelper.c:3799 /media/test/ruby/build/ruby(vm_call_method_each_type+0x264) [0x5de0c662f4e4] ../vm_insnhelper.c:4775 ./ruby(vm_call_method+0x2d4) [0x5de0c662efd4] /media/test/ruby/build/ruby(vm_sendish+0x10e) [0x5de0c65f7f99] ../vm_insnhelper.c:5972 /media/test/ruby/build/ruby(vm_exec_core) ../insns.def:851 ./ruby(vm_exec_loop+0x0) [0x5de0c65eda48] /media/test/ruby/build/ruby(rb_vm_exec) /media/test/ruby/build/../vm.c:2621 /media/test/ruby/build/ruby(rb_ec_exec_node+0x53) [0x5de0c62bfce1] /media/test/ruby/build/../eval.c:281 /media/test/ruby/build/ruby(ruby_run_node) /media/test/ruby/build/../eval.c:319 /media/test/ruby/build/ruby(rb_main+0x29) [0x5de0c62bb3a1] /media/test/ruby/build/../main.c:42 /media/test/ruby/build/ruby(main) /media/test/ruby/build/../main.c:62 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_call_main+0x80) [0x77f098629d90] ../sysdeps/nptl/libc_start_call_main.h:58 /lib/x86_64-linux-gnu/libc.so.6(call_init+0x0) [0x77f098629e40] ../csu/libc-start.c:392 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main_impl) ../csu/libc-start.c:379 /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main) (null):0 ./ruby(_start) [0x5de0c61e3d55] -- Other runtime information ----------------------------------------------- * Loaded script: ../triaged/set_initialize.rb * Loaded features: 0 enumerator.so 1 thread.rb 2 fiber.so 3 rational.so 4 complex.so 5 ruby2_keywords.rb 6 set.rb ``` -- https://bugs.ruby-lang.org/