printf(buffer) の危険性2006年06月15日 13時49分31秒

他人が書いたプログラムを読んでいると結構目に付く。これは、極めて危険な操作だ。fprintf(stderr, buffer) も同じく危険だ。


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 ができる。

この手にバグは一番見つけづらい。正常に動いているときは問題なく、何かがおかしいときに限って、更におかしな挙動をするのだから。しかも、他の人が書いたものだから、どこにこんな危険なのがあるのかも特定しづらい。

コメント

コメントをどうぞ

※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。

※なお、送られたコメントはブログの管理者が確認するまで公開されません。

名前:
メールアドレス:
URL:
コメント:

トラックバック

このエントリのトラックバックURL: http://uyota.asablo.jp/blog/2006/06/15/406044/tb

※なお、送られたトラックバックはブログの管理者が確認するまで公開されません。