Boost.Asio: 发送太大消息时出现分段错误
Boost.Asio: Segmentation fault when sending too big message
我的程序将一些内部日志保存到 .txt 文件中。
如果您通过 TCP(SSL 加密)连接到它,程序将发送日志文件的内容。
这是发送数据的代码:
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();
}
}
因此 NIUserSession::write
将日志文件内容作为字符串传递。
如果程序很长时间没有 运行,则日志文件很短,一切正常。但是,如果它运行一段时间后,日志文件变得越来越长,程序在尝试发送数据时会收到一个 SIGSEGV
。这是 gdb 日志:
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
我不明白为什么会这样。我可能必须给 boost::asio::buffer
一个尺码吗?
此外,io_service::run()
是 运行 在它自己的分离线程中。这会是个问题吗?
这是使用 asio 的常见问题。您正在使用 boost::asio::buffer(message)
发送缓冲区,它不会复制数据。它只是为数据创建一个引用,您负责这个对象(您的 message
)的生命周期,直到操作结束。但是当你退出函数 NIUserSession::write
时,所有堆栈变量都被销毁,包括你的 message
.
要解决此问题,您应该将数据放入生命周期更长的对象中,例如 shared_ptr。有效示例可以是这样的:
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 */
));
}
我的程序将一些内部日志保存到 .txt 文件中。 如果您通过 TCP(SSL 加密)连接到它,程序将发送日志文件的内容。
这是发送数据的代码:
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();
}
}
因此 NIUserSession::write
将日志文件内容作为字符串传递。
如果程序很长时间没有 运行,则日志文件很短,一切正常。但是,如果它运行一段时间后,日志文件变得越来越长,程序在尝试发送数据时会收到一个 SIGSEGV
。这是 gdb 日志:
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
我不明白为什么会这样。我可能必须给 boost::asio::buffer
一个尺码吗?
此外,io_service::run()
是 运行 在它自己的分离线程中。这会是个问题吗?
这是使用 asio 的常见问题。您正在使用 boost::asio::buffer(message)
发送缓冲区,它不会复制数据。它只是为数据创建一个引用,您负责这个对象(您的 message
)的生命周期,直到操作结束。但是当你退出函数 NIUserSession::write
时,所有堆栈变量都被销毁,包括你的 message
.
要解决此问题,您应该将数据放入生命周期更长的对象中,例如 shared_ptr。有效示例可以是这样的:
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 */
));
}