ERR06-C. assert() と abort() の終了動作を理解する
C言語仕様のセクション 7.2.1.1 は、assert()
の動作を次のように規定している [ISO/IEC 9899:2011]。
assert
マクロは、プログラム中に診断機能を付け加える。assert
マクロは、ボイド式に展開する。assert
マクロを実行するとき、expression
(スカラ型をもたなければならない。)が偽(すなわち、0と等しい)である場合、assert
マクロは、偽の値をもたらした特定の呼出しに関する情報(情報の中には、実引数のテキスト、ソースファイル名、ソース行番号およびそのassert
マクロの呼び出しを字句的に囲んでいる関数の名前を含む。後の3つはそれぞれ__FILE__
および__LINE__
の値ならびに識別子__func__)
の値とする)を処理系定義の書式で標準エラーストリームに書き込む。さらに、その後でabort
関数を呼び出す。
assert()
は abort()
を呼び出すため、atexit()
で登録された後処理関数は呼び出されない。プログラマの意図が、アサートが失敗した場合に適切に後処理動作を実行することである場合、実行時アサートは、可能な限り静的アサートに置き換えるべきである(「DCL03-C. 定数式の値をテストするには静的アサートを使う」を参照)。アサートが実行時データに基づいている場合、assert
は、採用しているエラー処理を行う実行時検査に置き換えるべきである(「ERR00-C. エラー処理には一貫性のある方針を採用する」を参照)。
プログラムの終了方法に関する詳細については「ERR04-C. プログラムの適切な終了方法を選択する」を、assert()
マクロの使用方法の詳細については「MSC11-C. 診断テストはアサートを使って組み込む」を参照のこと。
違反コード
以下のコード例では、プログラムの終了前に呼び出されて後処理を行う関数を定義している。
void cleanup(void) { /* 一時ファイルの削除、一貫性のある状態の復元など */ } int main(void) { if (atexit(cleanup) != 0) { /* エラー処理 */ } /* ... */ assert(/* 何も問題は起こらなかった */); /* ... */ }
しかし、上記のコードには assert
も使われており、アサートが失敗した場合、cleanup()
関数は呼び出されない。
適合コード
以下の解決法では、assert()
を呼び出す代わりに if
文を使用して exit()
を呼び出し、適切な終了ルーチンが実行されることを保証している。
void cleanup(void) { /* 一時ファイルの削除、一貫性のある状態の復元など */ } int main(void) { if (atexit(cleanup) != 0) { /* エラー処理 */ } /* ... */ if (/* 何らかの問題が起きた */) { exit(EXIT_FAILURE); } /* ... */ }
リスク評価
ファイル書き込み時に危険な abort()
呼び出しを行うと、ファイルが不整合な状態になるかもしれない。また、ファイルシステム上に重要な一時ファイルが残ることもある。
レコメンデーション |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
ERR06-C |
中 |
低 |
中 |
P4 |
L3 |
自動検出(最新の情報はこちら)
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
Compass/ROSE |
|
|
このルールの違反を検出できる。しかし、 |
関連するガイドライン
CERT C++ Secure Coding Standard | ERR06-CPP. Understand the termination behavior of assert() and abort() |
ISO/IEC TR 24772:2013 | Termination Strategy [REU] |
参考資料
[ISO/IEC 9899:2011] | Section 7.2.1.1, "The assert Macro" |
翻訳元
これは以下のページを翻訳したものです。
ERR06-C. Understand the termination behavior of assert() and abort() (revision 45)