I have a below snippet of c++ code which gives segfault. Could anyone explain why this gives segmentation fault?
#include <vector>
#include <memory>
class A {};
class B {
public:
std::vector<std::shared_ptr<A>>& getListOfB();
std::vector<std::shared_ptr<A>> m_ListOfB;
};
std::vector<std::shared_ptr<A>>& B::getListOfB()
{
return m_ListOfB;
}
using BPtr = std::shared_ptr<B>;
using AVector = std::vector<std::shared_ptr<A>>;
using APtr = std::shared_ptr<A>;
int main() {
std::shared_ptr<B> sharedPtrB = std::make_shared<B>();
AVector &aVector = sharedPtrB->getListOfB();
APtr report1 = std::make_shared<A>();
aVector.push_back(report1);
sharedPtrB = std::make_shared<B>();
aVector = sharedPtrB->getListOfB(); // <-- fault happened
return 0;
}
And running it gave me this stack trace.
0x00000000004013ea in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0xc50a25d35ec168ca) at /usr/include/c++/12/bits/shared_ptr_base.h:337
337 if (__atomic_load_n(__both_counts, __ATOMIC_ACQUIRE) == __unique_ref)
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.35-22.fc36.x86_64 libgcc-12.2.1-4.fc36.x86_64 libstdc++-12.2.1-4.fc36.x86_64
(gdb) bt
#0 0x00000000004013ea in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release (this=0xc50a25d35ec168ca) at /usr/include/c++/12/bits/shared_ptr_base.h:337
#1 0x00000000004015ef in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=0x41bf08, __in_chrg=<optimized out>) at /usr/include/c++/12/bits/shared_ptr_base.h:1071
#2 0x0000000000401536 in std::__shared_ptr<A, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=0x41bf00, __in_chrg=<optimized out>) at /usr/include/c++/12/bits/shared_ptr_base.h:1524
#3 0x0000000000401552 in std::shared_ptr<A>::~shared_ptr (this=0x41bf00, __in_chrg=<optimized out>) at /usr/include/c++/12/bits/shared_ptr.h:175
#4 0x000000000040315d in std::_Destroy<std::shared_ptr<A> > (__pointer=0x41bf00) at /usr/include/c++/12/bits/stl_construct.h:151
#5 0x0000000000402c15 in std::_Destroy_aux<false>::__destroy<__gnu_cxx::__normal_iterator<std::shared_ptr<A>*, std::vector<std::shared_ptr<A>, std::allocator<std::shared_ptr<A> > > > > (
__first=<error reading variable: Cannot access memory at address 0xc50a25d35ec168d2>, __last=<error reading variable: Cannot access memory at address 0x39>) at /usr/include/c++/12/bits/stl_construct.h:163
#6 0x0000000000402659 in std::_Destroy<__gnu_cxx::__normal_iterator<std::shared_ptr<A>*, std::vector<std::shared_ptr<A>, std::allocator<std::shared_ptr<A> > > > > (
__first=<error reading variable: Cannot access memory at address 0xc50a25d35ec168d2>, __last=<error reading variable: Cannot access memory at address 0x39>) at /usr/include/c++/12/bits/stl_construct.h:196
#7 0x0000000000402069 in std::_Destroy<__gnu_cxx::__normal_iterator<std::shared_ptr<A>*, std::vector<std::shared_ptr<A>, std::allocator<std::shared_ptr<A> > > >, std::shared_ptr<A> > (
__first=<error reading variable: Cannot access memory at address 0xc50a25d35ec168d2>, __last=<error reading variable: Cannot access memory at address 0x39>) at /usr/include/c++/12/bits/alloc_traits.h:850
#8 0x000000000040196e in std::vector<std::shared_ptr<A>, std::allocator<std::shared_ptr<A> > >::operator= (this=0x41bec0, __x=std::vector of length 0, capacity 0) at /usr/include/c++/12/bits/vector.tcc:244
#9 0x0000000000401281 in main () at snippet.cpp:29
>Solution :
The stack trace indicates that an error occurred during the execution of the code. Specifically, it seems to be related to the assignment aVector = sharedPtrB->getListOfB(); in the main function.
The issue arises because aVector is a reference to sharedPtrB->getListOfB(), and when you reassign aVector to sharedPtrB->getListOfB(), the vector m_ListOfB inside B gets destroyed, causing the shared pointers to be released. Consequently, when the original vector is destroyed, it tries to release the shared pointers again, leading to a double deletion and resulting in undefined behavior.
To resolve this issue, you can either avoid reassigning aVector to a new vector or modify your code to handle the ownership of shared pointers properly.
Solution -1
std::shared_ptr<B> sharedPtrB = std::make_shared<B>();
AVector& aVector = sharedPtrB->getListOfB();
APtr report1 = std::make_shared<A>();
aVector.push_back(report1);
// Do not reassign aVector here
// Alternatively, if you need to assign a new vector,
// create a new shared pointer for B instead
sharedPtrB = std::make_shared<B>();
AVector& newVector = sharedPtrB->getListOfB();
// Use the newVector as needed
Solution -2
std::shared_ptr<B> sharedPtrB = std::make_shared<B>();
AVector& aVector = sharedPtrB->getListOfB();
APtr report1 = std::make_shared<A>();
aVector.push_back(report1);
sharedPtrB = std::make_shared<B>();
AVector newVector = sharedPtrB->getListOfB(); // Create a new vector, not a
reference
// Use newVector as needed