Help us understand the problem. What is going on with this article?

DustMiteで、バグ再現最小コードを作る

More than 5 years have passed since last update.

D言語 Advent Calendar 2013の二日目の記事です。DustMiteに関する日本語のドキュメントが皆無だったので、DustMiteについて書きます。あと、DustMiteと検索する時は注意してください。

バグ報告をしよう!!

D言語のコアな機能を酷使していると、たまにdmdのバグを踏むことがあります。そんな時は、ぜひバグ報告をしましょう!!

でも、バグを再現する最小コード作るの面倒くさい

わかる。しかし、

shell
$ dmd bug.d
dmd: glue.c:1281: virtual unsigned int Type::totym(): Assertion `0' failed.

のように、特定のメッセージの出力とともにdmdが落ちるというバグの場合、DustMiteを使うと、それなりに簡単にバグ再現最小コードが作れます!!

https://github.com/CyberShadow/DustMite

DustMiteってなんぞ?

DustMiteは、D言語用のコードミニマイザです。こちらが指定したテスターを使い、テストをpassする最小のコードを総当りで探してくれるツールです。たとえば、

hoge.d
module hoge;

import std.stdio;

void main()
{
    int a;
    "hoge".writeln();
}

この、hogeと出力するだけのコードを、hogeと出力する部分のみを残して最小化したいとします。hoge.dをsrcディレクトリに入れ、DustMiteを使うと、

shell
$ cd src
$ rdmd hoge.d > ../out
$ cd ..
$ dustmite src "rdmd hoge.d 2>&1 | diff - ../out >/dev/null"

src.reducedディレクトリに、

hoge.d
import std.stdio;

void main()
{
"hoge".writeln;
}

のように、最小化されたhoge.dが作成されます。きれいにint a;が消え去りました。

DustMiteを使って、バグ再現性を保ちつつコードを減らす

上のような感じで、バグ再現性を保ちつつコードを減らすことが出来ます。試しに、Issue 11622の再現コードを減らしてみます。

bug11622.d
class A(T)
{
    B!T foo()
    {
        return new B!T;
    }
}

class B(T) : T
{
}

static assert(!__traits(compiles, {
    class C : A!C  { }
}));

bug11622.dをsrcディレクトリに放り込み、まずはエラーメッセージを保存しておきます。

shell
$ cd src
$ rdmd bug11622.d &> ../out
$ cd ..
$ cat out
dmd: glue.c:1281: virtual unsigned int Type::totym(): Assertion `0' failed.

DustMiteには、終了ステータスが、正しい出力の時に0、正しくない出力の時に0以外になるコマンドをテスターとして渡します。今回は、diffを使い、予め保存しておいたエラーメッセージと、実行結果を比較するというコマンドを作り、それを渡します。

shell
$ dustmite src "rdmd bug11622.d 2>&1 | diff - ../out > /dev/null"

第一引数には、最小化したいソースコード群が入ったディレクトリを、第二引数にはテスターとなるコマンドの文字列表現を渡します。DustMiteは、カレントディレクトリにテスト用のディレクトリを作り、そこにソースコード群をコピーした後、そのディレクトリにcdしてテストを実行するので、bug11622.dやoutのパスには気をつけてください。減らす作業が終了すると、src.reducedディレクトリ内に

bug11622.d
class A(T)
{
B!T foo()
{
return B!T;
}
}

class B(T) : T
{
}

static assert(!__traits(compiles, {
class C : A!C  { }
}));

減らされたbug11622.dが生成されます。どうやら、returnとnewを取り除いても同様のエラーメッセージとなるようです。

まとめ

上のような感じで、DustMiteを使うことで、バグ再現性を維持しつつコードの量をある程度減らすことが出来ます。と言っても完璧ではないので、DustMiteが減らしたコードを人間が減らし、またDustMiteに掛ける、と言った感じで補助的にDustMiteを使うと、とてもバグ再現最小コードの作成が楽になると思います。

運悪くdmdのバグを踏み抜いてしまった時、是非DustMiteを試してみてください。

youxkei
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away