DCL09-C. errno を返す関数は返り値を errno_t 型として定義する
errno
を返す既存の関数の多くは、int
型を返す関数として定義されている。これらの関数が、エラーステータスを返すのか値を返すのか、あるいはひどい場合はその両方の組み合わせを返すのか、関数宣言やプロトタイプを眺めただけではセマンティック上は分からない(「ERR02-C. 正常終了時の値とエラーの値は別の手段で通知する」を参照)。
TR 24731-1 では新たな型 errno_t
が導入されている。これは errno.h
および他のヘッダで int
型として定義された。TR 24731-1 で定義されている関数の多くはこの型の値を返す [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
は C 標準では定義されていないが、大概の処理系では利用可能であり、POSIX には定義されている。
リスク評価
エラー条件をテストし損ねると様々な脅威の脆弱性につながる恐れがある。errno
を返す関数を errno_t
型の返り値を返す関数として定義したとしてもこの手の問題を廃絶することはできないかもしれない。しかし、プログラマが返り値の目的を誤解することによって引き起こされるエラーは減らせるだろう。
レコメンデーション |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
DCL09-C |
低 |
低 |
低 |
P3 |
L3 |
関連するガイドライン
CERT C++ Secure Coding Standard | DCL09-CPP. Declare functions that return errno with a return type of errno_t |
ISO/IEC TR 24731-1:2007 | |
ISO/IEC TR 24772:2013 | Ignored Error Status and Unhandled Exceptions [OYB] |
MISRA-C | Rule 20.5 |
参考資料
[IEEE Std 1003.1:2013] |
翻訳元
これは以下のページを翻訳したものです。
DCL09-C. Declare functions that return errno with a return type of errno_t (revision 80)