#c #c 11 #boost #address-sanitizer
#c #c 11 #boost #средство очистки адресов
Вопрос:
У меня около 100 открытых TCP-сокетов, отслеживающих некоторые удаленные устройства. Это чистая связь между ведущим и ведомым. Где сервер является главным (который подключается к устройствам), а устройства являются подчиненными.
Мастер периодически отправляет запросы на все устройства и некоторое время ожидает получения ответов. Только после того, как предполагается, что операция отправки прошла успешно (вызван обработчик 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_codeamp;) /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_codeamp;, unsigned longamp;) /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 constamp;, 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 constamp;, 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_lockamp;, boost::asio::detail::scheduler_thread_infoamp;, boost::system::error_code constamp;) /usr/include/boost/asio/detail/impl/scheduler.ipp:401
#9 0x5fc7d1 in boost::asio::detail::scheduler::run(boost::system::error_codeamp;) /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 amp; (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_codeamp;) /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_codeamp;, unsigned longamp;) /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 constamp;, 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 constamp;, 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_lockamp;, boost::asio::detail::scheduler_thread_infoamp;, boost::system::error_code constamp;) /usr/include/boost/asio/detail/impl/scheduler.ipp:401
#15 0x5fc7d1 in boost::asio::detail::scheduler::run(boost::system::error_codeamp;) /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
Теперь буфер RX, объявленный в async_read some, вызывается как
m_invector = vector<byte>(RX_BUFFER_SIZE);
socket_.async_read_some(boost::asio::buffer(m_invector),
std::bind(amp;RemoteObject::handle_read, shared_from_this(),
std::placeholders::_1, std::placeholders::_2));
Таким образом, буфер всегда чист при запуске async_read_some.
Для завершения я добавляю процедуру boost recv для систем, отличных от Windows
signed_size_type recv(socket_type s, buf* bufs, size_t count,
int flags, boost::system::error_codeamp; 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, amp;msg, flags), ec); //LINE 784
if (result >= 0)
ec = boost::system::error_code();
return resu<
}
Я не могу понять суть: ASAN показывает ту же точку использования памяти, что и свободная, то есть boost / asio/detail/impl/socket_ops.ipp: 784, то есть системный вызов recvmsg.
У вас есть какие-либо подсказки?
Спасибо.
Комментарии:
1. Можете ли вы попробовать запустить под
export ASAN_OPTIONS=detect_container_overflow=0
?2. Я использую libasan-4.8.5 (из-за среды centos 7). Я пытался установить эту опцию, но у меня тот же результат.
3. «Я не могу понять суть: ASAN показывает ту же точку использования памяти, что и free» — Asan не показывает вам точку
free
, потому что какое-то внутреннее утверждение завершается ошибкой (что-то повредило заголовок буфера, скорее всего, из-за повреждения памяти). Затем он показывает вам трассировку стека для утверждения, а не дляfree
. Теперь, что касается сбоя, нам, вероятно, нужно увидеть более широкий контекст вокруг вызоваsocket_.async_read_some
. В частности, вы уверены, чтоm_invector
фрейм все еще существует при выполнении асинхронного вызова?