27 Nov 2003 mikehearn   » (Journeyer)

I'm starting to regret taking on this Wine porting work. The app basically works fine, as far as I can tell (though printing is proving problematic) but it is riddled with small yet annoying buglets. For instance, if you correct a spelling mistake in an editor, the context menu pops up shortly afterwards. Why? Because the application itself pokes the richedit control with a WM_RBUTTONUP message. Inscrutable.

Win32 has a very useful ability, namely an operating system level understanding of exceptions. It's called SEH, for "structured exception handling", and is what I feel like discussing at the moment. Linux has no such equivalent. Let's examine what happens when a thread faults on Windows and Linux, and see what we can learn from the other side.

Typically exceptions are handled by the language runtime in use, however moving this functionality down into lower level shared code has some significant advantages.

Let's pretend that a thread in my application dereferences a null pointer. This is invalid, as typically the lower regions of memory are protected, and therefore a page fault/access violation/segmentation fault will occur.

In Win32, what happens is as follows. The CPU delivers an interrupt which is handled by kernel mode code. The interrupt vector dispatches control to the KiUserExceptionDispatcher function, which begins the process of SEH invocation. Win32 SEH frames are stored on the stack, with a thread-local linked list pointing to each different frame in turn (the list is actually stored in the TEB). The SEH frames define things like a callback to be executed, which is passed a structure describing the nature of the exception. An exception type is identified by an unsigned int, and looks like (for an access violation) 0xc0000005.

As the stack is unwound, the callbacks are called twice. The first is to figure out how to handle the exception, and the second time is as the stack is unwound, giving implementors the ability to have "finally" type functionality. Eventually, even if the application has itself registered no handlers, control reaches an exception handler put in place by the operating system loader code. This calls the default handler code (UnhandledExceptionFilter) which on Windows calls some debugging hooks before finally displaying the famous "This application has performed an illegal operation" dialog box. Visual C++ exceptions are partly implemented on top of SEH, however SEH is not rich enough to fully support C++s needs, so there are limitations in interoperability. In particular C code cannot trap C++ exceptions.

Linux as an OS imposes no particular exception handling system on programs, in fact, it's not even aware of exceptions. Typically a signal delivered to an app will be handled and exception handling machinery built into the binary by the compiler will be invoked.

That works OK, but has a few problems. Firstly, it's not possible to throw C++ (or Python, or Java, or .NET etc) exceptions across C libraries. Even though you can compile C code with -fexceptions, typical programs are not expecting the stack to be unwound underneath them and so internal state can be corrupted by doing so. Even if people wanted to write exception-aware C code, there is no C API or ABI for doing it. There's no way to robustly translate exceptions from one environment to another - for instance, C++ exceptions thrown in a library used from Python would probably go badly wrong.

One possible solution is to have a third party library (or maybe a new part of glib) provide an explicit API for exception handling in C, similar to SEH. If rich enough, the most common error handling systems could be mapped to it, bringing us a little bit close to having interoperating code modules. It would also lead to the ability to catch up to Windows in some aspects - for instance, a unified crash handler window. Doing this properly would probably require co-operation from the libc and gcc maintainers however.

Latest blog entries     Older blog entries

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!