I made some modifications to this code snippet which is used to sendrecieve ICMP packets through ASIO APIs.
Here are the modifications that I made(full code snippet is seen below):
-
using the standard version API instead of the corresponding API provided by
Boost
- using
std::bind
instead ofboost::bind
- using
-
starting to use shared pointer
- using a shared pointer which points to
pinger
(i.e.std::shared_ptr<pinger> sp{new pinger(io_service, argv[1])};
) instead of contructing an instance directly by the default constructor ofpinger
(i.e.pinger p(io_service, argv[1]);
). - class
pinger
derives fromstd::enabled_shared_from_this<pinger>
now - the second argument passed to
boost::bind
is not athis
pointer anymore,I useshared_from_this()
to pass astd::shared_pointer
tostd::bind
.For exmple: my code istimer_.async_wait(std::bind(&pinger::start_send, shared_from_this()));
, whereas the orignal one istimer_.async_wait(boost::bind(&pinger::handle_timeout, this));
. - to avoid calling
shared_from_this()
in the constructor of classpinger
, thestart_send(); start_receive();
is moved out of the constructer and a new function namedInit()
is used to invoke these two aforemetioned functions.
- using a shared pointer which points to
-
using the non-throwing version
asio::raw_socket::send_to
and retrying to send ICMP packets when some error occurs.socket_.send_to(request_buffer.data(), destination_);
is replaced bysocket_.send_to(request_buffer.data(), destination_, flags, error);
- retry to send
ICMP
packets(bycalling timer_.async_wait(std::bind(&pinger::start_send, shared_from_this()));
whensocket_.send_to
faces to an error.
Here is my code snippet(icmp_header.hpp
& ipv4_header.hpp
are seen 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
The code snippet above works well when my local network is ok.Here is the output:
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
The program receives a signal SIGABRT and then aborts when I run sudo ifconfig wlp59s0 down
on purpose(to make sure whether the program is stable or not). Here is the backstrace I got by 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:
Thanks to @Basile Starynkevitch.
I try to use valgrind
to figure out the problem.I add add_compile_options(-Wall -Wextra)
in the CMakeLists.txt
(set (CMAKE_BUILD_TYPE debug)
has already been there when debugging with GDB
). I recompile the code sippet above and run it with sudo valgrind ...
. But what surprises me is that no signal is received now.
Here is the output which is seen in the terminal (with valgrind
on 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...
Here is what the valgrind.log
contains:
NOTE:1.since the program runs infinitely with valgrind
, the program is stopped by CTRL+C
. It’s strange that the same binary program still encounters SIGABRT with sudo gdb ...
when ifconfig down
is called in purpose.
2.The log is huge, full log is seen at 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)
What’s more, it’s strange that no signal would be recieved anymore if std::cout << "send_to failed1:" << error.message() << std::endl;
is commented out when sudo ifconfig wlp59s0 down
has been called. I don’t think the problem is with this expression.But I really can’t figure out where goes wrong. Could somebody shed some light on this matter?
(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:
Extra Information:
I am using boost-1.58
which is installed by sudo apt-get install libboost-all-dev
on ubuntu16.04
.
UPDATED:
Thanks to @273K’s generous help.
But the double free or corruption seems not caused by the wrong declaration of handle_receive()
because even if the program which does not invoke handle_receive()
anymore still faces a similar problem. Here is the backtrace.
2
Answers
I tried your code. The first error faced:
error C4700: uninitialized local variable 'flags' used
. I have corrected the definition:You have extended
void handle_receive(std::size_t length)
from the example tovoid handle_receive(boost::system::error_code error, std::size_t length)
. This is incorrect. According to the manual basic_raw_socket::async_receive, it must receiveerror
by const reference.After fixing those errors, the
SIGABRT
went away.error.message()
is supposed to accesserror
by reference, but your definition directs the compiler to accesserror
on the stack, that results in stack memory corruption, because the caller ofhandle_receive
placessizeof(void*)
bytes on the stack or in a CPU register, buterror.message()
usessizeof(boost::system::error_code)
bytes on the stack.The line expression
could be
Now, the fact that it crashes gives me the idea that you might be finding conflicting/incompatible versions of Boost System at runtime vs. at compile time. I know that
boost::error_code
received some layout-incompatible changes over time.Another source of such compatibility problem is when the linked libraries are built with very different compiler flags.
Use tools like
ldd
to check what libraries are actually found at runtime, and whether there are surprises. Also, check the preprocessed source (or e.g.BOOST_VERSION
) to see that no surprise header versions are picked up where you didn’t expect them.Inverting the burden of proof, I have created a docker environment to test your code and see that the problem is not reproduced, perhaps you can compare: ubu1604.zip containing:
File
Dockerfile
File
so/CMakeLists.txt
File
so/icmp_header.hpp
File
so/ipv4_header.hpp
File
so/test.cpp
Build:
Run:
Demo