4

In my understanding, a typical usage of setjmp() and longjmp() is exception handling (usage in libpng should be a famous example of that) and there will be at most one call of longjmp() for one setjmp() call.

Is it safely allowed to do longjmp() multiple times for one setjmp() call like this?

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

jmp_buf jb;
int i;

int main(void) {
    i = 0;
    setjmp(jb);
    printf("%d\n", i);
    i++;
    if (i < 10) longjmp(jb, 1);
    return 0;
}

Output:

0
1
2
3
4
5
6
7
8
9

I successfully got the expected output from this execution, but is this guaranteed? Or will jmp_buf invalidated when longjmp() is once used for that?

setcontext - Wikipedia says "They may be viewed as an advanced version of setjmp/longjmp; whereas the latter allows only a single non-local jump up the stack", but I didn't find descriptions that disallow multiple usage of longjmp() like this from N1570 7.13 Nonlocal jumps <setjmp.h>.

I know that using setjmp() and longjmp() is discouraged, but I am wondering if they can be used as a workaround when using loop statements (for, while, do-while) and goto statements is banned but using setjmp() and longjmp() is not banned in some programming quiz. (using recursion may be answers for this type of quiz, but it has risk of stack overflow when trying to deal with large data that require many iterations)

MikeCAT
  • 73,922
  • 11
  • 45
  • 70
  • 5
    It's allowed as long as the context that set the jump buffer (called `setjmp()`) hasn't been exited, so the values stored are still valid. – Jonathan Leffler Oct 02 '20 at 16:38
  • 1
    Section 7.13.2.1 paragraph 2 lists the cases where `longjmp(env)` is undefined. A repeated use of the same environment is not mentioned. – Barmar Oct 02 '20 at 16:46
  • @Barmar - Not sure it's indicative of much. The standard allows for things to be undefined by omission. – StoryTeller - Unslander Monica Oct 02 '20 at 16:59
  • @StoryTeller-UnslanderMonica True, but that philosophy may make almost everything undefined. Does it explicitly say that you can read a variable multiple times? – Barmar Oct 02 '20 at 17:11
  • @Barmar - Reductio ad absurdum nothwithstanding, it does specify when a variable's value gets modified or not. That's how we can know what behavior occurs. In this case it places no restrictions on what `longjmp` may do with its pointer to a `jmp_buf`'s contents. It could very well change as result of jumping. – StoryTeller - Unslander Monica Oct 02 '20 at 17:21
  • Such usage must be very common, as the typical use of setjmp/longjmp is to abandon some task when an error is encountered and return to the main loop. (Think of an interactive calculator that encounters an overflow at some deep level of its computation, and wants to get back to prompt the user for a new command). The typical, and AFAIK only sensible, way to write such code involves just one `setjmp` which may need to be jumped to an arbitrary number of times. So if this is not allowed then I think a huge amount of outstanding code is broken. – Nate Eldredge Oct 02 '20 at 19:55
  • 1
    @NateEldredge: Presumably, one could arrange for `setjmp()` to be reinvoked; it doesn't seem like your usage would become impossible if a jump context could only be used once, although it definitely does seem easier to reuse it. – Ben Voigt Oct 02 '20 at 21:11
  • Banning `goto` is silly in the 1st place, but allowing `longjmp` after you banned it => CRAZY – curiousguy Oct 03 '20 at 16:19

1 Answers1

2

Is it safely allowed to do longjmp() multiple times for one setjmp() call like this?

It is possible to construct a strictly conforming program that calls longjmp() multiple times to return to the point of the same setjmp() call. It comes down to the state of the abstract machine, including memory contents, and especially the state of the jmp_buf in which a setjmp() call records the state required to return to the point of that call. The standard specifies that

All accessible objects have values, and all other components of the abstract machine have state, as of the time the longjmp function was called, except that [... details that can be avoided or made immaterial ...].

(C2018 7.13.2.1/3)

In particular, that means that the longjmp() call must not change the value of the jmp_buf from which it gets its information, and there cannot be any hidden state elsewhere that longjmp() could update to mark the corresponding setjmp() as being used up. If machine state permits a conforming longjmp() call, then an equivalent longjmp() call must still be conforming after the resulting second (or third, etc.) return from the corresponding setjmp() call.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Note that this is not the case if the jmp_buf is an automatic local to the scope of the setjmp -- in that case the [...details] you elided come into play and its value becomes indeterminant – Chris Dodd Oct 02 '20 at 22:45
  • 1
    Note that if `i` was defined as a local automatic variable, its value after the `longjmp()` may or may not have been preserved by `setjmp()` so the behavior would be undefined. – chqrlie Oct 02 '20 at 23:25
  • 2
    @ChrisDodd The standard says that the value of an object becomes indeterminate if was modified between `setjmp` and `longjmp` invocations. Is `jmp_buf` modified in between? – Language Lawyer Oct 02 '20 at 23:37
  • @LanguageLawyer: one would assume that setjmp itself would modify the jmp_buf after being invoked. But I agree that there does not seem to be any reason for this to cause any problems. – Chris Dodd Oct 03 '20 at 00:15
  • @ChrisDodd _one would assume that setjmp itself would modify the jmp_buf after being invoked_ Maybe you mean *when* invoked, not *after*? – Language Lawyer Oct 03 '20 at 00:36
  • @ChrisDodd [I asked the question regarding local `jmp_buf`.](https://stackoverflow.com/q/72175952/315052) If you had asked already, feel free to dup. – jxh May 26 '22 at 03:56