Avoid using `setjmp()` and `longjmp()` for exception handlingCXX-W2015
There are issues with the use of the C standard library functions setjmp()
and
longjmp()
to simulate exception handling in C++ programs. While these functions
can be used to mimic the behavior of exceptions, they have several drawbacks
that can lead to undefined behavior and security vulnerabilities.
One major issue with using setjmp()
and longjmp()
is that they bypass automatic
resource management. When a program throws an exception, C++ automatically
calls destructors for any objects that were created on the stack. However,
setjmp()
and longjmp()
do not call destructors, which can result in resource
leaks and other undefined behavior.
Additionally, the use of setjmp()
and longjmp()
can result in denial-of-service
attacks. If an attacker can cause a program to call longjmp()
with a corrupted
jmp_buf
, the program may jump to an unexpected location, causing it to crash or
behave unpredictably.
The C++ Standard discourages the use of setjmp()
and longjmp()
for exception
handling and recommends using C++ exception handling mechanisms instead. The
recommended solution is to use standard C++ idioms such as try/catch blocks and
throw expressions for exception handling.
Bad practice
#include <csetjmp>
#include <iostream>
static jmp_buf env;
class NonTrivial {
int* value;
public:
NonTrivial() {
value = new int;
std::cout << "Mem allocated" << std::endl;
}
~NonTrivial() {
if (value)
delete value;
std::cout << "Mem released" << std::endl;
}
};
void memoryManagementWithLongjmp(void) {
NonTrivial n;
std::longjmp(env, 1); // The object `n.value` will leak
}
int main() {
if (setjmp(env) == 0)
memoryManagementWithLongjmp();
return 0;
}
Recommended
#include <csetjmp>
#include <iostream>
class NonTrivial {
int* value;
public:
NonTrivial() {
value = new int;
std::cout << "Mem allocated" << std::endl;
}
~NonTrivial() {
if (value)
delete value;
std::cout << "Mem released" << std::endl;
}
};
void memoryManagementWitTryCatch(void) {
NonTrivial n;
// Destructor will be called for `n` before thowing the exception
throw "Intensional";
}
int main() {
try {
memoryManagementWitTryCatch();
} catch (const char *exc) {
std::cout << "Catch block" << std::endl;
}
return 0;
}