2016-07-11 22 views
1

Mein Programm speichert einige interne Protokolle in einer .txt-Datei. Wenn Sie über TCP (SSL-verschlüsselt) eine Verbindung herstellen, sendet das Programm den Inhalt der Protokolldatei.Boost.Asio: Segmentierungsfehler beim Senden einer zu großen Nachricht

Dies ist der Code, der die Daten sendet:

void NIUserSession::write(std::string message) 
{ 
    std::cout << "Writing message" << std::endl; 
    message.append("<EOF>"); 
    boost::system::error_code ec; 
    boost::asio::async_write(this->socket_, boost::asio::buffer(message), 
         boost::asio::transfer_all(), boost::bind(&NIUserSession::writeHandler, 
                   this, boost::asio::placeholders::error, 
                   boost::asio::placeholders::bytes_transferred())); 
} 

void NIUserSession::writeHandler(const boost::system::error_code &error, std::size_t bytes_transferred) 
{ 
    std::cout << "Write Handler" << std::endl; 
    if(error) 
    { 
     std::cout << "Write handler error: " << error.message() << std::endl; 
     this->disconnect(); 
    } 
} 

So NIUserSession::write die Log-Datei Inhalt als String übergeben wird.

Wenn das Programm für eine sehr lange Zeit nicht ausgeführt wird, ist das Logfile kurz und alles funktioniert gut. Wenn es jedoch für eine Weile ausgeführt wird und die Protokolldatei länger und länger wird, wird das Programm eine SIGSEGV erhalten, wenn es versucht, die Daten zu senden. Dies ist das GDB-Protokoll:

Writing message 

Program received signal SIGSEGV, Segmentation fault. 
[Switching to Thread 0x7ffff4fe1700 (LWP 21047)] 
__memcpy_sse2_unaligned() at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:33 
33  ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S: No such file or directory. 
(gdb) where 
#0 __memcpy_sse2_unaligned() at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:33 
#1 0x00007ffff7998454 in ??() from /lib/x86_64-linux-gnu/libssl.so.1.0.0 
#2 0x00007ffff79985c3 in ??() from /lib/x86_64-linux-gnu/libssl.so.1.0.0 
#3 0x00000000004b7eca in boost::asio::ssl::detail::io_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::ssl::detail::write_op<boost::asio::const_buffers_1>, boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >, boost::asio::const_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, NIUserSession, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<NIUserSession*>, boost::arg<1> (*)(), boost::arg<2> > > > >::operator()(boost::system::error_code, unsigned long, int)() 
#4 0x00000000004b8bf8 in boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >, boost::asio::const_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, NIUserSession, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<NIUserSession*>, boost::arg<1> (*)(), boost::arg<2> > > >::operator()(boost::system::error_code const&, unsigned long, int)() 
#5 0x00000000004b7e6c in boost::asio::ssl::detail::io_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::ssl::detail::write_op<boost::asio::const_buffers_1>, boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >, boost::asio::const_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, NIUserSession, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<NIUserSession*>, boost::arg<1> (*)(), boost::arg<2> > > > >::operator()(boost::system::error_code, unsigned long, int)() 
#6 0x00000000004b965c in boost::asio::detail::reactive_socket_send_op<boost::asio::mutable_buffers_1, boost::asio::detail::write_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::asio::ssl::detail::io_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::ssl::detail::write_op<boost::asio::const_buffers_1>, boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >, boost::asio::const_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, NIUserSession, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<NIUserSession*>, boost::arg<1> (*)(), boost::arg<2> > > > > > >::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned long)() 
#7 0x00000000004add59 in boost::asio::detail::epoll_reactor::descriptor_state::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned long)() 
#8 0x00000000004ad911 in boost::asio::detail::task_io_service::run(boost::system::error_code&)() 
#9 0x00000000004a9c1f in NetInterface::init()() 
#10 0x00007ffff641aa60 in ??() from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 
#11 0x00007ffff566e184 in start_thread (arg=0x7ffff4fe1700) at pthread_create.c:312 
#12 0x00007ffff5b8237d in clone() at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111 

Ich verstehe nicht, warum es passiert. Muss ich vielleicht boost::asio::buffer eine Größe geben?

Auch io_service::run() läuft in einem eigenen abgetrennten Thread. Könnte das ein Problem sein?

+0

Valgrind kann die Zeilennummer angeben, an der der Fehler auftritt, hast du es versucht? –

+0

Naja ich denke das muss irgendwo tief in Boost.Asio sein, weil ich 'async_write' verwende. Die 'write'-Funktion wird aufgerufen, aber der' writeHandler' wird nie erreicht. Aber ich kann es immer noch versuchen. – Bobface

+0

Sehr seltsam, mit valgrind Ich erhalte kein Sigsegv ... – Bobface

Antwort

6

Dies ist das häufige Problem mit Asio-Nutzung. Sie senden Puffer mit boost::asio::buffer(message), der die Daten nicht kopiert. Es erstellt nur eine Referenz für die Daten und Sie sind verantwortlich für dieses Objekt (Ihre message) Lebensdauer bis zum Ende des Vorgangs. Aber wenn Sie die Funktion NIUserSession::write beenden, werden alle Stapelvariablen zerstört, einschließlich Ihrer message.

Um dies zu beheben, sollten Sie Ihre Daten in ein Objekt mit längerer Lebensdauer, zum Beispiel in shared_ptr. Ein gültiges Beispiel kann etwa so aussehen:

void NIUserSession::write(std::string &message_orig) 
{ 
    std::cout << "Writing message" << std::endl; 

    std::shared_ptr message = std::make_shared<std::string>(message_orig); 
    message->append("<EOF>"); 
    boost::system::error_code ec; 
    boost::asio::async_write(this->socket_, boost::asio::buffer(*message), 
     boost::asio::transfer_all(), boost::bind(&NIUserSession::writeHandler, 
       this, boost::asio::placeholders::error, 
       boost::asio::placeholders::bytes_transferred(), 
       message /* <- capture it into callback to guarantee lifetime */ 
       )); 
}