boost::asio destructor segfault?

I've got a class that's using ASIO to run a simple server listening for command messages from a remote interface. It's got some private members to help with this (class abridged for shortness): class ClassifierContext { private: io_service ioService_; t_socket_shptr socket_; }; It runs it's event loop in it's own thread (started with boost::thread) // Hosts thread to run IO event loop void ClassifierContext::io_loop() { try { connect(); } catch (std::exception &e) { RERROR("Error connecting to site server -- %s", e.what()); } // Work object prevents run() from stopping when it runs out of work asio::io_service::work work(ioService_); ioService_.run(); } And it periodically sends data back along a single socket associated with the ioService and also has an asynchronous read pending to listen for command messages (I can post this code if needed, it's just a couple async_sends and an async_read) The problem I'm seeing comes when the destructor for the class is run: ClassifierContext::~ClassifierContext() { ioService_.stop(); } Periodically (every 20 times or so) I get a segfault when the destructor for ioService_ is called. A representative stack trace looks like this: #0 0x0921bfd6 in ?? () #1 0x08125877 in boost::asio::detail::reactor_op_queue<int>::destroy_operations ( this=0x8ec5f40) at opt/linux/include/boost/asio/detail/reactor_op_queue.hpp:268 #2 0x081274ad in boost::asio::detail::epoll_reactor<false>::shutdown_service ( this=0x8ec5ed8) at opt/linux/include/boost/asio/detail/epoll_reactor.hpp:119 #3 0x08127b3b in ~service_registry (this=0x8ec5958) at opt/linux/include/boost/asio/detail/service_registry.hpp:75 #4 0x08127c29 in ~io_service (this=0x8492360) at opt/linux/include/boost/asio/impl/io_service.ipp:62 #5 0x08117110 in ~ClassifierContext (this=0x8492360) at ClassifierContext.cpp:91 #6 0xb781cbb9 in exit () from /lib/tls/i686/cmov/libc.so.6 #7 0xb780477d in __libc_start_main () from /lib/tls/i686/cmov/libc.so.6 #8 0x081079c1 in _start () at ../sysdeps/i386/elf/start.S:119 Has anyone seen a segfault like this before? It's intermittent so that tells me there's some kind of race condition. Any idea how I can work around it?

Sean McAllister wrote:
Has anyone seen a segfault like this before? It's intermittent so that tells me there's some kind of race condition. Any idea how I can work around it?
Could it be a dangling event handler that is being called? Do you use shared_ptr/shared_from_this? Cheers, Rutger

Not using a shared_ptr_from_this, but I am using shared_ptr wrapped objects
as parameters to my asynchronous callbacks...
On Thu, Mar 18, 2010 at 1:32 PM, Rutger ter Borg
Sean McAllister wrote:
Has anyone seen a segfault like this before? It's intermittent so that tells me there's some kind of race condition. Any idea how I can work around it?
Could it be a dangling event handler that is being called? Do you use shared_ptr/shared_from_this?
Cheers,
Rutger
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Sean McAllister wrote:
Not using a shared_ptr_from_this, but I am using shared_ptr wrapped objects as parameters to my asynchronous callbacks...
If you use patterns like boost::bind( &some_class::some_mem_fn, this, .... ) then it could be that the instance of some_class is destructed before the bind-expression is. If the handler is called with "operation cancelled" (which should happen with all waiting handlers if you call io_service.stop()), it tries to make a call into freed memory -- you can expect a crash, indeed. To solve this, one can use shared_from_this(), boost::bind( &some_class::some_mem_fn, shared_from_this(), .... ) to make sure the object's lifetime will be at least that of the incomplete handler. Cheers, Rutger

The only functions I'm binding with boost::bind are members of
ClassifierContext, eg:
ICMessage::async_read(socket_,
boost::bind(&ClassifierContext::handleCmdMsg,
this,
_1,_2,_3));
Since the io_service object is stopped in the destructor of
ClassifierContext, shouldn't that be OK? Or should
I still try to create a shared_from_this off of the ClassifierContext class?
On Thu, Mar 18, 2010 at 11:50 PM, Rutger ter Borg
Sean McAllister wrote:
Not using a shared_ptr_from_this, but I am using shared_ptr wrapped objects as parameters to my asynchronous callbacks...
If you use patterns like
boost::bind( &some_class::some_mem_fn, this, .... )
then it could be that the instance of some_class is destructed before the bind-expression is. If the handler is called with "operation cancelled" (which should happen with all waiting handlers if you call io_service.stop()), it tries to make a call into freed memory -- you can expect a crash, indeed. To solve this, one can use shared_from_this(),
boost::bind( &some_class::some_mem_fn, shared_from_this(), .... )
to make sure the object's lifetime will be at least that of the incomplete handler.
Cheers,
Rutger
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Sean McAllister wrote:
The only functions I'm binding with boost::bind are members of ClassifierContext, eg:
ICMessage::async_read(socket_,
boost::bind(&ClassifierContext::handleCmdMsg,
this, _1,_2,_3));
Since the io_service object is stopped in the destructor of ClassifierContext, shouldn't that be OK? Or should I still try to create a shared_from_this off of the ClassifierContext class?
Not sure, given you are running multiple threads. According to the documentation, io_service::stop() doesn't block, so it could still be needing the shared_from_this stuff. Another approach is to allocate the work object in your member io_loop of ClassifierContext, and in the destructor, do something like m_work_ptr.reset(); ioService_.run(); this makes sure all outstanding operations are finished. Cheers, Rutger

On Fri, Mar 19, 2010 at 7:45 AM, Rutger ter Borg
Sean McAllister wrote:
The only functions I'm binding with boost::bind are members of ClassifierContext, eg:
ICMessage::async_read(socket_,
boost::bind(&ClassifierContext::handleCmdMsg,
this, _1,_2,_3));
Since the io_service object is stopped in the destructor of ClassifierContext, shouldn't that be OK? Or should I still try to create a shared_from_this off of the ClassifierContext class?
Not sure, given you are running multiple threads. According to the documentation, io_service::stop() doesn't block, so it could still be needing the shared_from_this stuff.
Another approach is to allocate the work object in your member io_loop of ClassifierContext, and in the destructor, do something like
m_work_ptr.reset(); ioService_.run();
this makes sure all outstanding operations are finished.
Cheers,
Rutger
Hmmm, I've only got the one extra thread to run the asynchronous event loop in. If I have async_read events outstanding, wouldn't the above code cause my destructor to block until I've read another message (which may happen quite infrequently)?
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Sean McAllister wrote:
Hmmm, I've only got the one extra thread to run the asynchronous event loop in. If I have async_read events outstanding, wouldn't the above code cause my destructor to block until I've read another message (which may happen quite infrequently)?
That's right -- but you still would like to have all operations finished before the end of the destructor. If you need to close sockets, call, e.g., socket::close. Cheers, Rutger

Sean McAllister wrote:
Hmmm, I've only got the one extra thread to run the asynchronous event loop in. If I have async_read events outstanding, wouldn't the above code cause my
destructor
to block until I've read another message (which may happen quite infrequently)?
That's right -- but you still would like to have all operations finished before the end of the destructor. If you need to close sockets, call, e.g., socket::close.
Cheers,
Rutger
Oh duh, I should be calling stop on my io_service object and then joining
On Fri, Mar 19, 2010 at 8:36 AM, Rutger ter Borg
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
participants (2)
-
Rutger ter Borg
-
Sean McAllister