メインコンテンツ

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

CERT C++: ERR50-CPP

Do not abruptly terminate the program

説明

ルール定義

プログラムを突然終了しないようにします。1

Polyspace 実装

ルール チェッカーは、"関数 terminate() の暗黙的な呼び出し" をチェックします。

すべて展開する

問題

チェッカーは、関数 std::terminate() を暗黙的に呼び出す結果となる可能性がある状況にフラグを設定します。このような状況には以下が含まれます。

  • 例外が未処理のままである。次に例を示します。

    • 例外が処理されているものの、未処理例外を発生させる別の関数によりエスケープする。たとえば、catch ステートメントまたは例外ハンドラーが、未処理例外を発生する別の関数を呼び出す。

    • 空の throw ステートメントにより未処理例外が再発生する。

  • クラス デストラクターが例外を発生する。

  • std::atexit に渡される終了ハンドラーにより未処理例外が発生する。

リスク

使用しているハードウェアとソフトウェアによっては、terminate() の呼び出しは暗黙的に std::abort() 呼び出しにつながる可能性があり、これにより、スタック内の変数を削除せずにプログラムの実行が中止されます。このような異常終了はメモリ リークやセキュリティの脆弱性につながります。

修正方法

terminate() の暗黙的な呼び出しを回避するには、以下を行います。

  • 未処理例外を回避します。たとえば、main() またはタスクのメイン関数の操作を try-catch ブロック内で実行します。catch ブロックで以下を行います。

    • std::exception 型の例外を該当する catch ブロックで明示的に処理する。

    • サードパーティ ライブラリから発生する例外の基底クラスを処理する。

    • 予期せぬ例外を catch(...) ブロックで処理する。

  • デストラクターを noexcept として宣言し、デストラクター内の例外を処理する。

  • 終了ハンドラーですべての例外が処理される。

例 — terminate に対する暗黙的な呼び出し
#include <stdexcept>
int main(){   // Noncompliant
  try {
    // program code
  } catch (std::runtime_error& e) {
    // Handle runtime errors
  } catch (std::logic_error& e) {
    // Handle logic errors
  } catch (std::exception& e) {
    // Handle all expected exceptions
  }
  return 0;
}

この例では、main() で特定の型の例外を処理しています。予期せぬ例外は未処理のままであり、その結果、関数 terminate の暗黙的な呼び出しが行われ、これによりプログラムが突然停止します。main()terminate を暗黙的に呼び出すため、Polyspace® はこの欠陥を報告します。

修正 — 予期せぬ例外を処理する。

1 つの修正方法として、catch(...) ブロックを組み込んで予期せぬ例外を処理することにより、プログラムが正常終了できるようにします。

#include <stdexcept>
[[noreturn]] void gracefulExit(){
	// unwind stack and report errors
	std::terminate();
}
int main()   // Compliant
{
  try {
    // program code
  } catch (std::runtime_error& e) {
    // Handle runtime errors
  } catch (std::logic_error& e) {
    // Handle logic errors
  } catch (std::exception& e) {
    // Handle all expected exceptions
  }
  catch(...){
	  //Exit gracefully
	  gracefulExit();
  }
  return 0;
}

例 — 終了ハンドラーでの未処理例外

終了ハンドラー atexit_handler で、キャッチされない例外が発生します。関数 atexit_handler は、main の実行完了後に実行されます。この関数の未処理例外は他の場所では処理できないため、std::terminate() の暗黙的な呼び出しが行われる可能性があります。Polyspace はこの関数にフラグを設定します。

#include <stdexcept>
void atexit_handler(){//Noncompliant
	throw std::runtime_error("Error in atexit function");
}
void main(){
	try{
		//...
		std::atexit(atexit_handler);
	}catch(...){
		
	}
}
修正 — 終了ハンドラーですべての例外を処理する

この問題を修正するには、catch(...) ブロックを使用して、終了ハンドラー atexit_handler ですべての例外を処理します。

#include <stdexcept>
void atexit_handler(){
	try{
		//..
		throw std::runtime_error("Error in atexit function");
	}catch(...){
		//...
	}
}
void main(){
	try{
		//...
		std::atexit(atexit_handler);
	}catch(...){
		
	}
}

チェック情報

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

バージョン履歴

R2019a で導入

すべて展開する


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.