Project

General

Profile

Bug #21567

Updated by peterzhu2118 (Peter Zhu) 2 days ago

GitHub PR: https://github.com/ruby/ruby/pull/14487 

 When we require an object that is not a string, it will attempt to convert it to a string by calling to_str on it. If we modify the $LOADED_FEATURES array while it calls to_str, Ruby can crash because it can end up inserting the string in the wrong index in the array. 

 For example, the following script crashes: 

 ```ruby 
 require "tempfile" 

 class MyString 
   def initialize(path) 
     @path = path 
   end 

   def to_str 
     $LOADED_FEATURES.clear 
     @path 
   end 

   def to_path = @path 
 end 

 def create_ruby_file = Tempfile.create(["test", ".rb"]).path 

 require MyString.new(create_ruby_file) 
 $LOADED_FEATURES.unshift(create_ruby_file) 
 $LOADED_FEATURES << MyString.new(create_ruby_file) 
 require create_ruby_file 
 ``` 

 Crash log: 

 ``` 
 test.rb:21: [BUG] Segmentation fault at 0x0000000000000004 
 ruby 3.5.0dev (2025-09-09T09:29:35Z master ce94add7fb) +PRISM [arm64-darwin24] 

 -- Crash Report log information -------------------------------------------- 
   See Crash Report log file in one of the following locations: 
     * ~/Library/Logs/DiagnosticReports 
     * /Library/Logs/DiagnosticReports 
   for more details. 
 Don't forget to include the above Crash Report log file in bug reports. 

 -- Control frame information ----------------------------------------------- 
 c:0003 p:---- s:0011 e:000010 CFUNC    :require 
 c:0002 p:0076 s:0006 e:000005 EVAL     test.rb:21 [FINISH] 
 c:0001 p:0000 s:0003 E:0001b0 DUMMY    [FINISH] 

 -- Ruby level backtrace information ---------------------------------------- 
 test.rb:21:in '<main>' 
 test.rb:21:in 'require' 

 -- Threading information --------------------------------------------------- 
 Total ractor count: 1 
 Ruby thread count for this ractor: 1 

 -- Machine register context ------------------------------------------------ 
   x0: 0x0000000000000004    x1: 0x000000000000c800    x2: 0x0000000000000000 
   x3: 0x0000000000000000    x4: 0x0000000000000205    x5: 0x0000000000000000 
   x6: 0x0000000000000000    x7: 0x0000000000000001 x18: 0x0000000000000000 
 x19: 0x0000000209dfc0b0 x20: 0x0000000209dfc018 x21: 0x000000016ee8ab58 
 x22: 0x0fffffff0009d71d x23: 0x0000000209dfc018 x24: 0x0000000209dfc150 
 x25: 0x000000016ee8acc0 x26: 0x0000000000000000 x27: 0x0000000000000000 
 x28: 0x0000000000000000    lr: 0x0000000101244140    fp: 0x000000016ee887f0 
   sp: 0x000000016ee887d0 

 -- C level backtrace information ------------------------------------------- 
 miniruby(rb_print_backtrace+0x24) [0x101317b08] vm_dump.c:843 
 miniruby(rb_print_backtrace) (null):0 
 miniruby(rb_vm_bugreport+0x26c) [0x101317d94] vm_dump.c:1175 
 miniruby(rb_bug_for_fatal_signal+0xa4) [0x10105ddac] error.c:1130 
 miniruby(sig_do_nothing+0x0) [0x1012278c0] signal.c:948 
 miniruby(sigsegv) (null):0 
 /usr/lib/system/libsystem_platform.dylib(_sigtramp+0x38) [0x19c1216a4] 
 miniruby(rb_str_new_frozen+0x1c) [0x101244140] string.c:1495 
 miniruby(rb_check_realpath_internal+0x68) [0x101077804] file.c:4679 
 miniruby(rb_check_realpath+0x2c) [0x101077aa4] file.c:4765 
 miniruby(get_loaded_features_index+0x37c) [0x1010f9c94] load.c:467 
 miniruby(rb_feature_p+0xd0) [0x1010f8174] load.c:582 
 miniruby(search_required+0xac) [0x1010f6ad4] load.c:1193 
 miniruby(require_internal+0x274) [0x1010f7518] load.c:1424 
 miniruby(rb_require_string_internal+0x94) [0x1010f6830] load.c:1571 
 miniruby(rb_require_string+0x58) [0x1010f66e8] load.c:1557 
 miniruby(rb_f_require+0x1c) [0x1010f6684] load.c:1150 
 miniruby(ractor_safe_call_cfunc_1+0x38) [0x101306c28] vm_insnhelper.c:3696 
 miniruby(vm_call_cfunc_with_frame_+0x250) [0x1012f857c] vm_insnhelper.c:3873 
 miniruby(vm_call_cfunc_with_frame+0x6c) [0x1012f8834] vm_insnhelper.c:3919 
 miniruby(vm_sendish+0x1a8) [0x1012c990c] vm_insnhelper.c:6087 
 miniruby(vm_exec_core+0x4050) [0x1012cfb48] insns.def:900 
 miniruby(vm_exec_loop+0x80) [0x1012e5448] vm.c:2666 
 miniruby(rb_vm_exec+0x134) [0x1012c9b40] vm.c:2645 
 miniruby(rb_iseq_eval_main+0x34) [0x1012e5628] vm.c:2919 
 miniruby(rb_ec_exec_node+0xe4) [0x10106d094] eval.c:282 
 miniruby(ruby_run_node+0x94) [0x10106cf64] eval.c:320 
 miniruby(rb_main+0x40) [0x100f7499c] main.c:42 
 miniruby(main+0x60) [0x100f74928] main.c:62 
 ``` 

Back