News for hackers. Stuff that matters.
Re:Let's write a setjmp by jagrsw on Sunday February 12, 2023 @04:35AM (#34761432)
While some programs/libs (most notably libjpeg) use setjmp/longjmp I tend to avoid using it:

  - It saves/restores registers, but does it really know of all, all registers of modern CPU variations? Could there be inconsistencies?
  - It's a goto, which restores some context (registers) and not others (memory), it's a little bit counterintuitive to think about, because this distinction in modern runtimes is fuzzy. How does it play with volatile vars?
  - I'm not sure how well it plays with less standard features of C (eg attribute(cleanup)) or with basic features of C++ like exception handling, or even class destructors, it's probably something to be avoided in conjunction with *jmp, and sticking to very procedural and basic C might work best here?
OTOH some programming gods recommend using it, so my hesitance is probably not well founded.
Re:Let's write a setjmp by adrian_b on Sunday February 12, 2023 @05:07AM (#34761601)
"setjmp/longjmp" must save/restore only those registers that are defined by the C ABI as being preserved across function calls.

The program point to where "longjmp" jumps is viewed by the compiler as a function return point, so the compiler assumes that all the other registers hold undefined values.

For most CPUs, the C ABI defines the SIMD registers as being not preserved across function calls, so "setjmp" does not need to save them. Had some of them been defined as preserved registers, "setjmp" would have also saved those.

"setjmp/longjmp" cannot be used in any C++ program, unless all the nested functions that occur between a "setjmp" and a "longjmp" are C functions. This may happen in C libraries which are linked into C++ programs and which may use "setjmp/longjmp" internally, without interfering with C++ objects.

As you say, "attribute(cleanup)" is not something specified in the C language standard, so you cannot expect that "longjmp" will invoke the cleanup function, unless you use a specific libc implementation, whose documentation explicitly says that its "longjmp" will invoke the cleanup functions, when the program is compiled with a certain C compiler. I am not aware of any such "longjmp" implementation.

If you want to use exceptions in a C program, you must use "setjmp/longjmp". If you do not want to use exceptions in a C program, you have no need for them.

The same happens in any other programming language. If you do not want to use exceptions in a C++ program, you have no need to use keywords like "try" and "throw".

Re:Let's write a setjmp by murdoze on Sunday February 12, 2023 @06:01AM (#34761892)
One of the largest C++ projects I worked on was compiled with exceptions disabled (-fno-exceptions).

Still in production, for 20 years now.

Re:Let's write a setjmp by chaosite on Sunday February 12, 2023 @06:28AM (#34762018)
Google famously doesn't use exceptions for C++, and Google's C++ code is not exception-safe (https://google.github.io/styleguide/cppguide.html#Exceptions.)
Re:Let's write a setjmp by flohofwoe on Sunday February 12, 2023 @06:05AM (#34761906)
I wonder though if setjmp/longjmp was designed with exceptions in mind, or just as a general escape hatch for the 'tamed' structured goto in C (my guess would be the latter).
Re:Let's write a setjmp by bregma on Sunday February 12, 2023 @07:05AM (#34762206)
Specifically, The C++ Programming Language standard ISO/IEC 14882:2011 18.10/4 [support.runtime] says this.

> A setjmp/longjmp call pair has undefined behavior if replacing the setjmp and longjmp by catch and throw would invoke any non-trivial destructors for any automatic objects.

Of course, the C++ language runtime is usually written in pure C, and at least one naive implementation of the C++ try/catch mechanism uses setjmp/longjmp under the hood.

Re:Let's write a setjmp by comex on Sunday February 12, 2023 @02:33PM (#34766044)
> I am not aware of any such "longjmp" implementation.

Clang on Windows behaves this way! That is, when targeting the Visual C++ runtime, as opposed to MinGW.

With the Visual C++ toolchain and runtime, longjmp behaves like a C++ exception throw and goes through a whole stack unwinding routine, unlike on Unix (and MinGW) where it just sets a few registers and branches. This has the downside of being much slower, but the benefit that longjmp will run destructors of C++ local variables as it unwinds (as well as SEH `__finally` blocks), making it less of a footgun in C++ code.

Visual C++ itself doesn't support GCC extensions like `__attribute__((cleanup))`, but these days Clang is highly compatible with Visual C++ while also supporting GCC extensions.

Re:Let's write a setjmp by Findecanor on Sunday February 12, 2023 @05:35AM (#34761753)
The only local variables you can count on being preserved are "volatile" variables initialised before the setjmp() call, and then not changed.

That's all the guarantee the C standard gives. Anything else is specific to compiler/OS.

Re:Let's write a setjmp by adrian_b on Sunday February 12, 2023 @06:19AM (#34761959)
As you have phrased them, the standard guarantees seem weaker than they are actually specified in the C standard.

Where a "longjmp" returns after a "setjmp", everything is preserved exactly like after a normal function call (including the registers specified by the ABI),

"except that the values of objects of automatic storage duration that are local to the function containing the invocation of the corresponding setjmp macro that do not have volatile-qualified type and have been changed between the setjmp invocation and longjmp call are indeterminate."

For the most frequent use case, when "longjmp" is used to throw exceptions, the only local variables that can become indeterminate, according to the standard, are those that have been passed as arguments to functions invoked inside the C equivalent of a "try" block, or which have been explicitly modified in another way there. Any local variable that is not assigned to or passed as an argument there is preserved.

The standard behavior is normal, because where a "longjmp" returns it is not known where the execution of the nested functions has been aborted and whether any of their output parameters already store their expected final values or only some unpredictable temporary values.

Re:Let's write a setjmp by smcameron on Sunday February 12, 2023 @08:37AM (#34762704)
> While some programs/libs (most notably libjpeg) use setjmp/longjmp

Also libpng. What is it with these graphics guys that they can't just return an error code like a normal person?

Re:Let's write a setjmp by duskwuff on Sunday February 12, 2023 @04:02PM (#34766909)
libjpeg is a fairly old library (1991), so it isn't terribly surprising that it doesn't follow modern programming conventions.

libpng is only slightly newer (1995), and may have adopted the pattern from libjpeg.