MSC11-C. 診断テストはアサートを使って組み込む
assert() マクロを使用するなど、プログラムに診断テストを組み込むこと。
assert マクロは void 式に展開される。
#include <assert.h> void assert(scalar expression);
assert マクロは実行されると、expression(スカラ型であること)が偽である場合、 失敗したアサート(引数テキスト、ソースファイル名、ソース行番号、囲んでいる関数名を含む)に関する情報を、処理系定義の形式で標準エラーストリームに書き込み、その後で abort() 関数を呼び出す。
以下の例では、MAX_TABLE_SIZE * sizeof(char *) が SIZE_MAX を超えないという仮定に基づき、符号無し整数の乗算に対する整数のラップアラウンドのテストが省略されている。この仮定が正しいことはわかっているが、この仮定をコードとして書いておいてもまったく問題ない。
assert(size <= SIZE_MAX/sizeof(char *)); table_size = size * sizeof(char *);
アサートは主としてデバッグ時に用いられることを意図している。コードの出荷時にはNDEBUG(通常はコンパイラに渡すフラグとして)を定義することで無効にされる。つまり、アサートは誤った想定を予防するために使用するべきであって、実行時のエラー検査に使用してはならない。
アサートは以下の検査に使用すべきでない。
- 無効なユーザ入力
- 存在しないファイル
- メモリ不足
- 無効な権限
たとえば、バッファオーバーフローを予防するコードをアサートとして実装することはできない。なぜなら、実行環境に配備される実行ファイルに含まれなくてはならないからだ。
アサートはサーバプログラムや組込みシステムには適さない。size が何らかの方法でクライアントの入力から取得されるなど、攻撃者がアサートの失敗を引き起こすことができると、サービス運用妨害につながる可能性がある。そのような状況においては、ログファイルへの書き込みを行うなど、フェイルソフト方式を用いる方が適切である。
if (size > SIZE_MAX/sizeof(char *)) { fprintf( log_file, __FILE__ ": size %zu exceeds SIZE_MAX/sizeof(char *)\n", size ); size = SIZE_MAX/sizeof(char *); } table_size = size * sizeof(char *);
リスク評価
アサートは、脆弱性につながる欠陥を検出し、解消するための有用な診断ツールである。しかし、アサートを使用していないからといって、コードが正しくないというわけではない。
レコメンデーション | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
MSC11-C | 低 | 低 | 高 | P1 | L3 |
参考情報
- [ISO/IEC 9899:1999] Section 7.2.1, "Program diagnostics"
翻訳元
これは以下のページを翻訳したものです。