Setjmp.h
setjmp.h is a header defined in the C standard library to provide "non-local jumps": control flow that deviates from the usual subroutine call and return sequence. The complementary functions
setjmp
and longjmp
provide this functionality.A typical use of
setjmp
/longjmp
is implementation of an exception mechanism that exploits the ability of longjmp
to reestablish program or thread state, even across multiple levels of function calls. A less common use of setjmp
is to create syntax similar to coroutines.Member functions
setjmp
saves the current environment, at some point of program execution, into a platform-specific data structure that can be used at some later point of program execution by longjmp
to restore the program state to that saved by setjmp
into jmp_buf
. This process can be imagined to be a "jump" back to the point of program execution where setjmp
saved the environment. The return value from setjmp
indicates whether control reached that point normally or from a call to longjmp
. This leads to a common idiom: POSIX.1 does not specify whether
setjmp
and longjmp
save and restore the current set of blocked signals; if a program employs signal handling it should use POSIX's sigsetjmp
/siglongjmp
.Member types
The C99 Rationale describesjmp_buf
as being an array type for backward compatibility; existing code refers to jmp_buf
storage locations by name, which is only possible for array types.Caveats and limitations
When a "non-local goto" is executed viasetjmp
/longjmp
in C++, normal "stack unwinding" does not occur. Therefore, any required cleanup actions will not occur either. This could include closing file descriptors, flushing buffers, or freeing heap-allocated memory.If the function in which
setjmp
was called returns, it is no longer possible to safely use longjmp
with the corresponding jmp_buf
object. This is because the stack frame is invalidated when the function returns. Calling longjmp
restores the stack pointer, which—because the function returned—would point to a non-existent and potentially overwritten or corrupted stack frame.Similarly, C99 does not require that
longjmp
preserve the current stack frame. This means that jumping into a function which was exited via a call to longjmp
is undefined., 2005, 7.13.2.1:2 and footnote 211 However, most implementations of longjmp
leave the stack frame intact, allowing setjmp
and longjmp
to be used to jump back-and-forth between two or more functions—a feature exploited for [|multitasking].Compared to mechanisms in higher-level programming languages such as Python, Java, C++, C#, and even pre-C languages such as Algol 60, the technique of using
setjmp
/longjmp
to implement an exception mechanism is cumbersome. These languages provide more powerful exception handling techniques, while languages such as Scheme, Smalltalk, and Haskell provide even more general continuation-handling constructs.Example usage
Simple example
The example below shows the basic idea of setjmp. There,main
calls first
, which in turn calls second
. Then, second
jumps back into main
, skipping first
's call of printf
.- include
- include
void second
void first
int main
When executed, the above program will output:
second
main
Notice that although the
first
subroutine gets called, "first
" is never printed. "main
" gets printed as the conditional statement if
is executed a second time.Exception handling
In this example,setjmp
is used to bracket exception handling, like try
in some other languages. The call to longjmp
is analogous to a throw
statement, allowing an exception to return an error status directly to the setjmp
. The following code adheres to the 1999 ISO C standard and Single UNIX Specification by invoking setjmp
in a limited range of contexts:- As the condition to an
if
,switch
or iteration statement - As above in conjunction with a single
!
or comparison with an integer constant - As a statement
setjmp
can cause undefined behaviour, such as corruption of local variables; conforming compilers and environments are not required to protect or even warn against such usage. However, slightly more sophisticated idioms such as switch
are common in literature and practice, and remain relatively portable. A simple conforming methodology is presented below, where an additional variable is maintained along with the state buffer. This variable could be elaborated into a structure incorporating the buffer itself.In a more modern-looking example, the usual "try" block would be implemented as a setjmp, the "throw" as longjmp with the optional parameter as the exception, and the "catch" as the "else" block under "try".
- include
- include
- include
- include
static void second;
/* Use a file scoped static variable for the exception stack so we can access
* it anywhere within this translation unit. */
static jmp_buf exception_env;
static int exception_type;
int main
static void first
static void second
This program's output is:
calling first
entering first
calling second
entering second
second failed, exception type: 3; remapping to type 1
first failed, exception type: 1
Although the variable is technically not needed here since setjmp returns what nonzero value longjmp was called with, in practice a more elaborate global object would be used to accommodate richer exceptions.
In the real world, setjmp-longjmp used to be the standard way of exception handling in third party Windows C++ compilers, since the native Structured Exception Handling is not only poorly documented in general but also patented on 32-bit Windows.
Cooperative multitasking
provides thatlongjmp
is guaranteed to work only when the destination is a calling function, i.e., that the destination scope is guaranteed to be intact. Jumping to a function that has already terminated by return
or longjmp
is undefined. However, most implementations of longjmp
do not specifically destroy local variables when performing the jump. Since the context survives until its local variables are erased, it could actually be restored by setjmp
. In many environments, idioms such as if longjmp;
can allow a called function to effectively pause-and-resume at a setjmp
.This is exploited by thread libraries to provide cooperative multitasking facilities without using
setcontext
or other fiber facilities. Whereas setcontext
is a library service which can create an execution context in heap-allocated memory and can support other services such as buffer overflow protection, abuse of setjmp
is implemented by the programmer, who may reserve memory on the stack and fail to notify the library or operating system of the new operating context. On the other hand, a library's implementation of setcontext
may internally use setjmp
in a fashion similar to this example to save and restore a context, after it has been initialised somehow.Considering that
setjmp
to a child function will generally work unless sabotaged, and setcontext
, as part of POSIX, is not required to be provided by C implementations, this mechanism may be portable where the setcontext
alternative fails.Since no exception will be generated upon overflow of one of the multiple stacks in such a mechanism, it is essential to overestimate the space required for each context, including the one containing
main
and including space for any signal handlers that might interrupt regular execution. Exceeding the allocated space will corrupt the other contexts, usually with the outermost functions first. Unfortunately, systems requiring this kind of programming strategy are often also small ones with limited resources.- include
- include
void call_with_cushion;
void child;
int main " after first time that child yields
while
char space; // Reserve enough space for main to run
space = 1; // Do not optimize array out of existence
child;
while
/* Don't return. Instead we should set a flag to indicate that main
should stop yielding to us and then longjmp */