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