Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to catch exception from boost::asio::io_service::run

I have a TCP server on boost::asio, it listens for a connection and after getting it starts sending data blocks using boost::asio::write in a loop.

bool TcpServer::StartTcpServer(std::shared_ptr<boost::asio::io_service>  io_service)
{
    m_ioservice = io_service;
    m_acceptor.reset(new boost::asio::ip::tcp::acceptor(*m_ioservice, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), m_port)));
    m_socket = std::unique_ptr<boost::asio::ip::tcp::socket>(new boost::asio::ip::tcp::socket(*m_ioservice));

    m_socket->close();
    m_acceptor->async_accept(*m_socket, m_peer_endpoint,   boost::bind(&TcpServer::AcceptHandler, this, boost::asio::placeholders::error)); 

    m_io_thread.reset(new std::thread([this]{
    try
    {
        this->m_ioservice->run();
    }
    catch(const boost::system::system_error & err){print logs}
    catch(...){print another logs}
    }));
}

void TcpServer::AcceptHandler(const boost::system::error_code &ec)
{
    while(true)
    {
         try
         {
             boost::asio::write( *m_socket, boost::asio::buffer(data->c_str(), data->size()), boost::asio::transfer_all());  
         } 
         catch(const boost::system::system_error & err){print logs}
         catch(...){print another logs}
    }
}

If I manually stop a receiver an exception about broken pipe is thrown and handled properly. But sometimes broken pipe happens (cause of bad connection I suppose) and the exception miraculously falls through all the catches and the application is terminated:

terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::system::system_error> >'

Examining the core I see that it happened in boost::asio::write originated in io_service::run(). What am I doing wrong?

Also I tried to rewrite the TCP server using async_write but it still happens, no so often though.

EDIT1: if I stop the receiver manually causing broken pipe I get the exactly same exception and the exactly same callstack but this one I can handle.

EDIT2: from what I understand right now non-catchable exception may be the result of too much data sent too fast through the socket. Not sure though.

like image 537
Nikolay Kovalenko Avatar asked May 26 '16 12:05

Nikolay Kovalenko


1 Answers

The error message in terminate actually does explain what's happening. boost::exception_detail::clone_impl is failing. Without digging through the code, I'd assume it's used to implement the copy constructor of the exception class. If this copy constructor throws an exception during exception handling, it will bypass the exception block and the exception will propagate upwards. (Even when you catch by reference, copies may still be made by the compiler.)

Now I don't know why the copy constructor is failing; there's not enough in the question to know. But this question relating to asynchronous I/O had a very similar problem, and there the crux seems to have been that a shared_ptr was being destroyed before exception processing. Looks similar.

like image 167
eh9 Avatar answered Oct 20 '22 14:10

eh9