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. Asetjmp
/longjmp
call pair has undefined behavior if replacing thesetjmp
andlongjmp
bycatch
andthrow
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 | ||||
---|---|---|---|---|
| ||||
#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; } |
...
The above code produces the following results when compiled with Clang 3.8 for Linux, demonstrating that the undefined behavior in this instance is to fail program, on this platform, fails to destroy the local Counter
instance when the execution of f()
is terminated:. This is permissible as the behavior is undefined.
Code Block |
---|
Before setjmp(): Instances: 0 f(): Instances: 1 From longjmp(): Instances: 1 After longjmp(): Instances: 1 |
...
This compliant solution replaces the calls to setjmp()
and longjmp()
with a throw
expression and a catch
statement:.
Code Block | ||||
---|---|---|---|---|
| ||||
#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 |
...
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 |
---|---|---|---|---|---|
ERR52-CPP | Low | Probable | Medium | P4 | L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| include-setjmp | Fully checked | ||||||
Axivion Bauhaus Suite |
| CertC++-ERR52 | |||||||
Clang |
| cert-err52-cpp | Checked by clang-tidy . | ||||||
CodeSonar |
| BADFUNC.LONGJMP | Use of longjmp Use of setjmp | ||||||
Helix QAC |
| C++5015 | |||||||
Klocwork |
| MISRA.STDLIB.LONGJMP | |||||||
LDRA tool suite |
| 43 S | Fully implemented | ||||||
Parasoft C/C++test |
Secondary analysis
| CERT_CPP-ERR52-a | The facilities provided by <setjmp.h> should not be used | |||||||
Polyspace Bug Finder |
| CERT C++: ERR52-CPP | Checks for use of setjmp/longjmp (rule fully covered) | ||||||
RuleChecker |
| include-setjmp | Fully checked | ||||||
SonarQube C/C++ Plugin |
| S982 |
Related Vulnerabilities
Search for other vulnerabilities resulting from the violation of this rule on the CERT website.
Bibliography
[Henricson |
1997] | Rule 13.3, Do not use setjmp() and longjmp() |
[ISO/IEC 14882-2014] | Subclause 18.10, "Other Runtime Support" |
...
...