これは悶絶する…

auのW42CAとW42Hに強制再起動する不具合

インプレスのニュース配信を見ていて、ああまた何かバグが…と思って本文見たら超絶吹いた。

この特定の文字列とは、「%n」および「%S」のことで、「%」と「n」の間に0?255の半角数字や「+」「-」がある場合も該当する。

(;^ω^)%sと%nって…メールの表示にprintf()使ってて、メッセージを直接format指定(第1引数)のところに渡してたんやね。これはひじょーに赤面ものかも。実際はprintf()相当の関数を使ってると思うが、物凄く簡略化して書くとおそらく、
char *msg = "%s";
printf(msg);

ということをやっちゃったんだな。%sは文字列参照だからスタックに文字列へのポインタが積まれてると仮定し、あるはずのないポインタをスタックから取ってきて訳の判らないアドレスを文字列とみなしてNULLが出て来るまでかっ飛ぶ。で、表示用バッファかもしくはsprintf()系ならコピー先バッファがあふれてメモリ破壊。
%nは項目数を引数に指定されたポインタの指す領域に格納するので、これまたどこを指してるか判らないスタックの値を信じてメモリ書き換え。多分、関数の戻り番地あたりを参照してるだろうから、プログラム領域を破壊してThe Endかな。
文字列中に書式指定やエスケープシーケンス等の特殊文字が含まれる可能性がある場合は、絶対にformat指定の第1引数にそのまま渡しちゃいけない。やるなら、
char *msg = "%s";
printf("%s", msg);

と間接指定しないとまずい。そもそもprintf()相当を使わなければ…という話もあるが、printf()を使いたくなる気持ちも判らないでもない。
これ%sと%nと書いてるけど、%dやら%uやら%xも反応すると思うんだがどうなんだろう。ゴミの数値を表示するだけで暴走はしないだろうが、それもまずいと言えばまずいと思うんだが。
この手のバグはプログラマなら一度は経験するし避けては通れない試練だとは思う。が、やっぱ開発者は今頃恥ずかしい思いをしてるんだろうなあ。

コメント

  1. ほたるさん より:

    それすら完璧に忘れちまうほどのデスマが日立カシオで進行してたのかもしれんね(;^ω^)
    もしくは、タイミング的に合併一号の機械で現場はわやくちゃだったのかもしれん。

  2. itsu より:

    デスマで大量派遣投入か、もしくは時期的に新人大量投入かで、
    結局クォリティが保てなくなったのかなあ。
    たまにやっちゃうケアレスミスみたいなものだけど、
    常に頭に例外ケースを想定してコードを書くクセをつけないとねー。