Main Content

Use of setjmp/longjmp

setjmp and longjmp cause deviation from normal control flow

Description

This defect occurs when you use a combination of setjmp and longjmp or sigsetjmp and siglongjmp to deviate from normal control flow and perform non-local jumps in your code.

Risk

Using setjmp and longjmp, or sigsetjmp and siglongjmp has the following risks:

  • Nonlocal jumps are vulnerable to attacks that exploit common errors such as buffer overflows. Attackers can redirect the control flow and potentially execute arbitrary code.

  • Resources such as dynamically allocated memory and open files might not be closed, causing resource leaks.

  • If you use setjmp and longjmp in combination with a signal handler, unexpected control flow can occur. POSIX® does not specify whether setjmp saves the signal mask.

  • Using setjmp and longjmp or sigsetjmp and siglongjmp makes your program difficult to understand and maintain.

Fix

Perform nonlocal jumps in your code using setjmp/longjmp or sigsetjmp/siglongjmp only in contexts where such jumps can be performed securely. Alternatively, use POSIX threads if possible.

In C++, to simulate throwing and catching exceptions, use standard idioms such as throw expressions and catch statements.

Examples

expand all

#include <setjmp.h>
#include <signal.h>

extern int update(int);
extern void print_int(int);

static jmp_buf env;
void sighandler(int signum) {
    longjmp(env, signum);
}
void func_main(int i) {
    signal(SIGINT, sighandler);
    if (setjmp(env)==0) {
        while(1) {
            /* Main loop of program, iterates until SIGINT signal catch */
            i = update(i);
        }
    } else {
        /* Managing longjmp return */
        i = -update(i);
    }

    print_int(i);
    return;
}

In this example, the initial return value of setjmp is 0. The update function is called in an infinite while loop until the user interrupts it through a signal.

In the signal handling function, the longjmp statement causes a jump back to main and the return value of setjmp is now 1. Therefore, the else branch is executed.

Correction — Use Alternative to setjmp and longjmp

To emulate the same behavior more securely, use a volatile global variable instead of a combination of setjmp and longjmp.

#include <setjmp.h>
#include <signal.h>

extern int update(int);
extern void print_int(int);

volatile sig_atomic_t eflag = 0;

void sighandler(int signum) {
     eflag = signum;                   /* Fix: using global variable */
}

void func_main(int i) {
      /* Fix: Better design to avoid use of setjmp/longjmp */
    signal(SIGINT, sighandler);
    while(!eflag) {                   /* Fix: using global variable */
        /* Main loop of program, iterates until eflag is changed */
        i = update(i);
    }

    print_int(i);
    return;
}

Result Information

Group: Good practice
Language: C | C++
Default: Off
Command-Line Syntax: SETJMP_LONGJMP_USE
Impact: Low

Version History

Introduced in R2015b