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

安全・安心なIT社会のための、国内・国際連携を支援する

お問い合わせ サイトマップ English

Home > ラーニング > セキュアコーディング > CERT セキュアコーディングスタンダード > 02. 宣言と初期化 (DCL)

  1. HTTPS

02. 宣言と初期化 (DCL)

最終更新: 2010-04-14

DCL09-C. errno エラーコードを返す関数は返り値をerrno_t型として定義する

errno エラーコードを返す既存の関数の多くは、int 型を返す関数として定義されている。これらの関数が、エラーステータスを返すのか値を返すのか、あるいはひどい場合はその両方の組み合わせを返すのか、関数宣言やプロトタイプを眺めただけではセマンティック上は分からない。(「ERR02-C. 正常終了時の値とエラーの値は別の手段で通知する」を参照)

TR 24731-1 では新たな型 errno_t が導入されている。これはerrno.hおよび他のヘッダでint型として定義されている。TR 24731-1 で定義されている関数の多くはこの型の値を返す。errno_t 型は、errnoに出てくる値のみを含むオブジェクトの型として使用すべきである。たとえば、errno の値を返す関数は、返り値の型としてerrno_t を持つ関数として定義すべきである。

このレコメンデーションは TR 24731-1 に依存したもので、新規のコードの適切な場所で errno_t を使用することを推奨している。

違反コード

以下のコードは、opener() という関数が errno エラーコードを返すことを示している。しかし、この関数は int を返す関数として定義されている。したがって、返り値の持つ意味が本来あるべきほど明らかではない。

enum { NO_FILE_POS_VALUES = 3 };

int opener(
  FILE *file, 
  int *width, 
  int *height, 
  int *data_offset
) {
  int file_w;
  int file_h;
  int file_o;
  fpos_t offset;

  if (file == NULL) { return EINVAL; }
  errno = 0;
  if (fgetpos(file, &offset) != 0) { return errno; }
  if (fscanf(file, "%i %i %i", &file_w, &file_h, &file_o) 
        != NO_FILE_POS_VALUES) { 
    return EIO; 
  }

  errno = 0;
  if (fsetpos(file, &offset) != 0) { return errno; }

  if (width != NULL) { *width = file_w; }
  if (height != NULL) { *height = file_h; }
  if (data_offset != NULL) { *data_offset = file_o; }

  return 0;
}

ただし、このレコメンデーションに違反したコード例は、「ERR30-C. 関数を呼び出す前に errno をゼロに初期化し、関数の異常終了時にのみ errno を参照する」には適合している。

適合コード

以下の解決法では、opener() 関数が errno_t 型の値を返しており、この関数がエラーコードを返すことが明確になっている。

#include <errno.h>

enum { NO_FILE_POS_VALUES = 3 };

errno_t opener(
  FILE *file, 
  int *width, 
  int *height, 
  int *data_offset
) {
  int file_w;
  int file_h;
  int file_o;
  fpos_t offset;

  if (file == NULL) { return EINVAL; }
  errno = 0;
  if (fgetpos(file, &offset) != 0 ) { return errno; }
  if (fscanf(file, "%i %i %i", &file_w, &file_h, &file_o) 
        != NO_FILE_POS_VALUES) { 
    return EIO; 
  }

  errno = 0;
  if (fsetpos(file, &offset) != 0 ) { return errno; }

  if (width != NULL) { *width = file_w; }
  if (height != NULL) { *height = file_h; }
  if (data_offset != NULL) { *data_offset = file_o; }

  return 0;
}

注:EINVALEIO は C99 では定義されていないが、大概の処理系では利用可能であり、POSIX には定義されている。

リスク評価

エラー条件をテストし損ねると様々な脅威の脆弱性につながる恐れがある。errno を返す関数を errno_t 型の返り値を返す関数として定義したとしてもこの手の問題を廃絶することはできないかもしれない。しかし、プログラマが返り値の目的を誤解することによって引き起こされるエラーは減らせるだろう。

レコメンデーション 深刻度 可能性 修正コスト 優先度 レベル
DCL09-C P3 L3
参考情報
  • [ISO/IEC 9899:1999] Section 6.7.5.3, "Function declarators (including prototypes)"
  • [ISO/IEC PDTR 24772] "NZN Returning error status"
  • [ISO/IEC TR 24731-1:2007]
  • [MISRA 04] Rule 20.5
  • [Open Group 04]
翻訳元

DCL09-C. Declare functions that return an errno error code with a return type of errno_t

Top へ