Rule A15-3-3 (required, implementation, partially-automated)

Main function and a task main function shall catch at least: base class exceptions from all third-party libraries used, std::exception and all otherwise unhandled exceptions.

Rationale

If a program throws an unhandled exception in main function, as well as in init thread function, the program terminates in an implementation-defined manner. In particular, it is implementation-defined whether the call stack is unwound, before termination, so the destructors of any automatic objects may or may not be executed. By enforcing the provision of a “last-ditch catch-all”, the developer can ensure that the program terminates in a consistent manner. Exceptions hierarchy from external libraries may be completely separate from C++ Standard Library std::exception. Handling such base exception classes separately may provide some additional information about application termination causes.

Example

//% $Id: A15-3-3.cpp 309502 2018-02-28 09:17:39Z michal.szczepankiewicz $
#include <stdexcept>

//base exception class from external library that is used
class ExtLibraryBaseException {};

int MainGood(int, char**) // Compliant

{
try
{
// program code
}
catch (std::runtime_error& e)
{
// Handle runtime errors
}
catch (std::logic_error& e)
{
// Handle logic errors
}
catch (ExtLibraryBaseException &e)
{
// Handle all expected exceptions
// from an external library
}
catch (std::exception& e)
{
// Handle all expected exceptions
}
catch (...)
{

// Handle all unexpected exceptions
}

return 0;
}
int MainBad(int, char**) // Non-compliant - neither unexpected exceptions

// nor external libraries exceptions are caught

{
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;
}
void ThreadMainGood() // Compliant
{
try
{
// thread code
}
catch (ExtLibraryBaseException &e)
{
// Handle all expected exceptions
// from an external library
}
catch (std::exception& e)
{
// Handle all expected exception
}
catch (...)
{
// Handle all unexpected exception
}
}

void ThreadMainBad()

// Non-compliant - neither unexpected exceptions
// nor external libraries exceptions are caught

{

try
{
// thread code
}
catch (std::exception& e)
{
// Handle all expected exceptions
}

// Uncaught unexpected exception will cause an immediate program termination
}

See also

MISRA C++ 2008 [7]: 15-3-2 There should be at least one exception handler to catch all otherwise unhandled exceptions. SEI CERT C++ [10]: ERR51-CPP. Handle all exceptions Effective Java 2nd Edition [15]: Item 65: Don’t ignore exceptions Rule A15-3-4 (required, implementation, non-automated) 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.

Rationale

Catching an exception through catch-all handlers does not provide any detailed information about caught exception. This does not allow to take meaningful actions to recover from an exception other than to re-throw it. This is inefficient and results in code that is difficult to maintain.

Example

//% $Id: A15-3-4.cpp 289436 2017-10-04 10:45:23Z michal.szczepankiewicz $
#include <stdexcept>
#include <thread>
extern std::int32_t Fn(); // Prototype of external third-party library function
void F1() noexcept(false)
{
try
{
std::int32_t ret = Fn();
// ...
}

// ...
catch (...) // Compliant

{
// Handle all unexpected exceptions from fn() function
}
}
void F2() noexcept(false)
{
std::int32_t ret =
Fn(); // Non-compliant - can not be sure whether fn() throws or not

if (ret < 10)
{
throw std::underflow_error("Error");
}

else if (ret < 20)
{
// ...
}
else if (ret < 30)
{
throw std::overflow_error("Error");
}

else
{
throw std::range_error("Error");
}
}
void F3() noexcept(false)
{
try
{
F2();
}

catch (std::exception& e) // Non-compliant - caught exception is too
// general, no information which error occured
{
// Nothing to do
throw;
}
}
void F4() noexcept(false)
{
try
{
F3();
}

catch (...) // Non-compliant - no information about the exception
{

// Nothing to do
throw;
}
}
class ExecutionManager
{
public:
ExecutionManager() = default;
void Execute() noexcept(false)
{
try
{
F3();
}

// ...
catch (std::exception& e) // Compliant
{
// Handle all expected exceptions
}
catch (...) // Compliant
{
// Handle all unexpected exceptions
}
}
};
void ThreadMain() noexcept
{
try
{
F3();
}

// ...
catch (std::exception& e) // Compliant
{
// Handle all expected exceptions
}
catch (...) // Compliant
{
// Handle all unexpected exceptions
}
}
int main(int, char**)

{
try
{
ExecutionManager execManager;
execManager.Execute();
// ...
std::thread t(&ThreadMain);

// ...
F4();
}

// ...
catch (std::exception& e) // Compliant
{
// Handle all expected exceptions
}
catch (...) // Compliant
{
// Handle all unexpected exceptions
}

return 0;
}

See also

none