API09-C. 互換性のある値には同じ型を使用する
互換性のある値には、必ず、同じ型を使用する。ある関数の返り値が別の関数の引数に使用される場合、2 つの値は必ず同じ型にすべきである。互換性のある値に同じ型を使用することで、返り値を引数として別の関数に渡す際に型変換が発生せず、変換エラーを低減することができる。
違反コード
問題の潜在的な原因の1つは、POSIX が関数の返り値に様々な意味を持たせる傾向があることに端を発するとも考えられる。たとえば、エラーの場合の返り値は −1、成功の場合の返り値は 0、あるいは正の値で実行結果を示す、といったように(「ERR02-C. 正常終了時の値とエラーの値は別の手段で通知する」を参照)。read()
システムコールのインタフェースはその好例である。このアプローチでは、符号無しと符号付きの値を自然と混在させることになるため、変換エラーの発生につながる可能性がある。
OpenSSH では、「割り込まれた場合は再試行」する関数 atomicio()
を使用してほとんどの I/O 呼出しを行っている。次のコードは、atomicio.c
,v 1.12 2003/07/31 をやや簡略化したものである。関数 f()
は、read()
と vwrite()
のいずれかを示す。
ssize_t atomicio(f, fd, _s, n) ssize_t (*f) (int, void *, size_t); int fd; void *_s; size_t n; { char *s = _s; ssize_t res, pos = 0; while (n > pos) { res = (f) (fd, s + pos, n - pos); switch (res) { case -1: if (errno == EINTR || errno == EAGAIN) continue; case 0: return (res); default: pos += res; } } return (pos); }
この関数には非常に多くの問題点があるが、このレコメンデーションに関する事項のみ指摘すると次のようになる。
atomicio()
関数はssize_t
型の値を返す(これは必ず符号付きの型である)。サイズが負の値になることはないため、ssize_t
型を使用している点にインタフェース設計の不備がはっきりと表れている。res
とpos
がどちらもssize_t
として宣言されている。- 式
n - pos
では、通常の算術変換によりpos
が符号付き型から符号無し型に変換される(「INT02-C. 整数変換のルールを理解する」を参照)。
適合コード
atomicio.c
,v 1.25 2007/06/25 の atomicio()
では、常に符号無しの値を返し、エラー報告には errno
を使用するように修正されている。
size_t atomicio(ssize_t (*f) (int, void *, size_t), int fd, void *_s, size_t n) { char *s = _s; size_t pos = 0; ssize_t res; struct pollfd pfd; pfd.fd = fd; pfd.events = f == read ? POLLIN : POLLOUT; while (n > pos) { res = (f) (fd, s + pos, n - pos); switch (res) { case -1: if (errno == EINTR) continue; if (errno == EAGAIN) { (void)poll(&pfd, 1, -1); continue; } return 0; case 0: errno = EPIPE; return pos; default: pos += (size_t)res; } } return (pos); }
このバージョンの atomicio()
関数には次の変更が加えられている。
atomicio()
関数の返り値をsize_t
型とした。pos
をsize_t
型として宣言するようにした。- 代入
pos += (size_t)res
において、f()
の符号付きの返り値を明示的にsize_t
へキャストをするようにした。 - 式
n - pos
において暗黙的型変換が生じる必要がない。
符号付き型を使わなくてよいようにすると、符号付き/符号無しの比較に関するコンパイラ警告を有効化し、指摘される問題点をすべて修正するといった作業が容易になる(「MSC00-C. 高い警告レベルで警告を出さずにコンパイルする」を参照)。
リスク評価
関数の返り値がエラー表示子を兼ねることで生じるリスクは、数値化が難しいため「低」と評価されている。しかし、そのような状況で、プログラマが状態コードを検査しなかったり、正しく検査しなかったりすると、深刻な結果をもたらす可能性がある。
レコメンデーション |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
API09-C |
低 |
低 |
高 |
P1 |
L3 |
関連するガイドライン
ISO/IEC TR 24731-1:2007 |
参考資料
[Miller 2007] | "Security Measures in OpenSSH" |
翻訳元
これは以下のページを翻訳したものです。
API09-C. Compatible values should have the same type (revision 18)