The setjmp() macro should be invoked from only one of the contexts listed in subclause 7.13.12.1 of the of the C Standard [ISO/IEC 9899:20112024]. Invoking setjmp() outside of one of these contexts results in undefined behavior. (See undefined behavior 125.)
...
Implementation Details
Compiled at -O0 for x86-64 using GCC 7.5 or Clang 8.0 on Ubuntu 18.04 (Linux for x86-64), the preceding example outputs the following when run:
...
Because g() has finished executing at the time longjmp() is called, it is no longer on the stack. When do_stuff() is invoked, its stack frame occupies the same memory as the old stack frame of g(). In this case, a was located in the same location as the return address of function g(). The call to memcpy() assignment of b overwrites the return address, so when longjmp() sends control back to function g(), the function returns to the wrong address (in this case, to function bad()).
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
jmp_buf buf;
void f(void) {
int i = 0;
if (setjmp(buf) != 0) {
printf("%i\n", i);
/* ... */
}
i = 2;
g();
}
void g(void) {
/* ... */
longjmp(buf, 1);
}
|
Implementation Details
Calling f() will print 2 if you compile with -O0, but will print 0 if you compile with -O2. This involves using GCC 7.5 or Clang 8.0 on Ubuntu 18.04 (Linux x86-64).
Compliant Solution
If an object local to the function that invoked setjmp() needs to be accessed after longjmp() returns control to the function, the object should be volatile-qualified:
| Code Block | ||||
|---|---|---|---|---|
| ||||
jmp_buf buf;
void f(void) {
volatile int i = 0;
if (setjmp(buf) != 0) {
printf("%i\n", i);
/* ... */
}
i = 2;
g();
}
void g(void) {
/* ... */
longjmp(buf, 1);
}
|
This will now correctly print 2 regardless of optimization level.
Risk Assessment
Recommendation | Severity | Likelihood | Detectable | Remediation CostRepairable | Priority | Level |
|---|---|---|---|---|---|---|
MSC22-C | Low | Probable | No | MediumNo | P4P2 | L3 |
Automated Detection
| Tool | Version | Checker | Description | ||||||
|---|---|---|---|---|---|---|---|---|---|
| CodeSonar |
| BADFUNC.LONGJMP BADFUNC.SETJMP | Use of longjmp Use of setjmp | ||||||
| LDRA tool suite |
| 43 S | Enhanced enforcement | ||||||
| Parasoft C/C++test |
| CERT_C-MSC22-a | The setjmp macro and the longjmp function shall facilities provided by <setjmp.h> should not be used | ||||||
| Polyspace Bug Finder |
| CERT C: Rec. MSC22-C | Checks for use of setjmp/longjmp (rec. fully covered) | ||||||
| SonarQube C/C++ Plugin |
| S982 |
...