dearblue · GitHub

I checked the following with bin/mruby built with build_config/default.rb.

$i = 0
class C
  def ==(other)
    GC.start
    ($i += 1) == 3
  end
end
a = 5.times.map { C.new }
x = a.delete(C.new)
GC.start
p x   # => #<String:0x2545eba2a790>     ## <-- where did this string object originate?
p x   # => "#<String:0x2545eba2a790>"   ## <-- why is it enclosed in double quotes?
      # I expected #<C:0x2a935722a6f0> to be printed twice

This can cause problems if the mrb_equal() called by mrb_ary_delete() internally calls the obj.== method.
Therefore, the following precautions should be taken.

  • The need first for mrb_gc_protect() when holding an object in a ret variable after mrb_equal().
    If an object in a ret variable is GC'd with a subsequent obj.== method, the recycled object is the return value of Array#delete.
  • After calling mrb_equal(), the ary and len variables need to be updated and call ary_modify().
    If the array object is modified by obj.== method, it will hold invalid values.

Alternatively, it would be better to raise an exception when a change to the array object is detected, as was done in commit 752ebe6 .

For the moment, just a report.

The reason I noticed this problem is that bin/mrbtest crashed when I built with a test patch for #6222 which emulates stack address changes.

Read the original on github.com ↗