CertC++-ERR51

Handle all exceptions

Required inputs: IR, StaticSemanticAnalysis

When an exception is thrown, control is transferred to the nearest handler with a type that matches the type of the exception thrown. If no matching handler is directly found within the handlers for a try block in which the exception is thrown, the search for a matching handler continues to dynamically search for handlers in the surrounding try blocks of the same thread. The C++ Standard, [except.handle], paragraph 9 [ ISO/IEC 14882-2014], states the following:

If no matching handler is found, the function std::terminate() is called; whether or not the stack is unwound before this call to std::terminate() is implementation-defined.

The default terminate handler called by  std::terminate() calls  std::abort(), which abnormally terminates the process. When std::abort() is called, or if the implementation does not unwind the stack prior to calling  std::terminate(), destructors for objects may not be called and external resources can be left in an indeterminate state. Abnormal process termination is the typical vector for  denial-of-service attacks. For more information on implicitly calling  std::terminate(), see  ERR50-CPP. Do not abruptly terminate the program.

All exceptions thrown by an application must be caught by a matching exception handler. Even if the exception cannot be gracefully recovered from, using the matching exception handler ensures that the stack will be properly unwound and provides an opportunity to gracefully manage external resources before terminating the process.

As per ERR50-CPP-EX1, a program that encounters an unrecoverable exception may explicitly catch the exception and terminate, but it may not allow the exception to remain uncaught. One possible solution to comply with this rule, as well as with ERR50-CPP, is for the  main() function to catch all exceptions. While this does not generally allow the application to recover from the exception gracefully, it does allow the application to terminate in a controlled fashion.

Noncompliant Code Example

In this noncompliant code example, neither  f() nor main() catch exceptions thrown by  throwing_func(). Because no matching handler can be found for the exception thrown,  std::terminate() is called.

void throwing_func() noexcept(false);
 
void f() {
  throwing_func();
}
 
int main() {
  f();
}
Compliant Solution

In this compliant solution, the main entry point handles all exceptions, which ensures that the stack is unwound up to the main() function and allows for graceful management of external resources.

void throwing_func() noexcept(false);

void f() {
  throwing_func();
}

int main() {
  try {
    f();
  } catch (...) {
    // Handle error
  }
}
Noncompliant Code Example

In this noncompliant code example, the thread entry point function  thread_start() does not catch exceptions thrown by  throwing_func(). If the initial thread function exits because an exception is thrown,  std::terminate() is called.

#include <thread>

void throwing_func() noexcept(false);
 
void thread_start() {
  throwing_func();
}
 
void f() {
  std::thread t(thread_start);
  t.join();
}
Compliant Solution

In this compliant solution, the  thread_start() handles all exceptions and does not rethrow, allowing the thread to terminate normally.

#include <thread>

void throwing_func() noexcept(false);

void thread_start(void) {
  try {
    throwing_func();
  } catch (...) {
    // Handle error
  }
}

void f() {
  std::thread t(thread_start);
  t.join();
}
Risk Assessment

Allowing the application to abnormally terminate can lead to resources not being freed, closed, and so on. It is frequently a vector for denial-of-service attacks.

Rule Severity Likelihood Remediation Cost Priority Level
ERR51-CPP Low Probable Medium P4 L3
Related Guidelines

This rule is a subset of  ERR50-CPP. Do not abruptly terminate the program.

MITRE CWE CWE-754, Improper Check for Unusual or Exceptional Conditions
Bibliography
[ ISO/IEC 14882-2014] Subclause 15.1, "Throwing an Exception"
Subclause 15.3, "Handling an Exception"
Subclause 15.5.1, "The std::terminate() Function"
[ MISRA 2008] Rule 15-3-2 (Advisory)
Rule 15-3-4 (Required)
Excerpt from SEI CERT C++ Coding Standard [https://cmu-sei.github.io/secure-coding-standards/sei-cert-cpp-coding-standard/rules/exceptions-and-error-handling-err/err51-cpp], Copyright (C) 1995-2026 Carnegie Mellon University. See section 9.4. "3rd-Party Licenses" in the documentation for full details.

Possible Messages

Key

Text

Severity

Disabled

exception_escaping_main

Uncaught exception escaping from main or additional entry point

None

False

Options

exclude_exception_base_classes

exclude_exception_base_classes : set[bauhaus.analysis.config.QualifiedName] = set()

Exclude issues for the exception types mentioned in this set of qualified names. Also excludes classes derived from those class names as well as pointers or references to any of these class types.
 

generate_violation_path

generate_violation_path : bool = True

Whether to compute a trace for the exception. This improves the usability of the violation description, but requires additional computing which might slow down the rule.
 

inspect_at_exit_handlers

inspect_at_exit_handlers : bool = True

Whether to also inspect at_exit() handlers-functions.
 

inspect_atexit_entry_points

inspect_atexit_entry_points : bool = False

Whether to inspect routines set by the atexit/std::atexit function.
 

inspect_thread_main

inspect_thread_main : bool = True

Whether to also inspect thread main functions.