SHIVA PRASAD
2012-Jun-19 11:14 UTC
[LLVMdev] [LLVMDev] Object in a try-catch block not being destroyed even after an exception
Dear LLVM Members, The below source code from gcc test suite replicates the problem which i am facing. When it is built with clang, it throws an abort (highlighted). The following are my observations - 1. The object(tmp) is not getting destroyed immediately after the exception is thrown. In case of Clang, the object is getting destroyed at a later point of time. 2. In case of gcc, the scope of the object created inside the try-catch block is limited to the block. Once the exception is thrown, the object(tmp) is destroyed. 3. The assembly files for both clang and gcc were generated and compared, wherein the sequence of operations look similar. 4. I also tried the MS-Visual Studio compiler, which gives a result similar to gcc. As per my understanding of the C++ standard, the object has to be destroyed as soon as the exception is thrown. Please let me know which is the correct behavior and suggest me the changes required. Thanks & Regards, Shivaprasad shivahms at gmail.com /******************************************************************Source Code Start*******************************************************************/ extern "C" void abort (); int thrown; int as; struct a { a () { ++as; } ~a () { --as; if (thrown++ == 0) throw 42; } }; int f (a const&) { return 1; } int f (a const&, a const&) { return 1; } int bs; int as_sav; struct b { b (...) { ++bs; } ~b () { --bs; as_sav = as; } }; bool p; void g() { if (p) throw 42; } int main () { thrown = 0; try { b tmp(f (a(), a())); g(); } catch (...) {} // We throw when the first a is destroyed, which should destroy b before // the other a. if (as_sav != 1) abort (); thrown = 0; try { b tmp(f (a())); g(); } catch (...) {} if (bs != 0) abort (); } /******************************************************************Source Code End*******************************************************************/ -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20120619/ed14ef5a/attachment.html>
Joshua Cranmer
2012-Jun-19 19:19 UTC
[LLVMdev] [LLVMDev] Object in a try-catch block not being destroyed even after an exception
On 6/19/2012 7:14 AM, SHIVA PRASAD wrote:> Dear LLVM Members, > > The below source code from gcc test suite replicates the > problem which i am facing. When it is built with clang, it throws an > abort(highlighted). > The following are my observations - > > 1. The object(tmp) is not getting destroyed immediately after the > exception is thrown. In case of Clang, the object is getting > destroyed at a later point of time. > 2. In case of gcc, the scope of the object created inside the > try-catch block is limited to the block. Once the exception is > thrown, the object(tmp) is destroyed. > 3. The assembly files for both clang and gcc were generated and > compared, wherein the sequence of operations look similar. > 4. I also tried the MS-Visual Studio compiler, which gives a result > similar to gcc.This looks specific to clang, not to LLVM, so moving to cfe-dev. [Source code below not elided for anyone on cfe-dev who isn't on llvmdev; I have more comments trailing, so scroll down].> As per my understanding of the C++ standard, the object has to be > destroyed as soon as the exception is thrown. > Please let me know which is the correct behavior and suggest me the > changes required. > > > Thanks & Regards, > Shivaprasad > shivahms at gmail.com <mailto:shivahms at gmail.com> > > /******************************************************************Source > Code > Start*******************************************************************/ > extern "C" void abort (); > > int thrown; > > int as; > struct a { > a () { ++as; } > ~a () { --as; if (thrown++ == 0) throw 42; } > }; > > int f (a const&) { return 1; } > int f (a const&, a const&) { return 1; } > > int bs; > int as_sav; > struct b { > b (...) { ++bs; } > ~b () { --bs; as_sav = as; } > }; > > bool p; > void g() > { > if (p) throw 42; > } > > int main () { > thrown = 0; > try { > b tmp(f (a(), a())); > > g(); > } > catch (...) {} > > // We throw when the first a is destroyed, which should destroy b before > // the other a. > if (as_sav != 1) > abort (); > > thrown = 0; > try { > b tmp(f (a())); > > g(); > } > catch (...) {} > > if (bs != 0) > abort (); > } > /******************************************************************Source > Code > End*******************************************************************/ >What clang is generating can be approximated by the following pseudocode: atmp1, atmp2, btmp = alloca space for temporaries call a::a on atmp1 try { call a::a on atmp2 try { call f(atmp1, atmp2) call b::b on btmp } catch { } finally { call a::~a on atmp2 } } catch { } finally { call a::~a on atmp1 } // NOW b is "constructed" Looking at the output IR, the best interpretation I can give is that Clang is cleaning up the temporary arguments before calling the new variable constructed. The question, of course, is whether or not this is legal per the C++ spec. C++11 section 12.2, par 3 states that> Temporary objects are destroyed as the last step > in evaluating the full-expression (1.9) that (lexically) contains the > point where they were created.Section 1.9, par 10 has an example which states that the full expression associated with the call to the constructor in this case is indeed the actual constructor call. Section 15.2, par 1 states:> As control passes from a throw-expression to a handler, destructors > are invoked for all automatic objects > constructed since the try block was entered. The automatic objects are > destroyed in the reverse order of the > completion of their construction.I'm not 100% what the correct interpretation is in this case. It comes down to whether b should be considered constructed before or after the full expression of the declarator is completed. -- Joshua Cranmer News submodule owner DXR coauthor -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20120619/767f196e/attachment.html>
John McCall
2012-Jun-19 21:15 UTC
[LLVMdev] [cfe-dev] [LLVMDev] Object in a try-catch block not being destroyed even after an exception
On Jun 19, 2012, at 12:19 PM, Joshua Cranmer wrote:> What clang is generating can be approximated by the following pseudocode: > atmp1, atmp2, btmp = alloca space for temporaries > call a::a on atmp1 > try { > call a::a on atmp2 > try { > call f(atmp1, atmp2) > call b::b on btmp > } catch { > } finally { > call a::~a on atmp2 > } > } catch { > } finally { > call a::~a on atmp1 > } > // NOW b is "constructed" > > Looking at the output IR, the best interpretation I can give is that Clang is cleaning up the temporary arguments before calling the new variable constructed. The question, of course, is whether or not this is legal per the C++ spec. C++11 section 12.2, par 3 states that >> Temporary objects are destroyed as the last step >> in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. > > Section 1.9, par 10 has an example which states that the full expression associated with the call to the constructor in this case is indeed the actual constructor call. > > Section 15.2, par 1 states: >> As control passes from a throw-expression to a handler, destructors are invoked for all automatic objects >> constructed since the try block was entered. The automatic objects are destroyed in the reverse order of the >> completion of their construction. > > I'm not 100% what the correct interpretation is in this case. It comes down to whether b should be considered constructed before or after the full expression of the declarator is completed.b should be considered constructed as soon as its constructor completes. This is a bug in clang. John.
Reasonably Related Threads
- [LLVMdev] [LLVMDev] Object in a try-catch block not being destroyed even after an exception
- [Bug 974] Record Badlogins for all supported Authentication methods
- Btmp and Wmtp log rotate
- Estimating parameters for a bimodal distribution
- /dev/null permission changes figured out