https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125771

            Bug ID: 125771
           Summary: Double destructor call during aggregate initialization
                    with designated initializers when an exception is
                    thrown.
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: i.kashurnikov at gmail dot com
  Target Milestone: ---

Created attachment 64726
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=64726&action=edit
Code demonstrating the problem

We encountered a double-free error when an exception is thrown during aggregate
initialization using C++20 designated initializers.

Problem summary:
- C++20 aggregate initialization with designated initializers
- Exception thrown during initialization of one field
- Fully constructed subobject is destructed twice => double free
- Reproducible on GCC 12+...trunk; works correctly on GCC < 12 and Clang



Godbolt: https://godbolt.org/z/sPM9asncW
Code (also attached):
----
#include <memory>
#include <string>
#include <stdexcept>
#include <iostream>


struct C{
    C(int i){
        std::cerr << "C" << std::endl;
        p = new int(i);
    }   

    ~C(){
        std::cerr << "~C" << std::endl;
        delete p;       
    }

    C(const C&) = delete;
    C& operator=(const C&) = delete;
    C(C&&) = delete;
    C& operator=(C&&) = delete;

    int* p;
};


struct A{
    ~A(){
        std::cerr << "~A" << std::endl;
    }

    struct B{
        ~B(){
             std::cerr << "~B" << std::endl;
        }

        C c;
        int i;
    };

    B b;
    std::shared_ptr<float> p;
};

auto makeExc(){
    throw std::runtime_error("throw");
    return std::make_shared<float>(12);
}

int main(int argc, char** argv){
    try{
        A a{
            .b = {
                .c = C(10)
            },
            .p = makeExc()
        };
    }
    catch(const std::exception&){
        std::cerr << "EXCEPTION" << std::endl;
    }
    return 0;
}

--------
gcc --std=c++20 bug.cpp -o test_bug
Output:
C
~B
~C
~C
free(): double free detected in tcache 2
Program terminated with signal: SIGSEGV

Reply via email to