Issue #21996 has been updated by rwstauner (Randy Stauner). Backport changed from 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: REQUIRED to 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: DONE ruby_4_0 commit:6fd2ae629a40353a3f377718544e1a3ee7a1ab65 merged revision(s) commit:f2d0ef269b47af7d0e658016903bd8917c32899a. ---------------------------------------- Bug #21996: Crash when modifying instance variables during inspect or Marshal dump https://bugs.ruby-lang.org/issues/21996#change-117775 * Author: jhawthorn (John Hawthorn) * Status: Closed * Backport: 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: DONE ---------------------------------------- In #15968 describes an issue where instance variables being modified lead to incorrect Marshal output being generated, which was partially solved by checking for the number of IVs changing and raising an exception. However, if enough IVs removed this could cause the buffer to be moved/re-embedded, but we'd still attempt to read the now removed variables. I've found this reproduces back to Ruby 3.3, but suspect there are other ways to hit issues on older versions. We've seen the test from #15968 start failing on CI recently (likely because the changes to size pools makes this crash reproducible) https://github.com/ruby/ruby/actions/runs/24247666394/job/70803324392 ``` ruby class Evil def initialize(parent) @parent = parent end def marshal_dump @parent.instance_variables.each { |v| @parent.remove_instance_variable(v) } {} end def marshal_load(data) = nil end obj = Object.new obj.instance_variable_set(:@evil, Evil.new(obj)) 10.times { |i| obj.instance_variable_set(:"@v#{i}", 0) } Marshal.dump(obj) # SEGV ``` ``` ruby class Evil def initialize(parent) @parent = parent end def inspect @parent.instance_variables.each { |v| @parent.remove_instance_variable(v) } "" end end obj = Object.new obj.instance_variable_set(:@evil, Evil.new(obj)) 10.times { |i| obj.instance_variable_set(:"@v#{i}", 0) } obj.inspect # SEGV ``` -- https://bugs.ruby-lang.org/