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

FIO17-C. fread() を使用するときは、null 終端文字に依存しない

C 言語規格 [ISO/IEC 9899:1999] で定義されている fread() 関数は、読み取った文字列を明示的に null 終端しない。

構文
size_t fread(void * restrict ptr, size_t size, size_t nmemb, FILE * restrict stream)

機能
fread 関数は、stream が指すストリームから、最大 nmemb 個の大きさ size の要素を、ptr が指す配列に読み取る。

ファイルの内容に null 終端された文字列が含まれていても、nmemb が文字列の長さより短い場合は、fread() 関数は nmemb 文字以降を読み取らない。fread() は読み取った文字列の終端に null 文字を追加しない。

違反コード

ファイル内に null 終端された文字列があり、null 終端バイト文字列を抽出する必要があると仮定する。

#include <stdio.h>
#include <stdlib.h>

int main (void) {

    FILE *fp;
    size_t size;
    long length;
    char *buffer;

    fp = fopen("file.txt", "rb");

    if (fp == NULL) {
      /* ファイルオープンエラーの処理 */
    }

    /* ファイルサイズの取得 */
    if (fseek(fp, 0, SEEK_END) != 0) {
      /* fseek エラーの処理 */
    }

    length = ftell(fp);

    if (fseek(fp, 0L, SEEK_SET) != 0) {
      /* fseek エラーの処理 */
    }

    /* ファイル全体を格納するメモリを割り当てる */
    buffer = (char*) malloc(length);
    if (buffer == NULL) {
      /* メモリ割り当てエラーの処理 */
    }

    /* size に値を設定 */

    if (fread(buffer, 1, size, fp) < size) {
      /* ファイル読み取りエラーの処理 */
    }
    fclose(fp);

    return 0;
}

size がファイル(file.txt)全体の長さよりも短い場合は、buffer は正しく null 終端されない。

適合コード

上記のコード例を修正するには、buffer のサイズをファイル全体の長さと比較して、sizelength と一致しない場合をエラーとして識別する必要がある。現時点ではこのエラーの処理はプログラマに委ねられている。

#include <stdio.h>
#include <stdlib.h>

int main (void) {

    FILE *fp;
    size_t size;
    long length;
    char *buffer;

    fp = fopen("file.txt", "rb");

    if (fp == NULL) {
      /* ファイルオープンエラーの処理 */
    }

    /* ファイルサイズの取得 */
    if (fseek(fp, 0, SEEK_END) != 0) {
      /* fseek エラーの処理 */
    }
    length = ftell(fp);

    if (fseek(fp, 0L, SEEK_SET) != 0) {
      /* fseek エラーの処理 */
    }

    /* ファイル全体を格納するメモリを割り当てる */
    buffer = (char*) malloc(length);
    if (buffer == NULL) {
      /* メモリ割り当てエラーの処理 */
    }

    /* ... ここで size を設定する ... */
    if (length != size) {
      /* size がファイルの長さでない場合の処理 */
    }
    /* ... 追加のコード ... */

    if (fread(buffer, 1, size, fp) < size) {
      /* ファイル読み取りエラーの処理 */
    }

    fclose(fp);

    return 0;
}
リスク評価

fread() 関数を使って入力ストリームを読み取る際、読み取る文字列は fread() 関数によって明示的に null 終端されない。そのため、バッファへの書き込み操作はオーバーランを引き起こし、プログラムを異常終了させるおそれがある。

レコメンデーション 深刻度 可能性 修正コスト 優先度 レベル
FIO17-C P6 L2
参考情報
翻訳元

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

FIO17-C. Do not rely on an ending null character when using fread()

Top へ

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