Versions Compared

Key

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

The C Language standard library facilities setjmp() and longjmp() can be used 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. However, these facilities bypass automatic resource management and can result in resource leaks, and denial-of-service attacks.

The C++ Standard, [support.runtime], paragraph 4, states [ISO/IEC 14882-2003, section 18.7 paragraph 4. says2014]:

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

...

 and throw would invoke any non-trivial destructors for any automatic objects.

Do not call setjmp() or longjmp(); their usage can be replaced by more standard idioms such as throw expressions and catch statements.

Noncompliant Code Example

Calling longjmp() prevents local class variables from being properly destroyed, as can be demonstrated by the following code: 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.

Code Block
bgColor#FFcccc
langcpp
#include <csetjmp>
#include <iostream>
using namespace std;

static jmp_buf env;

class
struct Counter {
public:
  static int Instances;

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


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

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

int main() {

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

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

Implementation Details

The above code produces , on a Linux machine running g++ 4.3the following results when compiled with Clang 3.5 for Linux, demonstrating that the undefined behavior in this instance is to fail to destroy the local Counter instance when the execution of f() is terminated:

Code Block
Before setjmp(): Instances: 0
funcf(): Instances: 1
From longjmp(): Instances: 1
After longjmp(): Instances: 1

...

Compliant Solution

Use exceptions instead of This compliant solution replaces the calls to setjmp() and and longjmp(), as throwing exceptions will still invoke destructors of local class variables. with a throw expression and a catch statement:

Code Block
bgColor#ccccff
langcpp
#include <iostream>
using namespace std;

classstruct Counter {
public:
  static int Instances;

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

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

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

int main() {

  std::cout << "Before trythrow: Instances: " << Counter::Instances << std::endl;
  try {
    funcf();
  } catch (...const char *E) {
    std::cout << "InFrom catch: Instances: " << Counter::Instances << std::endl;
  }

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

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

Code Block
Before trythrow: Instances: 0
funcf(): Instances: 1
InFrom 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

ERR34-CPP

lowLow

probableProbable

mediumMedium

P4

L3

Automated Detection

Tool

Version

Checker

Description

 PRQA QA-C++

 
Include Page
PRQA QA-C++_v
PRQA QA-C++_v

Secondary Analysis

 

Related Vulnerabilities

Search for other vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

 

 

Bibliography

...

...

18.

...

10, "Other Runtime Support"
[Henricson 97]Rule 13.3, "Do not

...

use setjmp()

...

 and longjmp()

 .