Bug #3136
closedSegfault when shutting down face while there are multiple scheduled transmissions
100%
Description
The following snippet reproduces the error:
Face face;
face.expressInterest(Name("/Hello/World/!"), bind([]{}), bind([]{}));
face.processEvents(time::seconds(1));
face.expressInterest(Name("/Bye/World/1"), bind([]{}), bind([]{}));
face.expressInterest(Name("/Bye/World/2"), bind([]{}), bind([]{}));
face.expressInterest(Name("/Bye/World/3"), bind([]{}), bind([]{}));
face.shutdown();
face.processEvents(time::seconds(1));
Expected: no error
Actual: segfault
Updated by Alex Afanasyev over 9 years ago
- Status changed from In Progress to Code review
Updated by Alex Afanasyev over 9 years ago
- Status changed from Code review to Closed
Updated by Junxiao Shi over 8 years ago
- Status changed from Closed to Feedback
segfaults still occur in the test case on trusty64 platform.
Sometimes the error message is different ("segmentation fault" vs "memory access violation") when I specify -s n
aka --catch_system_errors no
.
vagrant@m0217:~/ndn-cxx$ build/tests/integrated/face -t TestFaces/ShutdownWhileSendInProgress
Running 1 test case...
unknown location(0): fatal error in "ShutdownWhileSendInProgress": memory access violation at address: 0x00000010: no mapping at fault address
../tests/integrated/face.cpp(510): last checkpoint
*** 1 failure detected in test suite "ndn-cxx Integrated Tests (Face)"
vagrant@m0217:~/ndn-cxx$ valgrind build/tests/integrated/face -t TestFaces/ShutdownWhileSendInProgress
==21948== Memcheck, a memory error detector
==21948== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==21948== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==21948== Command: build/tests/integrated/face -t TestFaces/ShutdownWhileSendInProgress
==21948==
Running 1 test case...
==21948== Invalid read of size 8
==21948== at 0x510EDFD: ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>::handleAsyncWrite(boost::system::error_code const&, std::_List_iterator<std::list<ndn::Block, std::allocator<ndn::Block> > >) (stream-transport.hpp:199)
==21948== by 0x510EA1C: operator()<const boost::system::error_code&, std::_List_iterator<std::list<ndn::Block, std::allocator<ndn::Block> > >&, void> (functional:601)
==21948== by 0x510EA1C: __call<void, const boost::system::error_code&, long unsigned int const&, 0ul, 1ul, 2ul> (functional:1296)
==21948== by 0x510EA1C: operator()<const boost::system::error_code&, long unsigned int const&, void> (functional:1355)
==21948== by 0x510EA1C: boost::asio::detail::write_op<boost::asio::basic_stream_socket<boost::asio::local::stream_protocol, boost::asio::stream_socket_service<boost::asio::local::stream_protocol> >, std::list<ndn::Block, std::allocator<ndn::Block> >, boost::asio::detail::transfer_all_t, std::_Bind<std::_Mem_fn<void (ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>::*)(boost::system::error_code const&, std::_List_iterator<std::list<ndn::Block, std::allocator<ndn::Block> > >)> (ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>*, std::_Placeholder<1>, std::_List_iterator<std::list<ndn::Block, std::allocator<ndn::Block> > >)> >::operator()(boost::system::error_code const&, unsigned long, int) (write.hpp:192)
==21948== by 0x510F0C3: operator() (bind_handler.hpp:127)
==21948== by 0x510F0C3: asio_handler_invoke<boost::asio::detail::binder2<boost::asio::detail::write_op<boost::asio::basic_stream_socket<boost::asio::local::stream_protocol>, std::list<ndn::Block>, boost::asio::detail::transfer_all_t, std::_Bind<std::_Mem_fn<void (ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>::*)(const boost::system::error_code&, std::_List_iterator<std::list<ndn::Block> >)>(ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>*, std::_Placeholder<1>, std::_List_iterator<std::list<ndn::Block> >)> >, boost::system::error_code, long unsigned int> > (handler_invoke_hook.hpp:64)
==21948== by 0x510F0C3: invoke<boost::asio::detail::binder2<boost::asio::detail::write_op<boost::asio::basic_stream_socket<boost::asio::local::stream_protocol>, std::list<ndn::Block>, boost::asio::detail::transfer_all_t, std::_Bind<std::_Mem_fn<void (ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>::*)(const boost::system::error_code&, std::_List_iterator<std::list<ndn::Block> >)>(ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>*, std::_Placeholder<1>, std::_List_iterator<std::list<ndn::Block> >)> >, boost::system::error_code, long unsigned int>, std::_Bind<std::_Mem_fn<void (ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>::*)(const boost::system::error_code&, std::_List_iterator<std::list<ndn::Block> >)>(ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>*, std::_Placeholder<1>, std::_List_iterator<std::list<ndn::Block> >)> > (handler_invoke_helpers.hpp:37)
==21948== by 0x510F0C3: asio_handler_invoke<boost::asio::detail::binder2<boost::asio::detail::write_op<boost::asio::basic_stream_socket<boost::asio::local::stream_protocol>, std::list<ndn::Block>, boost::asio::detail::transfer_all_t, std::_Bind<std::_Mem_fn<void (ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>::*)(const boost::system::error_code&, std::_List_iterator<std::list<ndn::Block> >)>(ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>*, std::_Placeholder<1>, std::_List_iterator<std::list<ndn::Block> >)> >, boost::system::error_code, long unsigned int>, boost::asio::basic_stream_socket<boost::asio::local::stream_protocol>, std::list<ndn::Block>, boost::asio::detail::transfer_all_t, std::_Bind<std::_Mem_fn<void (ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>::*)(const boost::system::error_code&, std::_List_iterator<std::list<ndn::Block> >)>(ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>*, std::_Placeholder<1>, std::_List_iterator<std::list<ndn::Block> >)> > (write.hpp:565)
==21948== by 0x510F0C3: invoke<boost::asio::detail::binder2<boost::asio::detail::write_op<boost::asio::basic_stream_socket<boost::asio::local::stream_protocol>, std::list<ndn::Block>, boost::asio::detail::transfer_all_t, std::_Bind<std::_Mem_fn<void (ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>::*)(const boost::system::error_code&, std::_List_iterator<std::list<ndn::Block> >)>(ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>*, std::_Placeholder<1>, std::_List_iterator<std::list<ndn::Block> >)> >, boost::system::error_code, long unsigned int>, boost::asio::detail::write_op<boost::asio::basic_stream_socket<boost::asio::local::stream_protocol>, std::list<ndn::Block>, boost::asio::detail::transfer_all_t, std::_Bind<std::_Mem_fn<void (ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>::*)(const boost::system::error_code&, std::_List_iterator<std::list<ndn::Block> >)>(ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>*, std::_Placeholder<1>, std::_List_iterator<std::list<ndn::Block> >)> > > (handler_invoke_helpers.hpp:37)
==21948== by 0x510F0C3: boost::asio::detail::reactive_socket_send_op<boost::asio::detail::consuming_buffers<boost::asio::const_buffer, std::list<ndn::Block, std::allocator<ndn::Block> > >, boost::asio::detail::write_op<boost::asio::basic_stream_socket<boost::asio::local::stream_protocol, boost::asio::stream_socket_service<boost::asio::local::stream_protocol> >, std::list<ndn::Block, std::allocator<ndn::Block> >, boost::asio::detail::transfer_all_t, std::_Bind<std::_Mem_fn<void (ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>::*)(boost::system::error_code const&, std::_List_iterator<std::list<ndn::Block, std::allocator<ndn::Block> > >)> (ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>*, std::_Placeholder<1>, std::_List_iterator<std::list<ndn::Block, std::allocator<ndn::Block> > >)> > >::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned long) (reactive_socket_send_op.hpp:107)
==21948== by 0x4FF2BB8: complete (task_io_service_operation.hpp:37)
==21948== by 0x4FF2BB8: do_run_one (task_io_service.ipp:384)
==21948== by 0x4FF2BB8: boost::asio::detail::task_io_service::run(boost::system::error_code&) (task_io_service.ipp:153)
==21948== by 0x4FEA867: run (io_service.ipp:59)
==21948== by 0x4FEA867: ndn::Face::processEvents(boost::chrono::duration<long, boost::ratio<1l, 1000l> > const&, bool) (face.cpp:464)
==21948== by 0x409702: ndn::tests::TestFaces::ShutdownWhileSendInProgress::test_method() (face.cpp:517)
==21948== by 0x409E92: ndn::tests::TestFaces::ShutdownWhileSendInProgress_invoker() (face.cpp:506)
==21948== by 0x41400C: invoke<void (*)()> (callback.hpp:56)
==21948== by 0x41400C: boost::unit_test::ut_detail::callback0_impl_t<boost::unit_test::ut_detail::unused, void (*)()>::invoke() (callback.hpp:89)
==21948== by 0x58A11F0: ??? (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.54.0)
==21948== by 0x587C545: boost::execution_monitor::catch_signals(boost::unit_test::callback0<int> const&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.54.0)
==21948== by 0x587CD82: boost::execution_monitor::execute(boost::unit_test::callback0<int> const&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.54.0)
==21948== by 0x58A12F1: boost::unit_test::unit_test_monitor_t::execute_and_translate(boost::unit_test::test_case const&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.54.0)
==21948== Address 0xa01fce8 is 24 bytes inside a block of size 8,960 free'd
==21948== at 0x4C2C2BC: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21948== by 0x510C316: deallocate (new_allocator.h:110)
==21948== by 0x510C316: deallocate (alloc_traits.h:377)
==21948== by 0x510C316: std::_Sp_counted_ptr_inplace<ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol>, std::allocator<ndn::StreamTransportImpl<ndn::UnixTransport, boost::asio::local::stream_protocol> >, (__gnu_cxx::_Lock_policy)2>::_M_destroy() (shared_ptr_base.h:417)
==21948== by 0x418497: std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() (shared_ptr_base.h:161)
==21948== by 0x510BAE3: ~__shared_count (shared_ptr_base.h:546)
==21948== by 0x510BAE3: ~__shared_ptr (shared_ptr_base.h:781)
==21948== by 0x510BAE3: reset (shared_ptr_base.h:882)
==21948== by 0x510BAE3: ndn::UnixTransport::close() (unix-transport.cpp:108)
==21948== by 0x4FEA9F6: ndn::Face::asyncShutdown() (face.cpp:487)
==21948== by 0x4FEAACE: operator() (face.cpp:477)
==21948== by 0x4FEAACE: asio_handler_invoke<ndn::Face::shutdown()::__lambda19> (handler_invoke_hook.hpp:64)
==21948== by 0x4FEAACE: invoke<ndn::Face::shutdown()::__lambda19, ndn::Face::shutdown()::__lambda19> (handler_invoke_helpers.hpp:37)
==21948== by 0x4FEAACE: boost::asio::detail::completion_handler<ndn::Face::shutdown()::{lambda()#1}>::do_complete(boost::asio::detail::task_io_service*, boost::asio::detail::task_io_service_operation*, boost::system::error_code const&, unsigned long) (completion_handler.hpp:68)
==21948== by 0x4FF2BB8: complete (task_io_service_operation.hpp:37)
==21948== by 0x4FF2BB8: do_run_one (task_io_service.ipp:384)
==21948== by 0x4FF2BB8: boost::asio::detail::task_io_service::run(boost::system::error_code&) (task_io_service.ipp:153)
==21948== by 0x4FEA867: run (io_service.ipp:59)
==21948== by 0x4FEA867: ndn::Face::processEvents(boost::chrono::duration<long, boost::ratio<1l, 1000l> > const&, bool) (face.cpp:464)
==21948== by 0x409702: ndn::tests::TestFaces::ShutdownWhileSendInProgress::test_method() (face.cpp:517)
==21948== by 0x409E92: ndn::tests::TestFaces::ShutdownWhileSendInProgress_invoker() (face.cpp:506)
==21948== by 0x41400C: invoke<void (*)()> (callback.hpp:56)
==21948== by 0x41400C: boost::unit_test::ut_detail::callback0_impl_t<boost::unit_test::ut_detail::unused, void (*)()>::invoke() (callback.hpp:89)
==21948== by 0x58A11F0: ??? (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.54.0)
==21948==
*** No errors detected
==21948==
==21948== HEAP SUMMARY:
==21948== in use at exit: 0 bytes in 0 blocks
==21948== total heap usage: 11,407 allocs, 11,407 frees, 2,372,205 bytes allocated
==21948==
==21948== All heap blocks were freed -- no leaks are possible
==21948==
==21948== For counts of detected and suppressed errors, rerun with: -v
==21948== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Updated by Junxiao Shi over 8 years ago
note-3 valgrind log indicates a memory access error in StreamTransportImpl<BaseTransport, Protocol>::handleAsyncWrite
, m_transport
variable.
If the face is destructed when a socket sending operation is in progress, the Transport
and StreamTransportImpl
are destructed as well, but the socket may still call the handleAsyncWrite
on an destructed instance, causing the memory error.
One potential solution is to inherit StreamTransportImpl<BaseTransport, Protocol>
from enable_shared_from_this
, and change the bind expression where handleAsyncWrite
is used to bind to a shared_ptr
rather than this
.
I'll test this solution. If it works, other bind expressions need to be changed as well.
Updated by Junxiao Shi over 8 years ago
- Status changed from Feedback to Resolved
- Assignee changed from Alex Afanasyev to Junxiao Shi
- Target version changed from v0.4 to v0.5
https://gerrit.named-data.net/2964 corrects code style in src/transport/
in preparation for the fix.
https://gerrit.named-data.net/2965 has the fix.
After this fix, valgrind build/tests/integrated/face -t TestFaces/ShutdownWhileSendInProgress
reports no memory error.
build/tests/integrated/face
still fails in other test cases, but they are irrelevant to this issue and will be investigated separately.