setjmp()
should only be invoked from one of the contexts listed in §7.13.1.1 of [[ISO/IEC 9899:1999]]. Invoking setjmp()
outside of one of these contexts results in undefined behavior (see Undefined Behavior 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).
longjmp()
should never be used to return control to a function that has terminated execution (see Undefined Behavior 120).
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.
Noncompliant Code Example
The following noncompliant code example calls setjmp()
in an assignment statement, resulting in undefined behavior.
jmp_buf buf; void f() { int i = setjmp(buf); if (i == 0) { g(); } else { /* longjmp was invoked */ } } void g() { /* ... */ longjmp(buf, 1); }
Compliant Solution
Placing the call to setjmp()
in the if
statement and (optionally) comparing it with a constant integer removes the undefined behavior.
jmp_buf buf; void f() { if (setjmp(buf) == 0) { g(); } else { /* longjmp was invoked */ } } void g() { /* ... */ longjmp(buf, 1); }
Noncompliant Code Example
Any attempt to longjmp()
to a function that has terminated execution results in undefined behavior.
jmp_buf buf; void f() { g(); h(); return; } void g() { if (setjmp(buf) != 0) { /* longjmp was invoked*/ } return; } void h() { /* ... */ longjmp(buf, 1); }
Compliant Solution
longjmp()
should only be used when the function containing the corresponding setjmp()
is guaranteed not to have terminated execution, as in the following example.
jmp_buf buf; void f() { if (setjmp(buf) != 0) { /* longjmp was invoked */ } else { h(); } return; } void h() { /* ... */ longjmp(buf, 1); }
Noncompliant Code Example
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() { int i = 0; if (setjmp(buf) != 0) { printf("%i\n", i); /* ... */ } i = 2; g(); } void g() { /* ... */ longjmp(buf, 1); }
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.
jmp_buf buf; void f() { volatile int i = 0; if (setjmp(buf) != 0) { printf("%i\n", i); /* ... */ } i = 2; g(); } void g() { /* ... */ longjmp(buf, 1); }
Risk Assessment
Recommendation |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
MSC22-C |
low |
probably |
medium |
P4 |
L3 |
References
[[ISO/IEC 9899:1999]] Section 7.13, "Nonlocal jumps <setjmp.h>", Section J.2, "Portability issues"