Rubyの#13053を読んでみる(3)
前々回、
前回でlen[0]、len[1]が明らかになったので、select_bang_ensure
をみていきます。
修正前コード
static VALUE select_bang_ensure(VALUE a) { volatile struct select_bang_arg *arg = (void *)a; VALUE ary = arg->ary; long len = RARRAY_LEN(ary); long i1 = arg->len[0], i2 = arg->len[1]; if (i2 < i1) { if (i1 < len) { RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr + i2, ptr + i1, VALUE, len - i1); }); } ARY_SET_LEN(ary, len - i1 + i2); } return ary; }
さてlen, i1, i2について考えます。i1 = arg->len[0]
は元々のArrayの長さで、i2 = arg->len[1]
がselect!後のArrayの長さとわかっています。
最後にlenですが、引数として受け取ったarg->ary
の長さとなります。しかしこれ、呼び出し元のrb_ary_select_bangを軽く読んでみても何が入るか良くわからず。。
#13503のケースを考える
arg->ary
に何が渡されているかパッとはわからないので、
立ち返ってhttps://bugs.ruby-lang.org/issues/13053のスニペットを考えます。
ary = [1,2,3,4,5] ary.select! { |i| ary.clear if i==5; false } p ary #=> [] p ary.size #=> -5
今までの結果から、i1=5、 i2=0。これに、ARRAY_SET_LEN(ary, len - i1 + i2) #=> -5
なので、lenは0です。多分どこかでselect_bang_ensureに渡されるargs->len
の値が狂っていそうです。
修正後コード
ここで#13053の修正方法を見てみます。
static VALUE select_bang_ensure(VALUE a) { volatile struct select_bang_arg *arg = (void *)a; VALUE ary = arg->ary; long len = RARRAY_LEN(ary); long i1 = arg->len[0], i2 = arg->len[1]; if (i2 < len && i2 < i1) { long tail = 0; if (i1 < len) { tail = len - i1; RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr + i2, ptr + i1, VALUE, tail); }); } ARY_SET_LEN(ary, i2 + tail); } return ary; }
このコードだとlen=0のときif (i2 < len && i2 < i1) {
で偽となるので、p ary.size #=> 0
となりそうですね。
チケットのコメントを見ると下記の記載があります。
Shrinking the Array from the block invoked by Array#select! or Array#reject! causes the Array to be a negative number size. Ensure that the resulting Array won't be smaller than 0.
超訳:"lenを0未満にはしないようにした"
なんだか本対処じゃなくってフェールセーフ処理っぽいですね。 つまりargs->lenが0となっている根本原因は他にありそうです。
まとめ
- rubyのissue #13053と、共にArray#select!の処理を追ってきた
rb_ary_select_bang
がArray#select!の入口で、そこからselect_bang_i
とselect_bang_ensure
を呼ぶselect_bang_i
は、select!後のArrayを生成select_bang_ensure
は、select!後のArray.lengthを設定(#13053はここにフェールセーフ処理を追加した)
今後
rubyのissueの雰囲気はつかめたので、
args->ary
に0が渡されている元を追ってみたいと思います。
スポンサードリンク
- 作者: Yugui
- 出版社/メーカー: オライリージャパン
- 発売日: 2008/06/26
- メディア: 大型本
- 購入: 27人 クリック: 644回
- この商品を含むブログ (253件) を見る