Exceptions in C with Longjmp and Setjmp
di.unipi.it
di.unipi.it
First, you rarely want to use setjmp() and longjmp(), but _setjmp() and _longjmp(), or sigsetjmp(..., 0) and siglongjmp(..., 0) to avoid saving and restoring the signal mask. You'll rarely be modifying the signal mask in between, and the additional kernel calls to save/restore the signal mask are pretty expensive.
Second, any function that uses setjmp() or friends should have its variables declared volatile (or at least those that you rely on after executing a longjmp()). Otherwise, you risk that they do not have the proper value after a longjmp(). In particular, variables that are stored in registers and were modified between setjmp() and longjmp() will typically be restored to the value they had when setjmp() has called, not the value they had when you called the function that resulted in a longjmp() (and optimizing compilers may introduce further bugs). Unfortunately, declaring a variable as volatile will typically prevent quite a few optimizations, but it's still necessary for correctness.
This third one makes using longjmp for exceptions almost untenable in real life code. You can make it easier to track and free memory correctly by using a pool allocator for the whole program, which may or may not be realistic, but I once wrote a webserver this way (from scratch, hey it was the 90s).
Better yet, simply free memory at the exception throw site, if possible.
This frees everything, which isn't what you want. What if you've passed your pointer off to somewhere else where it's still in use?
> Better yet, simply free memory at the exception throw site, if possible.
Most of the time, your exceptions are coming from low levels, like IO libraries, that don't know anything about the memory that you've allocated.
Yeah, but that's why you put exception handlers around anything that you expect to throw an exception, IO being a big one. Dealing with memory cleanup is definitely something that should be handled in the function allocating the memory.
The thing about an exception is that you can't do about it in a number of scopes. When you encounter the exception you just just jump to the scope where you can do something about it.
If you use libraries that use internal malloc'ed memory, etc, you have to clean at the exception call site by calling the library cleanup function.
No, it's pretty simple. Postgres does it with something called regions: your code essentially becomes transaction-based, where resources that need cleanup are put into a region associated with a try block, and all remaining resources at the end of the block's (successful or failed) execution are freed. It requires slightly more work than in C++, obviously, because you're not using C++.
I picked it up after tptacek recommended it here on HN, and it's definitely worth every penny if you want to do any C programming on a reasonably sized project.
http://mail.gnome.org/archives/gnome-list/1999-December/msg0...
it kept coming up, too: http://mail.gnome.org/archives/gtk-devel-list/2001-February/...
Here is what GLib 2.0 ended up with instead, which works well: http://developer.gnome.org/glib/2.31/glib-Error-Reporting.ht...
https://github.com/postgres/postgres/blob/master/src/include...
I'll probably publish it one day, but it needs a little cleaning pass. If you are interested, let me know.
Forget ETRY once and you can kiss your afternoon goodbye while you debug.