Main Content

MISRA C++:2008 Rule 15-3-1

Exceptions shall be raised only after startup and before termination of the program

Since R2020b

Description

Rule Definition

Exceptions shall be raised only after startup and before termination of the program.

Rationale

In c++, the process of exception handling runs during execution of main(), where exceptions arising in different scopes are handled by exception handlers in the same or adjacent scopes. Before starting the execution of main(), the compiler is in startup phase, and after finishing the execution of main(), the compiler is in termination phase. During these two phases, the compiler performs a set of predefined operations but does not execute any code.

If an exception is raised during either the startup phase or the termination phase, you cannot write an exception handler that the compiler can execute in those phases. For instance, you might implement main() as a function-try-catch block to handle exceptions. The catch blocks in main() can handle only the exceptions raised in main(). None of the catch blocks can handle exceptions raised during startup or termination phase. When such exceptions are raised, the compiler might abnormally terminate the code execution without unwinding the stack. Consider this code where the construction and destruction of the static object obj might cause an exception.

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

static A obj;

main(){
	//...
}
The static object obj is constructed by calling A() before main() starts, and it is destroyed by calling ~A() after main() ends. When A() or ~A() raises an exception, no exception handler can be matched with them. Based on the implementation, such an exception can result in program termination without stack unwinding, leading to memory leak and security vulnerabilities.

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.

Polyspace Implementation

Polyspace® flags global or static variable declaration that uses a callable entity that might raise an exception. For instance:

  • Functions: 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, uses 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 function do not raise exceptions.

Polyspace ignores:

  • Exceptions raised in destructors

  • Exceptions raised in atext() operations

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

Troubleshooting

If you expect a rule violation but Polyspace does not report it, see Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

This example shows how Polyspace flags construction or initialization of a global or static variable that might raise an exception. Consider this code where static and global objects are initialized by using various callable entities.

#include <stdexcept>
#include <string>
class C
{
public:
	C ( ){throw ( 0 );}
	~C ( ){throw ( 0 );}
};
int LibraryFunc();                                    
int LibraryFunc_noexcept_false() noexcept(false);     
int LibraryFunc_noexcept_true() noexcept(true);       
int  g() noexcept {                                   
	throw std::runtime_error("dead code");
	return 0;
}
int f() noexcept {                                    
	return g();                                         
}
int init(int a) {
	if (a>10) {
		throw std::runtime_error("invalid case");
	}
	return a;
}
void* alloc(size_t s) noexcept {          
	return new int[s];
}
int a = LibraryFunc() + 
LibraryFunc_noexcept_true();            // Compliant
int c =
LibraryFunc_noexcept_false() +          // Noncompliant
LibraryFunc_noexcept_true();
static C static_c;                      //Noncompliant

C &get_static_c(){
	return static_c;
}
C global_c;                             //Noncompliant 
int a3 = f();                           //Compliant
int b3 = g();                           //Noncompliant
int a4 = init(5);                       //Noncompliant
int b5 = init(20);                      //Noncompliant
int* arr = (int*)alloc(5);              //Noncompliant

int main(){
	//...
}

  • The global pointer arr is initialized by using the function alloc(). Because alloc() uses new to allocate memory, it can raise an exception when initializing arr during the startup of the program. Polyspace flags the declaration of arr and highlights the use of new in the function alloc().

  • The integer variable b3 is initialized by calling the function g(), which is specified as noexcept. Polyspace deduces that the correct exception specification of g() is noexcept(false) because it contains a throw() statement. Initializing the global variable b3 by using g() might raise an exception when initializing arr during the startup of the program. Polyspace flags the declaration of b3 and highlights the throw statement in g(). The declaration of a3 by calling f() is not flagged. Because f() is a noexcept function that does not throw, and calls another noexcept function, Polyspace deduces that f() does not raise an exception.

  • The global variables a4 and b5 are initialized by calling the function init(). The function init() might raise an exception in certain cases, depending on the context. Because Polyspace deduces the exception specification of a function statically, it assumes that init() might raise an exception regardless of context. Consequently, Polyspace flags the declarations of both a4 and b5, even though init() raises an exception only when initializing b5.

  • The global variable global_int is initialized by calling two external functions. The external function LibraryFunc_noexcept_false() is specified as noexcept(false) and Polyspace assumes that this external function might raise an exception. Polyspace flags the declaration of global_int. Polyspace does not flag the declaration of a because it is initialized by calling external functions that are not specified as noexcept(false).

  • The static variable static_c and the nonstatic global variable global_cis declared and initialized by using the constructor of the class C, which might raise an exception. Polyspace flags the declarations of these variables and highlights the throw() statement in the constructor of class C.

Check Information

Group: Exception handling
Category: Required

Version History

Introduced in R2020b