printf(buffer) の危険性 ― 2006年06月15日 13時49分31秒
FILE *Fopen(const char *path, const char *mode)
{
FILE *fd = fopen(path, mode);
if(fd == NULL)
fprintf(stderr, path);
return fd;
}
等とやるのが、よく見られる間違いだ。
FILE *Fopen(const char *path, const char *mode)
{
FILE *fd = fopen(path, mode);
#if !DEBUG
if(fd == NULL)
#endif
fprintf(stderr, path);
return fd;
}
とやってみよう。デバッグしようと #define DEBUG 1 とすると、動かなくなるコードの完成だ。
さて、何が危険か判っただろうか。もし、パスに % が含まれていたら、fprintf が暴走する。UNIX で % をパス名に使うことは稀だが、VOS では致命症になる。VOS のパス名は、%system1#disk1>system>include_library などとなるからである。
Fopen("%system1#disk1>system>include_library>stdio.h", "r");
などとやってみよう。printf が %system1 の %s を文字列と解釈し、次の引数を探しにいくのである。もちろん、そこには正しい引数など存在しない。core dump などが起きるのである。
printf 系の関数では、整形済の文字列を渡すのなら
printf("%s", buffer);
にしなければいけない。運がよければ、core 等で判るかも知れないが、大体スタックが破壊されていて、何も役に立たない。なお、VOS での core file は keep file と呼ばれる。例えば、emacs が死ぬと emacs.kp ができる。
この手にバグは一番見つけづらい。正常に動いているときは問題なく、何かがおかしいときに限って、更におかしな挙動をするのだから。しかも、他の人が書いたものだから、どこにこんな危険なのがあるのかも特定しづらい。
最近のコメント