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

FIO18-C. fwrite() が書き込み操作を null 文字で終了すると想定しない

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 個の文字がファイルに書き込まれる。size2size1 よりも大きい場合、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
参考情報
翻訳元

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

FIO18-C. Never expect fwrite() to terminate the writing process at a NULL character

Top へ

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