Versions Compared

Key

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

...

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.

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

x86_64

64

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

No other state information is saved.

Noncompliant Code Example

...

Code Block
bgColor#FFCCCC
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 was invoked*/: i = %d\n", i);
    exit(0);
  }
  return;
}

void h(void) {
  char b[16];
  /* ... */memset(b, 0, 16);
  longjmp(buf, 1);
}

Implementation Details

When compiled for i386 using GCC v4.1.2, the above example outputs the following when run:

Code Block
i = 10
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.

Compliant Solution

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

Code Block
bgColor#ccccff
jmp_buf buf;

void f(void) {
  volatile int i = 10;
  if (setjmp(buf) !== 0) {
    /* longjmp was invoked */printf("i = %d\n", i);
  } else {
    printf("longjmp: i = %d\n", i);
    hexit(0);
  }
  h();
  return;
}

void h(void) {
  char b[16];
  /* ... */memset(b, 0, 16);
  longjmp(buf, 1);
}

Implementation Details

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.

Noncompliant Code Example

...