Correct way to store shared_ptr objects in a stl::map
I have a class, called Reader_Factory, which creates file readers for a particular input file based on its type. Other objects will request a certain type of reader multiple times so I am caching the reader object in a STL map with its file name as the key. std::map<std::string, boost::shared_ptr<Reader> > Well when I include in sp_debug_hooks.cpp into my build along with defining -DBOOST_SP_ENABLE_DEBUG_HOOKS in the compiler's command line flags I am seeing a error come up with its destroying the Reader_Factory. *** errors detected in test suite "Reverse_Impl test suite"; see standard output for details test_one_node_per_section: sp_debug_hooks.cpp:201: void operator delete(void*): Assertion `*pm == allocated_scalar' failed. Checking the back trace in gdb (full backtrace below) I am seeing that Reader_Factory destructor is called followed by the std::map destructor followed by the reader object's destructor. So this made me think that perhaps I am doing something wrong with storing a reader object in the Reader_Factory class. Well gdb reports back that there was a segmentation fault in a destructor for a class called Data_Source. The line reades: 26 m_transfer_method->close(); Checking m_transfer_method in gdb reports: (gdb) p m_transfer_method $3 = {px = 0x8d8af58, pn = {pi_ = 0x8d8af80, id_ = 741732609}} (gdb) p *m_transfer_method.px $4 = {<libreverse::infrastructure::Data_Transfer_Base> = {_vptr.Data_Transfer_Base = 0x4}, m_config = {px = 0x8d7ff28, pn = {pi_ = 0x8d7ff40, id_ = 741732609}}, m_data = {px = 0x8d87360, pn = {pi_ = 0x8d873c8, id_ = 741732609}}} So I am not sure what is the segfault here. To help here is pseudo code similiar to what I am doing: class File_Reader { }; class B_Reader : public File_Reader {}; class Reader_Factory { public: virtual ~Reader_Factory(){} boost::shared_ptr<File_Reader> create_B_Reader ( std::string filename ) { boost::shared_ptr<File_Reader> tmp_ptr ( new B_Reader ( filename ) ); IF tmp_ptr->support_File_Type is TRUE THEN return reader ELSE throw an exception } boost::shared_ptr<File_Reader> get_Reader ( std::string filename ) { bool found = false; boost::shared_ptr<File_Reader> reader_ptr; // IF the File_Reader is already cached in the map THEN return pointer to it // ELSE // Find which reader will support it THEN set found to TRUE // (For example, see create_B_Reader) // IF found equal to TRUE and reader_ptr is set THEN check to see if its in the reader map // IF not THEN add it // ELSE we should not reach this point (abort. If it exists already then the first IF statement will catch it) Reader_Map_t::const_iterator cpos = reader_map.find ( filename ); if ( cpos == reader_map.end() ) { try { reader_ptr = this->create_B_Reader ( filename ); found = true; } catch ( std::exception& ) { found = false; } if ( ! found ) THEN throw exception saying unsupported file type else { if ( ( reader_map.insert ( std::make_pair ( filename, reader_ptr ) ) ).second == false ) THEN report exception saying duplicate entry the program is broken stop running } } else { reader_ptr = (*cpos).second; } return reader_ptr; } typedef std::map<std::string, boost::shared_ptr<File_Reader> > Reader_Map_t; Reader_Map_t reader_map; }; Is there a problem or problems with this design? Stephen ---------------------------------------------------------------------------- Full gdb output from SIGABRT given by sp_debug_hooks ---------------------------------------------------------------------------- #0 0x00367402 in __kernel_vsyscall () #1 0x47bd9d40 in raise () from /lib/libc.so.6 #2 0x47bdb591 in abort () from /lib/libc.so.6 #3 0x47bd338b in __assert_fail () from /lib/libc.so.6 #4 0x006c20ae in operator delete (p=0x8d9f2a8) at sp_debug_hooks.cpp:201 #5 0x006d4983 in __gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<unsigned int const, unsigned int> > >::deallocate ( this=0x8d8ae4c, __p=0x8d9f2a8) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/ext/new_allocator.h:94 #6 0x006d49b8 in std::_Rb_tree<unsigned int, std::pair<unsigned int const, unsigned int>, std::_Select1st<std::pair<unsigned int const, unsigned int> >, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, unsigned int> > >::_M_put_node (this=0x8d8ae4c, __p=0x8d9f2a8) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_tree.h:362 #7 0x006d4a18 in std::_Rb_tree<unsigned int, std::pair<unsigned int const, unsigned int>, std::_Select1st<std::pair<unsigned int const, unsigned int> >, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, unsigned int> > >::destroy_node (this=0x8d8ae4c, __p=0x8d9f2a8) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_tree.h:392 #8 0x006d4a8e in std::_Rb_tree<unsigned int, std::pair<unsigned int const, unsigned int>, std::_Select1st<std::pair<unsigned int const, unsigned int> >, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, unsigned int> > >::_M_erase (this=0x8d8ae4c, __x=0x8d9f2a8) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_tree.h:1266 #9 0x006d4a6e in std::_Rb_tree<unsigned int, std::pair<unsigned int const, unsigned int>, std::_Select1st<std::pair<unsigned int const, unsigned int> >, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, unsigned int> > >::_M_erase (this=0x8d8ae4c, __x=0x8d9e1a0) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_tree.h:1264 #10 0x006d4a6e in std::_Rb_tree<unsigned int, std::pair<unsigned int const, unsigned int>, std::_Select1st<std::pair<unsigned int const, unsigned int> >, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, unsigned int> > >::_M_erase (this=0x8d8ae4c, __x=0x8d9df20) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_tree.h:1264 #11 0x006d4a6e in std::_Rb_tree<unsigned int, std::pair<unsigned int const, unsigned int>, std::_Select1st<std::pair<unsigned int const, unsigned int> >, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, unsigned int> > >::_M_erase (this=0x8d8ae4c, __x=0x8d9d520) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_tree.h:1264 #12 0x006d4a6e in std::_Rb_tree<unsigned int, std::pair<unsigned int const, unsigned int>, std::_Select1st<std::pair<unsigned int const, unsigned int> >, std::less<unsigned int>, std::allocator<std::pair<unsigned int const, unsigned int> > >::_M_erase (this=0x8d8ae4c, __x=0x8d9c120) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_tree.h:1264 #13 0x006d4acd in ~_Rb_tree (this=0x8d8ae4c) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_tree.h:578 #14 0x006d4b29 in ~map (this=0x8d8ae4c) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_map.h:93 #15 0x006d0407 in ~Memory_Map (this=0x8d8ae28) at Memory_Map.cpp:75 #16 0x006d3ba8 in boost::checked_delete<libreverse::data_types::Memory_Map> (x=0x8d8ae28) at /usr/include/boost/checked_delete.hpp:34 #17 0x006d6645 in boost::detail::sp_counted_impl_p<libreverse::data_types::Memory_Map>::dispose (this=0x8d9e318) #18 0x0805e62c in boost::detail::sp_counted_base::release (this=0x8d9e318) at /usr/include/boost/detail/sp_counted_base_gcc_x86.hpp:145 #19 0x0805e66e in ~shared_count (this=0x8d89c38) at /usr/include/boost/detail/shared_count.hpp:159 #20 0x006d3024 in ~shared_ptr (this=0x8d89c34) at /usr/include/boost/shared_ptr.hpp:106 #21 0x00703c65 in ~File (this=0x8d89c28) at File.cpp:83 #22 0x0077c9bd in ~Elf_File (this=0x8d89c28) at ../../../../src/io/input/File_Readers/Elf/Elf_Header_Eident.h:10 #23 0x0077c9ed in boost::checked_delete<libreverse::elf_module::Elf_File<32u> > (x=0x8d89c28) at /usr/include/boost/checked_delete.hpp:34 #24 0x0077cb59 in boost::detail::sp_counted_impl_p<libreverse::elf_module::Elf_File<32u> >::dispose (this=0x8d9e788) at /usr/include/boost/detail/sp_counted_impl.hpp:76 #25 0x0805e62c in boost::detail::sp_counted_base::release (this=0x8d9e788) at /usr/include/boost/detail/sp_counted_base_gcc_x86.hpp:145 #26 0x0805e66e in ~shared_count (this=0x8d8b1b0) at /usr/include/boost/detail/shared_count.hpp:159 #27 0x00760b38 in ~shared_ptr (this=0x8d8b1ac) at /usr/include/boost/shared_ptr.hpp:106 #28 0x00769906 in ~Elf_Reader (this=0x8d8b1a8) at ../../../../src/io/input/File_Readers/Elf/Elf_Reader_T.cpp:44 #29 0x00760ffa in boost::checked_delete<libreverse::elf_module::Elf_Reader<32u> > (x=0x8d8b1a8) at /usr/include/boost/checked_delete.hpp:34 #30 0x0076ff35 in boost::detail::sp_counted_impl_p<libreverse::elf_module::Elf_Reader<32u> >::dispose (this=0x8d84410) at /usr/include/boost/detail/sp_counted_impl.hpp:76 #31 0x0805e62c in boost::detail::sp_counted_base::release (this=0x8d84410) at /usr/include/boost/detail/sp_counted_base_gcc_x86.hpp:145 #32 0x0805e66e in ~shared_count (this=0x8d8acd8) at /usr/include/boost/detail/shared_count.hpp:159 #33 0x00760a78 in ~shared_ptr (this=0x8d8acd4) at /usr/include/boost/shared_ptr.hpp:106 #34 0x00766ff7 in ~pair (this=0x8d8acd0) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_pair.h:69 #35 0x00767053 in __gnu_cxx::new_allocator<std::pair<std::string const, boost::shared_ptr<libreverse::io::File_Reader> > >::destroy (this=0xbff1b343, __p=0x8d8acd0) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/ext/new_allocator.h:107 #36 0x007672f1 in std::_Rb_tree<std::string, std::pair<std::string const, boost::shared_ptr<libreverse::io::File_Reader> >, std::_Select1st<std::pair<std::string const, boost::shared_ptr<libreverse::io::File_Reader> > >, std::less<std::string>, std::allocator<std::pair<std::string const, boost::shared_ptr<libreverse::io::File_Reader> > > >::destroy_node (this=0x8d8b184, __p=0x8d8acc0) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_tree.h:391 #37 0x00767384 in std::_Rb_tree<std::string, std::pair<std::string const, boost::shared_ptr<libreverse::io::File_Reader> >, std::_Select1st<std::pair<std::string const, boost::shared_ptr<libreverse::io::File_Reader> > >, std::less<std::string>, std::allocator<std::pair<std::string const, boost::shared_ptr<libreverse::io::File_Reader> > > >::_M_erase (this=0x8d8b184, __x=0x8d8acc0) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_tree.h:1266 #38 0x00767447 in ~_Rb_tree (this=0x8d8b184) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_tree.h:578 #39 0x007674a3 in ~map (this=0x8d8b184) at /usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/bits/stl_map.h:93 #40 0x0075fbb0 in ~Reader_Factory (this=0x8d8b180) at Reader_Factory.cpp:16 #41 0x007612b8 in boost::checked_delete<libreverse::io::Reader_Factory> (x=0x8d8b180) at /usr/include/boost/checked_delete.hpp:34 #42 0x0076ff79 in boost::detail::sp_counted_impl_p<libreverse::io::Reader_Factory>::dispose (this=0x8d8b018) at /usr/include/boost/detail/sp_counted_impl.hpp:76 #43 0x0805e62c in boost::detail::sp_counted_base::release (this=0x8d8b018) at /usr/include/boost/detail/sp_counted_base_gcc_x86.hpp:145 #44 0x0805e66e in ~shared_count (this=0x868890) at /usr/include/boost/detail/shared_count.hpp:159 #45 0x00760a52 in ~shared_ptr (this=0x86888c) at /usr/include/boost/shared_ptr.hpp:106 #46 0x0075fab4 in __tcf_1 () at Reader_Factory.cpp:14 #47 0x47bdcbe9 in __cxa_finalize () from /lib/libc.so.6 #48 0x006b4303 in __do_global_dtors_aux () from /usr/local/lib/libreverse.so.0 #49 0x0079cb2c in _fini () from /usr/local/lib/libreverse.so.0 #50 0x47ba2572 in _dl_fini () from /lib/ld-linux.so.2 #51 0x47bdc939 in exit () from /lib/libc.so.6 #52 0x47bc6f34 in __libc_start_main () from /lib/libc.so.6 #53 0x0805cf41 in _start ()
Stephen Torri wrote:
Well when I include in sp_debug_hooks.cpp into my build along with defining -DBOOST_SP_ENABLE_DEBUG_HOOKS in the compiler's command line flags I am seeing a error come up with its destroying the Reader_Factory.
*** errors detected in test suite "Reverse_Impl test suite"; see standard output for details test_one_node_per_section: sp_debug_hooks.cpp:201: void operator delete(void*): Assertion `*pm == allocated_scalar' failed.
[...]
#4 0x006c20ae in operator delete (p=0x8d9f2a8) at sp_debug_hooks.cpp:201
#5 0x006d4983 in __gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<unsigned int const, unsigned int> > >::deallocate ( this=0x8d8ae4c, __p=0x8d9f2a8) at
/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/ext/new_allocator.h:94
This is an internal std::map deallocation so it should never fail in such a way. I think that it's quite possible that a write through a dangling pointer has corrupted your heap. You might want to switch to valgrind as the problem doesn't appear to be shared_ptr-related (your use seems OK) and valgrind does much more intensive and thorough checks.
On Thu, March 29, 2007 19:40, Peter Dimov wrote:
Stephen Torri wrote:
Well when I include in sp_debug_hooks.cpp into my build along with defining -DBOOST_SP_ENABLE_DEBUG_HOOKS in the compiler's command line flags I am seeing a error come up with its destroying the Reader_Factory.
*** errors detected in test suite "Reverse_Impl test suite"; see standard output for details test_one_node_per_section: sp_debug_hooks.cpp:201: void operator delete(void*): Assertion `*pm == allocated_scalar' failed.
[...]
#4 0x006c20ae in operator delete (p=0x8d9f2a8) at sp_debug_hooks.cpp:201
#5 0x006d4983 in __gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<unsigned int const, unsigned int> > >::deallocate ( this=0x8d8ae4c, __p=0x8d9f2a8) at
/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/ext/new_allocator.h:94
This is an internal std::map deallocation so it should never fail in such a way. I think that it's quite possible that a write through a dangling pointer has corrupted your heap. You might want to switch to valgrind as the problem doesn't appear to be shared_ptr-related (your use seems OK) and valgrind does much more intensive and thorough checks.
I had some similar issue but not with shared_ptr. My problem was the redefinition for debug purposes (to make mem allocation statistics) of the global new operator. In this case the default allocator used the rewritten new operator to allocate container storage and the rewritten operator used the std::allocator and this cycle caused the behaviour. Is there any chance that this might be the cause? Try to write your own allocator for the container, which will forward the calls to really global new. With Kind Regards, Ovanes Markarian
Ovanes Markarian wrote:
I had some similar issue but not with shared_ptr. My problem was the redefinition for debug purposes (to make mem allocation statistics) of the global new operator. In this case the default allocator used the rewritten new operator to allocate container storage and the rewritten operator used the std::allocator and this cycle caused the behaviour. Is there any chance that this might be the cause?
Not likely, ::operator new in sp_debug_hooks just uses malloc to allocate memory and then marks it with a magic value for tracking purposes.
On Thu, 2007-03-29 at 20:40 +0300, Peter Dimov wrote:
#4 0x006c20ae in operator delete (p=0x8d9f2a8) at sp_debug_hooks.cpp:201
#5 0x006d4983 in __gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<unsigned int const, unsigned int> > >::deallocate ( this=0x8d8ae4c, __p=0x8d9f2a8) at
/usr/lib/gcc/i386-redhat-linux/4.1.1/../../../../include/c++/4.1.1/ext/new_allocator.h:94
This is an internal std::map deallocation so it should never fail in such a way. I think that it's quite possible that a write through a dangling pointer has corrupted your heap. You might want to switch to valgrind as the problem doesn't appear to be shared_ptr-related (your use seems OK) and valgrind does much more intensive and thorough checks.
I changed the XML parser I was using to remove a lot of the memory problems I had. Now the issue still remains. Valgrind says that my application does not leak anything. There are things that 4,767 bytes are possibly lost and 2,600 bytes still reachable. (gdb) bt #0 0x47ceb178 in main_arena () from /lib/libc.so.6 #1 0x6847ceb1 in ?? () #2 0x48027e03 in std::operator<< <char, std::char_traits<char>, std::allocator<char> > () from /usr/lib/libstdc++.so.6 #3 0x00b48806 in boost::io::detail::put_last<char, std::char_traits<char>, std::string> (os=@0xbfcd0fe4, x=@0xbfcd1454) at /usr/include/boost/format/feed_args.hpp:113 #4 0x00b48932 in boost::io::detail::put<char, std::char_traits<char>, std::allocator<char>, std::string&> (x=@0xbfcd1454, specs=@0x8828e58, res=@0x8828e5c, buf=@0xbfcd135c, loc_p=0x0) at /usr/include/boost/format/feed_args.hpp:150 #5 0x00b490d1 in boost::io::detail::distribute<char, std::char_traits<char>, std::allocator<char>, std::string&> ( self=@0xbfcd1324, x=@0xbfcd1454) at /usr/include/boost/format/feed_args.hpp:241 #6 0x00b49130 in boost::io::detail::feed<char, std::char_traits<char>, std::allocator<char>, std::string&> ( self=@0xbfcd1324, x=@0xbfcd1454) at /usr/include/boost/format/feed_args.hpp:251 #7 0x00b491f6 in boost::basic_format<char, std::char_traits<char>, std::allocator<char> >::operator%<std::string> ( this=0xbfcd1324, x=@0xbfcd1454) at /usr/include/boost/format/format_class.hpp:68 #8 0x00b44372 in libreverse::infrastructure::Configuration_Parser::parse_Data (this=0xbfcd1448) at Configuration_Parser.cpp:57 #9 0x00b4a579 in libreverse::infrastructure::Configurator::Instance (file=@0xbfcd150c) at Configurator.cpp:39 #10 0x00be82e3 in libreverse::infrastructure::Data_Source_Factory::Instance () at Data_Source_Factory.cpp:141 #11 0x00b32d44 in Component (this=0x88287d0, id=0) at Component.cpp:38 #12 0x00b2f98b in Null_Component (this=0x88287d0, id=0) at Null_Component.cpp:16 #13 0x00b2cebe in libreverse::infrastructure::Component_Factory::get_Null_Component (this=0x8828768, id=0) at Component_Factory.cpp:83 #14 0x00b091de in libreverse::api::Reverse::execute (this=0xbfcd1877, target_file=@0x8828484, input_type=@0x806acac, output_type=@0x806acf4) at Reverse.cpp:75 #15 0x0805559a in main (ac=3, av=0xbfcd1a74) at reverse.cpp:50 At line 57 in Configuration_Parser is a cout statement using a boost::format line. So with boost-1.33.1 there is something wrong when you create a shared library with boost format and give the BOOST_SP_ENABLE_HOOKS. Here is my autoconf script where I set the debug flags. Perhaps I am doing something here that is setting up the compiler to produce faulty output: AC_ARG_ENABLE(debug, AC_HELP_STRING(--enable-debug, [Have GCC compile with symbols (Default = no) ]), enable_debug=$enableval, enable_debug=no) if test "$enable_debug" = "yes" ; then GCC_CFLAGS="-g3 -O0 -Wall -Werror -Wextra -DDEBUG" GCC_CXXFLAGS="-g3 -O0 -Wall -Werror -Wextra -DDEBUG" else GCC_CFLAGS="$CFLAGS -Werror -DNO_DEBUG" GCC_CXXFLAGS="$CXXFLAGS -Werror -DNO_DEBUG" fi AC_ARG_ENABLE(debug-boost-pointers, AC_HELP_STRING(--enable-debug-boost-pointers, [Turn debugging code for boost shared pointers]), enable_debug_pointers=$enableval, enable_debug_pointers=no) if test "$enable_debug_pointers" = "yes"; then GCC_CXXFLAGS="$GCC_CXXFLAGS -DBOOST_SP_ENABLE_DEBUG_HOOKS" fi I don't know how just adding this flag to my system affects boost in such a way that I get this segfault. Since I still so lost I cannot give you a simple example saying "Compile and run this and you will see". Stephen
participants (3)
-
Ovanes Markarian
-
Peter Dimov
-
Stephen Torri