Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Parasoft C/C++test 2022.2

...

Code Block
bgColor#FFCCCC
langc
jmp_buf buf;
unsigned char b[] = {0xe5, 0x06, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00};

int main(void) {
  setup();
  do_stuff();
  return 0;
}

void setup(void) {
  f();
}

void f(void) {
  g();
}

void g(void#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>

static jmp_buf buf;
static void bad(void);

static void g(void) {
  if (setjmp(buf) == 0) {
    printf("setjmp() invoked\n");
  } else {
    printf("longjmp() invoked\n");
  }
}

static void do_stufff(void) {
  g();
}

static void setup(void) {
 char a[8];
  memcpy(a, b, 8) f();
}

void do_stuff(void) {
  void (*b)(void) = bad;
  /* ... */
  longjmp(buf, 1);
}

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

int main(void) {
  setup();
  do_stuff();
}

Implementation Details

Compiled for x86at -64 O0 using GCC 4.1.2 on Linux, the preceding 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
bgColor#ccccff
langc
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>

static jmp_buf buf;
unsignedstatic char b[] = {0xe5, 0x06, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00}void bad(void);

intvoid maindo_stuff(void) {
  ifvoid (setjmp*b)(bufvoid) == 0) {
    printf("setjmp() invoked\n");
  } else bad;
  /* ... */
  longjmp(buf, 1);
}

static void bad(void) {
    printf("longjmp() invokedShould not be called!\n");
  }
  do_stuff(exit(1);
  return 0;
}

voidint do_stuffmain(void) {
  char a[8];
  memcpy(a, b, 8);
  /* ... */
  longjmp(buf, 1);
}

void bad(void)if (setjmp(buf) == 0) {
    printf("setjmp() invoked\n");
  } else {
    printf("Should not be called!longjmp() invoked\n");
  }
  exitdo_stuff(1);
}
 

There is no risk of overwriting a return address because the stack frame of main() (the function that invoked setjmp()) is still on the stack; so when do_stuff() is invoked, the two stack frames will not overlap.

...

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

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

This will now correctly print 2 regardless of optimization level.

Risk Assessment

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

MSC22-C

Low

Probable

Medium

P4

L3

...

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 facilities provided by <setjmp.h> should not be used
Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

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

setjmp and longjmp cause deviation from normal control flow

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

...