Project

General

Profile

Actions

Bug #3136

closed

Segfault when shutting down face while there are multiple scheduled transmissions

Added by Alex Afanasyev over 8 years ago. Updated over 7 years ago.

Status:
Closed
Priority:
Normal
Assignee:
Category:
Base
Target version:
Start date:
08/26/2015
Due date:
% Done:

100%

Estimated time:

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

Actions #1

Updated by Alex Afanasyev over 8 years ago

  • Status changed from In Progress to Code review
Actions #2

Updated by Alex Afanasyev over 8 years ago

  • Status changed from Code review to Closed
Actions #3

Updated by Junxiao Shi almost 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)
Actions #4

Updated by Junxiao Shi over 7 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.

Actions #5

Updated by Junxiao Shi over 7 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.

Actions #6

Updated by Junxiao Shi over 7 years ago

  • Status changed from Resolved to Closed
Actions

Also available in: Atom PDF