setjmp and longjmp: Non-Local Jumps
Master non-local jumps for exception-like error handling in C. Learn how setjmp saves execution state and longjmp restores it, with practical use cases and important caveats.
Track Your Progress
Sign in to save your learning progress
What You Will Learn
- ✓Understand what non-local jumps are
- ✓Use setjmp to save execution context
- ✓Use longjmp to restore context and "jump back"
- ✓Implement exception-like error handling
- ✓Know the limitations and dangers of longjmp
01Introduction
C doesn't have built-in exception handling like C++ or Java. But what if you need to jump out of deeply nested function calls when an error occurs? Enter setjmp and longjmp — powerful (and dangerous!) functions that enable non-local jumps.
Warning: Advanced Topic
setjmp/longjmp bypass normal control flow and can lead to resource leaks, undefined behavior, and hard-to-debug code. Use them only when absolutely necessary and with great care.
What You'll Learn
- • How
setjmpsaves execution context - • How
longjmprestores it and "jumps back" - • Implementing exception-like error handling in C
- • The dangers and best practices
02What are Non-Local Jumps?
Normal control flow in C uses goto, break, continue, and return. But these only work within a single function. Non-local jumps allow you to jump from one function directly back to another function that called it (directly or indirectly).
1// Normal flow: Each function returns to its caller2main() → functionA() → functionB() → functionC()3 ← ← ← (returns)45// With longjmp: Jump directly from deep call to saved point6main() → functionA() → functionB() → functionC()7 ^ |8 └──────── longjmp jumps here! ─────────┘Think of it Like:
setjmp
"Save my current position" — like dropping a bookmark in a book
longjmp
"Go back to that saved position" — like teleporting back to the bookmark
03The setjmp.h Header
Include <setjmp.h> to use these functions:
1#include <setjmp.h>23// jmp_buf: A type that stores the execution context4jmp_buf env;56// setjmp: Save current execution context7// Returns 0 when called directly8// Returns non-zero value passed to longjmp when "returning" via longjmp9int setjmp(jmp_buf env);1011// longjmp: Restore saved context and "return" from setjmp12// val: The value setjmp will return (if val is 0, setjmp returns 1)13void longjmp(jmp_buf env, int val);What jmp_buf Stores:
- • Stack pointer (SP)
- • Program counter / instruction pointer (PC/IP)
- • Other CPU registers (implementation-defined)
- • Enough information to restore the exact execution state
04Basic Example
Let's see a simple example of how setjmp and longjmp work together:
1#include <stdio.h>2#include <setjmp.h>34jmp_buf jump_buffer;56void second_function(void) {7 printf("In second_function\n");8 printf("About to longjmp...\n");9 longjmp(jump_buffer, 42); // Jump back with value 4210 11 // This line NEVER executes!12 printf("This will never print\n");13}1415void first_function(void) {16 printf("In first_function, calling second_function\n");17 second_function();18 19 // This line NEVER executes when longjmp is called!20 printf("Back in first_function (never reached)\n");21}2223int main() {24 int result;25 26 printf("Setting jump point...\n");27 result = setjmp(jump_buffer);28 29 if (result == 0) {30 // First time: setjmp returns 031 printf("setjmp returned 0 (first call)\n");32 first_function();33 } else {34 // After longjmp: setjmp returns the value from longjmp35 printf("Returned via longjmp with value: %d\n", result);36 }37 38 printf("Program continues normally\n");39 return 0;40}Output:
setjmp returned 0 (first call)
In first_function, calling second_function
In second_function
About to longjmp...
Returned via longjmp with value: 42
Program continues normally
Execution Flow Explained:
- 1.
setjmp()saves context and returns 0 - 2. Code enters the
if (result == 0)branch - 3.
first_function()is called - 4.
second_function()is called - 5.
longjmp(jump_buffer, 42)restores the saved context - 6. Execution resumes at
setjmp(), which now returns 42 - 7. Code enters the
elsebranch
05Exception-Like Error Handling
The most common use of setjmp/longjmp is implementing try-catch style error handling in C:
1#include <stdio.h>2#include <setjmp.h>3#include <stdlib.h>45// Error codes6#define ERROR_NONE 07#define ERROR_FILE_NOT_FOUND 18#define ERROR_MEMORY_ALLOC 29#define ERROR_INVALID_DATA 31011// Global jump buffer (in real code, use thread-local storage)12jmp_buf error_handler;1314// Macros for try-catch-like syntax15#define TRY if (setjmp(error_handler) == 0)16#define CATCH(err) else17#define THROW(err) longjmp(error_handler, err)1819// Simulated functions that can "throw" errors20void read_file(const char *filename) {21 printf("Attempting to read '%s'...\n", filename);22 23 // Simulate file not found24 if (filename[0] == 'x') {25 THROW(ERROR_FILE_NOT_FOUND);26 }27 28 printf("File read successfully\n");29}3031void process_data(void) {32 printf("Processing data...\n");33 34 // Simulate memory allocation failure35 void *ptr = NULL; // Simulating failed malloc36 if (ptr == NULL) {37 // For this example, let's not throw here38 // THROW(ERROR_MEMORY_ALLOC);39 }40 41 printf("Data processed\n");42}4344void validate_data(int value) {45 printf("Validating value: %d...\n", value);46 47 if (value < 0) {48 THROW(ERROR_INVALID_DATA);49 }50 51 printf("Validation passed\n");52}5354void complex_operation(const char *filename, int value) {55 read_file(filename);56 process_data();57 validate_data(value);58}5960int main() {61 printf("=== Test 1: Normal execution ===\n");62 TRY {63 complex_operation("data.txt", 42);64 printf("Operation completed successfully!\n");65 }66 CATCH(error) {67 printf("Error occurred: %d\n", error);68 }69 70 printf("\n=== Test 2: File not found ===\n");71 TRY {72 complex_operation("xyz.txt", 42); // Will fail73 printf("This won't print\n");74 }75 CATCH(error) {76 printf("Caught error code: %d\n", error);77 }78 79 printf("\n=== Test 3: Invalid data ===\n");80 TRY {81 complex_operation("data.txt", -5); // Will fail validation82 printf("This won't print\n");83 }84 CATCH(error) {85 printf("Caught error code: %d\n", error);86 }87 88 printf("\nProgram ended normally\n");89 return 0;90}Output:
Attempting to read 'data.txt'...
File read successfully
Processing data...
Data processed
Validating value: 42...
Validation passed
Operation completed successfully!
=== Test 2: File not found ===
Attempting to read 'xyz.txt'...
Caught error code: 1
=== Test 3: Invalid data ===
Attempting to read 'data.txt'...
File read successfully
Processing data...
Data processed
Validating value: -5...
Caught error code: 3
Program ended normally
!Dangers and Limitations
1. Resource Leaks
longjmp doesn't call destructors or cleanup code. Memory, files, locks, and other resources allocated between setjmp and longjmp will leak!
void dangerous_function(void) { FILE *f = fopen("data.txt", "r"); void *mem = malloc(1000); do_something_that_might_longjmp(); free(mem); // Never reached if longjmp is called! fclose(f); // Resource leak!}2. Invalid After Function Returns
You MUST NOT call longjmp after the function that called setjmp has returned. The stack frame no longer exists!
jmp_buf buf;void setup_jump(void) { setjmp(buf); // Saves context in this stack frame} // Stack frame destroyed when function returns!void try_to_jump(void) { longjmp(buf, 1); // UNDEFINED BEHAVIOR! Stack frame gone!}3. Local Variable Corruption
Non-volatile local variables modified between setjmp and longjmp may have indeterminate values after longjmp. Use volatile for variables you need to preserve.
int count = 0;volatile int safe_count = 0; // Use volatile!if (setjmp(buf) == 0) { count++; safe_count++; longjmp(buf, 1);}// After longjmp:// count may be 0 or 1 (undefined!)// safe_count is guaranteed to be 14. Not Thread-Safe
A global jmp_buf cannot be shared between threads. Each thread needs its own jump buffer (use thread-local storage: _Thread_local in C11).
06Best Practices
Only Use When Necessary
Prefer normal error handling (return codes, error structs) when possible. Reserve setjmp/longjmp for deep error recovery or signal handling.
Keep setjmp in Long-Lived Functions
Call setjmp only in functions that remain on the stack (like main or event loops). Never call longjmp after the setjmp function has returned.
Use volatile for Important Variables
Mark any local variable modified between setjmp and longjmp as volatileto ensure its value is preserved.
Clean Up Resources Before longjmp
If you must use longjmp, ensure all resources are freed first, or use a cleanup mechanism that runs after catching the error.
07Real-World Use Cases
Error Recovery
Libraries like libpng and libjpeg use setjmp/longjmp to recover from errors in deeply nested parsing code.
Signal Handling
Jump out of signal handlers back to main code safely (using sigsetjmp/siglongjmp).
Coroutines/Fibers
Some cooperative threading implementations use setjmp/longjmp for context switching (though modern code uses ucontext or platform APIs).
Interpreters
Scripting language interpreters use setjmp for implementing break/continue/return across native C function boundaries.
08sigsetjmp and siglongjmp (POSIX)
For use with signal handlers, POSIX provides sigsetjmp and siglongjmp, which also save and restore the signal mask:
1#include <stdio.h>2#include <setjmp.h>3#include <signal.h>45sigjmp_buf jump_buffer;67void signal_handler(int sig) {8 printf("\nCaught signal %d, jumping back...\n", sig);9 siglongjmp(jump_buffer, 1); // Jump back safely from signal handler10}1112int main() {13 // Set up signal handler14 signal(SIGINT, signal_handler); // Handle Ctrl+C15 16 if (sigsetjmp(jump_buffer, 1) == 0) {17 // First call: 1 means save signal mask18 printf("Press Ctrl+C to trigger signal...\n");19 20 // Wait for signal (in real code, do actual work here)21 while (1) {22 // Busy loop - press Ctrl+C to escape23 }24 } else {25 // Returned via siglongjmp26 printf("Recovered from signal!\n");27 }28 29 printf("Program continues normally\n");30 return 0;31}Important Difference
sigsetjmp/siglongjmp save and restore the process's signal mask, which is important when jumping out of signal handlers. The second parameter to sigsetjmpcontrols whether to save the signal mask (non-zero = save it).
09Summary
Key Takeaways:
- ✓
setjmpsaves execution context;longjmprestores it - ✓
setjmpreturns 0 on first call; returnslongjmp's value on "return" - ✓Enables exception-like error handling in C
- ⚠Dangerous: Can cause resource leaks, undefined behavior, and hard-to-debug code
- ⚠Never
longjmpafter thesetjmpfunction has returned - ✓Use
volatilefor local variables modified between setjmp and longjmp - ✓Use
sigsetjmp/siglongjmpfor signal handlers (POSIX)
Test Your Knowledge
Related Tutorials
C Program Memory Layout
See how C programs are organized in RAM! Learn about Stack, Heap, Data, BSS, and Text segments. Essential for understanding memory.
Pointers in C
The most powerful feature in C! Pointers store memory addresses. Learn what they are, why they matter, and how to use them safely.
Functions in C
Organize code into reusable blocks! Functions let you write code once and use it many times. Learn to create, call, and pass data to functions.
Have Feedback?
Found something missing or have ideas to improve this tutorial? Let us know on GitHub!