[cfe-commits] r167534 - in /cfe/trunk: lib/CodeGen/CGException.cpp lib/CodeGen/CGObjCGNU.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenObjC/gnu-exceptions.m

David Chisnall David.Chisnall at cl.cam.ac.uk
Mon Nov 12 21:50:20 PST 2012


On 12 Nov 2012, at 20:10, John McCall wrote:

> On Nov 12, 2012, at 6:53 PM, David Chisnall <csdavec at swan.ac.uk> wrote:
>> On 11 Nov 2012, at 00:41, John McCall wrote:
>>> If you're going to do this, you need to have two different EH-resume blocks.
>>> The way it's written right now, whichever you ask for first is going to be what
>>> you get, even for later requests with a different parameter.
>>> 
>>> But really, I don't understand why you need this parameter at all.  The only
>>> place you're passing false is when asking for the block to branch to
>>> when an exception-specification fails to trigger.  This is actually still the
>>> "falling off the end of the EH scope" case, and should still be emitted with
>>> a resume instruction.  I don't think there's any 'resume' case where you
>>> actually want to call the rethrow function.
>> 
>> In that case, I'm confused.  The case that I have failing is that resuming an exception caught by an Objective-C catch (including a catchall) should use the throw function, but resuming one caught in an @finally directive or via a cleanup attribute.
> 
> Let me try to break this down.  I'm sure that you know a lot of this, but it's worth being clear.
> 
> LLVM's resume instruction is for resuming the current unwind process because the current function is done performing whatever cleanup work it requires.  That's why it has special semantics for the inliner:  the definition of "the current function" changes, and more stuff may need to happen before resuming out of the function (or the landing pad might even handle the exception now).  It's really just for resuming after all the cleanups have run.*
> 
> I assume that by "resuming an exception caught by an Objective-C catch" you mean rethrowing it with a "@throw;" statement.  It is generally inappropriate to use 'resume' for this because the rethrown exception might be caught by an enclosing handler in the function, or there might be more cleanups to run before leaving the function — in fact, in C++ (and ObjC with Darwin's personality) that's always true, because catch statements are always run inside a cleanup to perform __{cxa,objc}_end_catch.  But more directly, it is specifically impossible to use 'resume' for "@throw;" with your personality because you actually terminate the current unwind process before entering a landing pad that will handle the exception.  Therefore you will always need to start a new unwind process in this case.
> 
> For @finally statements, Clang actually emits them differently from how GCC does:  we use a catch-all, not a cleanup.  First, we want to provide a language guarantee that the @finally is executed;  if there are no handlers active on the stack, not all platforms run cleanups before calling the uncaught exception handler.  Second, a @finally block can actually terminate the current unwind process by leaving the block other than by falling off the end, and that's inappropriate for a cleanup.  So resuming out of a @finally is actually more like an "@throw;" than a resume — especially because, again, the @finally is not necessarily the outermost EH scope in the function.
> 
>> Do you have any suggestions for fixing this correctly?  It was working correctly in clang 3.0, but was broken during the EH refactoring at some subsequent point.
> 
> 1)  The EH resume block should always be using an actual 'resume'.
> 2)  You need to make sure that rethrowing an exception when falling out of @finally is done with your throw function.
> 
> John.
> 
> * There's a subtlety here.  In a context that doesn't require cleanups, an actual 'resume' instruction should always be unreachable, because the personality shouldn't ever land at a landing pad if the exception won't be handled and there are no cleanups.  However, optimization can make that logical point in the function reachable, because it might be inlined into a function that needs cleanups or provides more handlers.  So we emit code pessimistically assuming that we might be inlined, and we just hope that the backend will clean that up later (which it currently does not).
> 

Thanks John,

I think I actually misrepresented the problem.  The issue is with __attribute__((cleanup)) and other actual cleanups (e.g. some of the interaction between blocks and ARC code).  In this case, clang was incorrectly resuming.  I think I need to look at the test case again to work out exactly what it was doing.  This change fixed the test for me, but it may have broken some other corner cases.

To be honest, I don't want to spend much time on this - it would be more productive just to define a less brain damaged EH ABI for the GNUstep runtime to use and give up on GCC compatibility, as it seems that different GCC versions break different corner cases for much the same reason that we do: it's not possible to fix some without breaking others.

David





More information about the cfe-commits mailing list