Boost logo

Boost Users :

Subject: Re: [Boost-users] [Asio] io_service destructor never completes
From: OvermindDL1 (overminddl1_at_[hidden])
Date: 2010-07-19 16:55:36


On Tue, Jul 6, 2010 at 8:00 AM, Ragnar Cederlund
<ragnar.cederlund_at_[hidden]> 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.


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net