LLVM/Clang and setjmp/longjmp exception handling on MinGW

Hi,

In my neverending hobby quest to make all of LLVM better on Windows, I am now stumbling over setjmp/longjmp and sjlj exception handling. To test I’m linking with GCC 4.6’s libstdc++ and libgcc. The problem also occurs with libc++ and GCC’s libsupc++.

I have attached the assembly output for a very simple exception testing program:
#include
#include
using namespace std;

int main()
{
try { throw runtime_error( “Hello world!” ); }
catch( exception &e ) { cout << e.what(); }
}

GCC produces the sjlj initialization code, where Clang does not. Is sjlj exception handling not used with Clang or is this a genuine bug?

Will fixing this hinder future efforts of using/porting stdcxxrt and libunwind for MinGW, or will “flipping a hardcoded switch” be enough to make that transition?

Thanks!

Ruben

Hello Ruben,

GCC produces the sjlj initialization code, where Clang does not. Is sjlj
exception handling not used with Clang or is this a genuine bug?

Will fixing this hinder future efforts of using/porting stdcxxrt and
libunwind for MinGW, or will "flipping a hardcoded switch" be enough to make
that transition?

clang/llvm does not support sjlj exceptions (with the exception of arm/darwin).
So, please consider using dwarf-based eh (though it might be
incomplete on windows).

2011/10/9 Anton Korobeynikov <anton@korobeynikov.info>

Hello Ruben,

GCC produces the sjlj initialization code, where Clang does not. Is sjlj
exception handling not used with Clang or is this a genuine bug?

Will fixing this hinder future efforts of using/porting stdcxxrt and
libunwind for MinGW, or will “flipping a hardcoded switch” be enough to make
that transition?

clang/llvm does not support sjlj exceptions (with the exception of arm/darwin).
So, please consider using dwarf-based eh (though it might be
incomplete on windows).

GCC doesn’t have any Dwarf exception handling on 64-bit Windows, due to it being either extremely hard or impossible to get right. I would like to get Clang to produce working exception code for Windows. The “right way” is patented (SEH), so pretty of limits to anyone not from MS (or Borland, the patent holder). I’m not trying to wake up this discussion again. I just want to enable/implement/fix sjlj exception handling for Windows, in hopefully a MinGW GCC compatible way.

Thanks!

Ruben

Nope. SEH is not the right way of implementing exceptions on Win64 (it's not really the right way of implementing C++ exceptions on Win32 either). The right way is to use the Win64 exception ABI:

This is not patented, and is fairly similar to the DWARF zero-cost model, just with (in typical Microsoft fashion) different layouts for everything. The exception model in LLVM IR would map very cleanly to this, but (as far as I know) no one is working on it yet. It would be possible to use the same LSDA format as on other platforms, and just provide a struct UNWIND_INFO for each function pointing to this, with fairly minimal changes to the personality function. I'd be happy to make these changes in libcxxrt...

David

As called the patent is Win32 x86 specific implementations, IANAL.

Charles Davis had been working on implementing x64 EH. I don't know
how they work.
Ruben, I suppose Kai has been working for x64 EH, right?
(it is dw2-like implementation, IIRC)

Anyway, would you like us to implement sjlj on win32 x86?

...IANAL

2011/11/1 David Chisnall <csdavec@swan.ac.uk>

Nope. SEH is not the right way of implementing exceptions on Win64 (it’s not really the right way of implementing C++ exceptions on Win32 either). The right way is to use the Win64 exception ABI:

http://msdn.microsoft.com/en-us/library/1eyas8tf.aspx

This is not patented, and is fairly similar to the DWARF zero-cost model, just with (in typical Microsoft fashion) different layouts for everything. The exception model in LLVM IR would map very cleanly to this, but (as far as I know) no one is working on it yet. It would be possible to use the same LSDA format as on other platforms, and just provide a struct UNWIND_INFO for each function pointing to this, with fairly minimal changes to the personality function. I’d be happy to make these changes in libcxxrt…

What about associated stack unwinding? I’m not quite familiar with all this, and am kind of going half-blind on anything Google pops up. I did take a look at the Win64 EH specification, but couldn’t find the link to what’s happening in libcxxrt. And libcxxrt depends on libunwind or similar, so that needs to be handled appropriately as well. I would very much appreciate if you could make those changes to libcxxrt, although I’m unsure if I’m able to do anything sensible here…

2011/11/1 NAKAMURA Takumi <geek4civic@gmail.com>

2011/11/1 Ruben Van Boxem <vanboxem.ruben@gmail.com>:

GCC doesn’t have any Dwarf exception handling on 64-bit Windows, due to it
being either extremely hard or impossible to get right. I would like to get
Clang to produce working exception code for Windows. The “right way” is
patented (SEH), so pretty of limits to anyone not from MS (or Borland, the
patent holder). I’m not trying to wake up this discussion again. I just want
to enable/implement/fix sjlj exception handling for Windows, in hopefully a
MinGW GCC compatible way.

As called the patent is Win32 x86 specific implementations, IANAL.

Charles Davis had been working on implementing x64 EH. I don’t know
how they work.
Ruben, I suppose Kai has been working for x64 EH, right?
(it is dw2-like implementation, IIRC)

Anyway, would you like us to implement sjlj on win32 x86?

As it stands, Windows+Clang == no working exceptions, which… sucks. It would be nice to have a nasty sjlj fallback untill the “proper” solution arrives. I was trying to enable this for MinGW at least in Clang, but it seems adding a bool UseSjLjExceptions() const; to the Windows Toolchain that returns true isn’t doing anything :frowning:

Ruben

What about associated stack unwinding?

The generic stack unwinding part is provided by standard Windows libraries. They walk the stack and invoke the personality function for each frame. On other platforms this is done by libunwind or libgcc_s.

I'm not quite familiar with all this, and am kind of going half-blind on anything Google pops up. I did take a look at the Win64 EH specification, but couldn't find the link to what's happening in libcxxrt.

An exception implementation is typically split into two parts. One part is generic, one is language-specific. Most platforms use the CodeSourcery Itanium exception ABI (except ARM, which is just different to be difficult). This defines a set of DWARF tables for generic frame unwinding. Each table contains a pointer to a personality function and a pointer to a language-specific data area (LSDA). The contents of the LSDA are not specified in detail and can be anything that the compiler and personality function agree on.

The generic code walks the language-agnostic tables, unwinds the stack (on ARM, the personality function does this, because someone at ARM thought it was really clever to make every language reinvent the wheel), and invokes any personality function. This typically runs as a two-stage process, first just scanning the stack to find if the exception can be caught, and then doing the unwinding. The personality function is responsible for parsing the LSDA, working out whether there are any cleanups or catches that match this exception, and telling the generic part of the code how to install the stack frame to handle them.

And libcxxrt depends on libunwind or similar, so that needs to be handled appropriately as well.

libcxxrt provides the C++ language-specific part of the implementation. It requires a generic unwind library. It has been tested with libgcc_s and libunwind for this on platforms that use DWARF unwind tables. On Windows, it would need a new personality function, but (if the LSDA layout is the same) it would be able to reuse all of the helper functions, so the personality function itself would only be a few dozen lines of new code.

I would very much appreciate if you could make those changes to libcxxrt, although I'm unsure if I'm able to do anything sensible here...

There's no point making those changes without compiler support, because I can't test them, but ping me when there is compiler support (either in LLVM or Path64) and I'll see what I can do...

David

-- Sent from my Difference Engine