Kaylor, Andrew
2015-May-13 18:03 UTC
[LLVMdev] [WinEH] A hiccup for the Windows C++ exception handling
I've been working recently to get the following test case working for an x86_64-pc-windows-msvc target. void test1() { try { try { throw 1; } catch(...) { throw; } } catch (...) { } } I committed a patch earlier in the week to get the WinEHPrepare pass to produce IR that I thought was sufficient, but as I mentioned in the review I was still seeing runtime errors when executing a program compiled with this code. I have since figured out why the program crashes at runtime, but fixing it is going to be a bit tricky. It has to do with some wrinkles in how the Microsoft runtime handles the rethrown exceptions. As the code above is written, the outer catch should handle both the inner catch and its try-block and the outer catch handler should return to a location in the parent function. An ideal numbering of the EH states would look something like this: void test1() { // EH state = -1 try { // EH state = 0 try { // EH state = 1 throw 1; } catch(...) { // EH state = 2 throw; } // EH state = 0 } catch (...) { // EH state = 3 } // EH state = -1 } That would give us the following try map entries: Inner catch { TryLow = 1, TryHigh = 1, CatchHigh = 2 } Outer catch { TryLow = 0, TryHigh = 2, CatchHigh = 3 } Unfortunately, we can't deduce this from the IR because the outer catch handler is only ever seen to catch exceptions from within the inner catch. So we end up producing a try map like this. (Even this requires a small patch to the current code to avoid dropping the second entry entirely.) Inner catch { TryLow = 1, TryHigh = 1, CatchHigh = 3 } Outer catch { TryLow = 2, TryHigh = 2, CatchHigh = 3 } This causes the runtime to interpret the outer catch as if it were nested within the inner catch. In other words, the code is indistinguishable from this: void test2() { try { throw 1; } catch(...) { try { throw; } catch (...) { } } } And indeed, the prepared IR we produce for these two cases is the same. (There is a critical difference before WinEHPrepare that I'll discuss in a bit.) Here is where the runtime problem comes in. Because the runtime thinks the second catch is nested within the first, it doesn't actually rethrow the exception. It just passes it on to the second handler, which it expects to return to an address within the first catch handler. However, we aren't currently generating code that does that (in either case) because when we outline the first handler we insert a stub for the nested handler and without knowing what the second handler does, the block to which it should return appears to be unreachable. Knowing this, I can fix the simple case easily enough by changing the order in which the landing pads are processed so that I don't need to stub out the nested handler and can use its return targets to make the required block reachable. However, this opens a huge can of worms for non-trivial cases. There are scenarios (the original test case among them) where a nested handler should return to an block outside the enclosing handler. So how can the enclosing handler determine which blocks it should clone and which it shouldn't? I'm working on this now, but it is quickly becoming clear that our current cloning scheme is not well suited to handle it. So there are two issues here. 1) We need a better way to figure out which blocks should be in which handlers and properly remap the return statements in each handler accordingly. 2) We need a better way to compute the EH states. Anyway, I'm working on these problems right now. I'm still trying to solve the problems without redesigning our current scheme, but I don't think this is going to be the right long term solution. Thoughts? -Andy -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150513/c23442a8/attachment.html>
Reid Kleckner
2015-May-13 20:14 UTC
[LLVMdev] [WinEH] A hiccup for the Windows C++ exception handling
On Wed, May 13, 2015 at 11:03 AM, Kaylor, Andrew <andrew.kaylor at intel.com> wrote:> > So there are two issues here. > > > > 1) We need a better way to figure out which blocks should be in which > handlers and properly remap the return statements in each handler > accordingly. > > 2) We need a better way to compute the EH states. > > > > Anyway, I’m working on these problems right now. I’m still trying to > solve the problems without redesigning our current scheme, but I don’t > think this is going to be the right long term solution. >Yeah, we're on the same page. The current scheme is not the right long term solution. The SEH personality functions are not nearly as limiting. I was hoping that, like with SEH, we could completely throw away the information about try nesting and simply emit tables that are functionally correct. We knew it was theoretically impossible to always recover the nested try structure from Itanium-style landingpad IR, but now we know it is also *practically* impossible. :) Ultimately, I think something like the dispatchblock scheme I described will work better. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150513/baf69503/attachment.html>
Kaylor, Andrew
2015-May-13 20:43 UTC
[LLVMdev] [WinEH] A hiccup for the Windows C++ exception handling
Have got anything started with the dispatchblock plan? From: Reid Kleckner [mailto:rnk at google.com] Sent: Wednesday, May 13, 2015 1:15 PM To: Kaylor, Andrew Cc: David Majnemer <david.majnemer at gmail.com> (david.majnemer at gmail.com); LLVM Developers Mailing List Subject: Re: [WinEH] A hiccup for the Windows C++ exception handling On Wed, May 13, 2015 at 11:03 AM, Kaylor, Andrew <andrew.kaylor at intel.com<mailto:andrew.kaylor at intel.com>> wrote: So there are two issues here. 1) We need a better way to figure out which blocks should be in which handlers and properly remap the return statements in each handler accordingly. 2) We need a better way to compute the EH states. Anyway, I’m working on these problems right now. I’m still trying to solve the problems without redesigning our current scheme, but I don’t think this is going to be the right long term solution. Yeah, we're on the same page. The current scheme is not the right long term solution. The SEH personality functions are not nearly as limiting. I was hoping that, like with SEH, we could completely throw away the information about try nesting and simply emit tables that are functionally correct. We knew it was theoretically impossible to always recover the nested try structure from Itanium-style landingpad IR, but now we know it is also *practically* impossible. :) Ultimately, I think something like the dispatchblock scheme I described will work better. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20150513/cf16d91e/attachment.html>
Apparently Analagous Threads
- [LLVMdev] [WinEH] A hiccup for the Windows C++ exception handling
- [LLVMdev] [WinEH] A hiccup for the Windows C++ exception handling
- [LLVMdev] [WinEH] Cloning blocks that reference non-cloned PHI nodes
- [LLVMdev] [WinEH] Cloning blocks that reference non-cloned PHI nodes
- [LLVMdev] WinEH work to be done (in progress and otherwise)