10

I've read that setjmp "saves the program state" in the passed-in jmp_buf variable, but I haven't found any description of exactly what that entails. Does it make a copy of all the application's memory? Just the registers? The stack?

Lundin
  • 195,001
  • 40
  • 254
  • 396
Norg74
  • 246
  • 4
  • 14
  • 1
    Reason: it is implementation-defined. `setjmp()` does whatever needs to be done for a subsequent `longjmp()` to be successfull. Note: the standard avoids the term `stack`, because an implementation does not need to have a stack. That is why the rather vague term `program state` is used. – joop Aug 12 '14 at 15:35

4 Answers4

5

The following is from C in a Nutshell by Peter Prinz and Tony Crawford:

The setjmp() macro saves the current environment at the time of the call in a buffer specified by its argument. The environment includes the stack, and with it all variables that have automatic storage duration.

Here is what ISO/IEC 9899:TC2 has to say in section 7.13:

The environment of a call to the setjmp macro consists of information sufficient for a call to the longjmp function to return execution to the correct block and invocation of that block, were it called recursively. It does not include the state of the floating-point status flags, of open files, or of any other component of the abstract machine.

Here is an interesting reference by P.J. Plauger in his book, The Standard C Library:

One of the dangers [of implementing setjmp] lies in expression evaluation. A typical computer has some number of registers that it uses to hold intermediate results while evaluating an expression. Write a sufficiently complex expression, however, and you may exhaust the available registers... setjmp must guess how much "calling context" to store in the jmp_buf data object. It is a safe bet that certain registers must be saved.

And finally, from Expert C Programming by Peter Van Der Linden.

Setjmp saves a copy of the program counter and the current pointer to the top of the stack.

Based on the above information, it looks to me like the "current environment" is left up to the implementation.

embedded_guy
  • 1,939
  • 3
  • 24
  • 39
  • 1
    +1 for mentioning Plauger's book alone. That true gem of C lore should be put back into print... perhaps with a better coding style for the examples, but the explanations are great. – DevSolar Aug 12 '14 at 15:50
  • @DevSolar, Agreed. It is one of the most impressive books on C that I have had the opportunity to read. – embedded_guy Aug 12 '14 at 16:22
  • 1
    Very important note: Although it saves the stack pointer, it doesn't preserve stack contents. E.g. you can't use this to implement coroutines, without manually allocating separate stacks for them – Alexander Nov 03 '17 at 15:32
4

It's just the registers that need to be preserved across a function call according to the platforms ABI.

Source: disassembling setjmp on x86, x64, arm32, arm64 on various operating systems.

jtlim
  • 3,861
  • 1
  • 16
  • 14
  • 2
    Incomplete without mentioning the stack and program counter. – david.pfx Aug 12 '14 at 14:45
  • 3
    Stack pointer needs to be preserved across a function call, so it is implicitly mentioned. Program counter is obviously manipulated by longjmp to take you to the correct location. Floating point registers depend on the ABI, eg, on arm (iOS) registers s16-s31 are saved.... Once again, this is all encompassed by the ABI requirements – jtlim Aug 12 '14 at 15:23
1

From the setjmp manpage

   setjmp()  and  longjmp(3)  are  useful for dealing with errors and interrupts encountered in a
   low-level subroutine of a program.  setjmp() saves the stack context/environment  in  env  for
   later  use  by longjmp(3).  The stack context will be invalidated if the function which called
   setjmp() returns.

Essentially, it remembers the current stack location and register state. When you call longjmp, you jump back to the same program counter and stack location with some additional registers are restored.

These are often referred to as "non-local gotos". They are not like a fork that would copy memory state or anything like that.

dohashi
  • 1,771
  • 8
  • 12
  • 1
    No, you don't jump to a location on the stack. That would be fatal. – david.pfx Aug 12 '14 at 14:45
  • It works because you can't call a longjmp if you have exited the function that called setjmp. – dohashi Aug 12 '14 at 14:46
  • It is like your C function is a car going down the road. You get a flat tire. This would be fatal, but you instantly teleport to the tire repair shop, get the tire fixed, and teleport back on the road where you teleported from, still going the same speed. – Chris Reid Aug 20 '23 at 15:42
1

The setjmp() function saves the contents of most of the general purpose registers, in the same way as they would be saved on any function entry. It also saves the stack pointer and the return address. All these are placed in the buffer. It then arranges for the function to return zero.

The longjmp() function restores the general purpose registers and the stack pointer and then does a jump to the previously saved return address. In practice it may do this explicitly, or by setting up the stack and executing a normal function return. On this occasion the function returns a non-zero value.

The principle is the same, but the detail has varied quite a bit across the many different CPUs I have encountered.

david.pfx
  • 10,520
  • 3
  • 30
  • 63