Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

The C Language facilities setjmp() and longjmp() can be used as a poor attempt to simulate the throwing and catching of exceptions, but they are very low-level facilities, and using them can bypass proper resource management and the proper calling of destructors.

...

Non-Compliant Code Example

Calling longjmp() prevents local class variables from being properly destroyed, as can be demonstrated by the following code:

Code Block
bgColor#ccccff

#include <csetjmp>
#include <iostream>
using namespace std;

static jmp_buf env;

class Counter {
public:
  static int Instances;

  Counter() {Instances++;}
  ~Counter() {Instances--;}
private:
  Counter(const Counter& that);
  Counter& operator=(const Counter& that);
};

int Counter::Instances = 0;
class Error {};

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

int main() {

  cout << "Before setjmp(): Instances: " << Counter::Instances << endl;
  if (setjmp(env) == 0) {
    func();
  } else {
    cout << "From longjmp(): Instances: " << Counter::Instances << endl;
  }

  cout << "After longjmp(): Instances: " << Counter::Instances << endl;
}

produces, on a Linux machine running g++ 4.3:

Code Block

Before setjmp(): Instances: 0
func(): Instances: 1
From longjmp(): Instances: 1
After longjmp(): Instances: 1

Since the C++ standard leaves this behavior undefined, the compiler merely fails to invoke the destructor for the Counter object.

Compliant Solution

Use exceptions instead of setjmp() and longjmp(), as throwing exceptions will still invoke destructors of local class variables.

Code Block
bgColor#ccccff

#include <iostream>
using namespace std;

class Counter {
public:
  static int Instances;

  Counter() {Instances++;}
  ~Counter() {Instances--;}
private:
  Counter(const Counter& that);
  Counter& operator=(const Counter& that);
};

int Counter::Instances = 0;
class Error {};

void func() {
  Counter c;
  cout << "func(): Instances: " << Counter::Instances << endl;
  throw Error();
}

int main() {

  cout << "Before try: Instances: " << Counter::Instances << endl;
  try {
    func();
  } catch (...) {
  cout << "In catch: Instances: " << Counter::Instances << endl;
  }

  cout << "After catch: Instances: " << Counter::Instances << endl;
}

On the same platform (Linux, g++ 4.3), this code produces:

Code Block

Before try: Instances: 0
func(): Instances: 1
In catch: Instances: 0
After catch: Instances: 0

Exceptions

ERR34-EX1: The longjmp() function may be safely invoked if you can guarantee that no nontrivial destructors are bypassed between the longjmp() call and the corresponding setjmp().

Risk Assessment

Using setjmp() and longjmp() could lead to a denial-of-service attack due to resources not being properly destroyed.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

RES39-C

1 (low)

2 (probable)

2 (medium)

P4

L3

...