From: Yusuke ENDOH Date: 2008-01-24T00:03:24+09:00 Subject: [ruby-dev:33328] can modify array during iteration 遠藤と申します。 1.9 で以下のようにするとイテレート中の配列を書き換えることができます。 a = [0, 1, 2] a.each do a.each {} a.clear end p a #=> [] 内側の each が終わる時、a の ARY_ITERLOCK が解放されてしまうためです。 これを修正するためには、ARY_ITERLOCK がロックされている回数を保存し、 それが 0 になったときだけ書き換えを認めるようにしないといけないと思い ます。 関連して、以下のようにすると落ちます。Array#map! が、イテレート中に 書き換えられないことを前提にしていることが原因です。 $ ./ruby -e ' a = (0 ... 100000).to_a a.map! do |i| if i == 99999 a.each { } a.clear end i end ' -e:3: [BUG] Segmentation fault ruby 1.9.0 (2008-01-23 revision 0) [i686-linux] -- control frame ---------- c:0004 p:---- s:0010 b:0010 l:000009 d:000009 CFUNC :map! c:0003 p:0018 s:0007 b:0007 l:000006 d:000006 TOP -e:3 c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH :inherited c:0001 p:0000 s:0002 b:0002 l:000001 d:000001 TOP :17 --------------------------- DBG> : "-e:3:in `
'" -- backtrace of native function call (Use addr2line) -- 0x80f04a5 0x810f3ce 0x810f42b 0x80bf860 0xffffe440 0x80598b1 0x80fabf5 0x80eecc3 0x80ea5ee 0x80edeb4 0x80ee1ed 0x805a6f9 0x805e840 0x8058121 0xb7dc1ea8 0x8058031 ------------------------------------------------------- アボートしました 以下はアボートする問題に対するパッチです。 Index: array.c =================================================================== --- array.c (revision 15191) +++ array.c (working copy) @@ -1644,7 +1644,7 @@ rb_ary_modify(ary); for (i = 0; i < RARRAY_LEN(ary); i++) { - RARRAY_PTR(ary)[i] = rb_yield(RARRAY_PTR(ary)[i]); + rb_ary_store(ary, i, rb_yield(RARRAY_PTR(ary)[i])); } return ary; } -- Yusuke ENDOH