Timur Doumler via llvm-dev
2016-Jun-10 09:23 UTC
[llvm-dev] Windows: How to catch C++ exceptions in runtime-compiled code?
HI all,
Here in the JUCE team, we are working on porting the Projucer
<https://www.juce.com/releases/projucer-juce-4> C++ live coding engine to
Windows. Our main challenge now is how to catch C++ exceptions in
runtime-compiled code on Windows. This doesn’t work for us and we’re quite stuck
at this point.
I recently had a chat about this with Chandler Carruth at C++Now. Chandler
suggested that we post our problem to this mailing list, and that perhaps Reid
Kleckner and/or other people here may have some hints. Any ideas would be highly
appreciated!
In our case the RaiseException API function does not find the correct catch pad,
which may be caused by a ThrowInfo structure handed to _CxxThrowException being
empty. Apart from getting this right, is there anything else we possibly miss?
Windows API functions to be called for registering catch pads or so?
Some more details:
We're using Clang for compiling C++ code at runtime and the ORC libraries to
load and execute it in our application, which is itself compiled with MSVC. We
work with the release_38 branches of LLVM and Clang.
Static compilation of a simple test program with try/catch and throw works fine.
When compiling the same code at runtime and loading it with the ORC libraries,
every throw results in an unhandled exception. The point of interest seems to be
the throw handler for C++ exceptions (throw.cpp):
__declspec(noreturn) extern "C" void __stdcall
_CxxThrowException(void* pExceptionObject, _ThrowInfo* pThrowInfo)
{
...
RaiseException( ThisException.ExceptionCode,
ThisException.ExceptionFlags,
ThisException.NumberParameters,
(PULONG_PTR)&ThisException.params );
}
For some reason the call to RaiseException does not find or consider the
existing catch handler correctly. Comparing execution states when entering the
function between the two cases, static- vs. runtime-compiled, turns out that
pThrowInfo points to nulled memory in the runtime-compiled case, while it has
some data in the static-compiled case. Detailed information about the types can
be found here: http://www.openrce.org/articles/full_view/21
<http://www.openrce.org/articles/full_view/21>. Most likely the
"attributes" and "pCatchableTypeArray" members are required
for RaiseException to resolve the correct catch pad?
To find out why the ThrowInfo structure is empty in the runtime-compiled case,
we compared what happens during code generation. It looks like
CodeGenFunction::EmitCXXThrowExpr is the relevant function here and it does the
right thing, i.e. generating the global variable for the ThrowInfo in
MicrosoftCXXABI::emitThrow. Also the WinEHPrepare pass is running correctly as
it seems. Is there any extra work to do (at runtime/link-time?) for filling this
data structure? Any idea what else to check?
Our Clang language options do include: Exceptions, CXXExceptions, RTTI, RTTIData
Please reply to my colleague Stefan Gränitz (in Cc) who is in charge of this
project. Any kind of help or ideas would be really awesome.
Many thanks!
Timur
--
Timur Doumler
JUCE Senior Software Engineer
ROLI <http://www.roli.com/> extends the journey of music creation to
everyone. The acclaimed <http://www.roli.com/press/reviews>Seaboard GRAND
<http://www.roli.com/products/seaboard-grand> and Seaboard RISE
<http://www.roli.com/products/seaboard-rise> redefine how expressive and
versatile an electronic musical instrument can be. Our groundbreaking software
Equator <http://www.roli.com/equator> opens up new dimensions of sonic
expression, and is built with JUCE <http://www.juce.com/>, ROLI’s
proprietary coding platform, and the leading C++ framework for audio
applications globally. Blend <http://www.blend.io/> enables everyone to
seamlessly collaborate, share, and remix their music. And NOISE
<http://www.roli.com/noise> is the most expressive app ever made — see for
yourself: download it now for free!
<https://itunes.apple.com/app/noise-5d/id1011132019?ls=1&mt=8>
Mobile: +44 (0) 7539 947960
Office: +44 (0) 2072 542155
ROLI
2 Glebe Rd, London E8 4BD
www.roli.com <http://www.roli.com/>
-------------- next part --------------
An HTML attachment was scrubbed...
URL:
<http://lists.llvm.org/pipermail/llvm-dev/attachments/20160610/29212819/attachment.html>
Igor Minin via llvm-dev
2016-Jun-10 14:07 UTC
[llvm-dev] Windows: How to catch C++ exceptions in runtime-compiled code?
Hi, Timur. I may be wrong, but it seems that I faced similar problem before. The problem is that Windows checks memory region of exception handler forMEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE flag, that is not set by default and can't be set easily. Before Windows passes control to your handler it does the following checks: KiUserExceptionDispatcher ->RtlDispatchException -> RtlIsValidHandler (FAIL) So you need to enable this flag for your memory-generated code. As far as I know it is impossible if permanent DEP is enabled. So you can either run your process without DEP (not an option in the most cases), or use another way to deal with exceptions. One of the possible workarounds is VEH. You can look through OpenJDK as an example. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160610/78fb4a26/attachment-0001.html>
Timur Doumler via llvm-dev
2016-Jun-10 16:13 UTC
[llvm-dev] Windows: How to catch C++ exceptions in runtime-compiled code?
Hey Igor, Thanks a lot for your e-mail! I am Cc’ing Stefan Gränitz who is the one actually working on this project, hope this will be helpful. Cheers, Timur> On 10 Jun 2016, at 15:07, Igor Minin <igorm6387 at gmail.com> wrote: > > Hi, Timur. I may be wrong, but it seems that I faced similar problem before. > > The problem is that Windows checks memory region of exception handler for MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE flag, that is not set by default and can't be set easily. > > Before Windows passes control to your handler it does the following checks: > > KiUserExceptionDispatcher ->RtlDispatchException -> RtlIsValidHandler (FAIL) > > So you need to enable this flag for your memory-generated code. As far as I know it is impossible if permanent DEP is enabled. So you can either run your process without DEP (not an option in the most cases), or use another way to deal with exceptions. One of the possible workarounds is VEH. You can look through OpenJDK as an example.-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20160610/e77f7f8e/attachment.html>