forked from ruby/ruby
-
Notifications
You must be signed in to change notification settings - Fork 0
Fix ary_make_partial_step for compaction #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ary could change embeddedness due to compaction, so we should only get the pointer after allocations. The included test was crashing with: TestArray#test_slice_gc_compact_stress ruby/lib/pp.rb:192: [BUG] Segmentation fault at 0x0000000000000038
peterzhu2118
pushed a commit
that referenced
this pull request
Apr 3, 2024
* YJIT: A64: Use ADDS/SUBS/CMP (immediate) when possible We were loading 1 into a register and then doing ADDS/SUBS previously. That was particularly bad since those come up in fixnum operations. ```diff # integer left shift with rhs=1 - mov x11, #1 - subs x11, x1, x11 + subs x11, x1, #1 lsl x12, x11, #1 asr x13, x12, #1 cmp x13, x11 - b.ne #0x106ab60f8 - mov x11, #1 - adds x12, x12, x11 + b.ne #0x10903a0f8 + adds x12, x12, #1 mov x1, x12 ``` Note that it's fine to cast between i64 and u64 since the bit pattern is preserved, and the add/sub themselves don't care about the signedness of the operands. CMP is just another mnemonic for SUBS. * YJIT: A64: Split asm.mul() with immediates properly There is in fact no MUL on A64 that takes an immediate, so this instruction was using the wrong split method. No current usages of this form in YJIT. --------- Co-authored-by: Maxime Chevalier-Boisvert <maxime.chevalierboisvert@shopify.com>
peterzhu2118
added a commit
that referenced
this pull request
Jul 4, 2024
When Ruby is built with ASAN and RUBY_FREE_AT_EXIT is enabled, the following error occurs: READ of size 8 at 0x74c666610020 thread T0 #0 0x593b6712ecc6 in RB_BUILTIN_TYPE include/ruby/internal/value_type.h:191:30 #1 0x593b6712ecc6 in rb_gc_impl_shutdown_free_objects gc_impl.c:3208:17 ruby#2 0x593b6749a62e in ruby_vm_destruct vm.c:3133:17
peterzhu2118
added a commit
that referenced
this pull request
Oct 1, 2024
During compilation, we write keyword default values into the iseq, so we should mark it to ensure it does not get GC'd. This might fix issues on ASAN like http://ci.rvm.jp/logfiles/brlog.trunk_asan.20240927-194923 ==805257==ERROR: AddressSanitizer: use-after-poison on address 0x7b7e5e3e2828 at pc 0x5e09ac4822f8 bp 0x7ffde56b0140 sp 0x7ffde56b0138 READ of size 8 at 0x7b7e5e3e2828 thread T0 #0 0x5e09ac4822f7 in RB_BUILTIN_TYPE include/ruby/internal/value_type.h:191:30 #1 0x5e09ac4822f7 in rbimpl_RB_TYPE_P_fastpath include/ruby/internal/value_type.h:352:19 ruby#2 0x5e09ac4822f7 in gc_mark gc/default.c:4488:9 ruby#3 0x5e09ac51011e in rb_iseq_mark_and_move iseq.c:361:17 ruby#4 0x5e09ac4b85c4 in rb_imemo_mark_and_move imemo.c:386:9 ruby#5 0x5e09ac467544 in rb_gc_mark_children gc.c:2508:9 ruby#6 0x5e09ac482c24 in gc_mark_children gc/default.c:4673:5 ruby#7 0x5e09ac482c24 in gc_mark_stacked_objects gc/default.c:4694:9 ruby#8 0x5e09ac482c24 in gc_mark_stacked_objects_all gc/default.c:4732:12 ruby#9 0x5e09ac48c7f9 in gc_marks_rest gc/default.c:5755:9 ruby#10 0x5e09ac48c7f9 in gc_marks gc/default.c:5870:9 ruby#11 0x5e09ac48c7f9 in gc_start gc/default.c:6517:13
peterzhu2118
added a commit
that referenced
this pull request
Oct 2, 2024
During compilation, we write keyword default values into the iseq, so we should mark it to ensure it does not get GC'd. This might fix issues on ASAN like http://ci.rvm.jp/logfiles/brlog.trunk_asan.20240927-194923 ==805257==ERROR: AddressSanitizer: use-after-poison on address 0x7b7e5e3e2828 at pc 0x5e09ac4822f8 bp 0x7ffde56b0140 sp 0x7ffde56b0138 READ of size 8 at 0x7b7e5e3e2828 thread T0 #0 0x5e09ac4822f7 in RB_BUILTIN_TYPE include/ruby/internal/value_type.h:191:30 #1 0x5e09ac4822f7 in rbimpl_RB_TYPE_P_fastpath include/ruby/internal/value_type.h:352:19 ruby#2 0x5e09ac4822f7 in gc_mark gc/default.c:4488:9 ruby#3 0x5e09ac51011e in rb_iseq_mark_and_move iseq.c:361:17 ruby#4 0x5e09ac4b85c4 in rb_imemo_mark_and_move imemo.c:386:9 ruby#5 0x5e09ac467544 in rb_gc_mark_children gc.c:2508:9 ruby#6 0x5e09ac482c24 in gc_mark_children gc/default.c:4673:5 ruby#7 0x5e09ac482c24 in gc_mark_stacked_objects gc/default.c:4694:9 ruby#8 0x5e09ac482c24 in gc_mark_stacked_objects_all gc/default.c:4732:12 ruby#9 0x5e09ac48c7f9 in gc_marks_rest gc/default.c:5755:9 ruby#10 0x5e09ac48c7f9 in gc_marks gc/default.c:5870:9 ruby#11 0x5e09ac48c7f9 in gc_start gc/default.c:6517:13
peterzhu2118
added a commit
that referenced
this pull request
Nov 27, 2024
fill_lines is passed -1 for offset, which causes it to read the -1 index of traces. This is not valid memory as -1 is reading before the trace global variable in rb_print_backtrace. This code comes from commit 99d1f5f, where there used to be special handling for the -1 index. We can see this error in ASAN: ==71037==ERROR: AddressSanitizer: global-buffer-overflow on address 0x00010157abf8 at pc 0x00010116f3b8 bp 0x00016f92c3b0 sp 0x00016f92c3a8 READ of size 8 at 0x00010157abf8 thread T0 #0 0x10116f3b4 in debug_info_read addr2line.c:1945 #1 0x10116cc90 in fill_lines addr2line.c:2497 ruby#2 0x101169dbc in rb_dump_backtrace_with_lines addr2line.c:2635 ruby#3 0x100e56788 in rb_print_backtrace vm_dump.c:825 ruby#4 0x100e56db4 in rb_vm_bugreport vm_dump.c:1155 ruby#5 0x100734dc4 in rb_bug_without_die error.c:1085 ruby#6 0x100734ae4 in rb_bug error.c:109
peterzhu2118
added a commit
that referenced
this pull request
Nov 28, 2024
fill_lines is passed -1 for offset, which causes it to read the -1 index of traces. This is not valid memory as -1 is reading before the trace global variable in rb_print_backtrace. This code comes from commit 99d1f5f, where there used to be special handling for the -1 index. We can see this error in ASAN: ==71037==ERROR: AddressSanitizer: global-buffer-overflow on address 0x00010157abf8 at pc 0x00010116f3b8 bp 0x00016f92c3b0 sp 0x00016f92c3a8 READ of size 8 at 0x00010157abf8 thread T0 #0 0x10116f3b4 in debug_info_read addr2line.c:1945 #1 0x10116cc90 in fill_lines addr2line.c:2497 ruby#2 0x101169dbc in rb_dump_backtrace_with_lines addr2line.c:2635 ruby#3 0x100e56788 in rb_print_backtrace vm_dump.c:825 ruby#4 0x100e56db4 in rb_vm_bugreport vm_dump.c:1155 ruby#5 0x100734dc4 in rb_bug_without_die error.c:1085 ruby#6 0x100734ae4 in rb_bug error.c:109
peterzhu2118
added a commit
that referenced
this pull request
Nov 28, 2024
[Bug #20921] When we create a cache entry for a constant, the following sequence of events could happen: - vm_track_constant_cache is called to insert a constant cache. - In vm_track_constant_cache, we first look up the ST table for the ID of the constant. Assume the ST table exists because another iseq also holds a cache entry for this ID. - We then insert into this ST table with the iseq_inline_constant_cache. - However, while inserting into this ST table, it allocates memory, which could trigger a GC. Assume that it does trigger a GC. - The GC frees the one and only other iseq that holds a cache entry for this ID. - In remove_from_constant_cache, it will appear that the ST table is now empty because there are no more iseq with cache entries for this ID, so we free the ST table. - We complete GC and continue our st_insert. However, this ST table has been freed so we now have a use-after-free. This issue is very hard to reproduce, because it requires that the GC runs at a very specific time. However, we can make it show up by applying this patch which runs GC right before the st_insert to mimic the st_insert triggering a GC: diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 3cb23f0..a93998136a 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -6338,6 +6338,10 @@ vm_track_constant_cache(ID id, void *ic) rb_id_table_insert(const_cache, id, (VALUE)ics); } + if (id == rb_intern("MyConstant")) rb_gc(); + st_insert(ics, (st_data_t) ic, (st_data_t) Qtrue); } And if we run this script: Object.const_set("MyConstant", "Hello!") my_proc = eval("-> { MyConstant }") my_proc.call my_proc = eval("-> { MyConstant }") my_proc.call We can see that ASAN outputs a use-after-free error: ==36540==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000049528 at pc 0x000102f3ceac bp 0x00016d607a70 sp 0x00016d607a68 READ of size 8 at 0x606000049528 thread T0 #0 0x102f3cea8 in do_hash st.c:321 #1 0x102f3ddd0 in rb_st_insert st.c:1132 ruby#2 0x103140700 in vm_track_constant_cache vm_insnhelper.c:6345 ruby#3 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356 ruby#4 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424 ruby#5 0x1030bc1e0 in vm_exec_core insns.def:263 ruby#6 0x1030b55fc in rb_vm_exec vm.c:2585 ruby#7 0x1030fe0ac in rb_iseq_eval_main vm.c:2851 ruby#8 0x102a82588 in rb_ec_exec_node eval.c:281 ruby#9 0x102a81fe0 in ruby_run_node eval.c:319 ruby#10 0x1027f3db4 in rb_main main.c:43 ruby#11 0x1027f3bd4 in main main.c:68 ruby#12 0x183900270 (<unknown module>) 0x606000049528 is located 8 bytes inside of 56-byte region [0x606000049520,0x606000049558) freed by thread T0 here: #0 0x104174d40 in free+0x98 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x54d40) #1 0x102ada89c in rb_gc_impl_free default.c:8183 ruby#2 0x102ada7dc in ruby_sized_xfree gc.c:4507 ruby#3 0x102ac4d34 in ruby_xfree gc.c:4518 ruby#4 0x102f3cb34 in rb_st_free_table st.c:663 ruby#5 0x102bd52d8 in remove_from_constant_cache iseq.c:119 ruby#6 0x102bbe2cc in iseq_clear_ic_references iseq.c:153 ruby#7 0x102bbd2a0 in rb_iseq_free iseq.c:166 ruby#8 0x102b32ed0 in rb_imemo_free imemo.c:564 ruby#9 0x102ac4b44 in rb_gc_obj_free gc.c:1407 ruby#10 0x102af4290 in gc_sweep_plane default.c:3546 ruby#11 0x102af3bdc in gc_sweep_page default.c:3634 ruby#12 0x102aeb140 in gc_sweep_step default.c:3906 ruby#13 0x102aeadf0 in gc_sweep_rest default.c:3978 ruby#14 0x102ae4714 in gc_sweep default.c:4155 ruby#15 0x102af8474 in gc_start default.c:6484 ruby#16 0x102afbe30 in garbage_collect default.c:6363 ruby#17 0x102ad37f0 in rb_gc_impl_start default.c:6816 ruby#18 0x102ad3634 in rb_gc gc.c:3624 ruby#19 0x1031406ec in vm_track_constant_cache vm_insnhelper.c:6342 #20 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356 ruby#21 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424 ruby#22 0x1030bc1e0 in vm_exec_core insns.def:263 ruby#23 0x1030b55fc in rb_vm_exec vm.c:2585 ruby#24 0x1030fe0ac in rb_iseq_eval_main vm.c:2851 ruby#25 0x102a82588 in rb_ec_exec_node eval.c:281 ruby#26 0x102a81fe0 in ruby_run_node eval.c:319 ruby#27 0x1027f3db4 in rb_main main.c:43 ruby#28 0x1027f3bd4 in main main.c:68 ruby#29 0x183900270 (<unknown module>) previously allocated by thread T0 here: #0 0x104174c04 in malloc+0x94 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x54c04) #1 0x102ada0ec in rb_gc_impl_malloc default.c:8198 ruby#2 0x102acee44 in ruby_xmalloc gc.c:4438 ruby#3 0x102f3c85c in rb_st_init_table_with_size st.c:571 ruby#4 0x102f3c900 in rb_st_init_table st.c:600 ruby#5 0x102f3c920 in rb_st_init_numtable st.c:608 ruby#6 0x103140698 in vm_track_constant_cache vm_insnhelper.c:6337 ruby#7 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356 ruby#8 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424 ruby#9 0x1030bc1e0 in vm_exec_core insns.def:263 ruby#10 0x1030b55fc in rb_vm_exec vm.c:2585 ruby#11 0x1030fe0ac in rb_iseq_eval_main vm.c:2851 ruby#12 0x102a82588 in rb_ec_exec_node eval.c:281 ruby#13 0x102a81fe0 in ruby_run_node eval.c:319 ruby#14 0x1027f3db4 in rb_main main.c:43 ruby#15 0x1027f3bd4 in main main.c:68 ruby#16 0x183900270 (<unknown module>) This commit fixes this bug by adding a inserting_constant_cache_id field to the VM, which stores the ID that is currently being inserted and, in remove_from_constant_cache, we don't free the ST table for ID equal to this one. Co-Authored-By: Alan Wu <alanwu@ruby-lang.org>
peterzhu2118
added a commit
that referenced
this pull request
Nov 28, 2024
[Bug #20921] When we create a cache entry for a constant, the following sequence of events could happen: - vm_track_constant_cache is called to insert a constant cache. - In vm_track_constant_cache, we first look up the ST table for the ID of the constant. Assume the ST table exists because another iseq also holds a cache entry for this ID. - We then insert into this ST table with the iseq_inline_constant_cache. - However, while inserting into this ST table, it allocates memory, which could trigger a GC. Assume that it does trigger a GC. - The GC frees the one and only other iseq that holds a cache entry for this ID. - In remove_from_constant_cache, it will appear that the ST table is now empty because there are no more iseq with cache entries for this ID, so we free the ST table. - We complete GC and continue our st_insert. However, this ST table has been freed so we now have a use-after-free. This issue is very hard to reproduce, because it requires that the GC runs at a very specific time. However, we can make it show up by applying this patch which runs GC right before the st_insert to mimic the st_insert triggering a GC: diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 3cb23f0..a93998136a 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -6338,6 +6338,10 @@ vm_track_constant_cache(ID id, void *ic) rb_id_table_insert(const_cache, id, (VALUE)ics); } + if (id == rb_intern("MyConstant")) rb_gc(); + st_insert(ics, (st_data_t) ic, (st_data_t) Qtrue); } And if we run this script: Object.const_set("MyConstant", "Hello!") my_proc = eval("-> { MyConstant }") my_proc.call my_proc = eval("-> { MyConstant }") my_proc.call We can see that ASAN outputs a use-after-free error: ==36540==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000049528 at pc 0x000102f3ceac bp 0x00016d607a70 sp 0x00016d607a68 READ of size 8 at 0x606000049528 thread T0 #0 0x102f3cea8 in do_hash st.c:321 #1 0x102f3ddd0 in rb_st_insert st.c:1132 ruby#2 0x103140700 in vm_track_constant_cache vm_insnhelper.c:6345 ruby#3 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356 ruby#4 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424 ruby#5 0x1030bc1e0 in vm_exec_core insns.def:263 ruby#6 0x1030b55fc in rb_vm_exec vm.c:2585 ruby#7 0x1030fe0ac in rb_iseq_eval_main vm.c:2851 ruby#8 0x102a82588 in rb_ec_exec_node eval.c:281 ruby#9 0x102a81fe0 in ruby_run_node eval.c:319 ruby#10 0x1027f3db4 in rb_main main.c:43 ruby#11 0x1027f3bd4 in main main.c:68 ruby#12 0x183900270 (<unknown module>) 0x606000049528 is located 8 bytes inside of 56-byte region [0x606000049520,0x606000049558) freed by thread T0 here: #0 0x104174d40 in free+0x98 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x54d40) #1 0x102ada89c in rb_gc_impl_free default.c:8183 ruby#2 0x102ada7dc in ruby_sized_xfree gc.c:4507 ruby#3 0x102ac4d34 in ruby_xfree gc.c:4518 ruby#4 0x102f3cb34 in rb_st_free_table st.c:663 ruby#5 0x102bd52d8 in remove_from_constant_cache iseq.c:119 ruby#6 0x102bbe2cc in iseq_clear_ic_references iseq.c:153 ruby#7 0x102bbd2a0 in rb_iseq_free iseq.c:166 ruby#8 0x102b32ed0 in rb_imemo_free imemo.c:564 ruby#9 0x102ac4b44 in rb_gc_obj_free gc.c:1407 ruby#10 0x102af4290 in gc_sweep_plane default.c:3546 ruby#11 0x102af3bdc in gc_sweep_page default.c:3634 ruby#12 0x102aeb140 in gc_sweep_step default.c:3906 ruby#13 0x102aeadf0 in gc_sweep_rest default.c:3978 ruby#14 0x102ae4714 in gc_sweep default.c:4155 ruby#15 0x102af8474 in gc_start default.c:6484 ruby#16 0x102afbe30 in garbage_collect default.c:6363 ruby#17 0x102ad37f0 in rb_gc_impl_start default.c:6816 ruby#18 0x102ad3634 in rb_gc gc.c:3624 ruby#19 0x1031406ec in vm_track_constant_cache vm_insnhelper.c:6342 #20 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356 ruby#21 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424 ruby#22 0x1030bc1e0 in vm_exec_core insns.def:263 ruby#23 0x1030b55fc in rb_vm_exec vm.c:2585 ruby#24 0x1030fe0ac in rb_iseq_eval_main vm.c:2851 ruby#25 0x102a82588 in rb_ec_exec_node eval.c:281 ruby#26 0x102a81fe0 in ruby_run_node eval.c:319 ruby#27 0x1027f3db4 in rb_main main.c:43 ruby#28 0x1027f3bd4 in main main.c:68 ruby#29 0x183900270 (<unknown module>) previously allocated by thread T0 here: #0 0x104174c04 in malloc+0x94 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x54c04) #1 0x102ada0ec in rb_gc_impl_malloc default.c:8198 ruby#2 0x102acee44 in ruby_xmalloc gc.c:4438 ruby#3 0x102f3c85c in rb_st_init_table_with_size st.c:571 ruby#4 0x102f3c900 in rb_st_init_table st.c:600 ruby#5 0x102f3c920 in rb_st_init_numtable st.c:608 ruby#6 0x103140698 in vm_track_constant_cache vm_insnhelper.c:6337 ruby#7 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356 ruby#8 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424 ruby#9 0x1030bc1e0 in vm_exec_core insns.def:263 ruby#10 0x1030b55fc in rb_vm_exec vm.c:2585 ruby#11 0x1030fe0ac in rb_iseq_eval_main vm.c:2851 ruby#12 0x102a82588 in rb_ec_exec_node eval.c:281 ruby#13 0x102a81fe0 in ruby_run_node eval.c:319 ruby#14 0x1027f3db4 in rb_main main.c:43 ruby#15 0x1027f3bd4 in main main.c:68 ruby#16 0x183900270 (<unknown module>) This commit fixes this bug by adding a inserting_constant_cache_id field to the VM, which stores the ID that is currently being inserted and, in remove_from_constant_cache, we don't free the ST table for ID equal to this one. Co-Authored-By: Alan Wu <alanwu@ruby-lang.org>
peterzhu2118
added a commit
that referenced
this pull request
Nov 29, 2024
[Bug #20921] When we create a cache entry for a constant, the following sequence of events could happen: - vm_track_constant_cache is called to insert a constant cache. - In vm_track_constant_cache, we first look up the ST table for the ID of the constant. Assume the ST table exists because another iseq also holds a cache entry for this ID. - We then insert into this ST table with the iseq_inline_constant_cache. - However, while inserting into this ST table, it allocates memory, which could trigger a GC. Assume that it does trigger a GC. - The GC frees the one and only other iseq that holds a cache entry for this ID. - In remove_from_constant_cache, it will appear that the ST table is now empty because there are no more iseq with cache entries for this ID, so we free the ST table. - We complete GC and continue our st_insert. However, this ST table has been freed so we now have a use-after-free. This issue is very hard to reproduce, because it requires that the GC runs at a very specific time. However, we can make it show up by applying this patch which runs GC right before the st_insert to mimic the st_insert triggering a GC: diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 3cb23f0..a93998136a 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -6338,6 +6338,10 @@ vm_track_constant_cache(ID id, void *ic) rb_id_table_insert(const_cache, id, (VALUE)ics); } + if (id == rb_intern("MyConstant")) rb_gc(); + st_insert(ics, (st_data_t) ic, (st_data_t) Qtrue); } And if we run this script: Object.const_set("MyConstant", "Hello!") my_proc = eval("-> { MyConstant }") my_proc.call my_proc = eval("-> { MyConstant }") my_proc.call We can see that ASAN outputs a use-after-free error: ==36540==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000049528 at pc 0x000102f3ceac bp 0x00016d607a70 sp 0x00016d607a68 READ of size 8 at 0x606000049528 thread T0 #0 0x102f3cea8 in do_hash st.c:321 #1 0x102f3ddd0 in rb_st_insert st.c:1132 ruby#2 0x103140700 in vm_track_constant_cache vm_insnhelper.c:6345 ruby#3 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356 ruby#4 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424 ruby#5 0x1030bc1e0 in vm_exec_core insns.def:263 ruby#6 0x1030b55fc in rb_vm_exec vm.c:2585 ruby#7 0x1030fe0ac in rb_iseq_eval_main vm.c:2851 ruby#8 0x102a82588 in rb_ec_exec_node eval.c:281 ruby#9 0x102a81fe0 in ruby_run_node eval.c:319 ruby#10 0x1027f3db4 in rb_main main.c:43 ruby#11 0x1027f3bd4 in main main.c:68 ruby#12 0x183900270 (<unknown module>) 0x606000049528 is located 8 bytes inside of 56-byte region [0x606000049520,0x606000049558) freed by thread T0 here: #0 0x104174d40 in free+0x98 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x54d40) #1 0x102ada89c in rb_gc_impl_free default.c:8183 ruby#2 0x102ada7dc in ruby_sized_xfree gc.c:4507 ruby#3 0x102ac4d34 in ruby_xfree gc.c:4518 ruby#4 0x102f3cb34 in rb_st_free_table st.c:663 ruby#5 0x102bd52d8 in remove_from_constant_cache iseq.c:119 ruby#6 0x102bbe2cc in iseq_clear_ic_references iseq.c:153 ruby#7 0x102bbd2a0 in rb_iseq_free iseq.c:166 ruby#8 0x102b32ed0 in rb_imemo_free imemo.c:564 ruby#9 0x102ac4b44 in rb_gc_obj_free gc.c:1407 ruby#10 0x102af4290 in gc_sweep_plane default.c:3546 ruby#11 0x102af3bdc in gc_sweep_page default.c:3634 ruby#12 0x102aeb140 in gc_sweep_step default.c:3906 ruby#13 0x102aeadf0 in gc_sweep_rest default.c:3978 ruby#14 0x102ae4714 in gc_sweep default.c:4155 ruby#15 0x102af8474 in gc_start default.c:6484 ruby#16 0x102afbe30 in garbage_collect default.c:6363 ruby#17 0x102ad37f0 in rb_gc_impl_start default.c:6816 ruby#18 0x102ad3634 in rb_gc gc.c:3624 ruby#19 0x1031406ec in vm_track_constant_cache vm_insnhelper.c:6342 #20 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356 ruby#21 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424 ruby#22 0x1030bc1e0 in vm_exec_core insns.def:263 ruby#23 0x1030b55fc in rb_vm_exec vm.c:2585 ruby#24 0x1030fe0ac in rb_iseq_eval_main vm.c:2851 ruby#25 0x102a82588 in rb_ec_exec_node eval.c:281 ruby#26 0x102a81fe0 in ruby_run_node eval.c:319 ruby#27 0x1027f3db4 in rb_main main.c:43 ruby#28 0x1027f3bd4 in main main.c:68 ruby#29 0x183900270 (<unknown module>) previously allocated by thread T0 here: #0 0x104174c04 in malloc+0x94 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x54c04) #1 0x102ada0ec in rb_gc_impl_malloc default.c:8198 ruby#2 0x102acee44 in ruby_xmalloc gc.c:4438 ruby#3 0x102f3c85c in rb_st_init_table_with_size st.c:571 ruby#4 0x102f3c900 in rb_st_init_table st.c:600 ruby#5 0x102f3c920 in rb_st_init_numtable st.c:608 ruby#6 0x103140698 in vm_track_constant_cache vm_insnhelper.c:6337 ruby#7 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356 ruby#8 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424 ruby#9 0x1030bc1e0 in vm_exec_core insns.def:263 ruby#10 0x1030b55fc in rb_vm_exec vm.c:2585 ruby#11 0x1030fe0ac in rb_iseq_eval_main vm.c:2851 ruby#12 0x102a82588 in rb_ec_exec_node eval.c:281 ruby#13 0x102a81fe0 in ruby_run_node eval.c:319 ruby#14 0x1027f3db4 in rb_main main.c:43 ruby#15 0x1027f3bd4 in main main.c:68 ruby#16 0x183900270 (<unknown module>) This commit fixes this bug by adding a inserting_constant_cache_id field to the VM, which stores the ID that is currently being inserted and, in remove_from_constant_cache, we don't free the ST table for ID equal to this one. Co-Authored-By: Alan Wu <alanwu@ruby-lang.org>
peterzhu2118
added a commit
that referenced
this pull request
Nov 29, 2024
Rust strings are not null-terminated but rb_intern uses strlen on the string, which causes a use-of-uninitialized-value error in MSAN because it ends up reading past the end of the string. ==16730==WARNING: MemorySanitizer: use-of-uninitialized-value #0 0x555555b9ff7e in rb_intern /home/peter/src/ruby/build/../symbol.c:825:29 #1 0x555555e536c7 in yjit::codegen::reg_method_codegen::hd714bff47c241e12 /home/peter/src/ruby/build/../yjit/src/codegen.rs:10740:24 ruby#2 0x555555e5304a in yjit::codegen::yjit_reg_method_codegen_fns::h086ce92dc4885e15 /home/peter/src/ruby/build/../yjit/src/codegen.rs:10661:9 ruby#3 0x555555e9deb7 in rb_yjit_init /home/peter/src/ruby/build/../yjit/src/yjit.rs:40:5
peterzhu2118
added a commit
that referenced
this pull request
Dec 2, 2024
[Bug #20921] When we create a cache entry for a constant, the following sequence of events could happen: - vm_track_constant_cache is called to insert a constant cache. - In vm_track_constant_cache, we first look up the ST table for the ID of the constant. Assume the ST table exists because another iseq also holds a cache entry for this ID. - We then insert into this ST table with the iseq_inline_constant_cache. - However, while inserting into this ST table, it allocates memory, which could trigger a GC. Assume that it does trigger a GC. - The GC frees the one and only other iseq that holds a cache entry for this ID. - In remove_from_constant_cache, it will appear that the ST table is now empty because there are no more iseq with cache entries for this ID, so we free the ST table. - We complete GC and continue our st_insert. However, this ST table has been freed so we now have a use-after-free. This issue is very hard to reproduce, because it requires that the GC runs at a very specific time. However, we can make it show up by applying this patch which runs GC right before the st_insert to mimic the st_insert triggering a GC: diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 3cb23f0..a93998136a 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -6338,6 +6338,10 @@ vm_track_constant_cache(ID id, void *ic) rb_id_table_insert(const_cache, id, (VALUE)ics); } + if (id == rb_intern("MyConstant")) rb_gc(); + st_insert(ics, (st_data_t) ic, (st_data_t) Qtrue); } And if we run this script: Object.const_set("MyConstant", "Hello!") my_proc = eval("-> { MyConstant }") my_proc.call my_proc = eval("-> { MyConstant }") my_proc.call We can see that ASAN outputs a use-after-free error: ==36540==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000049528 at pc 0x000102f3ceac bp 0x00016d607a70 sp 0x00016d607a68 READ of size 8 at 0x606000049528 thread T0 #0 0x102f3cea8 in do_hash st.c:321 #1 0x102f3ddd0 in rb_st_insert st.c:1132 ruby#2 0x103140700 in vm_track_constant_cache vm_insnhelper.c:6345 ruby#3 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356 ruby#4 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424 ruby#5 0x1030bc1e0 in vm_exec_core insns.def:263 ruby#6 0x1030b55fc in rb_vm_exec vm.c:2585 ruby#7 0x1030fe0ac in rb_iseq_eval_main vm.c:2851 ruby#8 0x102a82588 in rb_ec_exec_node eval.c:281 ruby#9 0x102a81fe0 in ruby_run_node eval.c:319 ruby#10 0x1027f3db4 in rb_main main.c:43 ruby#11 0x1027f3bd4 in main main.c:68 ruby#12 0x183900270 (<unknown module>) 0x606000049528 is located 8 bytes inside of 56-byte region [0x606000049520,0x606000049558) freed by thread T0 here: #0 0x104174d40 in free+0x98 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x54d40) #1 0x102ada89c in rb_gc_impl_free default.c:8183 ruby#2 0x102ada7dc in ruby_sized_xfree gc.c:4507 ruby#3 0x102ac4d34 in ruby_xfree gc.c:4518 ruby#4 0x102f3cb34 in rb_st_free_table st.c:663 ruby#5 0x102bd52d8 in remove_from_constant_cache iseq.c:119 ruby#6 0x102bbe2cc in iseq_clear_ic_references iseq.c:153 ruby#7 0x102bbd2a0 in rb_iseq_free iseq.c:166 ruby#8 0x102b32ed0 in rb_imemo_free imemo.c:564 ruby#9 0x102ac4b44 in rb_gc_obj_free gc.c:1407 ruby#10 0x102af4290 in gc_sweep_plane default.c:3546 ruby#11 0x102af3bdc in gc_sweep_page default.c:3634 ruby#12 0x102aeb140 in gc_sweep_step default.c:3906 ruby#13 0x102aeadf0 in gc_sweep_rest default.c:3978 ruby#14 0x102ae4714 in gc_sweep default.c:4155 ruby#15 0x102af8474 in gc_start default.c:6484 ruby#16 0x102afbe30 in garbage_collect default.c:6363 ruby#17 0x102ad37f0 in rb_gc_impl_start default.c:6816 ruby#18 0x102ad3634 in rb_gc gc.c:3624 ruby#19 0x1031406ec in vm_track_constant_cache vm_insnhelper.c:6342 #20 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356 ruby#21 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424 ruby#22 0x1030bc1e0 in vm_exec_core insns.def:263 ruby#23 0x1030b55fc in rb_vm_exec vm.c:2585 ruby#24 0x1030fe0ac in rb_iseq_eval_main vm.c:2851 ruby#25 0x102a82588 in rb_ec_exec_node eval.c:281 ruby#26 0x102a81fe0 in ruby_run_node eval.c:319 ruby#27 0x1027f3db4 in rb_main main.c:43 ruby#28 0x1027f3bd4 in main main.c:68 ruby#29 0x183900270 (<unknown module>) previously allocated by thread T0 here: #0 0x104174c04 in malloc+0x94 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x54c04) #1 0x102ada0ec in rb_gc_impl_malloc default.c:8198 ruby#2 0x102acee44 in ruby_xmalloc gc.c:4438 ruby#3 0x102f3c85c in rb_st_init_table_with_size st.c:571 ruby#4 0x102f3c900 in rb_st_init_table st.c:600 ruby#5 0x102f3c920 in rb_st_init_numtable st.c:608 ruby#6 0x103140698 in vm_track_constant_cache vm_insnhelper.c:6337 ruby#7 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356 ruby#8 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424 ruby#9 0x1030bc1e0 in vm_exec_core insns.def:263 ruby#10 0x1030b55fc in rb_vm_exec vm.c:2585 ruby#11 0x1030fe0ac in rb_iseq_eval_main vm.c:2851 ruby#12 0x102a82588 in rb_ec_exec_node eval.c:281 ruby#13 0x102a81fe0 in ruby_run_node eval.c:319 ruby#14 0x1027f3db4 in rb_main main.c:43 ruby#15 0x1027f3bd4 in main main.c:68 ruby#16 0x183900270 (<unknown module>) This commit fixes this bug by adding a inserting_constant_cache_id field to the VM, which stores the ID that is currently being inserted and, in remove_from_constant_cache, we don't free the ST table for ID equal to this one. Co-Authored-By: Alan Wu <alanwu@ruby-lang.org>
peterzhu2118
added a commit
that referenced
this pull request
Dec 3, 2024
[Bug #20921] When we create a cache entry for a constant, the following sequence of events could happen: - vm_track_constant_cache is called to insert a constant cache. - In vm_track_constant_cache, we first look up the ST table for the ID of the constant. Assume the ST table exists because another iseq also holds a cache entry for this ID. - We then insert into this ST table with the iseq_inline_constant_cache. - However, while inserting into this ST table, it allocates memory, which could trigger a GC. Assume that it does trigger a GC. - The GC frees the one and only other iseq that holds a cache entry for this ID. - In remove_from_constant_cache, it will appear that the ST table is now empty because there are no more iseq with cache entries for this ID, so we free the ST table. - We complete GC and continue our st_insert. However, this ST table has been freed so we now have a use-after-free. This issue is very hard to reproduce, because it requires that the GC runs at a very specific time. However, we can make it show up by applying this patch which runs GC right before the st_insert to mimic the st_insert triggering a GC: diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 3cb23f0..a93998136a 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -6338,6 +6338,10 @@ vm_track_constant_cache(ID id, void *ic) rb_id_table_insert(const_cache, id, (VALUE)ics); } + if (id == rb_intern("MyConstant")) rb_gc(); + st_insert(ics, (st_data_t) ic, (st_data_t) Qtrue); } And if we run this script: Object.const_set("MyConstant", "Hello!") my_proc = eval("-> { MyConstant }") my_proc.call my_proc = eval("-> { MyConstant }") my_proc.call We can see that ASAN outputs a use-after-free error: ==36540==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000049528 at pc 0x000102f3ceac bp 0x00016d607a70 sp 0x00016d607a68 READ of size 8 at 0x606000049528 thread T0 #0 0x102f3cea8 in do_hash st.c:321 #1 0x102f3ddd0 in rb_st_insert st.c:1132 ruby#2 0x103140700 in vm_track_constant_cache vm_insnhelper.c:6345 ruby#3 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356 ruby#4 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424 ruby#5 0x1030bc1e0 in vm_exec_core insns.def:263 ruby#6 0x1030b55fc in rb_vm_exec vm.c:2585 ruby#7 0x1030fe0ac in rb_iseq_eval_main vm.c:2851 ruby#8 0x102a82588 in rb_ec_exec_node eval.c:281 ruby#9 0x102a81fe0 in ruby_run_node eval.c:319 ruby#10 0x1027f3db4 in rb_main main.c:43 ruby#11 0x1027f3bd4 in main main.c:68 ruby#12 0x183900270 (<unknown module>) 0x606000049528 is located 8 bytes inside of 56-byte region [0x606000049520,0x606000049558) freed by thread T0 here: #0 0x104174d40 in free+0x98 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x54d40) #1 0x102ada89c in rb_gc_impl_free default.c:8183 ruby#2 0x102ada7dc in ruby_sized_xfree gc.c:4507 ruby#3 0x102ac4d34 in ruby_xfree gc.c:4518 ruby#4 0x102f3cb34 in rb_st_free_table st.c:663 ruby#5 0x102bd52d8 in remove_from_constant_cache iseq.c:119 ruby#6 0x102bbe2cc in iseq_clear_ic_references iseq.c:153 ruby#7 0x102bbd2a0 in rb_iseq_free iseq.c:166 ruby#8 0x102b32ed0 in rb_imemo_free imemo.c:564 ruby#9 0x102ac4b44 in rb_gc_obj_free gc.c:1407 ruby#10 0x102af4290 in gc_sweep_plane default.c:3546 ruby#11 0x102af3bdc in gc_sweep_page default.c:3634 ruby#12 0x102aeb140 in gc_sweep_step default.c:3906 ruby#13 0x102aeadf0 in gc_sweep_rest default.c:3978 ruby#14 0x102ae4714 in gc_sweep default.c:4155 ruby#15 0x102af8474 in gc_start default.c:6484 ruby#16 0x102afbe30 in garbage_collect default.c:6363 ruby#17 0x102ad37f0 in rb_gc_impl_start default.c:6816 ruby#18 0x102ad3634 in rb_gc gc.c:3624 ruby#19 0x1031406ec in vm_track_constant_cache vm_insnhelper.c:6342 #20 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356 ruby#21 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424 ruby#22 0x1030bc1e0 in vm_exec_core insns.def:263 ruby#23 0x1030b55fc in rb_vm_exec vm.c:2585 ruby#24 0x1030fe0ac in rb_iseq_eval_main vm.c:2851 ruby#25 0x102a82588 in rb_ec_exec_node eval.c:281 ruby#26 0x102a81fe0 in ruby_run_node eval.c:319 ruby#27 0x1027f3db4 in rb_main main.c:43 ruby#28 0x1027f3bd4 in main main.c:68 ruby#29 0x183900270 (<unknown module>) previously allocated by thread T0 here: #0 0x104174c04 in malloc+0x94 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x54c04) #1 0x102ada0ec in rb_gc_impl_malloc default.c:8198 ruby#2 0x102acee44 in ruby_xmalloc gc.c:4438 ruby#3 0x102f3c85c in rb_st_init_table_with_size st.c:571 ruby#4 0x102f3c900 in rb_st_init_table st.c:600 ruby#5 0x102f3c920 in rb_st_init_numtable st.c:608 ruby#6 0x103140698 in vm_track_constant_cache vm_insnhelper.c:6337 ruby#7 0x1030b91d8 in vm_ic_track_const_chain vm_insnhelper.c:6356 ruby#8 0x1030b8cf8 in rb_vm_opt_getconstant_path vm_insnhelper.c:6424 ruby#9 0x1030bc1e0 in vm_exec_core insns.def:263 ruby#10 0x1030b55fc in rb_vm_exec vm.c:2585 ruby#11 0x1030fe0ac in rb_iseq_eval_main vm.c:2851 ruby#12 0x102a82588 in rb_ec_exec_node eval.c:281 ruby#13 0x102a81fe0 in ruby_run_node eval.c:319 ruby#14 0x1027f3db4 in rb_main main.c:43 ruby#15 0x1027f3bd4 in main main.c:68 ruby#16 0x183900270 (<unknown module>) This commit fixes this bug by adding a inserting_constant_cache_id field to the VM, which stores the ID that is currently being inserted and, in remove_from_constant_cache, we don't free the ST table for ID equal to this one. Co-Authored-By: Alan Wu <alanwu@ruby-lang.org>
peterzhu2118
added a commit
that referenced
this pull request
Dec 20, 2024
When searching for native extensions, if the name does not end in ".so" then we create a new string and append ".so" so it. If the native extension is in static_ext_inits, then we could trigger a GC in the rb_filesystem_str_new_cstr. This could cuase the GC to free lookup_name since we don't use the local variable anymore. This bug was caught in this ASAN build: http://ci.rvm.jp/results/trunk_asan@ruby-sp1/5479182 ==435614==ERROR: AddressSanitizer: use-after-poison on address 0x715a63022da0 at pc 0x5e7463873e4e bp 0x7fff383c8b00 sp 0x7fff383c82c0 READ of size 14 at 0x715a63022da0 thread T0 #0 0x5e7463873e4d in __asan_memcpy (/tmp/ruby/build/trunk_asan/ruby+0x214e4d) (BuildId: 607411c0626a2f66b4c20c02179b346aace20898) #1 0x5e7463b50a82 in memcpy /usr/include/x86_64-linux-gnu/bits/string_fortified.h:29:10 ruby#2 0x5e7463b50a82 in ruby_nonempty_memcpy /tmp/ruby/src/trunk_asan/include/ruby/internal/memory.h:671:16 ruby#3 0x5e7463b50a82 in str_enc_new /tmp/ruby/src/trunk_asan/string.c:1035:9 ruby#4 0x5e74639b97dd in search_required /tmp/ruby/src/trunk_asan/load.c:1126:21 ruby#5 0x5e74639b97dd in require_internal /tmp/ruby/src/trunk_asan/load.c:1274:17 ruby#6 0x5e74639b83c1 in rb_require_string_internal /tmp/ruby/src/trunk_asan/load.c:1401:22 ruby#7 0x5e74639b83c1 in rb_require_string /tmp/ruby/src/trunk_asan/load.c:1387:12
peterzhu2118
added a commit
that referenced
this pull request
Dec 23, 2024
When searching for native extensions, if the name does not end in ".so" then we create a new string and append ".so" so it. If the native extension is in static_ext_inits, then we could trigger a GC in the rb_filesystem_str_new_cstr. This could cuase the GC to free lookup_name since we don't use the local variable anymore. This bug was caught in this ASAN build: http://ci.rvm.jp/results/trunk_asan@ruby-sp1/5479182 ==435614==ERROR: AddressSanitizer: use-after-poison on address 0x715a63022da0 at pc 0x5e7463873e4e bp 0x7fff383c8b00 sp 0x7fff383c82c0 READ of size 14 at 0x715a63022da0 thread T0 #0 0x5e7463873e4d in __asan_memcpy (/tmp/ruby/build/trunk_asan/ruby+0x214e4d) (BuildId: 607411c0626a2f66b4c20c02179b346aace20898) #1 0x5e7463b50a82 in memcpy /usr/include/x86_64-linux-gnu/bits/string_fortified.h:29:10 ruby#2 0x5e7463b50a82 in ruby_nonempty_memcpy /tmp/ruby/src/trunk_asan/include/ruby/internal/memory.h:671:16 ruby#3 0x5e7463b50a82 in str_enc_new /tmp/ruby/src/trunk_asan/string.c:1035:9 ruby#4 0x5e74639b97dd in search_required /tmp/ruby/src/trunk_asan/load.c:1126:21 ruby#5 0x5e74639b97dd in require_internal /tmp/ruby/src/trunk_asan/load.c:1274:17 ruby#6 0x5e74639b83c1 in rb_require_string_internal /tmp/ruby/src/trunk_asan/load.c:1401:22 ruby#7 0x5e74639b83c1 in rb_require_string /tmp/ruby/src/trunk_asan/load.c:1387:12
peterzhu2118
pushed a commit
that referenced
this pull request
May 7, 2025
…uby#13231) This change addresses the following ASAN error: ``` ==36597==ERROR: AddressSanitizer: heap-use-after-free on address 0x512000396ba8 at pc 0x7fcad5cbad9f bp 0x7fff19739af0 sp 0x7fff19739ae8 WRITE of size 8 at 0x512000396ba8 thread T0 [643/756] 36600=optparse/test_summary #0 0x7fcad5cbad9e in free_fast_fallback_getaddrinfo_entry /home/runner/work/ruby-dev-builder/ruby-dev-builder/ext/socket/raddrinfo.c:3046:22 #1 0x7fcad5c9fb48 in fast_fallback_inetsock_cleanup /home/runner/work/ruby-dev-builder/ruby-dev-builder/ext/socket/ipsocket.c:1179:17 ruby#2 0x7fcadf3b611a in rb_ensure /home/runner/work/ruby-dev-builder/ruby-dev-builder/eval.c:1081:5 ruby#3 0x7fcad5c9b44b in rsock_init_inetsock /home/runner/work/ruby-dev-builder/ruby-dev-builder/ext/socket/ipsocket.c:1289:20 ruby#4 0x7fcad5ca22b8 in tcp_init /home/runner/work/ruby-dev-builder/ruby-dev-builder/ext/socket/tcpsocket.c:76:12 ruby#5 0x7fcadf83ba70 in vm_call0_cfunc_with_frame /home/runner/work/ruby-dev-builder/ruby-dev-builder/./vm_eval.c:164:15 ... ``` A `struct fast_fallback_getaddrinfo_shared` is shared between the main thread and two child threads. This struct contains an array of `fast_fallback_getaddrinfo_entry`. `fast_fallback_getaddrinfo_entry` and `fast_fallback_getaddrinfo_shared` were freed separately, and if `fast_fallback_getaddrinfo_shared` was freed first and then an attempt was made to free a `fast_fallback_getaddrinfo_entry`, a `heap-use-after-free` could occur. This change avoids that possibility by separating the deallocation of the addrinfo memory held by `fast_fallback_getaddrinfo_entry` from the access and lifecycle of the `fast_fallback_getaddrinfo_entry` itself.
peterzhu2118
added a commit
that referenced
this pull request
May 8, 2025
[Bug #18119] When we create classes, it pushes the class to the subclass list of the superclass. This access needs to be synchronized because multiple Ractors may be creating classes with the same superclass, which would cause race conditions and cause the linked list to be corrupted. For example, we can reproduce with this script crashing: workers = (0...8).map do Ractor.new do loop do 100.times.map { Class.new } Ractor.yield nil end end end 100.times { Ractor.select(*workers) } With ASAN enabled, we can see that there are use-after-free errors: ==176013==ERROR: AddressSanitizer: heap-use-after-free on address 0x5030000974f0 at pc 0x62f9e56f892d bp 0x7a503f1ffd90 sp 0x7a503f1ffd88 WRITE of size 8 at 0x5030000974f0 thread T4 #0 0x62f9e56f892c in rb_class_remove_from_super_subclasses class.c:149:24 #1 0x62f9e58c9dd2 in rb_gc_obj_free gc.c:1262:9 ruby#2 0x62f9e58f6e19 in gc_sweep_plane gc/default/default.c:3450:21 ruby#3 0x62f9e58f686a in gc_sweep_page gc/default/default.c:3535:13 ruby#4 0x62f9e58f12b4 in gc_sweep_step gc/default/default.c:3810:9 ruby#5 0x62f9e58ed2a7 in gc_sweep gc/default/default.c:4058:13 ruby#6 0x62f9e58fac93 in gc_start gc/default/default.c:6402:13 ruby#7 0x62f9e58e8b69 in heap_prepare gc/default/default.c:2032:13 ruby#8 0x62f9e58e8b69 in heap_next_free_page gc/default/default.c:2255:9 ruby#9 0x62f9e58e8b69 in newobj_cache_miss gc/default/default.c:2362:38 ... 0x5030000974f0 is located 16 bytes inside of 24-byte region [0x5030000974e0,0x5030000974f8) freed by thread T4 here: #0 0x62f9e562f28a in free (miniruby+0x1fd28a) (BuildId: 5ad6d9e7cec8318df6726ea5ce34d3c76d0d0233) #1 0x62f9e58ca2ab in rb_gc_impl_free gc/default/default.c:8102:9 ruby#2 0x62f9e58ca2ab in ruby_sized_xfree gc.c:5029:13 ruby#3 0x62f9e58ca2ab in ruby_xfree gc.c:5040:5 ruby#4 0x62f9e56f88e6 in rb_class_remove_from_super_subclasses class.c:152:9 ruby#5 0x62f9e58c9dd2 in rb_gc_obj_free gc.c:1262:9 ruby#6 0x62f9e58f6e19 in gc_sweep_plane gc/default/default.c:3450:21 ruby#7 0x62f9e58f686a in gc_sweep_page gc/default/default.c:3535:13 ruby#8 0x62f9e58f12b4 in gc_sweep_step gc/default/default.c:3810:9 ruby#9 0x62f9e58ed2a7 in gc_sweep gc/default/default.c:4058:13 ... previously allocated by thread T5 here: #0 0x62f9e562f70d in calloc (miniruby+0x1fd70d) (BuildId: 5ad6d9e7cec8318df6726ea5ce34d3c76d0d0233) #1 0x62f9e58c8e1a in calloc1 gc/default/default.c:1472:12 ruby#2 0x62f9e58c8e1a in rb_gc_impl_calloc gc/default/default.c:8138:5 ruby#3 0x62f9e58c8e1a in ruby_xcalloc_body gc.c:4964:12 ruby#4 0x62f9e58c8e1a in ruby_xcalloc gc.c:4958:34 ruby#5 0x62f9e56f906e in push_subclass_entry_to_list class.c:88:13 ruby#6 0x62f9e56f906e in rb_class_subclass_add class.c:111:38 ruby#7 0x62f9e56f906e in RCLASS_SET_SUPER internal/class.h:257:9 ruby#8 0x62f9e56fca7a in make_metaclass class.c:786:5 ruby#9 0x62f9e59db982 in rb_class_initialize object.c:2101:5
peterzhu2118
added a commit
that referenced
this pull request
May 8, 2025
[Bug #18119] When we create classes, it pushes the class to the subclass list of the superclass. This access needs to be synchronized because multiple Ractors may be creating classes with the same superclass, which would cause race conditions and cause the linked list to be corrupted. For example, we can reproduce with this script crashing: workers = (0...8).map do Ractor.new do loop do 100.times.map { Class.new } Ractor.yield nil end end end 100.times { Ractor.select(*workers) } With ASAN enabled, we can see that there are use-after-free errors: ==176013==ERROR: AddressSanitizer: heap-use-after-free on address 0x5030000974f0 at pc 0x62f9e56f892d bp 0x7a503f1ffd90 sp 0x7a503f1ffd88 WRITE of size 8 at 0x5030000974f0 thread T4 #0 0x62f9e56f892c in rb_class_remove_from_super_subclasses class.c:149:24 #1 0x62f9e58c9dd2 in rb_gc_obj_free gc.c:1262:9 ruby#2 0x62f9e58f6e19 in gc_sweep_plane gc/default/default.c:3450:21 ruby#3 0x62f9e58f686a in gc_sweep_page gc/default/default.c:3535:13 ruby#4 0x62f9e58f12b4 in gc_sweep_step gc/default/default.c:3810:9 ruby#5 0x62f9e58ed2a7 in gc_sweep gc/default/default.c:4058:13 ruby#6 0x62f9e58fac93 in gc_start gc/default/default.c:6402:13 ruby#7 0x62f9e58e8b69 in heap_prepare gc/default/default.c:2032:13 ruby#8 0x62f9e58e8b69 in heap_next_free_page gc/default/default.c:2255:9 ruby#9 0x62f9e58e8b69 in newobj_cache_miss gc/default/default.c:2362:38 ... 0x5030000974f0 is located 16 bytes inside of 24-byte region [0x5030000974e0,0x5030000974f8) freed by thread T4 here: #0 0x62f9e562f28a in free (miniruby+0x1fd28a) (BuildId: 5ad6d9e7cec8318df6726ea5ce34d3c76d0d0233) #1 0x62f9e58ca2ab in rb_gc_impl_free gc/default/default.c:8102:9 ruby#2 0x62f9e58ca2ab in ruby_sized_xfree gc.c:5029:13 ruby#3 0x62f9e58ca2ab in ruby_xfree gc.c:5040:5 ruby#4 0x62f9e56f88e6 in rb_class_remove_from_super_subclasses class.c:152:9 ruby#5 0x62f9e58c9dd2 in rb_gc_obj_free gc.c:1262:9 ruby#6 0x62f9e58f6e19 in gc_sweep_plane gc/default/default.c:3450:21 ruby#7 0x62f9e58f686a in gc_sweep_page gc/default/default.c:3535:13 ruby#8 0x62f9e58f12b4 in gc_sweep_step gc/default/default.c:3810:9 ruby#9 0x62f9e58ed2a7 in gc_sweep gc/default/default.c:4058:13 ... previously allocated by thread T5 here: #0 0x62f9e562f70d in calloc (miniruby+0x1fd70d) (BuildId: 5ad6d9e7cec8318df6726ea5ce34d3c76d0d0233) #1 0x62f9e58c8e1a in calloc1 gc/default/default.c:1472:12 ruby#2 0x62f9e58c8e1a in rb_gc_impl_calloc gc/default/default.c:8138:5 ruby#3 0x62f9e58c8e1a in ruby_xcalloc_body gc.c:4964:12 ruby#4 0x62f9e58c8e1a in ruby_xcalloc gc.c:4958:34 ruby#5 0x62f9e56f906e in push_subclass_entry_to_list class.c:88:13 ruby#6 0x62f9e56f906e in rb_class_subclass_add class.c:111:38 ruby#7 0x62f9e56f906e in RCLASS_SET_SUPER internal/class.h:257:9 ruby#8 0x62f9e56fca7a in make_metaclass class.c:786:5 ruby#9 0x62f9e59db982 in rb_class_initialize object.c:2101:5
peterzhu2118
added a commit
that referenced
this pull request
May 8, 2025
[Bug #18119] When we create classes, it pushes the class to the subclass list of the superclass. This access needs to be synchronized because multiple Ractors may be creating classes with the same superclass, which would cause race conditions and cause the linked list to be corrupted. For example, we can reproduce with this script crashing: workers = (0...8).map do Ractor.new do loop do 100.times.map { Class.new } Ractor.yield nil end end end 100.times { Ractor.select(*workers) } With ASAN enabled, we can see that there are use-after-free errors: ==176013==ERROR: AddressSanitizer: heap-use-after-free on address 0x5030000974f0 at pc 0x62f9e56f892d bp 0x7a503f1ffd90 sp 0x7a503f1ffd88 WRITE of size 8 at 0x5030000974f0 thread T4 #0 0x62f9e56f892c in rb_class_remove_from_super_subclasses class.c:149:24 #1 0x62f9e58c9dd2 in rb_gc_obj_free gc.c:1262:9 ruby#2 0x62f9e58f6e19 in gc_sweep_plane gc/default/default.c:3450:21 ruby#3 0x62f9e58f686a in gc_sweep_page gc/default/default.c:3535:13 ruby#4 0x62f9e58f12b4 in gc_sweep_step gc/default/default.c:3810:9 ruby#5 0x62f9e58ed2a7 in gc_sweep gc/default/default.c:4058:13 ruby#6 0x62f9e58fac93 in gc_start gc/default/default.c:6402:13 ruby#7 0x62f9e58e8b69 in heap_prepare gc/default/default.c:2032:13 ruby#8 0x62f9e58e8b69 in heap_next_free_page gc/default/default.c:2255:9 ruby#9 0x62f9e58e8b69 in newobj_cache_miss gc/default/default.c:2362:38 ... 0x5030000974f0 is located 16 bytes inside of 24-byte region [0x5030000974e0,0x5030000974f8) freed by thread T4 here: #0 0x62f9e562f28a in free (miniruby+0x1fd28a) (BuildId: 5ad6d9e7cec8318df6726ea5ce34d3c76d0d0233) #1 0x62f9e58ca2ab in rb_gc_impl_free gc/default/default.c:8102:9 ruby#2 0x62f9e58ca2ab in ruby_sized_xfree gc.c:5029:13 ruby#3 0x62f9e58ca2ab in ruby_xfree gc.c:5040:5 ruby#4 0x62f9e56f88e6 in rb_class_remove_from_super_subclasses class.c:152:9 ruby#5 0x62f9e58c9dd2 in rb_gc_obj_free gc.c:1262:9 ruby#6 0x62f9e58f6e19 in gc_sweep_plane gc/default/default.c:3450:21 ruby#7 0x62f9e58f686a in gc_sweep_page gc/default/default.c:3535:13 ruby#8 0x62f9e58f12b4 in gc_sweep_step gc/default/default.c:3810:9 ruby#9 0x62f9e58ed2a7 in gc_sweep gc/default/default.c:4058:13 ... previously allocated by thread T5 here: #0 0x62f9e562f70d in calloc (miniruby+0x1fd70d) (BuildId: 5ad6d9e7cec8318df6726ea5ce34d3c76d0d0233) #1 0x62f9e58c8e1a in calloc1 gc/default/default.c:1472:12 ruby#2 0x62f9e58c8e1a in rb_gc_impl_calloc gc/default/default.c:8138:5 ruby#3 0x62f9e58c8e1a in ruby_xcalloc_body gc.c:4964:12 ruby#4 0x62f9e58c8e1a in ruby_xcalloc gc.c:4958:34 ruby#5 0x62f9e56f906e in push_subclass_entry_to_list class.c:88:13 ruby#6 0x62f9e56f906e in rb_class_subclass_add class.c:111:38 ruby#7 0x62f9e56f906e in RCLASS_SET_SUPER internal/class.h:257:9 ruby#8 0x62f9e56fca7a in make_metaclass class.c:786:5 ruby#9 0x62f9e59db982 in rb_class_initialize object.c:2101:5
peterzhu2118
added a commit
that referenced
this pull request
May 8, 2025
[Bug #18119] When we create classes, it pushes the class to the subclass list of the superclass. This access needs to be synchronized because multiple Ractors may be creating classes with the same superclass, which would cause race conditions and cause the linked list to be corrupted. For example, we can reproduce with this script crashing: workers = (0...8).map do Ractor.new do loop do 100.times.map { Class.new } Ractor.yield nil end end end 100.times { Ractor.select(*workers) } With ASAN enabled, we can see that there are use-after-free errors: ==176013==ERROR: AddressSanitizer: heap-use-after-free on address 0x5030000974f0 at pc 0x62f9e56f892d bp 0x7a503f1ffd90 sp 0x7a503f1ffd88 WRITE of size 8 at 0x5030000974f0 thread T4 #0 0x62f9e56f892c in rb_class_remove_from_super_subclasses class.c:149:24 #1 0x62f9e58c9dd2 in rb_gc_obj_free gc.c:1262:9 ruby#2 0x62f9e58f6e19 in gc_sweep_plane gc/default/default.c:3450:21 ruby#3 0x62f9e58f686a in gc_sweep_page gc/default/default.c:3535:13 ruby#4 0x62f9e58f12b4 in gc_sweep_step gc/default/default.c:3810:9 ruby#5 0x62f9e58ed2a7 in gc_sweep gc/default/default.c:4058:13 ruby#6 0x62f9e58fac93 in gc_start gc/default/default.c:6402:13 ruby#7 0x62f9e58e8b69 in heap_prepare gc/default/default.c:2032:13 ruby#8 0x62f9e58e8b69 in heap_next_free_page gc/default/default.c:2255:9 ruby#9 0x62f9e58e8b69 in newobj_cache_miss gc/default/default.c:2362:38 ... 0x5030000974f0 is located 16 bytes inside of 24-byte region [0x5030000974e0,0x5030000974f8) freed by thread T4 here: #0 0x62f9e562f28a in free (miniruby+0x1fd28a) (BuildId: 5ad6d9e7cec8318df6726ea5ce34d3c76d0d0233) #1 0x62f9e58ca2ab in rb_gc_impl_free gc/default/default.c:8102:9 ruby#2 0x62f9e58ca2ab in ruby_sized_xfree gc.c:5029:13 ruby#3 0x62f9e58ca2ab in ruby_xfree gc.c:5040:5 ruby#4 0x62f9e56f88e6 in rb_class_remove_from_super_subclasses class.c:152:9 ruby#5 0x62f9e58c9dd2 in rb_gc_obj_free gc.c:1262:9 ruby#6 0x62f9e58f6e19 in gc_sweep_plane gc/default/default.c:3450:21 ruby#7 0x62f9e58f686a in gc_sweep_page gc/default/default.c:3535:13 ruby#8 0x62f9e58f12b4 in gc_sweep_step gc/default/default.c:3810:9 ruby#9 0x62f9e58ed2a7 in gc_sweep gc/default/default.c:4058:13 ... previously allocated by thread T5 here: #0 0x62f9e562f70d in calloc (miniruby+0x1fd70d) (BuildId: 5ad6d9e7cec8318df6726ea5ce34d3c76d0d0233) #1 0x62f9e58c8e1a in calloc1 gc/default/default.c:1472:12 ruby#2 0x62f9e58c8e1a in rb_gc_impl_calloc gc/default/default.c:8138:5 ruby#3 0x62f9e58c8e1a in ruby_xcalloc_body gc.c:4964:12 ruby#4 0x62f9e58c8e1a in ruby_xcalloc gc.c:4958:34 ruby#5 0x62f9e56f906e in push_subclass_entry_to_list class.c:88:13 ruby#6 0x62f9e56f906e in rb_class_subclass_add class.c:111:38 ruby#7 0x62f9e56f906e in RCLASS_SET_SUPER internal/class.h:257:9 ruby#8 0x62f9e56fca7a in make_metaclass class.c:786:5 ruby#9 0x62f9e59db982 in rb_class_initialize object.c:2101:5
peterzhu2118
added a commit
that referenced
this pull request
May 9, 2025
[Bug #18119] When we create classes, it pushes the class to the subclass list of the superclass. This access needs to be synchronized because multiple Ractors may be creating classes with the same superclass, which would cause race conditions and cause the linked list to be corrupted. For example, we can reproduce with this script crashing: workers = (0...8).map do Ractor.new do loop do 100.times.map { Class.new } Ractor.yield nil end end end 100.times { Ractor.select(*workers) } With ASAN enabled, we can see that there are use-after-free errors: ==176013==ERROR: AddressSanitizer: heap-use-after-free on address 0x5030000974f0 at pc 0x62f9e56f892d bp 0x7a503f1ffd90 sp 0x7a503f1ffd88 WRITE of size 8 at 0x5030000974f0 thread T4 #0 0x62f9e56f892c in rb_class_remove_from_super_subclasses class.c:149:24 #1 0x62f9e58c9dd2 in rb_gc_obj_free gc.c:1262:9 ruby#2 0x62f9e58f6e19 in gc_sweep_plane gc/default/default.c:3450:21 ruby#3 0x62f9e58f686a in gc_sweep_page gc/default/default.c:3535:13 ruby#4 0x62f9e58f12b4 in gc_sweep_step gc/default/default.c:3810:9 ruby#5 0x62f9e58ed2a7 in gc_sweep gc/default/default.c:4058:13 ruby#6 0x62f9e58fac93 in gc_start gc/default/default.c:6402:13 ruby#7 0x62f9e58e8b69 in heap_prepare gc/default/default.c:2032:13 ruby#8 0x62f9e58e8b69 in heap_next_free_page gc/default/default.c:2255:9 ruby#9 0x62f9e58e8b69 in newobj_cache_miss gc/default/default.c:2362:38 ... 0x5030000974f0 is located 16 bytes inside of 24-byte region [0x5030000974e0,0x5030000974f8) freed by thread T4 here: #0 0x62f9e562f28a in free (miniruby+0x1fd28a) (BuildId: 5ad6d9e7cec8318df6726ea5ce34d3c76d0d0233) #1 0x62f9e58ca2ab in rb_gc_impl_free gc/default/default.c:8102:9 ruby#2 0x62f9e58ca2ab in ruby_sized_xfree gc.c:5029:13 ruby#3 0x62f9e58ca2ab in ruby_xfree gc.c:5040:5 ruby#4 0x62f9e56f88e6 in rb_class_remove_from_super_subclasses class.c:152:9 ruby#5 0x62f9e58c9dd2 in rb_gc_obj_free gc.c:1262:9 ruby#6 0x62f9e58f6e19 in gc_sweep_plane gc/default/default.c:3450:21 ruby#7 0x62f9e58f686a in gc_sweep_page gc/default/default.c:3535:13 ruby#8 0x62f9e58f12b4 in gc_sweep_step gc/default/default.c:3810:9 ruby#9 0x62f9e58ed2a7 in gc_sweep gc/default/default.c:4058:13 ... previously allocated by thread T5 here: #0 0x62f9e562f70d in calloc (miniruby+0x1fd70d) (BuildId: 5ad6d9e7cec8318df6726ea5ce34d3c76d0d0233) #1 0x62f9e58c8e1a in calloc1 gc/default/default.c:1472:12 ruby#2 0x62f9e58c8e1a in rb_gc_impl_calloc gc/default/default.c:8138:5 ruby#3 0x62f9e58c8e1a in ruby_xcalloc_body gc.c:4964:12 ruby#4 0x62f9e58c8e1a in ruby_xcalloc gc.c:4958:34 ruby#5 0x62f9e56f906e in push_subclass_entry_to_list class.c:88:13 ruby#6 0x62f9e56f906e in rb_class_subclass_add class.c:111:38 ruby#7 0x62f9e56f906e in RCLASS_SET_SUPER internal/class.h:257:9 ruby#8 0x62f9e56fca7a in make_metaclass class.c:786:5 ruby#9 0x62f9e59db982 in rb_class_initialize object.c:2101:5
peterzhu2118
pushed a commit
that referenced
this pull request
Jun 11, 2025
In commit d42b9ff, an optimization was introduced that can speed up Regexp#match by 15% when it matches with strings of different encodings. This optimization, however, does not work across ractors. To fix this, we only use the optimization if no ractors have been started. In the future, we could use atomics for the reference counting if we find it's needed and if it's more performant. The backtrace of the misbehaving native thread: ``` * frame #0: 0x0000000189c94388 libsystem_kernel.dylib`__pthread_kill + 8 frame #1: 0x0000000189ccd88c libsystem_pthread.dylib`pthread_kill + 296 frame ruby#2: 0x0000000189bd6c60 libsystem_c.dylib`abort + 124 frame ruby#3: 0x0000000189adb174 libsystem_malloc.dylib`malloc_vreport + 892 frame ruby#4: 0x0000000189adec90 libsystem_malloc.dylib`malloc_report + 64 frame ruby#5: 0x0000000189ae321c libsystem_malloc.dylib`___BUG_IN_CLIENT_OF_LIBMALLOC_POINTER_BEING_FREED_WAS_NOT_ALLOCATED + 32 frame ruby#6: 0x00000001001c3be4 ruby`onig_free_body(reg=0x000000012d84b660) at regcomp.c:5663:5 frame ruby#7: 0x00000001001ba828 ruby`rb_reg_prepare_re(re=4748462304, str=4748451168) at re.c:1680:13 frame ruby#8: 0x00000001001bac58 ruby`rb_reg_onig_match(re=4748462304, str=4748451168, match=(ruby`reg_onig_search [inlined] rbimpl_RB_TYPE_P_fastpath at value_type.h:349:14 ruby`reg_onig_search [inlined] rbimpl_rstring_getmem at rstring.h:391:5 ruby`reg_onig_search at re.c:1781:5), args=0x000000013824b168, regs=0x000000013824b150) at re.c:1708:20 frame ruby#9: 0x00000001001baefc ruby`rb_reg_search_set_match(re=4748462304, str=4748451168, pos=<unavailable>, reverse=0, set_backref_str=1, set_match=0x0000000000000000) at re.c:1809:27 frame ruby#10: 0x00000001001bae80 ruby`rb_reg_search0(re=<unavailable>, str=<unavailable>, pos=<unavailable>, reverse=<unavailable>, set_backref_str=<unavailable>, match=<unavailable>) at re.c:1861:12 [artificial] frame ruby#11: 0x0000000100230b90 ruby`rb_pat_search0(pat=<unavailable>, str=<unavailable>, pos=<unavailable>, set_backref_str=<unavailable>, match=<unavailable>) at string.c:6619:16 [artificial] frame ruby#12: 0x00000001002287f4 ruby`rb_str_sub_bang [inlined] rb_pat_search(pat=4748462304, str=4748451168, pos=0, set_backref_str=1) at string.c:6626:12 frame ruby#13: 0x00000001002287dc ruby`rb_str_sub_bang(argc=1, argv=0x00000001381280d0, str=4748451168) at string.c:6668:11 frame ruby#14: 0x000000010022826c ruby`rb_str_sub ``` You can reproduce this by running: ``` RUBY_TESTOPTS="--name=/test_str_capitalize/" make test-all TESTS=test/ruby/test_m17n.comb ``` However, you need to run it with multiple ractors at once. Co-authored-by: jhawthorn <john@hawthorn.email>
peterzhu2118
pushed a commit
that referenced
this pull request
Jul 2, 2025
`name` is used via `RSTRING_PTR` within rb_str_catf, which may allocate and thus potentially trigger GC. Although `name` is still referenced by a local variable, the compiler might optimize away the reference before the GC sees it, especially under aggressive optimization or when debugging tools like ASAN are used. This patch adds an explicit `RB_GC_GUARD` to ensure `name` is kept alive until after the last use. While it's not certain this is the root cause of the following observed use-after-poison ASAN error, I believe this fix is indeed needed and hopefully a likely candidate for preventing the error. ``` ==1960369==ERROR: AddressSanitizer: use-after-poison on address 0x7ec6a00f1d88 at pc 0x5fb5bcafcf2e bp 0x7ffcc1178cb0 sp 0x7ffcc1178470 READ of size 61 at 0x7ec6a00f1d88 thread T0 #0 0x5fb5bcafcf2d in __asan_memcpy (/tmp/ruby/build/trunk_asan/ruby+0x204f2d) (BuildId: 6d92c84a27b87cfd253c38eeb552593f215ffb3d) #1 0x5fb5bcde1fa5 in memcpy /usr/include/x86_64-linux-gnu/bits/string_fortified.h:29:10 ruby#2 0x5fb5bcde1fa5 in ruby_nonempty_memcpy /tmp/ruby/src/trunk_asan/include/ruby/internal/memory.h:758:16 ruby#3 0x5fb5bcde1fa5 in ruby__sfvwrite /tmp/ruby/src/trunk_asan/sprintf.c:1083:9 ruby#4 0x5fb5bcde1521 in BSD__sprint /tmp/ruby/src/trunk_asan/vsnprintf.c:318:8 ruby#5 0x5fb5bcde0fbc in BSD_vfprintf /tmp/ruby/src/trunk_asan/vsnprintf.c:1215:3 ruby#6 0x5fb5bcdde4b1 in ruby_vsprintf0 /tmp/ruby/src/trunk_asan/sprintf.c:1164:5 ruby#7 0x5fb5bcddd648 in rb_str_vcatf /tmp/ruby/src/trunk_asan/sprintf.c:1234:5 ruby#8 0x5fb5bcddd648 in rb_str_catf /tmp/ruby/src/trunk_asan/sprintf.c:1245:11 ruby#9 0x5fb5bcf97c67 in location_format /tmp/ruby/src/trunk_asan/vm_backtrace.c:462:9 ruby#10 0x5fb5bcf97c67 in location_to_str /tmp/ruby/src/trunk_asan/vm_backtrace.c:493:12 ruby#11 0x5fb5bcf90a37 in location_to_str_dmyarg /tmp/ruby/src/trunk_asan/vm_backtrace.c:795:12 ruby#12 0x5fb5bcf90a37 in backtrace_collect /tmp/ruby/src/trunk_asan/vm_backtrace.c:786:28 ruby#13 0x5fb5bcf90a37 in backtrace_to_str_ary /tmp/ruby/src/trunk_asan/vm_backtrace.c:804:9 ruby#14 0x5fb5bcf90a37 in rb_backtrace_to_str_ary /tmp/ruby/src/trunk_asan/vm_backtrace.c:816:9 ruby#15 0x5fb5bd335b25 in exc_backtrace /tmp/ruby/src/trunk_asan/error.c:1904:15 ruby#16 0x5fb5bd335b25 in rb_get_backtrace /tmp/ruby/src/trunk_asan/error.c:1924:16 ``` https://ci.rvm.jp/results/trunk_asan@ruby-sp1/5810304
peterzhu2118
pushed a commit
that referenced
this pull request
Jul 12, 2025
This change addresses the following ASAN error: ``` ==1973462==ERROR: AddressSanitizer: heap-use-after-free on address 0x5110002117dc at pc 0x749c307c8a65 bp 0x7ffc3af331d0 sp 0x7ffc3af331c8 READ of size 4 at 0x5110002117dc thread T0 #0 0x749c307c8a64 in rb_getaddrinfo /tmp/ruby/src/trunk_asan/ext/socket/raddrinfo.c:564:14 #1 0x749c307c8a64 in rsock_getaddrinfo /tmp/ruby/src/trunk_asan/ext/socket/raddrinfo.c:1008:21 ruby#2 0x749c307cac48 in rsock_addrinfo /tmp/ruby/src/trunk_asan/ext/socket/raddrinfo.c:1049:12 ruby#3 0x749c307b10ae in init_inetsock_internal /tmp/ruby/src/trunk_asan/ext/socket/ipsocket.c:62:23 ruby#4 0x562c5b2e327e in rb_ensure /tmp/ruby/src/trunk_asan/eval.c:1080:18 ruby#5 0x749c307aafd4 in rsock_init_inetsock /tmp/ruby/src/trunk_asan/ext/socket/ipsocket.c:1318:12 ruby#6 0x749c307b3b78 in tcp_svr_init /tmp/ruby/src/trunk_asan/ext/socket/tcpserver.c:39:12 ``` Fixed to avoid accessing memory that has already been freed after calling `free_getaddrinfo_arg`.
peterzhu2118
pushed a commit
that referenced
this pull request
Jul 12, 2025
This is notably faster: no need to hash indices. Before: ``` plum% samply record ~/.rubies/ruby-zjit/bin/ruby --zjit benchmarks/getivar.rb ruby 3.5.0dev (2025-07-10T14:40:49Z master 51252ef) +ZJIT dev +PRISM [arm64-darwin24] itr: time #1: 5311ms ruby#2: 49ms ruby#3: 49ms ruby#4: 48ms ``` After: ``` plum% samply record ~/.rubies/ruby-zjit/bin/ruby --zjit benchmarks/getivar.rb ruby 3.5.0dev (2025-07-10T15:09:06Z mb-benchmark-compile 42ffd3c) +ZJIT dev +PRISM [arm64-darwin24] itr: time #1: 1332ms ruby#2: 49ms ruby#3: 48ms ruby#4: 48ms ```
peterzhu2118
pushed a commit
that referenced
this pull request
Jul 29, 2025
Previously, ZJIT miscompiled the following because of native SP interference. def a(n1,n2,n3,n4,n5,n6,n7,n8) = [n8] a(0,0,0,0,0,0,0, :ok) Commented problematic disassembly: ; call rb_ary_new_capa mov x0, #1 mov x16, #0x1278 movk x16, #0x4bc, lsl ruby#16 movk x16, #1, lsl ruby#32 blr x16 ; call rb_ary_push mov x1, x0 str x1, [sp, #-0x10]! ; c_push() from alloc_regs() mov x0, x1 ; arg0, the array ldur x1, [sp] ; meant to be arg1=n8, but sp just moved! mov x16, #0x3968 movk x16, #0x4bc, lsl ruby#16 movk x16, #1, lsl ruby#32 blr x16 Since the frame pointer stays constant in the body of the function, static offsets based on it don't run the risk of being invalidated by SP movements. Pass the registers to preserve through Insn::FrameSetup. This allows ARM to use STP and waste no gaps between EC, SP, and CFP. x86 now preserves and restores RBP since we use it as the frame pointer. Since all arches now have a frame pointer, remove offset based SP movement in the epilogue and restore registers using the frame pointer.
peterzhu2118
added a commit
that referenced
this pull request
Jul 30, 2025
During Ruby's shutdown, we no longer need to check the fstr of the symbol because we don't use the fstr anymore for freeing the symbol. This can also fix the following ASAN error: ==2721247==ERROR: AddressSanitizer: use-after-poison on address 0x75fa90a627b8 at pc 0x64a7b06fb4bc bp 0x7ffdf95ba9b0 sp 0x7ffdf95ba9a8 READ of size 8 at 0x75fa90a627b8 thread T0 #0 0x64a7b06fb4bb in RB_BUILTIN_TYPE include/ruby/internal/value_type.h:191:30 #1 0x64a7b06fb4bb in rb_gc_shutdown_call_finalizer_p gc.c:357:18 ruby#2 0x64a7b06fb4bb in rb_gc_impl_shutdown_call_finalizer gc/default/default.c:3045:21 ruby#3 0x64a7b06fb4bb in rb_objspace_call_finalizer gc.c:1739:5 ruby#4 0x64a7b06ca1b2 in rb_ec_finalize eval.c:165:5 ruby#5 0x64a7b06ca1b2 in rb_ec_cleanup eval.c:256:5 ruby#6 0x64a7b06c98a3 in ruby_cleanup eval.c:179:12
peterzhu2118
added a commit
that referenced
this pull request
Jul 31, 2025
During Ruby's shutdown, we no longer need to check the fstr of the symbol because we don't use the fstr anymore for freeing the symbol. This can also fix the following ASAN error: ==2721247==ERROR: AddressSanitizer: use-after-poison on address 0x75fa90a627b8 at pc 0x64a7b06fb4bc bp 0x7ffdf95ba9b0 sp 0x7ffdf95ba9a8 READ of size 8 at 0x75fa90a627b8 thread T0 #0 0x64a7b06fb4bb in RB_BUILTIN_TYPE include/ruby/internal/value_type.h:191:30 #1 0x64a7b06fb4bb in rb_gc_shutdown_call_finalizer_p gc.c:357:18 ruby#2 0x64a7b06fb4bb in rb_gc_impl_shutdown_call_finalizer gc/default/default.c:3045:21 ruby#3 0x64a7b06fb4bb in rb_objspace_call_finalizer gc.c:1739:5 ruby#4 0x64a7b06ca1b2 in rb_ec_finalize eval.c:165:5 ruby#5 0x64a7b06ca1b2 in rb_ec_cleanup eval.c:256:5 ruby#6 0x64a7b06c98a3 in ruby_cleanup eval.c:179:12
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
ary could change embeddedness due to compaction, so we should only get the pointer after allocations.
The included test was crashing with: