Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Wiki MarkupThe {{setjmp()}} macro should only be invoked from only one of the contexts listed in §7subclause 7.13.1.1 of \[of the C Standard [ISO/IEC 9899:1999|AA. References#ISO/IEC 9899-1999]\2011]. Invoking {{setjmp()}} outside of one of these contexts results in undefined behavior (see [Undefined Behavior 119|CC. Undefined Behavior#ub_119]).. (See undefined behavior 125.)

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).. (See undefined behaviors 127 and 10.)

The longjmp() function should never be used to return control to a function that has terminated execution (see Undefined Behavior 120).. (See undefined behavior 126.)

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 POSIX sigsetjmp() function should be used.

This recommendation is related to SIG32SIG30-C. Do not call longjmp() from inside a signal handler and Call only asynchronous-safe functions within signal handlers and ENV32-C. All atexit exit handlers must return normally.

Implementation Details

glibc v2.11.1 defines the jmp_buf type as follows:

...

Platform

...

jmp_buf Size

...

Registers Saved

...

i386

...

24

...

ebx, esi, edi, ebp, esp eip

...

...

64

...

rbx, rbp, r12, r13, r14, r15, rsp, rip

No other state information is saved.

Noncompliant Code Example

This noncompliant code example calls setjmp() in an assignment statement, resulting in undefined behavior.:

Code Block
bgColor#FFCCCC
langc

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.:

Code Block
bgColor#ccccff
langc

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.:

Code Block
bgColor#FFCCCC
langc

jmp_buf buf;
unsigned char b[] = {0xe5, 0x06, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00};

voidint fmain(void) {
  gsetup();
  hdo_stuff();
  return 0;
}

void gsetup(void) {
  volatile int i = 10;
f();
}

void f(void) {
  g();
}

void g(void) {
  if (setjmp(buf) == 0) {
    printf("i = %dsetjmp() invoked\n", i);
  } else {
    printf("longjmp: i = %d() invoked\n", i);
    exit(0);
  }
  return;
}

void hdo_stuff(void) {
  char ba[168];
  memsetmemcpy(ba, 0b, 168);
  /* ... */
  longjmp(buf, 1);
}

void bad(void) {
  printf("Should not be called!\n");
  exit(1);
}

Implementation Details

When compiled for i386 Compiled for x86-64 using GCC v44.1.2 on Linux, the above the preceding example outputs the following when run:

Code Block
i = 10
i = 0setjmp() invoked
longjmp() invoked
Should not be called!

Because g() has finished executing at the time longjmp() is called, it is no longer on the stack. When hdo_stuff() is invoked, its stackframe overwrites the stackframe stack frame occupies the same memory as the old stack frame of g(). In this case i , a was located in the same location as the end of array breturn address of function g(). The call to memsetmemcpy() sets the four bytes that i occupied in g() to 0 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()), it prints out a value of 0.

If the array b were user specified, the user would be able to set the return address of function g() to any location.

Compliant Solution

The longjmp() function should only be used when only when the function containing the corresponding setjmp() is guaranteed not to have completed execution, as in the following example.:

Code Block
bgColor#ccccff
langc

jmp_buf buf;

void f(void) {
  volatile int i = 10;
  unsigned char b[] = {0xe5, 0x06, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00};

int main(void) {
  if (setjmp(buf) == 0) {
    printf("i = %dsetjmp() invoked\n", i);
  } else {
    printf("longjmp: i = %d() invoked\n", i);
    exit(0);
  }
  hdo_stuff();
  return 0;
}

void hdo_stuff(void) {
  char ba[168];
  memsetmemcpy(ba, 0b, 168);
  /* ... */
  longjmp(buf, 1);
}

void bad(void) {

Implementation Details

  printf("Should not be called!\n");
  exit(1);
}

There In this example there is no risk of overwriting i a return address because the stackframe of f(stack frame of main() (the function that invoked setjmp()) is still on the stack, ; so when h do_stuff() is invoked, the two stackframes stack frames will not overlap.

Noncompliant Code Example

NonIn this noncompliant example, non-volatile-qualified objects local to the function that invoked the corresponding setjmp() have indeterminate values after longjmp() has been is executed if their value has been changed since the invocation of setjmp().:

Code Block
bgColor#FFCCCC
langc

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.:

Code Block
bgColor#ccccff
langc

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);
}

Risk Assessment

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

MSC22-C

low

Low

probably

Probable

medium

Medium

P4

L3

References

Automated Detection

ToolVersionCheckerDescription
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

BADFUNC.LONGJMP

BADFUNC.SETJMP

Use of longjmp

Use of setjmp

LDRA tool suite
Include Page
LDRA_V
LDRA_V
43 SEnhanced enforcement
Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V

CERT_C-MSC22-a

The setjmp macro and the longjmp function shall not be used
Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C: Rec. MSC22-CChecks for use of setjmp/longjmp (rec. fully covered)


SonarQube C/C++ Plugin
Include Page
SonarQube C/C++ Plugin_V
SonarQube C/C++ Plugin_V
S982


...

Image Added Image Added Image Added Wiki Markup\[[ISO/IEC 9899:1999|AA. References#ISO/IEC 9899-1999]\] Section 7.13, "Nonlocal jumps <setjmp.h>", Section J.2, "Portability issues"