
19 Jul
2010
19 Jul
'10
8:55 p.m.
On Tue, Jul 6, 2010 at 8:00 AM, Ragnar Cederlund <ragnar.cederlund@illuminatelabs.com> wrote: > On Fri, Jul 2, 2010 at 5:55 PM, Ragnar Cederlund <ragnar.cederlund...> > wrote: >> >> I'm having trouble with the io_service destructor never completing. > > [...] > > I've finally been able to reproduce the hang on my own machine and have a > small example that exhibits this problem (built using Visual Studio 2005 in > debug mode): > > #include <iostream> > #include <boost/asio.hpp> > #include <boost/bind.hpp> > > using namespace boost::asio; > > class ConnectCommand; > typedef boost::shared_ptr<ConnectCommand> ConnectCommandPtr; > > class ConnectCommand { > public: > ConnectCommand(io_service &io_service) > : m_IoService(io_service) > , m_Socket(io_service) > {} > > void Execute() { > std::cout << "Attempting connection" << std::endl; > > ip::tcp::endpoint ep(ip::address_v4::from_string("127.0.0.1"), 7780); > > m_Socket.async_connect(ep, > boost::bind(&ConnectCommand::Handle_Connect, > this, placeholders::error)); > > // Stop without waiting for the result > m_IoService.stop(); > } > > private: > void Handle_Connect(boost::system::error_code &e) > { > std::cout << "Connect returned: " << e << "." << std::endl; > } > > boost::asio::io_service &m_IoService; > boost::asio::ip::tcp::socket m_Socket; > }; > > class AsioHang { > public: > > void Run() { > m_ConnectCommand.reset(new ConnectCommand(m_IoService)); > m_ConnectCommand->Execute(); > > m_IoService.run(); > } > > private: > ConnectCommandPtr m_ConnectCommand; // destroyed after io_service object > boost::asio::io_service m_IoService; > }; > > int _tmain(int argc, _TCHAR* argv[]) > { > { > AsioHang hang; > hang.Run(); > > std::cout << "After Run()" << std::endl; > } > return 0; > } > > > In this example, there is a flaw in that the ConnectCommand is destroyed > after the io_service object, but the ConnectCommand has a reference to the > io_service. > > I would have expected this to lead to a crash or similar and this is indeed > the case if I attach a debugger to the program and step through it. But if I > just run the program without the debugger attached, the io_service > destructor just never completes. > > I believe that a variation of the error in the code above is what caused the > problems for me and I assume that this should be written off as more or less > undefined behavior caused by badly managed object lifetimes. > > Thank you all who responded and thank you Sergei for pointing out that there > is a specific asio mailing list. I am still not sure this is the issue in Wt then, as its code is well used and worked in past Boost version. Also, your example does not compile: 1>q:\overminddl1's documents\visual studio 2005\projects\boostasiobugtest\boostasiobugtest\boostasiobugtest.cpp(55) : error C2061: syntax error : identifier '_TCHAR' Changing that to a normal main function, I get these errors: 1>r:\sdks\boost\built_head\include\boost-1_44\boost\bind\bind.hpp(313) : error C2664: 'R boost::_mfi::mf1<R,T,A1>::operator ()<ConnectCommand>(const U &,A1) const' : cannot convert parameter 2 from 'const boost::system::error_code' to 'boost::system::error_code &' 1> with 1> [ 1> R=void, 1> T=ConnectCommand, 1> A1=boost::system::error_code &, 1> U=ConnectCommand * 1> ] 1> Conversion loses qualifiers 1> r:\sdks\boost\built_head\include\boost-1_44\boost\bind\bind_template.hpp(47) : see reference to function template instantiation 'void boost::_bi::list2<A1,A2>::operator ()<F,boost::_bi::list1<const boost::system::error_code &>>(boost::_bi::type<T>,F &,A &,int)' being compiled 1> with 1> [ 1> A1=boost::_bi::value<ConnectCommand *>, 1> A2=boost::arg<1>, 1> F=boost::_mfi::mf1<void,ConnectCommand,boost::system::error_code &>, 1> T=void, 1> A=boost::_bi::list1<const boost::system::error_code &> 1> ] 1> r:\sdks\boost\built_head\include\boost-1_44\boost\asio\detail\bind_handler.hpp(40) : see reference to function template instantiation 'void boost::_bi::bind_t<R,F,L>::operator ()<Arg1>(const A1 &)' being compiled 1> with 1> [ 1> R=void, 1> F=boost::_mfi::mf1<void,ConnectCommand,boost::system::error_code &>, 1> L=boost::_bi::list2<boost::_bi::value<ConnectCommand *>,boost::arg<1>>, 1> Arg1=boost::system::error_code, 1> A1=boost::system::error_code 1> ] 1> r:\sdks\boost\built_head\include\boost-1_44\boost\asio\detail\bind_handler.hpp(39) : while compiling class template member function 'void boost::asio::detail::binder1<Handler,Arg1>::operator ()(void)' 1> with 1> [ 1> Handler=boost::_bi::bind_t<void,boost::_mfi::mf1<void,ConnectCommand,boost::system::error_code &>,boost::_bi::list2<boost::_bi::value<ConnectCommand *>,boost::arg<1>>>, 1> Arg1=boost::system::error_code 1> ] 1> r:\sdks\boost\built_head\include\boost-1_44\boost\asio\basic_socket.hpp(650) : see reference to class template instantiation 'boost::asio::detail::binder1<Handler,Arg1>' being compiled 1> with 1> [ 1> Handler=boost::_bi::bind_t<void,boost::_mfi::mf1<void,ConnectCommand,boost::system::error_code &>,boost::_bi::list2<boost::_bi::value<ConnectCommand *>,boost::arg<1>>>, 1> Arg1=boost::system::error_code 1> ] 1> q:\overminddl1's documents\visual studio 2005\projects\boostasiobugtest\boostasiobugtest\boostasiobugtest.cpp(24) : see reference to function template instantiation 'void boost::asio::basic_socket<Protocol,SocketService>::async_connect<boost::_bi::bind_t<R,F,L>>(const boost::asio::ip::basic_endpoint<InternetProtocol> &,ConnectHandler)' being compiled 1> with 1> [ 1> Protocol=boost::asio::ip::tcp, 1> SocketService=boost::asio::stream_socket_service<boost::asio::ip::tcp>, 1> R=void, 1> F=boost::_mfi::mf1<void,ConnectCommand,boost::system::error_code &>, 1> L=boost::_bi::list2<boost::_bi::value<ConnectCommand *>,boost::arg<1>>, 1> InternetProtocol=boost::asio::ip::tcp, 1> ConnectHandler=boost::_bi::bind_t<void,boost::_mfi::mf1<void,ConnectCommand,boost::system::error_code &>,boost::_bi::list2<boost::_bi::value<ConnectCommand *>,boost::arg<1>>> 1> ] So I added a const to your Handle_Connect line to get void Handle_Connect(const boost::system::error_code &e) and it now builds. This was also on VS2k5. It now compiles, and when I run it, I get an access violation with this call stack: BoostASIOBugTest.exe!boost::shared_ptr<void>::~shared_ptr<void>() + 0x3e bytes C++ > BoostASIOBugTest.exe!boost::asio::detail::scoped_lock<boost::asio::detail::win_mutex>::scoped_lock<boost::asio::detail::win_mutex>(boost::asio::detail::win_mutex & m={...}) Line 37 C++ BoostASIOBugTest.exe!boost::asio::detail::win_iocp_socket_service_base::destroy(boost::asio::detail::win_iocp_socket_service_base::base_implementation_type & impl={...}) Line 79 C++ BoostASIOBugTest.exe!boost::asio::stream_socket_service<boost::asio::ip::tcp>::destroy(boost::asio::detail::win_iocp_socket_service<boost::asio::ip::tcp>::implementation_type & impl={...}) Line 102 C++ BoostASIOBugTest.exe!boost::asio::basic_io_object<boost::asio::stream_socket_service<boost::asio::ip::tcp> >::~basic_io_object<boost::asio::stream_socket_service<boost::asio::ip::tcp> >() Line 86 C++ BoostASIOBugTest.exe!boost::asio::basic_socket<boost::asio::ip::tcp,boost::asio::stream_socket_service<boost::asio::ip::tcp> >::~basic_socket<boost::asio::ip::tcp,boost::asio::stream_socket_service<boost::asio::ip::tcp> >() Line 1054 + 0x3a bytes C++ BoostASIOBugTest.exe!boost::asio::basic_stream_socket<boost::asio::ip::tcp,boost::asio::stream_socket_service<boost::asio::ip::tcp> >::~basic_stream_socket<boost::asio::ip::tcp,boost::asio::stream_socket_service<boost::asio::ip::tcp> >() + 0x2b bytes C++ BoostASIOBugTest.exe!ConnectCommand::~ConnectCommand() + 0x2e bytes C++ BoostASIOBugTest.exe!ConnectCommand::`scalar deleting destructor'() + 0x2b bytes C++ BoostASIOBugTest.exe!boost::checked_delete<ConnectCommand>(ConnectCommand * x=0x003742c0) Line 34 + 0x2b bytes C++ BoostASIOBugTest.exe!boost::detail::sp_counted_impl_p<ConnectCommand>::dispose() Line 78 + 0xc bytes C++ BoostASIOBugTest.exe!boost::detail::sp_counted_base::release() Line 102 + 0xf bytes C++ BoostASIOBugTest.exe!boost::detail::shared_count::~shared_count() Line 221 C++ BoostASIOBugTest.exe!boost::shared_ptr<ConnectCommand>::~shared_ptr<ConnectCommand>() + 0x2e bytes C++ BoostASIOBugTest.exe!AsioHang::~AsioHang() + 0x63 bytes C++ BoostASIOBugTest.exe!main(int argc=1, char * * argv=0x00374128) Line 63 C++ This is with the latest Boost Trunk as of about an hour ago, and the issue in Wt is also still happening. As stated, Wt does not throw an access violation, nor do I think it is even destroying anything, read my above posts to see what is happening in ASIO in it.