Contents

Setjmp and Longjmp in C

setjmp and longjmp in C

1. What are setjmp and longjmp?

  • setjmp and longjmp are C standard library functions (in `<setjmp.h>`) used for **non-local jumps**—transferring control across function calls.
  • Think of them as a way to save a place in the code (setjmp) and jump back to it from somewhere else (longjmp), bypassing the normal stack unwinding.
  • Syntax:
    • int setjmp(jmp_buf env);
    • void longjmp(jmp_buf env, int val);
  • jmp_buf is a type capable of holding all the information needed to restore the program state.

2. Why do we need setjmp and longjmp?

  • C does not natively support exceptions (like try-catch in C++/Java).
  • In complex C programs, especially embedded or systems code, you sometimes need to escape from deeply nested function calls if an error or special event occurs.
  • Alternatives (like return codes) can make the code messy and hard to maintain.
  • setjmp/longjmp enable a kind of manual exception handling or error recovery.

3. How does setjmp/longjmp work internally?

setjmp

  • Saves the stack context (registers, stack pointer, program counter, maybe more) in a `jmp_buf`.
  • Returns 0 when called directly.
  • Returns a nonzero value if returning via a longjmp.

longjmp

  • Restores the stack context previously saved by setjmp.
  • Continues execution as if setjmp just returned, but with the value passed to longjmp.
  • Does not unwind/destruct objects like C++ (no destructors or cleanup).
  • Can cause issues if misused: resources might leak, or stack may be corrupted if not used carefully.

Visual Flow:

main()
  |
  |---- foo()
  |       |
  |       |---- bar()
  |              |---- setjmp(jb)    <-- saves state here, returns 0
  |              |---- do something
  |              |---- longjmp(jb, 42) <-- jumps back to setjmp, returns 42
  |
  |--- execution resumes in bar(), after setjmp, value==42

4. Use cases, code examples

a) Error Handling Example

#include <stdio.h>
#include <setjmp.h>

jmp_buf env;

void subtask() {
    printf("subtask: error occurred!\n");
    longjmp(env, 1);  // Jump back to saved point in main()
}

int main() {
    if (setjmp(env) == 0) {
        printf("Normal flow, calling subtask...\n");
        subtask();
        printf("This won't print\n");
    } else {
        printf("Recovered from error using longjmp!\n");
    }
    return 0;
}

Output:

Normal flow, calling subtask...
subtask: error occurred!
Recovered from error using longjmp!

b) Nested Function Example: (simulate try-catch)

#include <stdio.h>
#include <setjmp.h>

jmp_buf jb;

void deep() {
    printf("In deep(), something went wrong!\n");
    longjmp(jb, 999);
}

void mid() {
    printf("In mid(), calling deep...\n");
    deep();
    printf("This won't print\n");
}

int main() {
    int code = setjmp(jb);
    if (code == 0) {
        printf("Main, calling mid...\n");
        mid();
        printf("This won't print\n");
    } else {
        printf("Caught error code: %d\n", code);
    }
}

Output:

Main, calling mid...
In mid(), calling deep...
In deep(), something went wrong!
Caught error code: 999

c) Handling Resource Cleanup

  • setjmp/longjmp do not call destructors or free resources automatically. You must manually handle resource cleanup!
  • Use with caution, especially with allocated memory, file handles, or locks.

5. What can we do more?

  • For exception-safe cleanup, prefer goto-based error handling + cleanup labels in C, or use C++ with RAII.
  • sigsetjmp/siglongjmp: For POSIX signals, these functions can also save/restore the signal mask (more robust in signal handlers).
  • Modern C (since C11): `_Noreturn` attribute for functions that don’t return (like those calling longjmp).

sigsetjmp/siglongjmp

  • Like setjmp/longjmp but handle signal masks.
  • Use when dealing with asynchronous signal handling.

Downsides, Caveats, and Best Practices

  • setjmp/longjmp can make code hard to read, debug, and maintain.
  • Never use across threads or after the stack frame of setjmp is gone.
  • Avoid use with C++ code or any code with non-trivial stack objects (won’t call destructors!).
  • Always document their use very clearly in your codebase.
  • Use mainly in legacy code, or where no alternatives exist.

7. Summary Table

Featuresetjmplongjmp
PurposeSave stack contextRestore context/jump
Return0 (direct),None (never returns)
>0 (via longjmp)
Typical UseError recoveryError escape/abort