Fix out-of-bounds read in rb_location_ary_to_backtrace

rb_location_ary_to_backtrace was not checking the length of the array before
reading the first element. It can be reproduced by the following script:

    begin
      raise
    rescue
      $@ = []
    end

With assertions enabled, it crashes with:

    internal/array.h:143: Assertion Failed: RARRAY_AREF:i < RARRAY_LEN(ary)
    ruby 3.5.0dev (2025-09-10T19:01:16Z array-aref-assert-.. c431de0c64) +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:0004 p:---- s:0015 e:000014 CFUNC  :set_backtrace
    c:0003 p:0013 s:0012 e:000009 RESCUE test.rb:4
    c:0002 p:0004 s:0006 e:000005 EVAL   test.rb:1 [FINISH]
    c:0001 p:0000 s:0003 E:001bb0 DUMMY  [FINISH]

    -- Ruby level backtrace information ----------------------------------------
    test.rb:1:in '<main>'
    test.rb:4:in 'rescue in <main>'
    test.rb:4:in 'set_backtrace'

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

    -- C level backtrace information -------------------------------------------
    miniruby(rb_vm_bugreport+0xb88) [0x1002adb88] vm_dump.c:1175
    miniruby(rb_vm_bugreport) (null):0
    miniruby(rb_assert_failure_detail+0xd4) [0x1003fbf90] error.c:1215
    miniruby(rb_assert_failure_detail+0x0) [0x1003fbebc] error.c:1191
    miniruby(rb_assert_failure) (null):0
    miniruby(RARRAY_AREF+0x20) [0x1003f82c8] internal/array.h:143
    miniruby(rb_keyword_error_new.cold.2) class.c:2867
    miniruby(rb_keyword_error_new.cold.4) (null):0
    miniruby(rb_location_ary_to_backtrace+0x244) [0x1002a8a60] internal/array.h:143
    miniruby(RB_TEST+0x0) [0x1000ba648] error.c:2111
    miniruby(exc_set_backtrace) error.c:2112
    miniruby(vm_call0_body+0x7d0) [0x1002a414c] vm_eval.c:164
    miniruby(rb_vm_call0+0x100) [0x100286ee4] vm_eval.c:101
    miniruby(set_backtrace+0xfc) [0x1000c88a4] eval_error.c:75
    miniruby(rb_gvar_set_entry+0x10) [0x100269230] variable.c:990
    miniruby(rb_gvar_set) variable.c:1021
    miniruby(vm_exec_core+0x1258) [0x10027a744] insns.def:319
    miniruby(rb_vm_exec+0x324) [0x100277a8c] vm.c:2666
    miniruby(rb_ec_exec_node+0x74) [0x1000c4a38] eval.c:282
    miniruby(ruby_run_node+0x64) [0x1000c4968] eval.c:320
    miniruby(rb_main+0x1c) [0x100000980] main.c:42
    miniruby(main) main.c:62
This commit is contained in:
Peter Zhu 2025-09-10 19:53:13 -04:00
parent f164e1c03a
commit b62753246e

View File

@ -858,7 +858,7 @@ rb_backtrace_to_location_ary(VALUE self)
VALUE
rb_location_ary_to_backtrace(VALUE ary)
{
if (!RB_TYPE_P(ary, T_ARRAY) || !rb_frame_info_p(RARRAY_AREF(ary, 0))) {
if (!RB_TYPE_P(ary, T_ARRAY) || RARRAY_LEN(ary) == 0 || !rb_frame_info_p(RARRAY_AREF(ary, 0))) {
return Qfalse;
}