首页 > 解决方案 > ASAN 显示 heap-use-after-free 而 boost::asio 在套接字上调用纯 recv

问题描述

我有大约 100 个打开的 TCP 套接字,监视一些远程设备。这是一个纯粹的主从通信。服务器是主机(连接到设备)并且设备是从机。

Master 定期向所有设备发送请求,并等待一段时间等待响应的到来。只有在发送操作应该成功(调用了处理程序 handle_send)之后,套接字才会触发 async_read_some 直到消息完成。当服务器收到一条好消息时,它将停止启动 async_read_some,因为它不应该再接收任何消息。

随机地,ASAN 会在 recv 阶段抱怨未分配的缓冲区(当调用真正的系统调用“recvmsg”时 [参见 boost 1.66 /usr/include/boost/asio/detail/impl/socket_ops.ipp:784])

我们在一台 linux 机器上,当我使用 boost 1.53 时也会出现同样的问题

这是堆栈跟踪:

==7779==ERROR: AddressSanitizer: heap-use-after-free on address 0x611001478a40 at pc 0x503308 bp 0x7ffdea424a70 sp 0x7ffdea424a40
WRITE of size 53 at 0x611001478a40 thread T0
\#0 0x503307 in __interceptor_recvmsg (/usr/tsp/bin/tspinger+0x503307)
\#1 0x8a62c7 in boost::asio::detail::socket_ops::recv(int, iovec*, unsigned long, int, boost::system::error_code&) /usr/include/boost/asio/detail/impl/socket_ops.ipp:784
\#2 0x8a5457 in boost::asio::detail::socket_ops::non_blocking_recv(int, iovec*, unsigned long, int, bool, boost::system::error_code&, unsigned long&) /usr/include/boost/asio/detail/impl/socket_ops.ipp:877
\#3 0x8a4ac3 in boost::asio::detail::reactive_socket_recv_op_base<boost::asio::mutable_buffers_1>::do_perform(boost::asio::detail::reactor_op*) /usr/include/boost/asio/detail/reactive_socket_recv_op.hpp:55
\#4 0x681c4e in boost::asio::detail::reactor_op::perform() /usr/include/boost/asio/detail/reactor_op.hpp:44
\#5 0x6f9a98 in boost::asio::detail::epoll_reactor::descriptor_state::perform_io(unsigned int) /usr/include/boost/asio/detail/impl/epoll_reactor.ipp:743
\#6 0x6f8a30 in boost::asio::detail::epoll_reactor::descriptor_state::do_complete(void*, boost::asio::detail::scheduler_operation*, boost::system::error_code const&, unsigned long) /usr/include/boost/asio/detail/impl/epoll_reactor.ipp:774
\#7 0x603207 in boost::asio::detail::scheduler_operation::complete(void*, boost::system::error_code const&, unsigned long) /usr/include/boost/asio/detail/scheduler_operation.hpp:40
\#8 0x5fe649 in boost::asio::detail::scheduler::do_run_one(boost::asio::detail::conditionally_enabled_mutex::scoped_lock&, boost::asio::detail::scheduler_thread_info&, boost::system::error_code const&) /usr/include/boost/asio/detail/impl/scheduler.ipp:401
\#9 0x5fc7d1 in boost::asio::detail::scheduler::run(boost::system::error_code&) /usr/include/boost/asio/detail/impl/scheduler.ipp:154
\#10 0x5e5e85 in boost::asio::io_context::run() /usr/include/boost/asio/impl/io_context.ipp:62
0x611001478a40 is located 0 bytes inside of 209-byte region [0x611001478a40,0x611001478b11)
freed by thread T0 here:
==7779==AddressSanitizer CHECK failed: /builddir/build/BUILD/llvm-3.4.2.src/projects/compiler-rt/lib/sanitizer_common/sanitizer_stackdepot.cc:184 "((id & (1u << 31))) == ((0))" (0x80000000, 0x0)
\#0 0x52fe0f in __asan::AsanCheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) (/usr/tsp/bin/tspinger+0x52fe0f)
\#1 0x535671 in __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) (/usr/tsp/bin/tspinger+0x535671)
\#2 0x53bb8d in __sanitizer::StackDepotGet(unsigned int, unsigned long*) (/usr/tsp/bin/tspinger+0x53bb8d)
\#3 0x4f0c54 in __asan::AsanChunkView::GetFreeStack(__sanitizer::StackTrace*) (/usr/tsp/bin/tspinger+0x4f0c54)
\#4 0x52d096 in __asan::DescribeHeapAddress(unsigned long, unsigned long) (/usr/tsp/bin/tspinger+0x52d096)
\#5 0x52e211 in __asan_report_error (/usr/tsp/bin/tspinger+0x52e211)
\#6 0x503323 in __interceptor_recvmsg (/usr/tsp/bin/tspinger+0x503323)
\#7 0x8a62c7 in boost::asio::detail::socket_ops::recv(int, iovec*, unsigned long, int, boost::system::error_code&) /usr/include/boost/asio/detail/impl/socket_ops.ipp:784
\#8 0x8a5457 in boost::asio::detail::socket_ops::non_blocking_recv(int, iovec*, unsigned long, int, bool, boost::system::error_code&, unsigned long&) /usr/include/boost/asio/detail/impl/socket_ops.ipp:877
\#9 0x8a4ac3 in boost::asio::detail::reactive_socket_recv_op_base<boost::asio::mutable_buffers_1>::do_perform(boost::asio::detail::reactor_op*) /usr/include/boost/asio/detail/reactive_socket_recv_op.hpp:55
\#10 0x681c4e in boost::asio::detail::reactor_op::perform() /usr/include/boost/asio/detail/reactor_op.hpp:44
\#11 0x6f9a98 in boost::asio::detail::epoll_reactor::descriptor_state::perform_io(unsigned int) /usr/include/boost/asio/detail/impl/epoll_reactor.ipp:743
\#12 0x6f8a30 in boost::asio::detail::epoll_reactor::descriptor_state::do_complete(void*, boost::asio::detail::scheduler_operation*, boost::system::error_code const&, unsigned long) /usr/include/boost/asio/detail/impl/epoll_reactor.ipp:774
\#13 0x603207 in boost::asio::detail::scheduler_operation::complete(void*, boost::system::error_code const&, unsigned long) /usr/include/boost/asio/detail/scheduler_operation.hpp:40
\#14 0x5fe649 in boost::asio::detail::scheduler::do_run_one(boost::asio::detail::conditionally_enabled_mutex::scoped_lock&, boost::asio::detail::scheduler_thread_info&, boost::system::error_code const&) /usr/include/boost/asio/detail/impl/scheduler.ipp:401
\#15 0x5fc7d1 in boost::asio::detail::scheduler::run(boost::system::error_code&) /usr/include/boost/asio/detail/impl/scheduler.ipp:154
\#16 0x5e5e85 in boost::asio::io_context::run() /usr/include/boost/asio/impl/io_context.ipp:62

现在在 async_read some 中声明的 RX 缓冲区被称为

m_invector = vector<byte>(RX_BUFFER_SIZE);
socket_.async_read_some(boost::asio::buffer(m_invector),
                   std::bind(&RemoteObject::handle_read, shared_from_this(),
                      std::placeholders::_1, std::placeholders::_2));

因此,当 async_read_some 启动时,缓冲区始终是干净的。为了完成,我为非 Windows 系统添加了 boost recv 例程

signed_size_type recv(socket_type s, buf* bufs, size_t count,
    int flags, boost::system::error_code& ec)
{
  clear_last_error();
  msghdr msg = msghdr();
  msg.msg_iov = bufs;
  msg.msg_iovlen = static_cast<int>(count);
  signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec); //LINE 784
  if (result >= 0)
    ec = boost::system::error_code();
  return result;
}

我不明白这一点:ASAN 显示相同的内存使用点和空闲点,即 boost/asio/detail/impl/socket_ops.ipp:784,即系统的 recvmsg 调用。

你有什么线索吗?

谢谢。

标签: c++c++11boostaddress-sanitizer

解决方案


推荐阅读