[cfe-dev] [Bug] Wrong Exception Handling : Destructor not called immediately

John McCall rjmccall at apple.com
Wed Apr 23 13:37:54 PDT 2014


On Apr 23, 2014, at 11:02 AM, suyog sarda <sardask01 at gmail.com> wrote:

> Hi all,
> 
> Finally !! Some interesting findings from my side on why this issue is happening. I will try to explain my findings with pseudo code :
> 
> Sample pseudo code and how clang process it :
> 
> Consider our code having three class a,b and c
> 
> main()
> {
>     try {
>            b tmp1();
>            c tmp2(b(a));
>      }
> 
>    catch {...}
> }
> 
> A piece of code in clang to focus :
> 
> void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
>   EnterCXXTryStmt(S);
>   EmitStmt(S.getTryBlock());
>   ExitCXXTryStmt(S);
> }
> 
> There is an EHStack, which will contain entries which will be popped out to emit cleanup code (destructor) in case of exception happening. 
> 
> When try-catch block is encountered, we visit 'EmitStmt' function, after some more function call we visit following code for emitting code for local variables tmp1 and tmp2:
> 
> void CodeGenFunction::EmitAutoVarDecl(const VarDecl &D) {
>   AutoVarEmission emission = EmitAutoVarAlloca(D);
>   EmitAutoVarInit(emission);
>   EmitAutoVarCleanups(emission);
> }
> 
> First we visit EmitAutoVarInit where some initialization happens by visiting inner expression. For tmp1 object inner expression is empty, so next function EmitAutoVarCleanup will be called and entry of this object tmp1 will be put into EHStack. Since the scope of tmp1 is till end of try block, it will remain in EHStack till try block exits.
> 
> Next, We visit second object tmp2 construction, where inner expression consist of temporaries. We visit function EmitAutoVarInit where we process inner expression. Entries of Inner temporary are added into EHStack till all temporary entries are processed, but as soon as the processing of all temporaries gets over i.e. their scope gets over, these entries are popped out of EHstack and their destructor is called as a part of cleanup code. 
> Please note we are yet to add entry of tmp2 in EHStack as we are yet to visit EmitAutoVarCleanups function.
> 
> Now, The main problem starts - if any of the destructor of temporaries throw, we visit EHStack, pop out each entry from EHStack and emit cleanup code (destructor) for each entry. Note that, the entry of outermost local variable is still not present in the EHStack as we are yet to visit function EmitAutoVarCleanups, as a result of this, its cleanup code (destructor) is not emitted and we land into resource leak!!
> 
> I just altered the order of function calls - first call EmitAutoVarCleanups and then EmitAutoVarInit - which ensures that entry of auto variables are added in EHStack before we process inner expression. This resolves our original issue 'init-temp1.c', however it introduces 10 regressions all related to location of destructors of temporaries. 
> 
> This is a resource leak issue and hence i am pressing more on it (Order in which destructors should be called is not clear, but we should eliminate atleast the resource leak). I am not sure although if my approach to resolve this issue is ok. Basically, we somehow need to ensure that auto object entry gets added in EHStack (may be a call to EmitAutoVarCleanups function) before we pop out entries for temporaries.

Your proposed change causes the destructor for the auto object to be run if the initializer throws, even if the auto var constructor hasn’t been run yet.

John.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20140423/a2c39b11/attachment.html>


More information about the cfe-dev mailing list