メインコンテンツ

MISRA C++:2008 Rule 15-1-1

The assignment-expression of a throw statement shall not itself cause an exception to be thrown

説明

ルール定義

The assignment-expression of a throw statement shall not itself cause an exception to be thrown. 1

根拠

C++ では、throw ステートメントを使用して、例外を明示的に発生させることができます。コンパイラは、このような throw ステートメントを次の 2 段階で実行します。

  • まず、throw ステートメントの引数を作成します。コンパイラは、コンストラクターを呼び出すか、代入式を評価して引数オブジェクトを作成します。

  • 次に、作成したオブジェクトを例外として発生させます。コンパイラは、例外オブジェクトを互換性のあるハンドラーと一致させようとします。

コンパイラが throw ステートメントで予期された例外を作成しているときに予期せぬ例外が発生した場合は、予期された例外ではなく、予期せぬ例外が発生します。throw ステートメントでクラス myException の明示的な例外が発生する次のコードを考えます。

class myException{
	myException(){
		msg = new char[10];
		//...
	}
	//...
};

foo(){
	try{
		//..
		throw myException();
	}
	catch(myException& e){
		//...
	}
}
一時的な myException オブジェクトの構成中に、new 演算子が bad_alloc 例外を発生させる可能性があります。このような場合は、throw ステートメントが myException ではなく bad_alloc 例外を発生させます。myException は予期された例外のため、catch ブロックには bad_alloc との互換性がありません。bad_alloc 例外は未処理例外になります。この例外は、スタックのアンワインドを行わずにプログラムの異常終了を引き起こす可能性があり、リソース リークやセキュリティの脆弱性につながります。

throw ステートメントの引数から発生する予期せぬ例外がリソース リークやセキュリティの脆弱性を引き起こす可能性があります。このような望ましくない結果を防ぐには、throw ステートメント内の引数として例外を発生させる可能性のある式の使用を避けます。

Polyspace 実装

Polyspace® は、例外を発生させる可能性のある throw ステートメント内の式にフラグを設定します。例外を発生させる可能性のある式:

  • noexcept(false) として指定された関数

  • 明示的な throw ステートメントが複数含まれている関数

  • メモリ割り当て操作を実行するコンストラクター

  • 動的キャスティングを含む式

トラブルシューティング

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

すべて展開する

この例は、Polyspace が、予期せぬ例外を発生させる可能性のある throw ステートメント内の式にフラグを設定する様子を示しています。

int f_throw() noexcept(false);

class WithDynamicAlloc {
public:
	WithDynamicAlloc(int n) {
		m_data = new int[n];   
	}
	~WithDynamicAlloc() {
		delete[] m_data;
	}
private:
	int* m_data;
};

class MightThrow {
public:
	MightThrow(bool b) {
		if (b) {
			throw 42;
		}
	}
};

class Base {
	virtual void bar() =0;
};
class Derived: public Base {
	void bar();
};
class UsingDerived {
public:
	UsingDerived(const Base& b) {
		m_d = 
		dynamic_cast<const Derived&>(b);
	}
private:
	Derived m_d;
};
class CopyThrows {
public:
	CopyThrows() noexcept(true);
	CopyThrows(const CopyThrows& other) noexcept(false);
};
int foo(){
	try{
		//...
		throw WithDynamicAlloc(10); //Noncompliant
		//...
		throw MightThrow(false);//Noncompliant
		throw MightThrow(true);//Noncompliant
		//...
		Derived d;
		throw  UsingDerived(d);// Noncompliant
		//... 
		throw f_throw(); //Noncompliant
		CopyThrows except;
		throw except;//Noncompliant
	}
	catch(WithDynamicAlloc& e){
		//... 
	}
	catch(MightThrow& e){
		//... 
	}
	catch(UsingDerived& e){
		//... 
	}
}

  • コンストラクター WithDynamicAlloc(10) を呼び出すことによって WithDyamicAlloc オブジェクトを構築する場合は、動的メモリ割り当て中に例外が発生する可能性があります。式 WithDynamicAlloc(10) で例外が発生する可能性があるため、Polyspace は throw ステートメント throw WithDynamicAlloc(10); にフラグを設定します。

  • コンストラクター UsingDervide() を呼び出すことによって UsingDerived オブジェクトを構築する場合は、動的キャスト操作中に例外が発生する可能性があります。式 UsingDerived(d) で例外が発生する可能性があるため、Polyspace は、ステートメント throw UsingDerived(d) にフラグを設定します。

  • 関数 MightThrow() では、関数に対する入力に応じて例外が発生する可能性があります。Polyspace は関数を静的に解析するため、関数 MightThrow() が例外を発生させる可能性があることを前提とします。Polyspace は、ステートメントの throw MightThrow(false)throw MightThrow(true) にフラグを設定します。

  • ステートメント throw except では、クラス CopyThrows のコピー コンストラクターを暗黙的に呼び出すことによってオブジェクト except がコピーされます。コピー コンストラクターは noexcept(false) として指定されているため、Polyspace は、コピー操作で例外が発生する可能性があることを前提とします。Polyspace は、ステートメント throw except にフラグを設定します。

  • 関数 f_throw()noexcept(false) として指定されているため、Polyspace は、この関数で例外が発生する可能性があることを前提とします。Polyspace は、ステートメント throw f_throw() にフラグを設定します。

チェック情報

グループ: Exception Handling
カテゴリ: 必要

バージョン履歴

R2020b で導入


1 All MISRA coding rules and directives are © Copyright The MISRA Consortium Limited 2021.

The MISRA coding standards referenced in the Polyspace Bug Finder™ documentation are from the following MISRA standards:

  • MISRA C:2004

  • MISRA C:2012

  • MISRA C:2023

  • MISRA C++:2008

  • MISRA C++:2023

MISRA and MISRA C are registered trademarks of The MISRA Consortium Limited 2021.