Bug 66451 - Array not fully destructed if element destructor throws exception
Summary: Array not fully destructed if element destructor throws exception
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.9.2
: P3 normal
Target Milestone: 12.0
Assignee: Jason Merrill
URL:
Keywords: wrong-code
Depends on:
Blocks:
 
Reported: 2015-06-07 19:36 UTC by Jonathan Dodd
Modified: 2022-01-11 22:34 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2015-06-08 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Dodd 2015-06-07 19:36:33 UTC
If an array element throws during destruction, undestructed elements in that array are not destructed. Other local variables are destructed. Clang calls destructors on all automatic objects, regardless whether in or out of an array.

(And yes, I know throwing from destructors should be avoided, but that's hardly the point ;p)

Relevant sections from standard
-------------------------------

s15.2:

As control passes from the point where an exception is thrown to a handler, destructors are invoked for all automatic objects constructed since the try block was entered. ...

An object of any storage duration whose initialization or destruction is terminated by an exception will have destructors executed for all of its fully constructed subobjects

s1.8:

A subobject can be ... an array element.


Test case
---------
#include <iostream>
#include <exception>

using namespace std;

class A {
public:
  A(int new_a) : a(new_a) { }

  ~A() noexcept(false) {
    cout << "a" << a <<".~A() ";

    if(std::uncaught_exception())
      cout << "Unwinding";

    cout << endl;

    if(a==4)
      throw a;
  } 

  int a;
};

int main()
{
  try {
    A a1(1), a2(2);
    A arr[] = {3,4,5};

  } catch(...) { }
}

Output (g++ 4.9.2)
------------------

a5.~A() 
a4.~A() 
a2.~A() Unwinding
a1.~A() Unwinding


Output (clang 3.5.0)
--------------------
a5.~A() 
a4.~A() 
a3.~A() Unwinding
a2.~A() Unwinding
a1.~A() Unwinding
Comment 1 Jonathan Wakely 2015-06-08 09:03:16 UTC
(In reply to Jonathan Dodd from comment #0)
> If an array element throws during destruction, undestructed elements in that
> array are not destructed. Other local variables are destructed. Clang calls
> destructors on all automatic objects, regardless whether in or out of an
> array.

Not always ;-)  https://llvm.org/bugs/show_bug.cgi?id=22877

This is probably related to PR66139
Comment 2 GCC Commits 2022-01-07 00:25:43 UTC
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:2fbc45486e13facfeb05bd6ddf70ff9973a30a3c

commit r12-6331-g2fbc45486e13facfeb05bd6ddf70ff9973a30a3c
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Jan 5 09:49:37 2022 -0500

    c++: keep destroying array after one dtor throws [PR66451]
    
    When we're cleaning up an array, if one destructor throws, we should still
    try to clean up the rest of the array.  We can use TRY_CATCH_EXPR for this,
    instead of a TARGET_EXPR like my other recent patches, because a destructor
    call can't involve any temporaries that need to live longer.
    
    I thought about only doing this when we call build_vec_delete_1 from
    build_vec_init, but it seems appropriate for delete-expressions as well;
    we've said that the array's lifetime is over, it makes sense to keep trying
    to destroy it.  The standard isn't clear, but clang seems to agree with me.
    
            PR c++/66451
    
    gcc/cp/ChangeLog:
    
            * init.c (build_vec_delete_1): Handle throwing dtor.
            (build_vec_init): Tell it we're in a cleanup already.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/eh/array3.C: New test.
            * g++.dg/eh/array1.C: Mark destructor as throw().
            * g++.dg/ipa/devirt-40.C: Likewise.
            * g++.dg/warn/pr83054.C: Likewise.
            * g++.dg/eh/delete1.C: Shorten array to one element.
Comment 3 Jason Merrill 2022-01-07 00:31:00 UTC
Fixed for GCC 12.