CertC++-ERR52¶
Do not use setjmp() or longjmp()
Required inputs: IR
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/longjmpcall pair has undefined behavior if replacing thesetjmpandlongjmpbycatchandthrowwould 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
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.
#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;
}
Implementation Details
The above code produces the following results when compiled with
Clang3.8 for Linux, demonstrating that the 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.
Before setjmp(): Instances: 0 f(): Instances: 1 From longjmp(): Instances: 1 After longjmp(): Instances: 1
Compliant Solution
This compliant solution replaces the calls to
setjmp() and
longjmp() with a
throw expression and a
catch statement.
#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;
}
This solution produces the following output.
Before throw: Instances: 0 f(): Instances: 1 From catch: Instances: 0 After catch: Instances: 0
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 |
|---|---|---|---|---|---|
| ERR52-CPP | Low | Probable | Medium | P4 | L3 |
Bibliography
| [ Henricson 1997] | Rule 13.3, Do not use
setjmp() and
longjmp()
|
| [ ISO/IEC 14882-2014] | Subclause 18.10, "Other Runtime Support" |
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
jump |
Do not use setjmp() or longjmp(). |
None |
False |
Options¶
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
jump_functions¶
jump_functions : set[bauhaus.analysis.config.QualifiedName] = {'longjmp', 'setjmp'}