FIO18-C. fwrite() が書き込み操作を null 文字で終了すると想定しない
C99 [ISO/IEC 9899:1999] では fwrite() 関数を次のように定義している。
size_t fwrite(const void *restrict ptr, size_t size, size_t nitems, FILE *restrict stream);
fwrite() 関数は、ptr が指す配列から、最大 nitems 個の大きさ size の要素を、stream が指すストリームに書き込む。それぞれのオブジェクトに対して、オブジェクトを unsigned char 型配列とみなして(その順番で)値を取り出し、fputc() 関数を size 回呼び出す。そのストリームのファイル位置表示子(定義されていれば)を書込みに成功した文字数分進める。エラーが発生した場合、そのストリームのファイル位置表示子の値は不定とする。
この定義では、fwrite() 関数は null 文字を検出するとファイルへの文字のコピーを停止するとは述べていない。したがって、fwrite() 関数を使用してファイルに null 終端バイト文字列を書き込む場合、必ず、文字列の長さに 1 を加えた長さ(null 文字を考慮して)を nitems パラメータとして使用せよ。
違反コード
以下のコード例では、バッファのサイズが size1 に格納されるが、size2 個の文字がファイルに書き込まれる。size2 が size1 よりも大きい場合、write() は null 文字の位置で文字のコピーを中止しない。
#include <stdio.h> char *buffer = NULL; size_t size1, size2; FILE *filedes; /* * size1 と size2 は正しく初期化されているものとする */ filedes = fopen("out.txt", "w+"); if (filedes == NULL) { /* エラー処理 */ } buffer = (char *)calloc( 1, size1); if (buffer == NULL) { /* エラー処理 */ } fwrite(buffer, 1, size2, filedes); free(buffer); buffer = NULL; fclose(filedes);
適合コード
以下の解決法は、正しい文字数がファイルに書き込まれることを保証している。
char *buffer = NULL; size_t size1, size2; FILE *filedes; /* * size1 は正しく初期化されているものとする */ filedes = fopen("out.txt", "w+"); if (filedes == NULL){ /* エラー処理 */ } buffer = (char *)calloc( 1, size1); if (buffer == NULL) { /* エラー処理 */ } /* * buffer に文字列を受け取る * バッファオーバーフローがないか検査 */ size2 = strlen(buffer) + 1; fwrite(buffer, 1, size2, filedes); free(buffer); buffer = NULL; fclose(filedes);
リスク評価
このレコメンデーションに違反した場合、null 終端されていない文字列がファイルに書き込まれることがある。その場合、ファイルに書き込まれた文字列をプログラムが null 終端バイト文字列として読み取ろうとしたときに問題が生じる。
レコメンデーション | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
FIO18-C | 中 | 中 | 中 | P12 | L1 |
参考情報
- http://www.opengroup.org/onlinepubs/009695399/functions/fwrite.html
- [ISO/IEC 9899:1999] Section 7.19.8.2, "The fwrite function"
翻訳元
これは以下のページを翻訳したものです。
FIO18-C. Never expect fwrite() to terminate the writing process at a NULL character