c++ - 使用 asio 时双重释放或损坏

标签 c++ ubuntu c++11 boost asio

我对此做了一些修改 code snippet用于通过 ASIO API 发送\接收 ICMP 数据包。

以下是我所做的修改(完整代码片段如下):

  1. 使用标准版API代替Boost提供的对应API

    • 使用 std::bind而不是 boost::bind
  2. 开始使用共享指针

    • 使用指向 pinger 的共享指针(即 std::shared_ptr<pinger> sp{new pinger(io_service, argv[1])}; )而不是通过 pinger 的默认构造函数直接构造实例(即 pinger p(io_service, argv[1]); )。
    • pinger源自 std::enabled_shared_from_this<pinger>现在
    • 第二个参数传递给 boost::bind不是 this指针了,我用 shared_from_this()通过 std::shared_pointerstd::bind .例如:我的代码是timer_.async_wait(std::bind(&pinger::start_send, shared_from_this())); ,而原始的是 timer_.async_wait(boost::bind(&pinger::handle_timeout, this)); .
    • 避免调用shared_from_this()在类 pinger 的构造函数中, start_send(); start_receive();被移出构造函数和一个名为 Init() 的新函数用于调用上述两个函数。
  3. 使用非抛出版本 asio::raw_socket::send_to并在发生错误时重试发送 ICMP 数据包。

    • socket_.send_to(request_buffer.data(), destination_);替换为 socket_.send_to(request_buffer.data(), destination_, flags, error);
    • 重试发送ICMP数据包(通过 calling timer_.async_wait(std::bind(&pinger::start_send, shared_from_this()));socket_.send_to 面临错误时。

这是我的代码片段(icmp_header.hppipv4_header.hpp 可见 here):

#if 1
#include "icmp_header.hpp"
#include "ipv4_header.hpp"
#include <boost/asio.hpp>
#include <functional>
#include <iostream>
#include <istream>
#include <memory>
#include <ostream>

using boost::asio::deadline_timer;
using boost::asio::ip::icmp;
namespace posix_time = boost::posix_time;

class pinger : public std::enable_shared_from_this<pinger> {
public:
  pinger(boost::asio::io_service &io_service, const char *destination)
      : resolver_(io_service), socket_(io_service, icmp::v4()),
        timer_(io_service), sequence_number_(0), num_replies_(0) {
    icmp::resolver::query query(icmp::v4(), destination, "");
    destination_ = *resolver_.resolve(query);
  }

  void init() {
    start_send();
    start_receive();
  }

private:
  void start_send() {
    std::string body("\"Hello!\" from Asio ping.");

    // Create an ICMP header for an echo request.
    icmp_header echo_request;
    echo_request.type(icmp_header::echo_request);
    echo_request.code(0);
    echo_request.identifier(get_identifier());
    echo_request.sequence_number(++sequence_number_);
    compute_checksum(echo_request, body.begin(), body.end());

    // Encode the request packet.
    boost::asio::streambuf request_buffer;
    std::ostream os(&request_buffer);
    os << echo_request << body;

    // Send the request.
    time_sent_ = posix_time::microsec_clock::universal_time();

    boost::system::error_code error;
    boost::asio::socket_base::message_flags flags;
    socket_.send_to(request_buffer.data(), destination_, flags, error);
    if (error) {
      std::cout << "send_to failed1:" << error.message() << std::endl;
      std::cout << "send_to failed2:" << std::endl;
      timer_.expires_at(time_sent_ + posix_time::seconds(1));
      timer_.async_wait(std::bind(&pinger::start_send, shared_from_this()));
    } else {
      // Wait up to five seconds for a reply.
      num_replies_ = 0;
      timer_.expires_at(time_sent_ + posix_time::seconds(5));
      timer_.async_wait(std::bind(&pinger::handle_timeout, shared_from_this()));
    }
  }

  void handle_timeout() {
    if (num_replies_ == 0)
      std::cout << "Request timed out" << std::endl;

    // Requests must be sent no less than one second apart.
    timer_.expires_at(time_sent_ + posix_time::seconds(1));
    timer_.async_wait(std::bind(&pinger::start_send, shared_from_this()));
  }

  void start_receive() {
    // Discard any data already in the buffer.
    reply_buffer_.consume(reply_buffer_.size());

    // Wait for a reply. We prepare the buffer to receive up to 64KB.
    socket_.async_receive(reply_buffer_.prepare(65536),
                          std::bind(&pinger::handle_receive, shared_from_this(),
                                    std::placeholders::_1,
                                    std::placeholders::_2));
  }

  void handle_receive(boost::system::error_code error, std::size_t length) {
    // The actual number of bytes received is committed to the buffer so that we
    // can extract it using a std::istream object.
    if (error) {
      std::cout << "error in handle_receive:"
                << boost::system::system_error(error).what() << std::endl;
    }

    reply_buffer_.commit(length);

    // Decode the reply packet.
    std::istream is(&reply_buffer_);
    ipv4_header ipv4_hdr;
    icmp_header icmp_hdr;
    is >> ipv4_hdr >> icmp_hdr;

    // We can receive all ICMP packets received by the host, so we need to
    // filter out only the echo replies that match the our identifier and
    // expected sequence number.
    if (is && icmp_hdr.type() == icmp_header::echo_reply &&
        icmp_hdr.identifier() == get_identifier() &&
        icmp_hdr.sequence_number() == sequence_number_) {
      // If this is the first reply, interrupt the five second timeout.
      if (num_replies_++ == 0)
        timer_.cancel();

      // Print out some information about the reply packet.
      posix_time::ptime now = posix_time::microsec_clock::universal_time();
      std::cout << length - ipv4_hdr.header_length() << " bytes from "
                << ipv4_hdr.source_address()
                << ": icmp_seq=" << icmp_hdr.sequence_number()
                << ", ttl=" << ipv4_hdr.time_to_live()
                << ", time=" << (now - time_sent_).total_milliseconds() << " ms"
                << std::endl;
    }

    start_receive();
  }

  static unsigned short get_identifier() {
#if defined(BOOST_WINDOWS)
    return static_cast<unsigned short>(::GetCurrentProcessId());
#else
    return static_cast<unsigned short>(::getpid());
#endif
  }

  icmp::resolver resolver_;
  icmp::endpoint destination_;
  icmp::socket socket_;
  deadline_timer timer_;
  unsigned short sequence_number_;
  posix_time::ptime time_sent_;
  boost::asio::streambuf reply_buffer_;
  std::size_t num_replies_;
};

int main(int argc, char *argv[]) {
  try {
    if (argc != 2) {
      std::cerr << "Usage: ping <host>" << std::endl;
#if !defined(BOOST_WINDOWS)
      std::cerr << "(You may need to run this program as root.)" << std::endl;
#endif
      return 1;
    }

    boost::asio::io_service io_service;
    std::shared_ptr<pinger> sp{new pinger(io_service, argv[1])};
    sp->init();
    io_service.run();
  } catch (std::exception &e) {
    std::cerr << "Exception: " << e.what() << std::endl;
  }
}
#endif

上面的代码片段在我的本地网络正常时运行良好。输出如下:

32 bytes from 192.168.1.51: icmp_seq=1, ttl=58, time=4 ms
32 bytes from 192.168.1.51: icmp_seq=2, ttl=58, time=3 ms
//omit...
//running a long long time

当我运行 sudo ifconfig wlp59s0 down 时,程序收到信号 SIGABRT 然后中止故意(以确保程序是否稳定)。这是我通过 GDB 获得的回溯

sudo gdb -q ./modified_ping 
Reading symbols from ./modified_ping...done.
(gdb) r 192.168.1.51
Starting program: /home/jhon/icmp/build/modified_ping 192.168.1.51
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
32 bytes from 192.168.1.51: icmp_seq=1, ttl=58, time=3 ms
32 bytes from 192.168.1.51: icmp_seq=2, ttl=58, time=4 ms
32 bytes from 192.168.1.51: icmp_seq=3, ttl=58, time=3 ms
32 bytes from 192.168.1.51: icmp_seq=4, ttl=58, time=3 ms   //NOTE:manually run `ifconfig down` on purpose
send_to failed1:
send_to failed2:
*** Error in `/home/jhon/icmp/build/modified_ping': double free or corruption (!prev): 0x0000000000699f80 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777f5)[0x7ffff6dc07f5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8038a)[0x7ffff6dc938a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7ffff6dcd58c]
/home/jhon/icmp/build/modified_ping[0x44bcd6]
/home/jhon/icmp/build/modified_ping[0x44ae36]
/home/jhon/icmp/build/modified_ping[0x449b56]
/home/jhon/icmp/build/modified_ping[0x447e09]
/home/jhon/icmp/build/modified_ping[0x445403]
/home/jhon/icmp/build/modified_ping[0x44e005]
/home/jhon/icmp/build/modified_ping[0x43f347]
/home/jhon/icmp/build/modified_ping[0x44de00]
/home/jhon/icmp/build/modified_ping[0x44db4e]
/home/jhon/icmp/build/modified_ping[0x44d6eb]
/home/jhon/icmp/build/modified_ping[0x44d3b6]
/home/jhon/icmp/build/modified_ping[0x44d0d9]
/home/jhon/icmp/build/modified_ping[0x44c9c7]
/home/jhon/icmp/build/modified_ping[0x44c03f]
/home/jhon/icmp/build/modified_ping[0x44b257]
/home/jhon/icmp/build/modified_ping[0x439e94]
/home/jhon/icmp/build/modified_ping[0x43ca93]
/home/jhon/icmp/build/modified_ping[0x43c4e8]
/home/jhon/icmp/build/modified_ping[0x43cdac]
/home/jhon/icmp/build/modified_ping[0x436b34]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7ffff6d69840]
/home/jhon/icmp/build/modified_ping[0x4059a9]
======= Memory map: ========
00400000-00486000 r-xp 00000000 08:02 94506936                           /home/jhon/icmp/build/modified_ping
00685000-00686000 r--p 00085000 08:02 94506936                           /home/jhon/icmp/build/modified_ping
00686000-00687000 rw-p 00086000 08:02 94506936                           /home/jhon/icmp/build/modified_ping
00687000-006b9000 rw-p 00000000 00:00 0                                  [heap]
7ffff0000000-7ffff0021000 rw-p 00000000 00:00 0 
7ffff0021000-7ffff4000000 ---p 00000000 00:00 0 
7ffff6d49000-7ffff6f09000 r-xp 00000000 08:02 14029372                   /lib/x86_64-linux-gnu/libc-2.23.so
7ffff6f09000-7ffff7109000 ---p 001c0000 08:02 14029372                   /lib/x86_64-linux-gnu/libc-2.23.so
7ffff7109000-7ffff710d000 r--p 001c0000 08:02 14029372                   /lib/x86_64-linux-gnu/libc-2.23.so
7ffff710d000-7ffff710f000 rw-p 001c4000 08:02 14029372                   /lib/x86_64-linux-gnu/libc-2.23.so
7ffff710f000-7ffff7113000 rw-p 00000000 00:00 0 
7ffff7113000-7ffff712a000 r-xp 00000000 08:02 14024978                   /lib/x86_64-linux-gnu/libgcc_s.so.1
7ffff712a000-7ffff7329000 ---p 00017000 08:02 14024978                   /lib/x86_64-linux-gnu/libgcc_s.so.1
7ffff7329000-7ffff732a000 r--p 00016000 08:02 14024978                   /lib/x86_64-linux-gnu/libgcc_s.so.1
7ffff732a000-7ffff732b000 rw-p 00017000 08:02 14024978                   /lib/x86_64-linux-gnu/libgcc_s.so.1
7ffff732b000-7ffff7433000 r-xp 00000000 08:02 14024798                   /lib/x86_64-linux-gnu/libm-2.23.so
7ffff7433000-7ffff7632000 ---p 00108000 08:02 14024798                   /lib/x86_64-linux-gnu/libm-2.23.so
7ffff7632000-7ffff7633000 r--p 00107000 08:02 14024798                   /lib/x86_64-linux-gnu/libm-2.23.so
7ffff7633000-7ffff7634000 rw-p 00108000 08:02 14024798                   /lib/x86_64-linux-gnu/libm-2.23.so
7ffff7634000-7ffff77a6000 r-xp 00000000 08:02 44435598                   /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7ffff77a6000-7ffff79a6000 ---p 00172000 08:02 44435598                   /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7ffff79a6000-7ffff79b0000 r--p 00172000 08:02 44435598                   /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7ffff79b0000-7ffff79b2000 rw-p 0017c000 08:02 44435598                   /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7ffff79b2000-7ffff79b6000 rw-p 00000000 00:00 0 
7ffff79b6000-7ffff79b9000 r-xp 00000000 08:02 44441454                   /usr/lib/x86_64-linux-gnu/libboost_system.so.1.58.0
7ffff79b9000-7ffff7bb8000 ---p 00003000 08:02 44441454                   /usr/lib/x86_64-linux-gnu/libboost_system.so.1.58.0
7ffff7bb8000-7ffff7bb9000 r--p 00002000 08:02 44441454                   /usr/lib/x86_64-linux-gnu/libboost_system.so.1.58.0
7ffff7bb9000-7ffff7bba000 rw-p 00003000 08:02 44441454                   /usr/lib/x86_64-linux-gnu/libboost_system.so.1.58.0
7ffff7bba000-7ffff7bd2000 r-xp 00000000 08:02 14024729                   /lib/x86_64-linux-gnu/libpthread-2.23.so
7ffff7bd2000-7ffff7dd1000 ---p 00018000 08:02 14024729                   /lib/x86_64-linux-gnu/libpthread-2.23.so
7ffff7dd1000-7ffff7dd2000 r--p 00017000 08:02 14024729                   /lib/x86_64-linux-gnu/libpthread-2.23.so
7ffff7dd2000-7ffff7dd3000 rw-p 00018000 08:02 14024729                   /lib/x86_64-linux-gnu/libpthread-2.23.so
7ffff7dd3000-7ffff7dd7000 rw-p 00000000 00:00 0 
7ffff7dd7000-7ffff7dfd000 r-xp 00000000 08:02 14024795                   /lib/x86_64-linux-gnu/ld-2.23.so
7ffff7fcb000-7ffff7fd2000 rw-p 00000000 00:00 0 
7ffff7ff6000-7ffff7ff7000 rw-p 00000000 00:00 0 
7ffff7ff7000-7ffff7ffa000 r--p 00000000 00:00 0                          [vvar]
7ffff7ffa000-7ffff7ffc000 r-xp 00000000 00:00 0                          [vdso]
7ffff7ffc000-7ffff7ffd000 r--p 00025000 08:02 14024795                   /lib/x86_64-linux-gnu/ld-2.23.so
7ffff7ffd000-7ffff7ffe000 rw-p 00026000 08:02 14024795                   /lib/x86_64-linux-gnu/ld-2.23.so
7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0 
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

Program received signal SIGABRT, Aborted.
0x00007ffff6d7e438 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
54      ../sysdeps/unix/sysv/linux/raise.c: no such file or folder
(gdb) bt
#0  0x00007ffff6d7e438 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1  0x00007ffff6d8003a in __GI_abort () at abort.c:89
#2  0x00007ffff6dc07fa in __libc_message (do_abort=do_abort@entry=2, fmt=fmt@entry=0x7ffff6ed9fd8 "*** Error in `%s': %s: 0x%s ***\n") at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007ffff6dc938a in malloc_printerr (ar_ptr=<optimized out>, ptr=<optimized out>, str=0x7ffff6eda108 "double free or corruption (!prev)", action=3) at malloc.c:5020
#4  _int_free (av=<optimized out>, p=<optimized out>, have_lock=0) at malloc.c:3874
#5  0x00007ffff6dcd58c in __GI___libc_free (mem=<optimized out>) at malloc.c:2975
#6  0x000000000044bcd6 in __gnu_cxx::new_allocator<char>::deallocate (this=0x7fffffffdd98, __p=0x699f80 "\b") at /usr/include/c++/4.9/ext/new_allocator.h:110
#7  0x000000000044ae36 in std::allocator_traits<std::allocator<char> >::deallocate (__a=..., __p=0x699f80 "\b", __n=128) at /usr/include/c++/4.9/bits/alloc_traits.h:514
#8  0x0000000000449b56 in std::_Vector_base<char, std::allocator<char> >::_M_deallocate (this=0x7fffffffdd98, __p=0x699f80 "\b", __n=128) at /usr/include/c++/4.9/bits/stl_vector.h:178
#9  0x0000000000447e09 in std::_Vector_base<char, std::allocator<char> >::~_Vector_base (this=0x7fffffffdd98, __in_chrg=<optimized out>) at /usr/include/c++/4.9/bits/stl_vector.h:160
#10 0x0000000000445403 in std::vector<char, std::allocator<char> >::~vector (this=0x7fffffffdd98, __in_chrg=<optimized out>) at /usr/include/c++/4.9/bits/stl_vector.h:425
#11 0x000000000044e005 in boost::asio::basic_streambuf<std::allocator<char> >::~basic_streambuf (this=0x7fffffffdd50, __in_chrg=<optimized out>)
    at /usr/include/boost/asio/basic_streambuf.hpp:111
#12 0x000000000043f347 in pinger::start_send (this=0x698d50) at /home/jhon/icmp/src/main.cpp:42
#13 0x000000000044de00 in std::_Mem_fn<void (pinger::*)()>::_M_call<std::shared_ptr<pinger>&> (this=0x7fffffffe140, __ptr=std::shared_ptr (count 4, weak 1) 0x698d50)
    at /usr/include/c++/4.9/functional:526
#14 0x000000000044db4e in std::_Mem_fn<void (pinger::*)()>::operator()<std::shared_ptr<pinger>&, , void>(std::shared_ptr<pinger>&) const (this=0x7fffffffe140, 
    __object=std::shared_ptr (count 4, weak 1) 0x698d50) at /usr/include/c++/4.9/functional:578
#15 0x000000000044d6eb in std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)>::__call<void, boost::system::error_code const&, 0ul>(std::tuple<boost::system::error_code const&>&&, std::_Index_tuple<0ul>) (this=0x7fffffffe140, __args=<unknown type in /home/jhon/icmp/build/modified_ping, CU 0xee6ae, DIE 0x1264e2>)
    at /usr/include/c++/4.9/functional:1264
#16 0x000000000044d3b6 in std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)>::operator()<boost::system::error_code const&, void>(boost::system::error_code const&) (
    this=0x7fffffffe140) at /usr/include/c++/4.9/functional:1323
#17 0x000000000044d0d9 in boost::asio::detail::binder1<std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)>, boost::system::error_code>::operator()() (this=0x7fffffffe140)
---Type <return> to continue, or q <return> to quit---
    at /usr/include/boost/asio/detail/bind_handler.hpp:47
#18 0x000000000044c9c7 in boost::asio::asio_handler_invoke<boost::asio::detail::binder1<std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)>, boost::system::error_code> >(boost::asio::detail::binder1<std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)>, boost::system::error_code>&, ...) (function=...)
    at /usr/include/boost/asio/handler_invoke_hook.hpp:69
#19 0x000000000044c03f in boost_asio_handler_invoke_helpers::invoke<boost::asio::detail::binder1<std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)>, boost::system::error_code>, std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)> >(boost::asio::detail::binder1<std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)>, boost::system::error_code>&, std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)>&) (function=..., context=...) at /usr/include/boost/asio/detail/handler_invoke_helpers.hpp:37
#20 0x000000000044b257 in boost::asio::detail::wait_handler<std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)> >::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned long) (owner=0x698c70, base=0x699af0) at /usr/include/boost/asio/detail/wait_handler.hpp:70
#21 0x0000000000439e94 in boost::asio::detail::task_io_service_operation::complete (this=0x699af0, owner=..., ec=..., bytes_transferred=0)
    at /usr/include/boost/asio/detail/task_io_service_operation.hpp:38
#22 0x000000000043ca93 in boost::asio::detail::task_io_service::do_run_one (this=0x698c70, lock=..., this_thread=..., ec=...) at /usr/include/boost/asio/detail/impl/task_io_service.ipp:372
#23 0x000000000043c4e8 in boost::asio::detail::task_io_service::run (this=0x698c70, ec=...) at /usr/include/boost/asio/detail/impl/task_io_service.ipp:149
#24 0x000000000043cdac in boost::asio::io_service::run (this=0x7fffffffe360) at /usr/include/boost/asio/impl/io_service.ipp:59
#25 0x0000000000436b34 in main (argc=2, argv=0x7fffffffe498) at /home/jhon/icmp/src/main.cpp:155

Valgrind:

感谢@Basile Starynkevitch。 我尝试使用 valgrind找出问题。我添加add_compile_options(-Wall -Wextra)CMakeLists.txt (使用 set (CMAKE_BUILD_TYPE debug) 进行调试时,GDB 已经存在)。我重新编译上面的代码 sippet 并使用 sudo valgrind ... 运行它.但令我惊讶的是,现在没有收到任何信号。

这是在终端中看到的输出(在 valgrind 上有 Ubuntu 16.04):

sudo valgrind --log-file=valgrind.log --error-limit=no --leak-check=full --tool=memcheck --show-reachable=yes ./modified_ping 192.168.1.51
32 bytes from 192.168.1.51: icmp_seq=1, ttl=58, time=90 ms
32 bytes from 192.168.1.51: icmp_seq=2, ttl=58, time=7 ms
32 bytes from 192.168.1.51: icmp_seq=3, ttl=58, time=11 ms
32 bytes from 192.168.1.51: icmp_seq=4, ttl=58, time=4 ms
32 bytes from 192.168.1.51: icmp_seq=5, ttl=58, time=3 ms
32 bytes from 192.168.1.51: icmp_seq=6, ttl=58, time=2 ms
send_to failed1:
send_to failed2:
send_to failed1:
send_to failed2:
send_to failed1:
send_to failed2:
//omit...

这里是valgrind.log包含: 注意:1.因为程序无限运行 valgrind ,程序被 CTRL+C 停止.奇怪的是同一个二进制程序仍然遇到带有sudo gdb ...的SIGABRT当ifconfig down是故意调用的。

2.日志很大,完整的日志见here .

sudo valgrind --log-file=valgrind.log --error-limit=no --leak-check=full --tool=memcheck --show-reachable=yes ./modified_ping 192.168.1.51


==9362== Memcheck, a memory error detector
==9362== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==9362== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==9362== Command: ./modified_ping 192.168.1.51
//...full log is seen at https://coliru.stacked-
==9362== 1,265 bytes in 55 blocks are definitely lost in loss record 18 of 20
==9362==    at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9362==    by 0x505823E: ??? (in /usr/lib/x86_64-linux-gnu/libboost_system.so.1.58.0)
==9362==    by 0x5058BFD: ??? (in /usr/lib/x86_64-linux-gnu/libboost_system.so.1.58.0)
==9362==    by 0x43731A: boost::system::error_code::message() const (error_code.hpp:357)
==9362==    by 0x43F0E9: pinger::start_send() (main.cpp:53)
==9362==    by 0x44DDFF: void std::_Mem_fn<void (pinger::*)()>::_M_call<std::shared_ptr<pinger>&>(std::shared_ptr<pinger>&, void const volatile*) const (in /home/jhon/icmp/build/modified_ping)
==9362==    by 0x44DB4D: void std::_Mem_fn<void (pinger::*)()>::operator()<std::shared_ptr<pinger>&, , void>(std::shared_ptr<pinger>&) const (functional:578)
==9362==    by 0x44D6EA: void std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)>::__call<void, boost::system::error_code const&, 0ul>(std::tuple<boost::system::error_code const&>&&, std::_Index_tuple<0ul>) (functional:1264)
==9362==    by 0x44D3B5: void std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)>::operator()<boost::system::error_code const&, void>(boost::system::error_code const&) (functional:1323)
==9362==    by 0x44D0D8: boost::asio::detail::binder1<std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)>, boost::system::error_code>::operator()() (bind_handler.hpp:47)
==9362==    by 0x44C9C6: void boost::asio::asio_handler_invoke<boost::asio::detail::binder1<std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)>, boost::system::error_code> >(boost::asio::detail::binder1<std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)>, boost::system::error_code>&, ...) (handler_invoke_hook.hpp:69)
==9362==    by 0x44C03E: void boost_asio_handler_invoke_helpers::invoke<boost::asio::detail::binder1<std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)>, boost::system::error_code>, std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)> >(boost::asio::detail::binder1<std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)>, boost::system::error_code>&, std::_Bind<std::_Mem_fn<void (pinger::*)()> (std::shared_ptr<pinger>)>&) (handler_invoke_helpers.hpp:37)
==9362== 
==9362== 65,536 bytes in 1 blocks are still reachable in loss record 19 of 20
==9362==    at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9362==    by 0x44BD8B: __gnu_cxx::new_allocator<char>::allocate(unsigned long, void const*) (new_allocator.h:104)
==9362==    by 0x44AEB9: std::allocator_traits<std::allocator<char> >::allocate(std::allocator<char>&, unsigned long) (alloc_traits.h:488)
==9362==    by 0x449CBB: std::_Vector_base<char, std::allocator<char> >::_M_allocate(unsigned long) (stl_vector.h:170)
==9362==    by 0x447F2D: std::vector<char, std::allocator<char> >::_M_default_append(unsigned long) (vector.tcc:557)
==9362==    by 0x44547E: std::vector<char, std::allocator<char> >::resize(unsigned long) (stl_vector.h:676)
==9362==    by 0x445C4F: boost::asio::basic_streambuf<std::allocator<char> >::reserve(unsigned long) (basic_streambuf.hpp:326)
==9362==    by 0x442D04: boost::asio::basic_streambuf<std::allocator<char> >::prepare(unsigned long) (basic_streambuf.hpp:207)
==9362==    by 0x43F6B5: pinger::start_receive() (main.cpp:82)
==9362==    by 0x43EDE1: pinger::init() (main.cpp:26)
==9362==    by 0x436B27: main (main.cpp:154)
==9362== 
==9362== 72,704 bytes in 1 blocks are still reachable in loss record 20 of 20
==9362==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9362==    by 0x52E4EFF: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21)
==9362==    by 0x40106F9: call_init.part.0 (dl-init.c:72)
==9362==    by 0x401080A: call_init (dl-init.c:30)
==9362==    by 0x401080A: _dl_init (dl-init.c:120)
==9362==    by 0x4000C69: ??? (in /lib/x86_64-linux-gnu/ld-2.23.so)
==9362==    by 0x1: ???
==9362==    by 0xFFF000652: ???
==9362==    by 0xFFF000662: ???
==9362== 
==9362== LEAK SUMMARY:
==9362==    definitely lost: 1,265 bytes in 55 blocks
==9362==    indirectly lost: 0 bytes in 0 blocks
==9362==      possibly lost: 0 bytes in 0 blocks
==9362==    still reachable: 139,978 bytes in 19 blocks
==9362==         suppressed: 0 bytes in 0 blocks
==9362== 
==9362== For counts of detected and suppressed errors, rerun with: -v
==9362== Use --track-origins=yes to see where uninitialised values come from
==9362== ERROR SUMMARY: 337 errors from 5 contexts (suppressed: 0 from 0)

更何况,奇怪的是如果std::cout << "send_to failed1:" << error.message() << std::endl; 就再也收不到信号了在 sudo ifconfig wlp59s0 down 时被注释掉已被调用。我不认为这个表达式有问题。但我真的不知道哪里出了问题。有人能解释一下这个问题吗?

(gdb) make  //after commenting out `std::cout << "send_to failed1:" << error.message() << std::endl;`
[100%] Built target modified_ping
(gdb) r 192.168.1.51
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/jhon/icmp/build/modified_ping 192.168.1.51
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
32 bytes from 192.168.1.51: icmp_seq=1, ttl=58, time=4 ms
32 bytes from 192.168.1.51: icmp_seq=2, ttl=58, time=7 ms
32 bytes from 192.168.1.51: icmp_seq=3, ttl=58, time=2 ms
32 bytes from 192.168.1.51: icmp_seq=4, ttl=58, time=3 ms
32 bytes from 192.168.1.51: icmp_seq=5, ttl=58, time=3 ms
32 bytes from 192.168.1.51: icmp_seq=6, ttl=58, time=4 ms
32 bytes from 192.168.1.51: icmp_seq=7, ttl=58, time=4 ms
32 bytes from 192.168.1.51: icmp_seq=8, ttl=58, time=5 ms
32 bytes from 192.168.1.51: icmp_seq=9, ttl=58, time=3 ms
32 bytes from 192.168.1.51: icmp_seq=10, ttl=58, time=2 ms
send_to failed2:
send_to failed2:
send_to failed2:
send_to failed2:
send_to failed2:
send_to failed2:
send_to failed2:
send_to failed2:
send_to failed2:
send_to failed2:
send_to failed2:
send_to failed2:
send_to failed2:
send_to failed2:

额外信息:

我正在使用 boost-1.58sudo apt-get install libboost-all-dev 安装在 ubuntu16.04 .

更新:

感谢@273K 的慷慨帮助。

但双重释放或损坏似乎不是由 handle_receive() 的错误声明引起的因为即使 program which does not invoke handle_receive() anymore still面临类似的问题。这里是 backtrace .

最佳答案

我试过你的代码。面临的第一个错误:error C4700: uninitialized local variable 'flags' used。我已经更正了定义:

boost::asio::socket_base::message_flags flags{};

您已将示例中的 void handle_receive(std::size_t length) 扩展为 void handle_receive(boost::system::error_code 错误,std::size_t 长度)。这是不正确的。根据手册basic_raw_socket::async_receive ,它必须通过 const 引用接收 error

void handle_receive(const boost::system::error_code &error,
                    std::size_t length)

修复这些错误后,SIGABRT 消失了。

error.message() 应该通过引用访问 error ,但是您的定义指示编译器访问堆栈上的 error ,这会导致堆栈内存损坏,因为 handle_receive 的调用者将 sizeof(void*) 字节放在堆栈或 CPU 寄存器中,但 error.message( ) 在堆栈上使用 sizeof(boost::system::error_code) 个字节。

关于c++ - 使用 asio 时双重释放或损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72710159/

相关文章:

ubuntu - unison:如何同步多个目录中的特定子文件夹?

c++ - clang 和 gcc 中的这个警告似乎不正确

c++ - 在 C++11 中,如何在 vector 上调用 std::max?

c++ - 在 C++ 中将 vector 设置为矩阵算法帮助

c++ - 优化的内存

java - 在数组中找到 3 个或更多相同的对象?

docker - $'\r' : command not found with Docker Compose

ubuntu - libpcre.so.3.13.1 中的 php5-fpm 段错误 6

c++ - 如何使用带有 future<T> vector 的基于范围的 for 循环

C++:语句 'TYPE& name(&TYPE);' 是什么意思?