メインコンテンツ

AUTOSAR C++14 Rule A15-4-2

If a function is declared to be noexcept, noexcept(true) or noexcept(<true condition>), then it shall not exit with an exception

説明

ルール定義

If a function is declared to be noexcept, noexcept(true) or noexcept(<true condition>), then it shall not exit with an exception.

根拠

呼び出し可能なエンティティが例外を発生させないように指定するには、それを noexceptnoexcept(true)、または noexcept(<true condition>) として指定します。コンパイラは、関数 noexcept が例外で終了することを想定していません。そのため、コンパイラは、関数 noexcept の例外処理プロセスを省略します。関数 noexcept が例外で終了すると、コンパイラが処理不能になります。

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

関数が例外を発生させないことがわかっている場合にだけ、その関数を noexcept または noexcept(true) として指定します。関数の例外指定が判断できない場合は、noexcept(false) を使用して指定します。

Polyspace 実装

noexceptnoexcept(true)、または noexcept(<true condition>) を使用して呼び出し可能なエンティティを指定した場合は、Polyspace® が呼び出し可能なエンティティの未処理例外をチェックし、例外で終了する可能性がある場合に呼び出し可能なエンティティにフラグを設定します。

呼び出し可能なエンティティが他の呼び出し可能なエンティティを呼び出すと、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 は例外が発生しない可能性があってもそのような関数にフラグを設定します。

トラブルシューティング

ルール違反が想定されるものの、Polyspace から報告されない場合は、コーディング規約違反が想定どおりに表示されない理由の診断を参照してください。

すべて展開する

この例では、Polyspace が、未処理例外を発生させる可能性のある関数 noexcept にどのようにフラグを設定するかを示します。複数の関数 noexcept を含む次のコードについて考えます。これらの関数は、他の呼び出し可能なエンティティ (関数、外部関数、バーチャル関数など) を呼び出します。

#include <stdexcept>
#include <typeinfo>
void LibraryFunc(); 
void LibraryFunc_noexcept_false() noexcept(false);  
void LibraryFunc_noexcept_true() noexcept(true);    



void SpecFalseCT() noexcept  // Noncompliant
{
	try {
		LibraryFunc_noexcept_false();
	} catch (int &e) {
		LibraryFunc_noexcept_false();  
	} catch (std::exception &e) {
	} catch (...) {
	}
}

class A {
public:
	virtual void f() {}              
};

class B : A {
public:
	virtual void f() noexcept {}     
};

class C : B {
public:
	virtual void f() noexcept {}     
};

class D : A {
public:
	virtual void f() noexcept(false) { throw(2);}
};

void A1(A &a) noexcept {          // Noncompliant
	a.f();
}

void D2(D &d) noexcept {          //Compliant
	try {
		d.f();
	} catch (int i) {
	} catch (...) {
	}
}

void B2(B *b) noexcept {          // Compliant
	b->f();
}
template <class T>
T f_tp(T a) noexcept(sizeof(T)<=4)    // Noncompliant
{
	if (sizeof(T) >4 ) {
		throw std::runtime_error("invalid case");
	}
	return a;
}
void instantiate(void)
{
	f_tp<char>(1);
}
void f() noexcept {               //Noncompliant
	throw std::runtime_error("dead code");
}

void g() noexcept {               // Compliant
	f();
}  

  • Polyspace は、関数テンプレート f_tp の宣言にフラグを設定します。以下に理由を説明します。

    • 条件 sizeof(T)<=4char の場合に true に評価されるため、テンプレートは関数 noexcept(true) になります。

    • Polyspace は、テンプレートの noexcept(true) インスタンスを静的に解析します。Polyspace は、条件 sizeof(T)>4false の場合でも、throw ステートメントが原因で、テンプレートで例外が発生する可能性があると推定します。つまり、Polyspace は、throw ステートメントに決して到達しない場合でも、テンプレートにフラグを設定します。

    Polyspace は、インスタンス化されていない関数テンプレートを無視します。

  • Polyspace は関数 noexcept SpecFaleCT() にフラグを設定します。これは、この関数が noexcept(false) 外部関数 LibraryFunc_noexcept_false() を呼び出しますが、try-catch ブロック内でカプセル化しないためです。この外部関数に対する呼び出しによって発生した例外は、未処理例外を発生させる可能性があります。

  • Polyspace は関数 noexcept A1() の宣言にフラグを設定します。これは、この関数が、入力パラメーター a がクラス D に属している場合に noexcept(false) 関数 D.f() を呼び出す可能性があるためです。入力パラメーターのクラスによっては、noexcept 多相型関数 A1() が未処理例外を発生させる可能性があります。

  • Polyspace は、関数 f() にフラグを設定します。これは、この関数が throw を使用して未処理例外を引き起こす関数 noexcept であるためです。Polyspace は、f() を呼び出す可能性のある関数 noexcept g() にはフラグを設定しません。これは、f()noexcept として指定されているためです。

  • Polyspace は、関数 noexcept(false) D.f() を呼び出す可能性のある関数 noexcept D2() にフラグを設定しません。これは、D2()catch(...) ブロックを使用することによって、発生する可能性のある例外を処理するためです。

チェック情報

グループ: Exception Handling
カテゴリ: Required、Automated