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 aretvariable aftermrb_equal().
If an object in aretvariable is GC'd with a subsequentobj.==method, the recycled object is the return value ofArray#delete. - After calling
mrb_equal(), thearyandlenvariables need to be updated and callary_modify().
If the array object is modified byobj.==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.