Personal tools
You are here: Home ブログ 井上 久々にCで面白いバグ(読者への挑戦状篇)
« August 2008 »
Su Mo Tu We Th Fr Sa
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
Recent comments
Re:Software Design 2008年2月号「Emacsマスターへの道」の原稿を公開 elim 2008-07-25
Re:Rails(ActiveRecord)のJOINのイディオム inoue 2008-06-20
Re:「ピアレビュー」を読みました Anonymous User 2008-05-12
Re:「ピアレビュー」を読みました inoue 2008-05-10
Re:「ピアレビュー」を読みました Anonymous User 2008-05-09
Re:「ピープルウェア」再読 inoue 2008-04-20
Re:僅か30分で3つのバグ - Rubyの落し穴 - inoue 2008-04-20
Re:僅か30分で3つのバグ - Rubyの落し穴 - rubikitch 2008-04-19
Re:ソフトウェアインスペクションの試行 horii 2008-03-31
Re:「ピープルウェア」再読 anaka 2008-03-31
Re:WEB+DB Press Vol.43の記事への指摘 yanagisawa 2008-03-25
Re:マルスケと月刊I/O あなか 2008-03-23
Categories
カテゴリなし
 
Document Actions

久々にCで面白いバグ(読者への挑戦状篇)

常日頃、面白いバグが無いかと探しています。見つけた時は嬉しくて、このアリエルエリアで紹介しています。

自分にとって面白いバグの条件は次のようになります。

  • 一瞬気づかないが、指摘されると、あっ、と思えるもの
  • コンパイラなど静的チェックでは見つからないもの
  • どこでも起こりうるもの

普遍性と意外性を備えたバグが、好みのバグです。単純なのに意外、という性質を備えていれば更に良しですが、理想的なバグはそうそう転がっていません。最近の不満は、社内で、Javaのコードインスペクションをしているのに、面白いバグを発見できないことです。社員が優秀すぎるのでしょうか。わざと見つけにくいバグを仕込むぐらいの男気が欲しいものです。

Javaではなく、Cで久々に面白いバグに出会いました。

こんなコードです(少し変えています)。

// buggy code
*(const char**)apr_array_push(arr) = arr->nelts == 0 ? "foo" : "bar";

背景となる説明(特にAPRのapr_array_push()の説明)がそれなりに必要です。しかし、バグの原因自体は、普遍性があります。

apr_array_push()とデータ型は次のようなコードです。説明に必要な部分だけを抜粋および少し改変してます。

struct apr_array_header_t {
    /** The amount of memory allocated for each element of the array */
    int elt_size;
    /** The number of active elements in the array */
    int nelts;
    /** The elements in the array */
    char *elts;
};
APR_DECLARE(void *) apr_array_push(apr_array_header_t *arr)
{
    //このメモリ確保のコードは改変しています
    arr->elts = apr_palloc(arr->pool, arr->elt_size * new_size); // don't care new_size
    ++arr->nelts;
    return arr->elts + (arr->elt_size * (arr->nelts - 1));
}

正直、非常に分かりづらいコードです。提供している機能は動的配列です。例えば文字列の配列なら次のイディオムで使えます(このAPIの是非は今日の主眼ではありません)。このイディオムだけ認識しておけば、内部実装にはあまり深入りしなくても大丈夫です。

apr_array_header_t* arr = apr_array_make(mp, 32, sizeof(const char*));
*(const char**)apr_array_push(arr) = "foo";
*(const char**)apr_array_push(arr) = "bar";
*(const char**)apr_array_push(arr) = "baz";

buggy codeは実際にはループの中にありました。3項演算子で参照しているarr->neltsは、動的配列の要素数です。つまり、コードの意図は配列の先頭にだけ"foo"を追加して、残りは"bar"を追加するというものです(実際のコードでは、配列に追加する値は違うものです)。

ここまでで、最初に挙げたbuggy codeのバグの原因を推理できる全ての手がかりを提示しました。推理小説であれば、読者への挑戦状を書くところです。

せっかくなので、解答篇は明日にします。

ヒント

  • ポインタ関連のバグではありません
  • Javaでは(残念ながら)同じバグを起こせません
  • K&R2の65ページ参照
The URL to Trackback this entry is:
http://dev.ariel-networks.com/Members/inoue/c-bug/tbping
Add comment

You can add a comment by filling out the form below. Plain text formatting.

(Required)
(Required)
(Required)
This helps us prevent automated spamming.
Captcha Image


Copyright(C) 2001 - 2006 Ariel Networks, Inc. All rights reserved.