Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: minor editorial changes

The C standard library facilities setjmp() and longjmp() can be used to simulate throwing and catching exceptions. However, these facilities bypass automatic resource management and can result in undefined behavior, commonly including resource leaks , and denial-of-service attacks.

The C++ Standard, [support.runtime], paragraph 4 [ISO/IEC 14882-2014], states the following:

The function signature longjmp(jmp_buf jbuf, int val) has more restricted behavior in this International Standard. A setjmp/longjmp call pair has undefined behavior if replacing the setjmp and longjmp by catch and throw would invoke any non-trivial destructors for any automatic objects.

...

Noncompliant Code Example

Calling longjmp() such that it would invoke a nontrivial destructor were the call replaced with a throw expression results in undefined behavior, as demonstrated in this noncompliant code example:If a throw expression would cause a nontrivial destructor to be invoked, then calling longjmp() in the same context will result in undefined behavior. In the following noncompliant code example, the call to longjmp() occurs in a context with a local Counter object. Since this object’s destructor is nontrivial, undefined behavior results.

Code Block
bgColor#FFcccc
langcpp
#include <csetjmp>
#include <iostream>

static jmp_buf env;

struct Counter {
  static int instances;
  Counter() { ++instances; }
  ~Counter() { --instances; }
};

int Counter::instances = 0;

void f() {
  Counter c;
  std::cout << "f(): Instances: " << Counter::instances << std::endl;
  std::longjmp(env, 1);
}

int main() {
  std::cout << "Before setjmp(): Instances: " << Counter::instances << std::endl;
  if (setjmp(env) == 0) {
    f();
  } else {
    std::cout << "From longjmp(): Instances: " << Counter::instances << std::endl;
  }
  std::cout << "After longjmp(): Instances: " << Counter::instances << std::endl;
}

...

This compliant solution replaces the calls to setjmp() and longjmp() with a throw expression and a catch statement:.

Code Block
bgColor#ccccff
langcpp
#include <iostream>

struct Counter {
  static int instances;
  Counter() { ++instances; }
  ~Counter() { --instances; }
};

int Counter::instances = 0;

void f() {
  Counter c;
  std::cout << "f(): Instances: " << Counter::instances << std::endl;
  throw "Exception";
}

int main() {
  std::cout << "Before throw: Instances: " << Counter::instances << std::endl;
  try {
    f();
  } catch (const char *E) {
    std::cout << "From catch: Instances: " << Counter::instances << std::endl;
  }
  std::cout << "After catch: Instances: " << Counter::instances << std::endl;
}

which This solution produces the following output:.

Code Block
Before throw: Instances: 0
f(): Instances: 1
From catch: Instances: 0
After catch: Instances: 0

...