The {{setjmp()}} macro should only be invoked from one of the contexts listed in §7.13.1.1 of \[[ISO/IEC 9899:1999|AA. References#ISO/IEC 9899-1999]\]. Invoking {{setjmp()}} outside of one of these contexts results in undefined behavior (see [Undefined Behavior 119|CC. Undefined Behavior#ub_119]). |
After invoking longjmp(), non-volatile-qualified local objects should not be accessed if their values could have changed since the invocation of setjmp(). Their value in this case is considered indeterminate and accessing them is undefined behavior (see Undefined Behavior 121, 10).
The longjmp() function should never be used to return control to a function that has terminated execution (see Undefined Behavior 120).
Signal masks, floating-point status flags, and the state of open files are not saved by the setjmp() function. If signal masks need to be saved, the sigsetjmp() function should be used.
This recommendation is related to SIG32-C. Do not call longjmp() from inside a signal handler and ENV32-C. All atexit handlers must return normally.
glibc v2.11.1 defines the jmp_buf type as follows:
Platform |
|
Registers Saved |
|---|---|---|
i386 |
24 |
|
x86_64 |
64 |
|
No other state information is saved.
This noncompliant code example calls setjmp() in an assignment statement, resulting in undefined behavior.
jmp_buf buf;
void f(void) {
int i = setjmp(buf);
if (i == 0) {
g();
} else {
/* longjmp was invoked */
}
}
void g(void) {
/* ... */
longjmp(buf, 1);
}
|
Placing the call to setjmp() in the if statement and (optionally) comparing it with a constant integer removes the undefined behavior, as shown in this compliant solution.
jmp_buf buf;
void f(void) {
if (setjmp(buf) == 0) {
g();
} else {
/* longjmp was invoked */
}
}
void g(void) {
/* ... */
longjmp(buf, 1);
}
|
Any attempt to invoke the longjmp() function to transfer control to a function that has completed execution results in undefined behavior.
jmp_buf buf;
void f(void) {
g();
h();
return;
}
void g(void) {
volatile int i = 10;
if (setjmp(buf) == 0) {
printf("i = %d\n", i);
} else {
printf("longjmp: i = %d\n", i);
exit(0);
}
return;
}
void h(void) {
char b[16];
memset(b, 0, 16);
longjmp(buf, 1);
}
|
When compiled for i386 using GCC v4.1.2, the above example outputs the following when run:
i = 10 longjmp: i = 0 |
Because g() has finished executing at the time longjmp() is called, it is no longer on the stack. When h() is invoked, its stackframe overwrites the stackframe of g(). In this case i was located in the same location as the end of array b. The call to memset() sets the four bytes that i occupied in g() to 0, so when longjmp() sends control back to function g(), it prints out a value of 0.
The longjmp() function should only be used when the function containing the corresponding setjmp() is guaranteed not to have completed execution, as in the following example.
jmp_buf buf;
void f(void) {
volatile int i = 10;
if (setjmp(buf) == 0) {
printf("i = %d\n", i);
} else {
printf("longjmp: i = %d\n", i);
exit(0);
}
h();
return;
}
void h(void) {
char b[16];
memset(b, 0, 16);
longjmp(buf, 1);
}
|
In this example there is no risk of overwriting i because the stackframe of f() is still on the stack, so when h is invoked, the two stackframes will not overlap.
Non-volatile-qualified objects local to the function that invoked the corresponding setjmp() have indeterminate values after longjmp() has been executed if their value has been changed since the invocation of setjmp().
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);
}
|
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.
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);
}
|
Recommendation |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
|---|---|---|---|---|---|
MSC22-C |
low |
probably |
medium |
P4 |
L3 |
\[[ISO/IEC 9899:1999|AA. References#ISO/IEC 9899-1999]\] Section 7.13, "Nonlocal jumps <setjmp.h>", Section J.2, "Portability issues" |