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;
}
リスク評価
同一のファイルを同時に複数回オープンすると、予期せぬエラーが発生したり、可搬性のない動作が生じる可能性がある。
ルール |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
FIO24-C |
中 |
中 |
高 |
P4 |
L3 |
自動検出(最新の情報はこちら)
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
CodeSonar |
8.1p0
|
IO.RACE IO.BRAW |
File system race condition File Open for Both Read and Write |
LDRA tool suite |
9.7.1
|
75 D |
一部実装済み |
Parasoft C/C++test |
2023.1 |
CERT_C-FIO24-a | Avoid race conditions while accessing files |
R2024a |
CERT C: Rec. FIO24-C | Checks for situations where previously opened resources are reopened (rec. fully covered) |
関連するガイドライン
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 89)