Personal tools
You are here: Home ブログ 井上 久々にCで面白いバグ(読者への挑戦状篇)
« December 2010 »
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 entries
Apache2.4のリリース予定は来年(2011年)初め(あくまで予定) inoue 2010-12-23
Herokuの発音 inoue 2010-12-20
雑誌記事「ソフトウェア・テストPRESS Vol.9」の原稿公開 inoue 2010-12-18
IPA未踏のニュース inoue 2010-12-15
労基法とチキンゲーム inoue 2010-12-06
フロントエンドエンジニア inoue 2010-12-03
ASCII.technologies誌にMapReduceの記事を書きました inoue 2010-11-25
技術評論社パーフェクトシリーズ絶賛発売中 inoue 2010-11-24
雑誌連載「Emacsのトラノマキ」の原稿(part8)公開 inoue 2010-11-22
RESTの当惑 inoue 2010-11-22
「プログラマのためのUXチートシート」を作りました inoue 2010-11-19
「ビューティフルコード」を読みました inoue 2010-11-16
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.