when I run my program everything goes fine. At the end it prints out this:
*** glibc detected *** ./streamShare: double free or corruption (fasttop): 0x08292130 ***
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6[0xcc2ff1]
/lib/tls/i686/cmov/libc.so.6[0xcc46f2]
/lib/tls/i686/cmov/libc.so.6(cfree+0x6d)[0xcc779d]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0x1c86f1]
./streamShare[0x804be7f]
./streamShare[0x804be3e]
./streamShare[0x804abc0]
./streamShare[0x804a5f2]
./streamShare[0x804a1c4]
./streamShare[0x804a1d7]
./streamShare[0x804a46a]
./streamShare[0x804ba45]
./streamShare[0x804b49c]
./streamShare[0x804ac68]
./streamShare[0x804ac48]
./streamShare[0x804a676]
./streamShare[0x804a237]
./streamShare[0x8049a3f]
./streamShare[0x804d2e5]
./streamShare[0x804d34d]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xc6eb56]
./streamShare[0x8049361]
I checked out, it happens when a function returns, where all the objects of the program are instatied automatically. Anyway I didn’t define any destructor for these objects, I tried to use STL Containers and TR1 shared_ptr. I guess everything happens in the default destructors. Is there a way to know where does it breaks up? I mean, I’d like to know which object distruction does the whole mess. I’m using these containers and shared pointers:
typedef std::tr1::shared_ptr<messageListener> mlsptr;
typedef std::map<const char*, mlsptr, ltstr> CONSTCHP2MSLST;
messageListener doesn’t have a distructor. And two of these vectors:
std::vector<MSG> queueto1;
where MSG destructor is:
MSG::~MSG() {
destroy();
}
void MSG::destroy() {
if (payload != NULL)
delete[] payload;
payload = NULL;
payloadLen = 0;
}
that never gave problems before and I this it shouldn’t ever…
Any recomendations how to track this problem? I’m clueless…
EDIT:
HERE IS VALGRIND OUTPUT:
valgrind ./streamShare -v
==25795== Memcheck, a memory error detector
==25795== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==25795== Using Valgrind-3.5.0-Debian and LibVEX; rerun with -h for copyright info
==25795== Command: ./streamShare -v
==25795==
==25795== Invalid free() / delete / delete[]
==25795== at 0x402454D: operator delete(void*) (vg_replace_malloc.c:346)
==25795== by 0x804BCC0: std::tr1::_Sp_deleter<streamShare::messageListener>::operator()(streamShare::messageListener*) const (shared_ptr.h:97)
==25795== by 0x804BC7F: std::tr1::_Sp_counted_base_impl<streamShare::messageListener*, std::tr1::_Sp_deleter<streamShare::messageListener>, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (shared_ptr.h:75)
==25795== by 0x804AAF7: std::tr1::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() (boost_sp_counted_base.h:140)
==25795== by 0x804A58D: std::tr1::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() (shared_ptr.h:153)
==25795== by 0x804A173: std::tr1::__shared_ptr<streamShare::messageListener, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() (shared_ptr.h:358)
==25795== by 0x804A186: std::tr1::shared_ptr<streamShare::messageListener>::~shared_ptr() (shared_ptr.h:834)
==25795== by 0x804A405: std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >::~pair() (stl_pair.h:68)
==25795== by 0x804D3D0: __gnu_cxx::new_allocator<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >::destroy(std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >*) (new_allocator.h:115)
==25795== by 0x804D337: std::_Rb_tree<char const*, std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >, std::_Select1st<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >, streamShare::ltstr, std::allocator<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > > >::_M_destroy_node(std::_Rb_tree_node<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >*) (stl_tree.h:383)
==25795== by 0x804D29B: std::_Rb_tree<char const*, std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >, std::_Select1st<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >, streamShare::ltstr, std::allocator<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > > >::_M_erase(std::_Rb_tree_node<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >*) (stl_tree.h:972)
==25795== by 0x804D27B: std::_Rb_tree<char const*, std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >, std::_Select1st<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >, streamShare::ltstr, std::allocator<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > > >::_M_erase(std::_Rb_tree_node<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >*) (stl_tree.h:970)
==25795== Address 0x42c3358 is 0 bytes inside a block of size 8 free'd
==25795== at 0x402454D: operator delete(void*) (vg_replace_malloc.c:346)
==25795== by 0x804BCC0: std::tr1::_Sp_deleter<streamShare::messageListener>::operator()(streamShare::messageListener*) const (shared_ptr.h:97)
==25795== by 0x804BC7F: std::tr1::_Sp_counted_base_impl<streamShare::messageListener*, std::tr1::_Sp_deleter<streamShare::messageListener>, (__gnu_cxx::_Lock_policy)2>::_M_dispose() (shared_ptr.h:75)
==25795== by 0x804AAF7: std::tr1::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() (boost_sp_counted_base.h:140)
==25795== by 0x804A58D: std::tr1::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() (shared_ptr.h:153)
==25795== by 0x804A173: std::tr1::__shared_ptr<streamShare::messageListener, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() (shared_ptr.h:358)
==25795== by 0x804A186: std::tr1::shared_ptr<streamShare::messageListener>::~shared_ptr() (shared_ptr.h:834)
==25795== by 0x804A405: std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >::~pair() (stl_pair.h:68)
==25795== by 0x804D3D0: __gnu_cxx::new_allocator<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >::destroy(std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >*) (new_allocator.h:115)
==25795== by 0x804D337: std::_Rb_tree<char const*, std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >, std::_Select1st<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >, streamShare::ltstr, std::allocator<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > > >::_M_destroy_node(std::_Rb_tree_node<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >*) (stl_tree.h:383)
==25795== by 0x804D29B: std::_Rb_tree<char const*, std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >, std::_Select1st<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >, streamShare::ltstr, std::allocator<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > > >::_M_erase(std::_Rb_tree_node<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >*) (stl_tree.h:972)
==25795== by 0x804D27B: std::_Rb_tree<char const*, std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> >, std::_Select1st<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >, streamShare::ltstr, std::allocator<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > > >::_M_erase(std::_Rb_tree_node<std::pair<char const* const, std::tr1::shared_ptr<streamShare::messageListener> > >*) (stl_tree.h:970)
==25795==
==25795==
==25795== HEAP SUMMARY:
==25795== in use at exit: 0 bytes in 0 blocks
==25795== total heap usage: 22 allocs, 30 frees, 496 bytes allocated
==25795==
==25795== All heap blocks were freed -- no leaks are possible
==25795==
==25795== For counts of detected and suppressed errors, rerun with: -v
==25795== ERROR SUMMARY: 8 errors from 1 contexts (suppressed: 19 from 8)
Judging by your Valgrind output, the problem is that an object pointed to by a
shared_ptris being deleted twice. One possibility of getting that is if you initialize twoshared_ptrwith the same raw pointer, e.g.:shared_ptris not magical, and it cannot know if the object you ask it to take care of is already owned by some other unrelatedshared_ptr, if all you give it is a raw pointer. In the example above, eachshared_ptrwill create its own reference counter, initialized to 1; when they die, each will decrement its own counter, see that it is 0, and delete the object, producing double deletion. I suspect your case is similar. If you show the code used to initializeshared_ptrobjects that are added to the vector, this can be verified.[EDIT] Since this is validated to be the cause of the crash now, let me elaborate a
bit on how to properly use
shared_ptr.First of all, the nature of the problem. The way
shared_ptris written, it works with any C++ type, and provides reference counting semantics. The obvious problem is that most types do not provide any space to store the reference counter (e.g. considershared_ptr<int>– there’s no extra space “inside”int). To work around this, for every shared object, a separate block of memory is allocated that contains the reference counter. This is done whenever you create ashared_ptrfrom a raw pointer. Theshared_ptrobject itself then stores the original raw pointer, and the pointer to reference counter (which is why it’s more “fat” than a raw pointer, which can be trivially checked withsizeof). When you create oneshared_ptrfrom another (using copy constructor or assignment operator), it copies the pointer to reference counter, so allshared_ptrinstances created from one another maintain a single counter, and guarantee correct deletion. But if you have two unrelated “families” ofshared_ptrobjects to the same objects (where two or more pointers were created from the same raw pointer), those “families” do not know about each other, and will refcount separately, and each will delete when it hits 0.What this means in practice is that, when using
shared_ptr, one must adhere to certain rules. Those depend on which implementation you use.With
std::tr1::shared_ptr, or older Boost versions, the only fully safe pattern for object allocation is this:In other words, the result of
newshould be immediately put into ashared_ptr– you can then copy the latter as much as you want.A reasonably safe pattern is also this:
shared_ptrimplements the usual transfer-of-ownership when initializing fromauto_ptr, and the semantics of the latter (so long as they’re correctly followed) ensure that only oneauto_ptrto an object should exist; thus, it is safe to construct ashared_ptrfrom that.Sometimes you also have to deal with C++ libraries which do not use
auto_ptrto indicate transfer of pointer ownership, but simply document the intent for specific functions. In those cases it should also be safe to useshared_ptr, but of course you should be sure that you’ve understood the documentation correctly…In C++0x
std::shared_ptr, and in newer versions ofboost::shared_ptr, there’s a helper provided to ensure correct instantiation of shared objects:The return type of
make_shared<T>()is alreadyshared_ptr<T>, so at no point you’re dealing with raw pointers in your code, reducing chance to get something wrong.