メインコンテンツ

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

CERT C++: ERR55-CPP

Honor exception specifications

説明

ルール定義

Honor exception specifications1

Polyspace 実装

ルール チェッカーは、"関数 noexcept が例外で終了" をチェックします。

すべて展開する

問題

この欠陥は、noexcept エンティティが例外で終了する可能性がある場合に発生します。コンパイラは、noexcept エンティティの例外処理プロセスを省略します。このようなエンティティが例外で終了すると、例外は未処理になり、プログラムの異常終了につながります。

noexcept エンティティが他の呼び出し可能エンティティを呼び出すと、Polyspace® は特定の仮定により未処理例外の可能性があるかどうかを計算します。

  • 関数:関数 noexcept が別の関数を呼び出すと、Polyspace は、呼び出された関数が noexcept(<false>) として指定されている場合にのみ、例外を発生させる可能性があるかどうかをチェックします。呼び出された関数が noexcept として指定されている場合、Polyspace は例外を発生させないものと仮定します。std::string のコンストラクターなど、一部の標準ライブラリ関数ではメモリ割り当てを実行するため関数へのポインターを使用し、これによって例外が発生する可能性があります。このような関数は noexcept(<false>) としては指定されないので、Polyspace はこのような標準ライブラリ関数を呼び出す関数にフラグを設定しません。

  • 外部関数:関数 noexcept が外部関数を呼び出すとき、外部関数が noexcept(<false>) として指定されている場合、Polyspace は関数宣言にフラグを設定します。

  • バーチャル関数:関数がバーチャル関数を呼び出すとき、そのバーチャル関数が派生クラスで noexcept(<false>) として指定されている場合、Polyspace は関数宣言にフラグを設定します。たとえば、関数 noexcept が基底クラスで noexcept(<true>) として宣言され、派生クラスでは noexcept(<false>) として宣言されたバーチャル関数を呼び出す場合、Polyspace は関数 noexcept の宣言にフラグを設定します。

  • 関数へのポインター:関数 noexcept が関数へのポインターを呼び出すとき、Polyspace は関数へのポインターによって例外が発生しないものと仮定します。

関数によって未処理例外が発生するかどうかを解析するとき、Polyspace は以下を無視します。

  • デストラクターで発生する例外

  • atexit() 操作で発生する例外

Polyspace は、例外のチェックの際に動的なコンテキストも無視します。たとえば、関数が特定の動的コンテキストでのみ未処理例外を発生させる可能性があるとします。Polyspace は例外が発生しない可能性があってもそのような関数にフラグを設定します。

リスク

関数 noexcept が例外で終了する場合、コンパイラは std::terminate() を暗黙的に呼び出します。関数 std::terminate() は処理系定義の方法でプログラム実行を終了します。つまり、プログラム終了の具体的なプロセスは、使用しているソフトウェアとハードウェアの特定の組み合わせに応じて異なります。たとえば、std:terminate()std::abort() を呼び出してスタックのアンワインドを行わずに実行を異常終了する可能性があり、リソース リークとセキュリティの脆弱性につながります。

修正方法

関数が例外で終了することはないとわかっている場合にのみ関数を noexcept または noexcept(true) として指定します。不明な場合は noexcept(false) を使用して指定します。

2 つの関数が noexcept として指定された次のコードを検討します。Polyspace はこれらの関数およびそれが呼び出す関数を静的に解析します。

#include <stdexcept>
#include <typeinfo>
bool f(bool flag){
	if(flag==true)
	throw flag;
	return flag;
	
}
void LibraryFunc_noexcept_false() noexcept(false);  
void SpecFalseCT() noexcept  // Noncompliant
{
	try {
		LibraryFunc_noexcept_false();
	} catch (int &e) {
		LibraryFunc_noexcept_false();  
	} catch (std::exception &e) {
	} catch (...) {
	}
}
bool flag = false;
void Caller() noexcept {          //Noncompliant
	try {
		if(f(flag)){
			//...
		}
	} catch (int i) {
		//...
	} 
}

  • Polyspace は関数 noexcept SpecFaleCT() にフラグを設定します。この関数は noexcept(false) 外部関数 LibraryFunc_noexcept_false() を呼び出しますが、発生する可能性がある例外を処理していないからです。これらの例外は、関数 noexcept を例外で終了させる可能性があります。

  • Polyspace は関数 noexcept Caller にフラグを設定します。この関数は noexcept(false) 関数 f() を呼び出しますが、これには明示的な throw ステートメントが含まれているからです。flagfalse であるとき throw ステートメントは実行されないとしても、Polyspace は動的なコンテキストを無視して Caller にフラグを設定します。

修正

関数定義の際、可能性のあるすべての例外が関数内で処理される場合にのみ noexcept として指定します。そうしない場合は、noexcept(false) として指定します。例外が動的なコンテキストで発生しない場合、この欠陥はコメントを使用して正当化します。

#include <stdexcept>
#include <typeinfo>
bool f(bool flag){
	if(flag==true)
	throw flag;
	return flag;
	
}
void LibraryFunc_noexcept_false() noexcept(false);  
void SpecFalseCT() noexcept(false)// Compliant
{
	try {
		LibraryFunc_noexcept_false();
	} catch (int &e) {
		LibraryFunc_noexcept_false();  
	} catch (std::exception &e) {
	} catch (...) {
	}
}
bool flag = false;
void Caller() noexcept{//Noncompliant // polyspace CERT-CPP:ERR55-CPP 
//[Justified:Unset] "Exception is not thrown when flag is false"
	try {
		if(f(flag)){
			//...
		}
	} catch (int i) {
		//...
	} 
}

  • 関数 SpecFalseCT は例外が発生する可能性がある外部関数を呼び出すので noexcept(false) として指定されるようになりました。この関数はこのルールに準拠しています。

  • 関数 f()flagfalse のときには例外を発生させません。関数 Caller はこの例外指定を使用しますが、Polyspace はフラグを設定します。Polyspace は動的なコンテキストを無視するからです。この欠陥はコメントを使用して正当化されています。

チェック情報

グループ: 08.例外とエラーの取り扱い (ERR)

バージョン履歴

R2020b で導入


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.