Home > ラーニング > セキュアコーディング > C セキュアコーディングスタンダード > 02. 宣言と初期化 (DCL)
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;
}
注:EINVAL と EIO は C99 では定義されていないが、大概の処理系では利用可能であり、POSIX には定義されている。
エラー条件をテストし損ねると様々な脅威の脆弱性につながる恐れがある。errno を返す関数を errno_t 型の返り値を返す関数として定義したとしてもこの手の問題を廃絶することはできないかもしれない。しかし、プログラマが返り値の目的を誤解することによって引き起こされるエラーは減らせるだろう。
| レコメンデーション | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
|---|---|---|---|---|---|
| DCL09-C | 低 | 低 | 低 | P3 | L3 |
DCL09-C. Declare functions that return an errno error code with a return type of errno_t