Main Content

Exception caught by value

catch statement accepts an object by value

Description

This defect occurs when a catch statement accepts an object by value.

Risk

If a throw statement passes an object and the corresponding catch statement accepts the exception by value, the object is copied to the catch statement parameter. This copy can lead to unexpected behavior such as:

  • Object slicing, if the throw statement passes a derived class object.

  • Undefined behavior of the exception, if the copy fails.

Fix

Catch the exception by reference or by pointer. Catching an exception by reference is recommended.

Examples

expand all

#include <exception>

extern void print_str(const char* p);
extern void throw_exception();

void func() {
    try {
        throw_exception();
    }

    catch(std::exception exc) {
        print_str(exc.what());
    }
}

In this example, the catch statement takes a std::exception object by value. Catching an exception by value causes copying of the object. It can cause undefined behavior of the exception if the copy fails.

Correction: Catch Exception by Reference

One possible solution is to catch the exception by reference.

#include <exception>

extern void print_str(const char* p);
extern void throw_exception();

void corrected_excpcaughtbyvalue() {
    try {
        throw_exception();
    }
    catch(std::exception& exc) {
        print_str(exc.what());
    }
}
#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;
}

In this example, the catch statement takes a BaseExc object by value. Catching exceptions by value causes copying of the object. The copying can cause:

  • Undefined behavior of the exception if it fails.

  • Object slicing if an exception of the derived class IOExc is caught.

Correction — Catch Exceptions by Reference

One possible correction is to catch exceptions by reference.

#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;
}

Result Information

Group: C++ Exception
Language: C++
Default: On for handwritten code, off for generated code
Command-Line Syntax: EXCP_CAUGHT_BY_VALUE
Impact: Medium

Version History

Introduced in R2015b