メインコンテンツ

AUTOSAR C++14 Rule A15-3-4

Catch-all (ellipsis and std::exception) handlers shall be used only in (a) main, (b) task main functions, (c) in functions that are supposed to isolate independent components and (d) when calling third-party code that uses exceptions not according to AUTOSAR C++14 guidelines

説明

ルール定義

Catch-all (ellipsis and std::exception) handlers shall be used only in (a) main, (b) task main functions, (c) in functions that are supposed to isolate independent components and (d) when calling third-party code that uses exceptions not according to AUTOSAR C++14 guidelines.

根拠

catch(std::exception) ブロックや catch(...) ブロックなどの catch-all ハンドラーは、さまざまなタイプの例外と一致します。このような catch-all ハンドラーを使用して例外を処理する場合は、発生した例外に関する詳細情報や固有情報を入手できません。このような catch-all ハンドラーは、発生した例外を処理するための有意義な対策を講じることができません。これらの catch-all ハンドラーが役立つのは、再び例外を発生させたり、アプリケーションを適切に終了したりすることによる予期せぬ例外の処理をする場合です。

catch-all ハンドラーが効果を発揮するのは特定の用途に対してであり、すべての関数に対して使用するのは非効率です。catch-all ハンドラーを使用する対象:

  • main 関数

  • タスク main 関数

  • AUTOSAR C++14 ガイドラインに準拠していない可能性のあるサードパーティ関数を呼び出す関数

  • コードの独立したコンポーネントを分離するように設計された関数

Polyspace 実装

Polyspace® は、以下のいずれにも当てはまらない場合、関数内の catch(std::exception) ブロックと catch(...) ブロックにフラグを設定します。

  • 関数 main() である。

  • タスク main 関数である。

  • 例外で終了する可能性のある外部関数またはサードパーティ関数を呼び出す。

Polyspace は関数 main() を検出します。関数をタスク main 関数として指定するには、以下のコンパイル オプションを使用します。

  • -entry-points <name>

  • -cyclic-tasks <name>

  • -interrupts <name>

トラブルシューティング

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

すべて展開する

この例では、Polyspace がタスク main 関数 EntryPoint と非エントリポイント関数 NonEntryPoint() 内の catch-all ハンドラーにどのようにフラグを設定するかを示します。関数 EntryPoint をタスク main 関数として指定するには、コンパイル オプション -entry-points EntryPoint を使用します。


#include <stdexcept>
#define MYEXCEPTION std::exception &
class ExceptionBased: std::exception {
};
typedef std::exception MyException;
typedef std::exception & MyExceptionRef;

void NonEntryPoint() 
{
	try {
		int i = 2;

		// ...
	} catch (int i) {                   // Compliant
	} catch (int &i) {                  // Compliant
	} catch (std::runtime_error e) {    // Compliant
	} catch (std::runtime_error& e) {   // Compliant
	} catch (std::exception *e) {       // Compliant
	} catch (std::exception e) {        // Noncompliant
	} catch (const std::exception& e) { // Noncompliant
	} catch(MyException e){             // Noncompliant
	} catch(ExceptionBased e){          // Compliant
	} catch (...) {                     // Noncompliant
	}
}
void EntryPoint() noexcept
{
	try {
		int i = 2;

		// ...
	} catch (MyException &e) {          // Compliant
	} catch (MyException e) {           // Compliant
	} catch (MyExceptionRef e) {        // Compliant
	} catch (ExceptionBased e) {        // Compliant
	} catch (const std::exception& e) { // Compliant
	} catch (MYEXCEPTION e) {           // Compliant
	}
}

関数 NonEntryPoint()main() でもタスク main 関数でもありません。この関数では、Polyspace が次の catch-all ブロックにフラグを設定します。

  • catch (std::exception e) ブロックは、クラス std::exception から派生するさまざまな例外と一致します。この catch-all ハンドラーは、main 関数またはタスク main 関数に有用です。NonEntryPoint()main() でもタスク main 関数でもないため、Polyspace はステートメント catch (std::exception e) にフラグを設定します。同じ理由で、Polyspace はステートメント catch (std::exception& e) にフラグを設定します。

  • MyException は、std::exceptiontypedef です。catch(MyException e) ブロックは、クラス std::except から派生するさまざまな例外と一致します。NonEntryPoint() は main 関数でもタスク main 関数でもないため、Polyspace はステートメント catch(MyException e) にフラグを設定します。

  • NonEntryPoint() は main 関数でもタスク main 関数でもないため、Polyspace はステートメント catch(...) にフラグを設定します。

関数 EntryPoint() はタスク main 関数として指定されています。Polyspace は、この関数内の catch-all ブロックにフラグを設定しません。

#include <stdexcept>
void Fextern_throw(void);
void Fextern_nothrow(void) noexcept(true);
void Foo0()
{
	try {
		Fextern_nothrow();
	} catch (...) {                 // Noncompliant
	}
}
void Foo1()
{
	try {
		try {
			Fextern_throw();
		} catch (...) {               // Compliant
		}
	} catch (std::exception& e) {   // Compliant
	}
}
void Foo2()
{
	try {
		try {
			Fextern_nothrow();
		} catch (...) {               // Noncompliant
			Fextern_throw();            
		}
	} catch (std::exception& e) {   // Compliant
	}
}
  • 関数 Foo0() は、noexcept(true) として指定されたサードパーティ関数 Fextern_nothrow() を呼び出します。サードパーティ コードが noexcept として指定されているため、Polyspace は Foo0() 内の catch(...) ブロックにフラグを設定します。

  • 関数 Foo1() は、例外を発生させる可能性のあるサードパーティ関数 Fextern_throw() を呼び出します。サードパーティ コードで例外が発生する可能性があるため、Polyspace は Foo1() 内の catch-all ハンドラー ブロックにフラグを設定しません。

  • 関数 Foo2() には、入れ子にされた try-catch ブロックが含まれています。内側のブロックでは、noexcept(true) と指定された外部関数 Fextern_nothrow() が呼び出されます。Polyspace は、内側の try-catch ブロック内の catch(...) ブロックにフラグを設定します。外側の try-catch 内の catch-all ブロックは準拠しています。これは、外部関数 Fextern_throw() によって引き起こされる可能性のある例外をこのブロックが処理するためです。

チェック情報

グループ: Exception handling
カテゴリ: Required、Non-automated

バージョン履歴

R2020b で導入