JPCERT コーディネーションセンター

FIO24-C. すでにオープンされているファイルをオープンしない

すでにオープンされているファイルをオープンしたときの動作は処理系定義である。C 言語規格 7.21.3 第8パラグラフには次のように規定されている[ISO/IEC 9899:2011]。

それ以外の(非一時)ファイルをオープンする関数は、ファイル名(file name)を必要とする。ファイル名は文字列とする。正しいファイル名の規則は、処理系定義とする。同一のファイルを同時に複数回オープンできるかどうかも、処理系定義とする。

いくつかの処理系では、同一ファイルを複数回同時にオープンすることを許可しない。したがって、移植性のあるコードにするには、このルールに違反したときの動作に依存してはならない。既にオープンされているファイルをさらにオープンする操作がエラーにならない処理系であっても、TOCTOU (time-of-check, time-of-use) 競合状態が存在し、ファイルが移動されたり削除されたりすることで、2度目の操作が1度目とは異なるファイルに対して行われる可能性がある(「FIO45-C. Avoid TOCTOU race conditions while accessing files for more details on TOCTOU race conditions」を参照)。

違反コード

次のコード例では、実行時のプログラムの状態をログに書き込んでいる。

#include <stdio.h>

void do_stuff(void) {
  FILE *logfile = fopen("log", "a");
  if (logfile == NULL) {
    /* エラー処理 */
  }
 
  /* do_stuff() の処理に関するログを書き込む */
  fprintf(logfile, "do_stuff\n");
}

int main(void) {
  FILE *logfile = fopen("log", "a");
  if (logfile == NULL) {
    /* エラー処理 */
  }

  /* main() の処理に関するログを書き込む */
  fprintf(logfile, "main\n");

  do_stuff();

  if (fclose(logfile) == EOF) {
    /* エラー処理 */
  }
  return 0;
}

ファイル log が2度オープンされているため(最初に main() で、次に do_stuff() で)、プログラムの動作は処理系定義である。

適合コード

次の適合コードでは、ファイルポインタへの参照を関数の引数として渡しており、関数は引数で渡されたファイルに対する操作を行う。ファイルポインタへの参照を渡すことで、同じファイルを何度もオープンする必要がなくなる。

#include <stdio.h>

void do_stuff(FILE *logfile) {
  /* do_stuff() の処理に関するログを書き込む */
  fprintf(logfile, "do_stuff\n");
}

int main(void) {
  FILE *logfile = fopen("log", "a");
  if (logfile == NULL) {
    /* エラー処理 */
  }

  /* main() の処理に関するログを書き込む */
  fprintf(logfile, "main\n");

  do_stuff(logfile);

  if (fclose(logfile) == EOF) {
    /* エラー処理 */
  }
  return 0;
}
リスク評価

同一のファイルを同時に複数回オープンすると、予期せぬエラーが発生したり、可搬性のない動作が生じる可能性がある。

ルール

深刻度

可能性

修正コスト

優先度

レベル

FIO31-C

P4

L3

自動検出

ツール

バージョン

チェッカー

説明

CodeSonar
4.5p1

IO.RACE
(customization)

File system race condition
Users can implement a custom check that triggers a warning if a file-opening function is called on a file that is already open

LDRA tool suite
9.7.1

75 D

一部実装済み

Polyspace Bug Finder

R2016b Opening previously opened resource Opening an already opened file
関連するガイドライン
SEI CERT C Coding Standard FIO45-C. Avoid TOCTOU race conditions while accessing files
SEI CERT C++ Coding Standard VOID FIO21-CPP. Do not simultaneously open the same file multiple times
MITRE CWE CWE-362, Concurrent Execution Using Shared Resource with Improper Synchronization ("Race Condition")
CWE-675, Duplicate Operations on Resource
参考資料
[ISO/IEC 9899:2011 Subclause 7.21.3, "Files"
翻訳元

これは以下のページを翻訳したものです。

FIO24-C. Do not open a file that is already open (revision 80)

Top へ

Topへ
最新情報(RSSメーリングリストTwitter