C & C++

C & C++

Made by DeepSource

Avoid using setjmp() and longjmp() for exception handling CXX-W2015

Bug risk
Minor

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;
}