メインコンテンツ

CERT C++: ERR61-CPP

lvalue 参照による例外のキャッチ

説明

ルール定義

lvalue 参照により例外をキャッチします。1

Polyspace 実装

ルール チェッカーは、"catch ステートメントでコピーによって初期化された例外オブジェクト" をチェックします。

すべて展開する

問題

次のような catch ステートメントを考えます。

catch (exceptionType customExc) {
  //...
}
この問題は、コピーによって例外オブジェクト customExc が初期化された場合に発生します。

リスク

exceptionType が非トリビアル コピー コンストラクターをもっている場合、またはスローされた例外が exceptionType から派生したクラスに属している場合、コピーにより、オブジェクトのスライスや未定義の動作が発生する可能性があります。

修正方法

例外を参照か const 参照によってキャッチします。

catch (exceptionType &customExc) {
  //...
}

例 - 値でキャッチされた派生クラスの例外
#include <exception>
#include <string>
#include <typeinfo>
#include <iostream>

// Class declarations
class BaseExc {
public:
    explicit BaseExc();
    virtual ~BaseExc() {};
protected:
    BaseExc(const std::string& type);
private:
    std::string _id;
};

class IOExc: public BaseExc {
public:
    explicit IOExc();
};

//Class method declarations
BaseExc::BaseExc():_id(typeid(this).name()) {
}
BaseExc::BaseExc(const std::string& type): _id(type) {
}
IOExc::IOExc(): BaseExc(typeid(this).name()) {
}

int input(void);

int main(void) {
    int rnd = input();
    try {
        if (rnd==0) {
            throw IOExc();
        } else {
            throw BaseExc();
        }
    }

   
    catch(BaseExc exc) {  //Noncompliant
        std::cout << "Intercept BaseExc" << std::endl;
    }
    return 0;
}

この例では、catch ステートメントが BaseExc オブジェクトを値により受け取っています。例外を値でキャッチしたことが原因で、オブジェクトのコピーが行われます。このコピーは、以下の原因となる場合があります。

  • 例外の未定義の動作 (失敗した場合)。

  • オブジェクトのスライス (派生クラス IOExc の例外がキャッチされた場合)。

修正 — 参照による例外のキャッチ

1 つの修正方法として、例外を参照でキャッチします。

#include <exception>
#include <string>
#include <typeinfo>
#include <iostream>

// Class declarations
class BaseExc {
public:
    explicit BaseExc();
    virtual ~BaseExc() {};
protected:
    BaseExc(const std::string& type);
private:
    std::string _id;
};

class IOExc: public BaseExc {
public:
    explicit IOExc();
};

//Class method declarations
BaseExc::BaseExc():_id(typeid(this).name()) {
}
BaseExc::BaseExc(const std::string& type): _id(type) {
}
IOExc::IOExc(): BaseExc(typeid(this).name()) {
}

int input(void);

int main(void) {
    int rnd = input();
    try {
        if (rnd==0) {
            throw IOExc();
        } else {
            throw BaseExc();
        }
    }


   
    catch(BaseExc& exc) {
        std::cout << "Intercept BaseExc" << std::endl;
    }
    return 0;
}

チェック情報

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

バージョン履歴

R2019b で導入


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.