1. 24
  1.  

  2. 4

    writing this article led me to try the GCC intrinsics, and I’m so impressed I’m still thinking about ways I can use them. My main thought is out-of-memory situations in arena allocators, using a non-local exit to roll back to a savepoint, even if just to return an error. This is nicer than either terminating the program or handling OOM errors on every allocation.

    If I may be patronizing for a moment: it’s cute to see someone rediscovering exceptions!

    (But by way of foreshadowing: there’s a reason C++ abandoned setjmp for try/catch back in the 1990s. Saving the registers to the stack any time there might be a need to do something on unwind turns out to be a performance problem. I can attest to this, based on a 1990s codebase I worked on.)

    1. 4

      It actually worse that that, if I remember the history correctly. Itanium’s setjmp and longjmp implementations were built on top of DWARF unwinding and GCC gained the builtins to support this. It’s a shame other platforms didn’t move to this model.

    2. 1

      This is fun. I am also pleased to learn about __builtin_longjmp! There’s a small aside in this article about the signal mask, which skates past a horrible abyss - which might even make it sensible to DIY longjmp.

      Some of the nastiness can be seen in the POSIX rationale for sigsetjmp which says that on BSD-like systems, setjmp and _setjmp correspond to sigsetjmp and setjmp on System V Unixes. The effect is that setjmp might or might not involve a system call to adjust the signal mask. The syscall overhead might be OK for exceptional error recovery, such as the arena out of memory example, but it’s likely to be more troublesome if you are implementing coroutines.

      But why would they need to mess with the signal mask? Well, if you are using BSD-style signals or you are using sigaction correctly, a signal handler will run with its signal masked. If you decide to longjmp out of the handler, you also need to take care to unmask the signal. On BSD-like systems, longjmp does that for you.

      The problem is that longjmp out of a signal handler is basically impossible to do correctly. (There’s a whole flamewar in the wg14 committee documents on this subject.) So this is another example of libc being optimized for the unusual, broken case at the cost of the typical case.