ワナビーエンジニアのブログ

なんでもいいから文化的な生活を送りたい

Rubyの#13053を読んでみる(1)

前回のあと、しばらくしてsvn updateし直してからmakeしてみたところ無事rubyのビルドが成功しました。やはり単に最新のrubyを使うだけでいろんなバグが踏めそうです。(普通にrubyを使うにはそれが目的でないとは無いと思いますが)

Issue読んでみる

さて、引き続いて今回はissueを読んでみます。 まずは、既にクローズされたチケットから読んでみて、雰囲気を味わうことを目的にします。

#13053

これを見ていきます。 Bug #13053: Array#select! can resize to negative size - Ruby trunk - Ruby Issue Tracking System

選んだ理由はなんとなくです。朝通勤中に電車でメールを見てたら[ruby-core:78739] で流れてきたので選んでみました。 タイトルから見るにArray#select!*1の問題みたいです。

descriptionを読む

まずはチケットのdescriptionを確認

Since Ruby 2.3 ([Feature #10714]), the following code cause the Array to be nagative number size.

ary = [1,2,3,4,5]
ary.select! { |i| ary.clear if i==5; false }
p ary #=> []
p ary.size #=> -5

コードで説明しているissueは分かりやすくて助かります。ary.select! { |i| ary.clear if i==5; false }は、配列をイテレートして、5だったら配列を空に、次行でブロックの戻り値をfalseとしています。 なんでこんなことすんの(´・ω・`)って思いますが、 aryは空になっているにもかかわらず、ary.sizeが-5になのは明らかに変で、0になるべきです。

因みにこれをruby-2.2.6で実行すると

irb(main):001:0> ary = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
irb(main):002:0> ary.select! { |i| ary.clear if i==5; false }
=> []
irb(main):003:0> p ary
[]
=> []
irb(main):004:0> p ary.size
0
=> 0

ちゃんとary.sizeが0になっています。

修正内容をみる

revision 57121で修正されていますので、diff*2を確認します。 rubyでは、svnredmineの連携を使用されているので見やすく良いです。 diffから見るに、trunk直下のarray.cとそのユニットテストが更新されことが確認できます。

testには、先ほどdescriptionでみた問題コードが記述されています。 これ、確かにテストにはなると思いますが、なんでこのテストコードでいいんだろう。。

testの内容も気になりますが、とりあえず置いといて、array.cの修正をみます。 redmineのdiffが見づらいのでgithubで確認しました。 array.c: do not resize to less than 0 · ruby/ruby@b5da45d · GitHub

修正前コード

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;
}

ふむ。まずselect_bang_ensure(VALUE a)っていう関数がなんぞやって感じですが、関数名から推察するにselect!の処理ルーチンのようです。

引数のVALUEは、値へのポインタです。(このあたりはRubyのしくみに書いてました) select_bang_arg構造体のaryメンバに配列情報が入っているみたいで、。 RARRAY_LEN(ary)は、マクロ処理で配列の長さを取得できるようです。

long i1 = arg->len[0], i2 = arg->len[1];

のlen[0]とlen[1]がパッと見わからなかったのでselect_bang_arg構造体を見ます。

struct select_bang_arg {
    VALUE ary;
    long len[2];
};

なるほど。何も説明が無い! 勘となりますが、len[0]が配列のheadへのポインタで、len[1]が配列のtailへのポインタ(´・ω・`)違う?

これは遡ってlenが何かを確認する必要がありそうです。 select_bang_ensure()は、rb_ary_select_bang()からrb_ensure()に関数ポインタを渡しているみたいなので、次回rb_ary_select_bang()から追ってみたいと思います。


ここまで気になったこと

array

Arrayなんてとっくに枯れて安定しているものと思っていましたが、 これみたいに機能追加でデグレがあるんですね。 こういうところは貢献していきやすいのではないかと思いました。

array.cのtest

テストこれで過不足ないのか感。やっぱDone better than perfect.なんでしょうか。

修正の確認環境

redmineにあるコードをコピペしたら、改行コードの関係か1行が2行にずれる。 githubで修正を確認しましたが、他に楽に差分確認する方法あるんでしょうか? Rubyコミッター方の作業環境(使用ツールとか使ってるwebサービスとか)に興味ある。

インデントがタブとスペース

array.c見ただけですが、タブとスペースがごっちゃまぜ(´・ω・`)(´・ω・`)(´・ω・`) 統一してほしいです! 宗教戦争になりそうですが・・・

redmine

会社でもredmine使っているのに、家でもredmineでissueみることになるなこれ(^ω^;三;^ω^) redmineがもうちょっと進化してくんない限りgithubがいいですなあ・・

スポンサードリンク

Rubyのしくみ -Ruby Under a Microscope-

Rubyのしくみ -Ruby Under a Microscope-

続く Rubyの#13053を読んでみる(2)