尝试引用已销毁的thread_info

时间:2018-07-20 08:28:39

标签: c++ boost shared-ptr boost-thread

编辑:我创建了一个独立的应用程序,该应用程序引起了问题。通常,它需要进行1000次以上的循环迭代(线程的创建/运行/连接),有时直到几千次迭代才会崩溃:

#include <boost/thread.hpp>
static void do_nothing() {}

int main() {
    int thread_count = 0;
    while (true) {
        thread_count++;
        boost::thread t1(boost::bind(&do_nothing));
        if (t1.joinable()) {
            t1.join();
        }
    }
}

这是地址清理器转储使用释放的内存后的地址:

=================================================================
==96437==ERROR: AddressSanitizer: heap-use-after-free on address 0x058526f4 at pc 0x000a22cb bp 0xbffff4a8 sp 0xbffff4a4
WRITE of size 4 at 0x058526f4 thread T0
atos(96439,0x100357380) malloc: enabling scribbling to detect mods to free blocks
    #0 0xa22ca in boost::detail::atomic_decrement(int _Atomic*) sp_counted_base_clang.hpp:36
    #1 0xa21be in boost::detail::sp_counted_base::release() sp_counted_base_clang.hpp:115
    #2 0xa2157 in boost::detail::shared_count::~shared_count() shared_count.hpp:473
    #3 0xa115b in boost::detail::shared_count::~shared_count() shared_count.hpp:472
    #4 0x1ae8e63 in boost::thread::join_noexcept() shared_ptr.hpp:779
    #5 0x989a8c in boost::thread::join() thread.hpp:766
    #6 0x989366 in main main.cpp

0x058526f4 is located 4 bytes inside of 16-byte region [0x058526f0,0x05852700)
freed by thread T0 here:
    #0 0x35ca20d in wrap__ZdlPv (libclang_rt.asan_osx_dynamic.dylib:i386+0x6520d)
    #1 0x9ab89c in boost::detail::sp_counted_impl_p<boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> > >::~sp_counted_impl_p() sp_counted_impl.hpp:53
    #2 0xa1dd1 in boost::detail::sp_counted_base::destroy() sp_counted_base_clang.hpp:97
    #3 0xa23e7 in boost::detail::sp_counted_base::weak_release() sp_counted_base_clang.hpp:131
    #4 0xa2262 in boost::detail::sp_counted_base::release() sp_counted_base_clang.hpp:118
    #5 0xa2157 in boost::detail::shared_count::~shared_count() shared_count.hpp:473
    #6 0xa115b in boost::detail::shared_count::~shared_count() shared_count.hpp:472
    #7 0x1ae8e56 in boost::thread::join_noexcept() shared_ptr.hpp:779
    #8 0x989a8c in boost::thread::join() thread.hpp:766
    #9 0x989366 in main main.cpp

previously allocated by thread T0 here:
    #0 0x35c9c0d in wrap__Znwm (libclang_rt.asan_osx_dynamic.dylib:i386+0x64c0d)
    #1 0x9ab357 in boost::detail::shared_count::shared_count<boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> > >(boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >*) shared_count.hpp:137
    #2 0x9ab214 in boost::detail::shared_count::shared_count<boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> > >(boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >*) shared_count.hpp:132
    #3 0x9aaf88 in void boost::detail::sp_pointer_construct<boost::detail::thread_data_base, boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> > >(boost::shared_ptr<boost::detail::thread_data_base>*, boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >*, boost::detail::shared_count&) shared_ptr.hpp:284
    #4 0x9aae3b in boost::shared_ptr<boost::detail::thread_data_base>::shared_ptr<boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> > >(boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >*) shared_ptr.hpp:362
    #5 0x99c804 in boost::shared_ptr<boost::detail::thread_data_base>::shared_ptr<boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> > >(boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >*) shared_ptr.hpp:361
    #6 0x99c407 in boost::shared_ptr<boost::detail::thread_data_base> boost::thread::make_thread_info<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >(boost::_bi::bind_t<void, void (*)(), boost::_bi::list0>, boost::disable_if_c<is_same<boost::decay<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >::type, boost::thread>::value, boost::thread::dummy*>::type) thread.hpp:229
    #7 0x99c120 in boost::thread::thread<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >(boost::_bi::bind_t<void, void (*)(), boost::_bi::list0>, boost::disable_if_c<boost::thread_detail::is_rv<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >::value, boost::thread::dummy*>::type) thread.hpp:299
    #8 0x989826 in boost::thread::thread<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >(boost::_bi::bind_t<void, void (*)(), boost::_bi::list0>, boost::disable_if_c<boost::thread_detail::is_rv<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >::value, boost::thread::dummy*>::type) thread.hpp:300
    #9 0x989366 in main main.cpp

SUMMARY: AddressSanitizer: heap-use-after-free sp_counted_base_clang.hpp:36 in boost::detail::atomic_decrement(int _Atomic*)
Shadow bytes around the buggy address:
  0x20b0a480: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x20b0a490: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x20b0a4a0: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x20b0a4b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x20b0a4c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x20b0a4d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa[fd]fd
  0x20b0a4e0: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x20b0a4f0: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x20b0a500: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x20b0a510: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x20b0a520: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb

 =================================================================
 ==96437==ERROR: AddressSanitizer: heap-use-after-free on address 0x058526f4 at pc 0x000a22cb bp 0xbffff4a8 sp 0xbffff4a4
 WRITE of size 4 at 0x058526f4 thread T0
     #0 0xa22ca in boost::detail::atomic_decrement(int _Atomic*) sp_counted_base_clang.hpp:36
     #1 0xa21be in boost::detail::sp_counted_base::release() sp_counted_base_clang.hpp:115
     #2 0xa2157 in boost::detail::shared_count::~shared_count() shared_count.hpp:473
     #3 0xa115b in boost::detail::shared_count::~shared_count() shared_count.hpp:472
     #4 0x1ae8e63 in boost::thread::join_noexcept() shared_ptr.hpp:779
     #5 0x989a8c in boost::thread::join() thread.hpp:766
     #6 0x989366 in main main.cpp

 0x058526f4 is located 4 bytes inside of 16-byte region [0x058526f0,0x05852700)
 freed by thread T0 here:
     #0 0x35ca20d in wrap__ZdlPv (libclang_rt.asan_osx_dynamic.dylib:i386+0x6520d)
     #1 0x9ab89c in boost::detail::sp_counted_impl_p<boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> > >::~sp_counted_impl_p() sp_counted_impl.hpp:53
     #2 0xa1dd1 in boost::detail::sp_counted_base::destroy() sp_counted_base_clang.hpp:97
     #3 0xa23e7 in boost::detail::sp_counted_base::weak_release() sp_counted_base_clang.hpp:131
     #4 0xa2262 in boost::detail::sp_counted_base::release() sp_counted_base_clang.hpp:118
     #5 0xa2157 in boost::detail::shared_count::~shared_count() shared_count.hpp:473
     #6 0xa115b in boost::detail::shared_count::~shared_count() shared_count.hpp:472
     #7 0x1ae8e56 in boost::thread::join_noexcept() shared_ptr.hpp:779
     #8 0x989a8c in boost::thread::join() thread.hpp:766
     #9 0x989366 in main main.cpp

 previously allocated by thread T0 here:
     #0 0x35c9c0d in wrap__Znwm (libclang_rt.asan_osx_dynamic.dylib:i386+0x64c0d)
     #1 0x9ab357 in boost::detail::shared_count::shared_count<boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> > >(boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >*) shared_count.hpp:137
     #2 0x9ab214 in boost::detail::shared_count::shared_count<boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> > >(boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >*) shared_count.hpp:132
     #3 0x9aaf88 in void boost::detail::sp_pointer_construct<boost::detail::thread_data_base, boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> > >(boost::shared_ptr<boost::detail::thread_data_base>*, boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >*, boost::detail::shared_count&) shared_ptr.hpp:284
     #4 0x9aae3b in boost::shared_ptr<boost::detail::thread_data_base>::shared_ptr<boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> > >(boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >*) shared_ptr.hpp:362
     #5 0x99c804 in boost::shared_ptr<boost::detail::thread_data_base>::shared_ptr<boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> > >(boost::detail::thread_data<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >*) shared_ptr.hpp:361
     #6 0x99c407 in boost::shared_ptr<boost::detail::thread_data_base> boost::thread::make_thread_info<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >(boost::_bi::bind_t<void, void (*)(), boost::_bi::list0>, boost::disable_if_c<is_same<boost::decay<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >::type, boost::thread>::value, boost::thread::dummy*>::type) thread.hpp:229
     #7 0x99c120 in boost::thread::thread<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >(boost::_bi::bind_t<void, void (*)(), boost::_bi::list0>, boost::disable_if_c<boost::thread_detail::is_rv<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >::value, boost::thread::dummy*>::type) thread.hpp:299
     #8 0x989826 in boost::thread::thread<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >(boost::_bi::bind_t<void, void (*)(), boost::_bi::list0>, boost::disable_if_c<boost::thread_detail::is_rv<boost::_bi::bind_t<void, void (*)(), boost::_bi::list0> >::value, boost::thread::dummy*>::type) thread.hpp:300
     #9 0x989366 in main main.cpp

 SUMMARY: AddressSanitizer: heap-use-after-free sp_counted_base_clang.hpp:36 in boost::detail::atomic_decrement(int _Atomic*)
 Shadow bytes around the buggy address:
   0x20b0a480: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
   0x20b0a490: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
   0x20b0a4a0: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
   0x20b0a4b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
   0x20b0a4c0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
 =>0x20b0a4d0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa[fd]fd
   0x20b0a4e0: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
   0x20b0a4f0: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
   0x20b0a500: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
   0x20b0a510: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
   0x20b0a520: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
 Shadow byte legend (one shadow byte represents 8 application bytes):
   Addressable:           00
   Partially addressable: 01 02 03 04 05 06 07
   Heap left redzone:       fa
   Freed heap region:       fd
   Stack left redzone:      f1
   Stack mid redzone:       f2
   Stack right redzone:     f3
   Stack after return:      f5
   Stack use after scope:   f8
   Global redzone:          f9
   Global init order:       f6
   Poisoned by user:        f7
   Container overflow:      fc
   Array cookie:            ac
   Intra object redzone:    bb
   ASan internal:           fe
   Left alloca redzone:     ca
   Right alloca redzone:    cb

构建环境:Boost 1.63在具有libc ++的macOS LLVM 9.0下构建(主机应用程序与此相同)。主机正在运行调试版本,因此没有编译器优化。 Boost可能是在优化的基础上构建的,但我必须对此进行研究。

有人对我应该去哪里有任何线索? TBH,我不确定在完全重置shared_ptr的情况下join_noexcept()在做什么–为什么有必要?我不认为这是Boost错误,但我对寻找位置感到迷惑。主机应用程序当然可以踩踏某些东西,但是我已经对此进行了广泛研究,但还没有发现任何东西。当join()发生时,崩溃始终会发生。

在创建上面的最小案例示例之前的原始帖子:在等待通过join()关闭通信线程时,我很少看到崩溃。崩溃很少发生,但是在每秒大约3次打开/关闭通信线程几个小时之后,我可以通过一些压力测试来重现它。

我在启用调试内存选项(僵尸块等)的情况下捕获了崩溃,并显示了in:

thread::join_noexcept()
{
            ...
            if(thread_info==local_thread_info)
            {
                thread_info.reset();
            }
            ...
}

由于条件为True,所以执行reset()会导致thread_data被如下所示的堆栈破坏:

detail::sp_counted_impl_p<boost::detail::thread_data<CThreadAdapter> >::~sp_counted_impl_p() at sp_counted_impl.hpp:53
detail::sp_counted_base::destroy() at sp_counted_base_clang.hpp:97
detail::sp_counted_base::weak_release() at sp_counted_base_clang.hpp:131
detail::sp_counted_base::release() at sp_counted_base_clang.hpp:118
detail::shared_count::~shared_count() at shared_count.hpp:473
detail::shared_count::~shared_count() at shared_count.hpp:472
shared_ptr<boost::detail::thread_data_base>::~shared_ptr() [inlined] at shared_ptr.hpp:779
shared_ptr<boost::detail::thread_data_base>::~shared_ptr() [inlined] at shared_ptr.hpp:779
shared_ptr<boost::detail::thread_data_base>::reset() [inlined] at shared_ptr.hpp:667
thread::join_noexcept() at thread.cpp:343
thread::join() at thread.hpp:766

(以上不是崩溃,而是释放内存的位置,稍后再引用)

然后,当销毁它的本地对象时,崩溃在同一join_noexcept()调用中发生。看来它尝试访问已释放的thread_data(我认为):

detail::atomic_decrement(int _Atomic*) at sp_counted_base_clang.hpp:36
detail::sp_counted_base::release() at sp_counted_base_clang.hpp:115
detail::shared_count::~shared_count() at shared_count.hpp:473
detail::shared_count::~shared_count() at shared_count.hpp:472
shared_ptr<boost::detail::thread_data_base>::~shared_ptr() [inlined] at shared_ptr.hpp:779
shared_ptr<boost::detail::thread_data_base>::~shared_ptr() [inlined] at shared_ptr.hpp:779
thread::join_noexcept() at thread.cpp:351
thread::join() at thread.hpp:766

2 个答案:

答案 0 :(得分:0)

添加的自包含代码价值一千个字。

很显然,该错误不在驱动程序代码中,因此很难将其归咎于boost。这样就离开了

  • 资源泄漏
  • 由于ODR / ABI问题导致的未定义行为

您的信息表明,您在使用兼容的编译器,库和标志构建库和测试程序时要格外小心。这种方式排除了ABI / ODR问题。

这使我陷入资源泄漏。在我看来,如果在“ joinable()”周围存在任何竞争,则有条件地加入的风险是不加入线程。我本来不会想到这种情况,但是在您简单的独立示例中,您可以看到以下情况之一是否可以消除崩溃:

  • 删除条件:

    PRIMES_FOO_X(func)
  • 避免竞争(通过延迟#include <boost/thread.hpp> #include <iostream> static void do_nothing() {} int main() { uintmax_t thread_count = 0; while (++thread_count) { boost::thread(do_nothing).join(); } std::cout << "Done\n"; } 退出,或通过使用同步原语向线程结束发出信号)。公平地说,这让我感到震惊,因为它是“解决方法”,它指示库错误。

答案 1 :(得分:0)

好吧,问题出在我正在用以下命令构建libboost_thread库中  BOOST_AC_USE_PTHREADS定义为BOOST_SP_USE_PTHREADS。我不确定是哪一种引起的,但是其中一种会导致线程析构函数崩溃,其中线程数据的shared_ptr被破坏两次。但是,在针对macOS时,这些标志都不需要。因此,通过删除它们(请参阅我的pull request here)可以避免崩溃。

尽管尝试使用pthread_mutex_t进行原子计数和shared_ptr锁定会导致macOS崩溃,但这似乎确实是个错误(请注意,发生的时间少于0.08%,但是如果像上面的代码片段那样紧缩循环,您会打它)。该问题可能很少遇到,因为在macOS上构建boost的默认行为并未定义这些常量。