简体   繁体   中英

Valgrind errors from boost::asio

I came across strange errors reported by valgrind when analyzing my program. Could you help me to find their source?

Minimal example

main.cpp:

#define BOOST_ASIO_ENABLE_HANDLER_TRACKING

#include "foo.h"
#include <iostream>

int main()
{
    boost::asio::io_service ioService;
    Foo foo(ioService);
    ioService.run();
    return EXIT_SUCCESS;
}

foo.h:

#include <boost/asio.hpp>

class Foo
{
private:
    boost::asio::ip::tcp::resolver resolver_;

public:
    Foo(boost::asio::io_service & ioService);

    virtual ~Foo()
    {}
};

foo.cpp:

#include "foo.h"

Foo::Foo(boost::asio::io_service & ioService) : resolver_(ioService)
{
}

When compiled with g++ -g3 -O0 -lboost_system -lpthread -o main./main.cpp./foo.cpp and executed with valgrind./main valgrind reports 5 errors of type invalid write.

==14905== Memcheck, a memory error detector
==14905== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==14905== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==14905== Command: ./main
==14905== 
==14905== Invalid write of size 1
==14905==    at 0x406724: boost::asio::detail::scheduler::scheduler(boost::asio::execution_context&, int) (scheduler.ipp:103)
==14905==    by 0x40CBF6: boost::asio::io_context::io_context(int) (io_context.ipp:44)
==14905==    by 0x40CE22: boost::asio::detail::resolver_service_base::resolver_service_base(boost::asio::io_context&) (resolver_service_base.ipp:40)
==14905==    by 0x40DC6A: boost::asio::detail::resolver_service<boost::asio::ip::tcp>::resolver_service(boost::asio::io_context&) (resolver_service.hpp:58)
==14905==    by 0x40DA56: boost::asio::execution_context::service* boost::asio::detail::service_registry::create<boost::asio::detail::resolver_service<boost::asio::ip::tcp>, boost::asio::io_context>(void*) (service_registry.hpp:87)
==14905==    by 0x40C88F: boost::asio::detail::service_registry::do_use_service(boost::asio::execution_context::service::key const&, boost::asio::execution_context::service* (*)(void*), void*) (service_registry.ipp:132)
==14905==    by 0x40D86D: boost::asio::detail::resolver_service<boost::asio::ip::tcp>& boost::asio::detail::service_registry::use_service<boost::asio::detail::resolver_service<boost::asio::ip::tcp> >(boost::asio::io_context&) (service_registry.hpp:39)
==14905==    by 0x40D6A0: boost::asio::detail::resolver_service<boost::asio::ip::tcp>& boost::asio::use_service<boost::asio::detail::resolver_service<boost::asio::ip::tcp> >(boost::asio::io_context&) (io_context.hpp:39)
==14905==    by 0x40D596: boost::asio::basic_io_object<boost::asio::detail::resolver_service<boost::asio::ip::tcp>, true>::basic_io_object(boost::asio::io_context&) (basic_io_object.hpp:224)
==14905==    by 0x40D498: boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::basic_resolver(boost::asio::io_context&) (basic_resolver.hpp:101)
==14905==    by 0x40C544: Foo::Foo(boost::asio::io_context&) (foo.cpp:3)
==14905==    by 0x402D79: main (main.cpp:10)
==14905==  Address 0x5f06110 is 0 bytes after a block of size 240 alloc'd
==14905==    at 0x4C2E94F: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==14905==    by 0x40CBE1: boost::asio::io_context::io_context(int) (io_context.ipp:44)
==14905==    by 0x40CE22: boost::asio::detail::resolver_service_base::resolver_service_base(boost::asio::io_context&) (resolver_service_base.ipp:40)
==14905==    by 0x40DC6A: boost::asio::detail::resolver_service<boost::asio::ip::tcp>::resolver_service(boost::asio::io_context&) (resolver_service.hpp:58)
==14905==    by 0x40DA56: boost::asio::execution_context::service* boost::asio::detail::service_registry::create<boost::asio::detail::resolver_service<boost::asio::ip::tcp>, boost::asio::io_context>(void*) (service_registry.hpp:87)
==14905==    by 0x40C88F: boost::asio::detail::service_registry::do_use_service(boost::asio::execution_context::service::key const&, boost::asio::execution_context::service* (*)(void*), void*) (service_registry.ipp:132)
==14905==    by 0x40D86D: boost::asio::detail::resolver_service<boost::asio::ip::tcp>& boost::asio::detail::service_registry::use_service<boost::asio::detail::resolver_service<boost::asio::ip::tcp> >(boost::asio::io_context&) (service_registry.hpp:39)
==14905==    by 0x40D6A0: boost::asio::detail::resolver_service<boost::asio::ip::tcp>& boost::asio::use_service<boost::asio::detail::resolver_service<boost::asio::ip::tcp> >(boost::asio::io_context&) (io_context.hpp:39)
==14905==    by 0x40D596: boost::asio::basic_io_object<boost::asio::detail::resolver_service<boost::asio::ip::tcp>, true>::basic_io_object(boost::asio::io_context&) (basic_io_object.hpp:224)
==14905==    by 0x40D498: boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::basic_resolver(boost::asio::io_context&) (basic_resolver.hpp:101)
==14905==    by 0x40C544: Foo::Foo(boost::asio::io_context&) (foo.cpp:3)
==14905==    by 0x402D79: main (main.cpp:10)
==14905== 
==14905== Invalid write of size 1
==14905==    at 0x40672F: boost::asio::detail::scheduler::scheduler(boost::asio::execution_context&, int) (scheduler.ipp:103)
==14905==    by 0x40CBF6: boost::asio::io_context::io_context(int) (io_context.ipp:44)
==14905==    by 0x40CE22: boost::asio::detail::resolver_service_base::resolver_service_base(boost::asio::io_context&) (resolver_service_base.ipp:40)
==14905==    by 0x40DC6A: boost::asio::detail::resolver_service<boost::asio::ip::tcp>::resolver_service(boost::asio::io_context&) (resolver_service.hpp:58)
==14905==    by 0x40DA56: boost::asio::execution_context::service* boost::asio::detail::service_registry::create<boost::asio::detail::resolver_service<boost::asio::ip::tcp>, boost::asio::io_context>(void*) (service_registry.hpp:87)
==14905==    by 0x40C88F: boost::asio::detail::service_registry::do_use_service(boost::asio::execution_context::service::key const&, boost::asio::execution_context::service* (*)(void*), void*) (service_registry.ipp:132)
==14905==    by 0x40D86D: boost::asio::detail::resolver_service<boost::asio::ip::tcp>& boost::asio::detail::service_registry::use_service<boost::asio::detail::resolver_service<boost::asio::ip::tcp> >(boost::asio::io_context&) (service_registry.hpp:39)
==14905==    by 0x40D6A0: boost::asio::detail::resolver_service<boost::asio::ip::tcp>& boost::asio::use_service<boost::asio::detail::resolver_service<boost::asio::ip::tcp> >(boost::asio::io_context&) (io_context.hpp:39)
==14905==    by 0x40D596: boost::asio::basic_io_object<boost::asio::detail::resolver_service<boost::asio::ip::tcp>, true>::basic_io_object(boost::asio::io_context&) (basic_io_object.hpp:224)
==14905==    by 0x40D498: boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::basic_resolver(boost::asio::io_context&) (basic_resolver.hpp:101)
==14905==    by 0x40C544: Foo::Foo(boost::asio::io_context&) (foo.cpp:3)
==14905==    by 0x402D79: main (main.cpp:10)
==14905==  Address 0x5f06111 is 1 bytes after a block of size 240 alloc'd
==14905==    at 0x4C2E94F: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==14905==    by 0x40CBE1: boost::asio::io_context::io_context(int) (io_context.ipp:44)
==14905==    by 0x40CE22: boost::asio::detail::resolver_service_base::resolver_service_base(boost::asio::io_context&) (resolver_service_base.ipp:40)
==14905==    by 0x40DC6A: boost::asio::detail::resolver_service<boost::asio::ip::tcp>::resolver_service(boost::asio::io_context&) (resolver_service.hpp:58)
==14905==    by 0x40DA56: boost::asio::execution_context::service* boost::asio::detail::service_registry::create<boost::asio::detail::resolver_service<boost::asio::ip::tcp>, boost::asio::io_context>(void*) (service_registry.hpp:87)
==14905==    by 0x40C88F: boost::asio::detail::service_registry::do_use_service(boost::asio::execution_context::service::key const&, boost::asio::execution_context::service* (*)(void*), void*) (service_registry.ipp:132)
==14905==    by 0x40D86D: boost::asio::detail::resolver_service<boost::asio::ip::tcp>& boost::asio::detail::service_registry::use_service<boost::asio::detail::resolver_service<boost::asio::ip::tcp> >(boost::asio::io_context&) (service_registry.hpp:39)
==14905==    by 0x40D6A0: boost::asio::detail::resolver_service<boost::asio::ip::tcp>& boost::asio::use_service<boost::asio::detail::resolver_service<boost::asio::ip::tcp> >(boost::asio::io_context&) (io_context.hpp:39)
==14905==    by 0x40D596: boost::asio::basic_io_object<boost::asio::detail::resolver_service<boost::asio::ip::tcp>, true>::basic_io_object(boost::asio::io_context&) (basic_io_object.hpp:224)
==14905==    by 0x40D498: boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::basic_resolver(boost::asio::io_context&) (basic_resolver.hpp:101)
==14905==    by 0x40C544: Foo::Foo(boost::asio::io_context&) (foo.cpp:3)
==14905==    by 0x402D79: main (main.cpp:10)
==14905== 
==14905== Invalid write of size 4
==14905==    at 0x40673D: boost::asio::detail::scheduler::scheduler(boost::asio::execution_context&, int) (scheduler.ipp:103)
==14905==    by 0x40CBF6: boost::asio::io_context::io_context(int) (io_context.ipp:44)
==14905==    by 0x40CE22: boost::asio::detail::resolver_service_base::resolver_service_base(boost::asio::io_context&) (resolver_service_base.ipp:40)
==14905==    by 0x40DC6A: boost::asio::detail::resolver_service<boost::asio::ip::tcp>::resolver_service(boost::asio::io_context&) (resolver_service.hpp:58)
==14905==    by 0x40DA56: boost::asio::execution_context::service* boost::asio::detail::service_registry::create<boost::asio::detail::resolver_service<boost::asio::ip::tcp>, boost::asio::io_context>(void*) (service_registry.hpp:87)
==14905==    by 0x40C88F: boost::asio::detail::service_registry::do_use_service(boost::asio::execution_context::service::key const&, boost::asio::execution_context::service* (*)(void*), void*) (service_registry.ipp:132)
==14905==    by 0x40D86D: boost::asio::detail::resolver_service<boost::asio::ip::tcp>& boost::asio::detail::service_registry::use_service<boost::asio::detail::resolver_service<boost::asio::ip::tcp> >(boost::asio::io_context&) (service_registry.hpp:39)
==14905==    by 0x40D6A0: boost::asio::detail::resolver_service<boost::asio::ip::tcp>& boost::asio::use_service<boost::asio::detail::resolver_service<boost::asio::ip::tcp> >(boost::asio::io_context&) (io_context.hpp:39)
==14905==    by 0x40D596: boost::asio::basic_io_object<boost::asio::detail::resolver_service<boost::asio::ip::tcp>, true>::basic_io_object(boost::asio::io_context&) (basic_io_object.hpp:224)
==14905==    by 0x40D498: boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::basic_resolver(boost::asio::io_context&) (basic_resolver.hpp:101)
==14905==    by 0x40C544: Foo::Foo(boost::asio::io_context&) (foo.cpp:3)
==14905==    by 0x402D79: main (main.cpp:10)
==14905==  Address 0x5f06114 is 4 bytes after a block of size 240 alloc'd
==14905==    at 0x4C2E94F: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==14905==    by 0x40CBE1: boost::asio::io_context::io_context(int) (io_context.ipp:44)
==14905==    by 0x40CE22: boost::asio::detail::resolver_service_base::resolver_service_base(boost::asio::io_context&) (resolver_service_base.ipp:40)
==14905==    by 0x40DC6A: boost::asio::detail::resolver_service<boost::asio::ip::tcp>::resolver_service(boost::asio::io_context&) (resolver_service.hpp:58)
==14905==    by 0x40DA56: boost::asio::execution_context::service* boost::asio::detail::service_registry::create<boost::asio::detail::resolver_service<boost::asio::ip::tcp>, boost::asio::io_context>(void*) (service_registry.hpp:87)
==14905==    by 0x40C88F: boost::asio::detail::service_registry::do_use_service(boost::asio::execution_context::service::key const&, boost::asio::execution_context::service* (*)(void*), void*) (service_registry.ipp:132)
==14905==    by 0x40D86D: boost::asio::detail::resolver_service<boost::asio::ip::tcp>& boost::asio::detail::service_registry::use_service<boost::asio::detail::resolver_service<boost::asio::ip::tcp> >(boost::asio::io_context&) (service_registry.hpp:39)
==14905==    by 0x40D6A0: boost::asio::detail::resolver_service<boost::asio::ip::tcp>& boost::asio::use_service<boost::asio::detail::resolver_service<boost::asio::ip::tcp> >(boost::asio::io_context&) (io_context.hpp:39)
==14905==    by 0x40D596: boost::asio::basic_io_object<boost::asio::detail::resolver_service<boost::asio::ip::tcp>, true>::basic_io_object(boost::asio::io_context&) (basic_io_object.hpp:224)
==14905==    by 0x40D498: boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::basic_resolver(boost::asio::io_context&) (basic_resolver.hpp:101)
==14905==    by 0x40C544: Foo::Foo(boost::asio::io_context&) (foo.cpp:3)
==14905==    by 0x402D79: main (main.cpp:10)
==14905== 
@asio|1589278153.511608|0|resolver@0x1ffefff910.cancel
==14905== Invalid write of size 1
==14905==    at 0x406D20: boost::asio::detail::scheduler::stop_all_threads(boost::asio::detail::conditionally_enabled_mutex::scoped_lock&) (scheduler.ipp:543)
==14905==    by 0x406A9E: boost::asio::detail::scheduler::stop() (scheduler.ipp:257)
==14905==    by 0x40CC67: boost::asio::io_context::stop() (io_context.ipp:121)
==14905==    by 0x40CF79: boost::asio::detail::resolver_service_base::base_shutdown() (resolver_service_base.ipp:58)
==14905==    by 0x40DFD9: boost::asio::detail::resolver_service<boost::asio::ip::tcp>::shutdown() (resolver_service.hpp:65)
==14905==    by 0x405335: boost::asio::detail::service_registry::shutdown_services() (service_registry.ipp:44)
==14905==    by 0x40568C: boost::asio::execution_context::shutdown() (execution_context.ipp:41)
==14905==    by 0x405630: boost::asio::execution_context::~execution_context() (execution_context.ipp:34)
==14905==    by 0x4070A1: boost::asio::io_context::~io_context() (io_context.ipp:55)
==14905==    by 0x402DA2: main (main.cpp:9)
==14905==  Address 0x5f06110 is 0 bytes after a block of size 240 alloc'd
==14905==    at 0x4C2E94F: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==14905==    by 0x40CBE1: boost::asio::io_context::io_context(int) (io_context.ipp:44)
==14905==    by 0x40CE22: boost::asio::detail::resolver_service_base::resolver_service_base(boost::asio::io_context&) (resolver_service_base.ipp:40)
==14905==    by 0x40DC6A: boost::asio::detail::resolver_service<boost::asio::ip::tcp>::resolver_service(boost::asio::io_context&) (resolver_service.hpp:58)
==14905==    by 0x40DA56: boost::asio::execution_context::service* boost::asio::detail::service_registry::create<boost::asio::detail::resolver_service<boost::asio::ip::tcp>, boost::asio::io_context>(void*) (service_registry.hpp:87)
==14905==    by 0x40C88F: boost::asio::detail::service_registry::do_use_service(boost::asio::execution_context::service::key const&, boost::asio::execution_context::service* (*)(void*), void*) (service_registry.ipp:132)
==14905==    by 0x40D86D: boost::asio::detail::resolver_service<boost::asio::ip::tcp>& boost::asio::detail::service_registry::use_service<boost::asio::detail::resolver_service<boost::asio::ip::tcp> >(boost::asio::io_context&) (service_registry.hpp:39)
==14905==    by 0x40D6A0: boost::asio::detail::resolver_service<boost::asio::ip::tcp>& boost::asio::use_service<boost::asio::detail::resolver_service<boost::asio::ip::tcp> >(boost::asio::io_context&) (io_context.hpp:39)
==14905==    by 0x40D596: boost::asio::basic_io_object<boost::asio::detail::resolver_service<boost::asio::ip::tcp>, true>::basic_io_object(boost::asio::io_context&) (basic_io_object.hpp:224)
==14905==    by 0x40D498: boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::basic_resolver(boost::asio::io_context&) (basic_resolver.hpp:101)
==14905==    by 0x40C544: Foo::Foo(boost::asio::io_context&) (foo.cpp:3)
==14905==    by 0x402D79: main (main.cpp:10)
==14905== 
==14905== Invalid write of size 1
==14905==    at 0x4067E2: boost::asio::detail::scheduler::shutdown() (scheduler.ipp:111)
==14905==    by 0x405335: boost::asio::detail::service_registry::shutdown_services() (service_registry.ipp:44)
==14905==    by 0x40568C: boost::asio::execution_context::shutdown() (execution_context.ipp:41)
==14905==    by 0x405630: boost::asio::execution_context::~execution_context() (execution_context.ipp:34)
==14905==    by 0x4070A1: boost::asio::io_context::~io_context() (io_context.ipp:55)
==14905==    by 0x40D37A: boost::asio::detail::scoped_ptr<boost::asio::io_context>::reset(boost::asio::io_context*) (scoped_ptr.hpp:63)
==14905==    by 0x40CFD5: boost::asio::detail::resolver_service_base::base_shutdown() (resolver_service_base.ipp:64)
==14905==    by 0x40DFD9: boost::asio::detail::resolver_service<boost::asio::ip::tcp>::shutdown() (resolver_service.hpp:65)
==14905==    by 0x405335: boost::asio::detail::service_registry::shutdown_services() (service_registry.ipp:44)
==14905==    by 0x40568C: boost::asio::execution_context::shutdown() (execution_context.ipp:41)
==14905==    by 0x405630: boost::asio::execution_context::~execution_context() (execution_context.ipp:34)
==14905==    by 0x4070A1: boost::asio::io_context::~io_context() (io_context.ipp:55)
==14905==  Address 0x5f06111 is 1 bytes after a block of size 240 alloc'd
==14905==    at 0x4C2E94F: operator new(unsigned long) (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==14905==    by 0x40CBE1: boost::asio::io_context::io_context(int) (io_context.ipp:44)
==14905==    by 0x40CE22: boost::asio::detail::resolver_service_base::resolver_service_base(boost::asio::io_context&) (resolver_service_base.ipp:40)
==14905==    by 0x40DC6A: boost::asio::detail::resolver_service<boost::asio::ip::tcp>::resolver_service(boost::asio::io_context&) (resolver_service.hpp:58)
==14905==    by 0x40DA56: boost::asio::execution_context::service* boost::asio::detail::service_registry::create<boost::asio::detail::resolver_service<boost::asio::ip::tcp>, boost::asio::io_context>(void*) (service_registry.hpp:87)
==14905==    by 0x40C88F: boost::asio::detail::service_registry::do_use_service(boost::asio::execution_context::service::key const&, boost::asio::execution_context::service* (*)(void*), void*) (service_registry.ipp:132)
==14905==    by 0x40D86D: boost::asio::detail::resolver_service<boost::asio::ip::tcp>& boost::asio::detail::service_registry::use_service<boost::asio::detail::resolver_service<boost::asio::ip::tcp> >(boost::asio::io_context&) (service_registry.hpp:39)
==14905==    by 0x40D6A0: boost::asio::detail::resolver_service<boost::asio::ip::tcp>& boost::asio::use_service<boost::asio::detail::resolver_service<boost::asio::ip::tcp> >(boost::asio::io_context&) (io_context.hpp:39)
==14905==    by 0x40D596: boost::asio::basic_io_object<boost::asio::detail::resolver_service<boost::asio::ip::tcp>, true>::basic_io_object(boost::asio::io_context&) (basic_io_object.hpp:224)
==14905==    by 0x40D498: boost::asio::ip::basic_resolver<boost::asio::ip::tcp>::basic_resolver(boost::asio::io_context&) (basic_resolver.hpp:101)
==14905==    by 0x40C544: Foo::Foo(boost::asio::io_context&) (foo.cpp:3)
==14905==    by 0x402D79: main (main.cpp:10)
==14905== 
==14905== 
==14905== HEAP SUMMARY:
==14905==     in use at exit: 1 bytes in 1 blocks
==14905==   total heap usage: 18 allocs, 17 frees, 79,744 bytes allocated
==14905== 
==14905== LEAK SUMMARY:
==14905==    definitely lost: 0 bytes in 0 blocks
==14905==    indirectly lost: 0 bytes in 0 blocks
==14905==      possibly lost: 0 bytes in 0 blocks
==14905==    still reachable: 1 bytes in 1 blocks
==14905==         suppressed: 0 bytes in 0 blocks
==14905== Rerun with --leak-check=full to see details of leaked memory
==14905== 
==14905== For lists of detected and suppressed errors, rerun with: -s
==14905== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 0 from 0)

I am using g++ 8.2.1 on openSUSE Leap 15.1, valgrind 3.15.0 and boost 1.66.0 (also tested with 1.71.0).

Some observations

  • No errors are reported without macro BOOST_ASIO_ENABLE_HANDLER_TRACKING .
  • No errors are reported if the body of a constructor Foo() is in foo.h (ie whole code is in one compilation unit).
  • No errors are reported without resolver_ in class Foo.

Bigger picture
I noticed that a bit more complicated program of mine was sometimes ignoring signals (also handled by boost::asio). So I added BOOST_ASIO_ENABLE_HANDLER_TRACKING and it started crashing (repeatedly) and valgrind started reporting 'Invalid write' errors (followed by an error of type 'Jump to an invalid address').

Speculations

  • Macro BOOST_ASIO_ENABLE_HANDLER_TRACKING revealed an error in boost::asio which causes my signals to be sometines ignored without the macro.
  • Valgrind generates a false alarm.
  • The most likely: my code contains an unforgivable and obvious error which I cannot see yet.

I don't see an unforgiveable mistake.

I do see a possible ODR violation. Define BOOST_ASIO_ENABLE_HANDLER_TRACKING globally or not at all. As it stands, you have one TU that defines it, one (or more) that doesn't. This is UB.

I've seen UB due to this particular condition in my own code-base before, so I'm pretty sure this is your problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM