Main Content

CERT C++: ERR58-CPP

Handle all exceptions thrown before main() begins executing

Since R2020b

Description

Rule Definition

Handle all exceptions thrown before main() begins executing.1

Polyspace Implementation

The rule checker checks for Exceptions raised during program startup.

Examples

expand all

Issue

This issue occurs when an exception might arise during the construction of global and static variables before main() begins executing. If an exception is raised during the startup phase, you cannot write an exception handler that the compiler can execute to handle the raised exception. This exception becomes an unhandled exception. For instance, you might implement main() as a function-try-catch block to handle exceptions. None of the catch blocks can handle exceptions raised during the startup phase and these raised exceptions become unhandled exceptions.

When you invoke callable entities to initialize or declare global or static variables, these entities are executed during program startup. Polyspace® checks whether these entities might raise exceptions during program startup by making certain assumptions.

  • Function: When you call an initializer function or constructor directly to initialize a global or static variable, Polyspace checks whether the function raises an exception and flags the variable declaration if the function might raise an exception. Polyspace deduces whether a function might raise an exception regardless of its exception specification. For instance, if a noexcept constructor raises an exception, Polyspace flags it. If the initializer or constructor calls another function, Polyspace assumes the called function might raise an exception only if it is specified as noexcept(<false>). Some standard library functions, such as the constructor of std::string, use pointers to functions to perform memory allocation, which might raise exceptions. Polyspace does not flag the variable declaration when these functions are used.

  • External function: When you call external functions to initialize a global or static variable, Polyspace flags the declaration if the external function is specified as noexcept(<false>).

  • Virtual function: When you call a virtual function to initialize a global or static variable, Polyspace flags it if the virtual function is specified as noexcept(<false>) in any derived class. For instance, if you use a virtual initializer function that is declared as noexcept(<true>) in the base class, and noexcept(<false>) in a subsequent derived class, Polyspace flags it.

  • Pointers to function: When you use a pointer to a function to initialize a global or static variable, Polyspace assumes that pointer to a function do not raise exceptions.

Polyspace ignores:

  • Exceptions raised in destructors

  • Exceptions raised in atexit() operations

Polyspace also ignores the dynamic context when checking for exceptions. For instance, you might initialize a global or static variable by using a function that raises exceptions only in a certain dynamic context. Polyspace flags such a declaration even if the exception might never be raised. You can justify such a violation by using comments in Polyspace.

Risk

When exceptions are not handled, the compiler might abnormally terminate the code execution without unwinding the stack depending on the set of hardware and software that you use. Consider this code where the construction of the static object obj might cause an exception.

class A{
	A(){throw(0);}	
};

static A obj;

main(){
	//...
}
The static object obj is constructed by calling A() before main() starts. When A() raises an exception, a handler cannot be matched with the raised exception. Based on the set of software and hardware that you use, such an exception can result in program termination without stack unwinding, leading to memory leak and security vulnerabilities.

Fix

Avoid operations that might raise an exception in the parts of your code that might be executed before startup or after termination of the program. For instance, avoid operations that might raise exceptions in the constructor and destructor of static or global objects.

Example

Consider this code where the construction of the global pointer arr requires dynamic memory allocation.

#include <stdexcept>
void* alloc(size_t s) noexcept {          
	return new int[s];
}
int* arr = (int*)alloc(5);//Noncompliant
int main(){
	//..
	return 0;
}

Dynamic memory allocation by using the new operator can raise an exception. Because constructing arr can raise an exception before main() begins execution, Polyspace flags the declaration.

Correction

Avoid operations that might raise exception when constructing global objects. For instance, you can initialize the global pointer arr by using a nullptr. Then allocate memory for arr in main() in a try-catch code block.

#include <stdexcept>
#include<vector>
void* alloc(size_t s) noexcept {          
	return new int[s];
}
int* arr =nullptr;
int main(){
	try{
		arr =  (int*)alloc(5);	
	}
	catch(std::bad_alloc e){
		//..
	}
	//..
	return 0;
}

In this case, the dynamic memory allocation operation raises the std::bad_alloc exception in main() where it can be handled by the catch blocks of code.

Check Information

Group: 08. Exceptions and Error Handling (ERR)

Version History

Introduced in R2020b

expand all


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.