【问题标题】:Valgrind errors with boost::thread_specific_ptr on GCC 8.3 + LinuxGCC 8.3 + Linux 上 boost::thread_specific_ptr 的 Valgrind 错误
【发布时间】:2020-01-26 09:20:31
【问题描述】:
  • 在 Docker 中运行的 Ubuntu 19
  • GCC 8.3
  • 提升 1.69
  • Valgrind 3.14.0

当应用程序关闭时,Valgrind 会报告以下 3 个问题:

==70== Mismatched free() / delete / delete []
==70==    at 0x483997B: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==70==    by 0x4870C89: check_free (dlerror.c:202)
==70==    by 0x4870C89: check_free (dlerror.c:186)
==70==    by 0x4870C89: free_key_mem (dlerror.c:221)
==70==    by 0x4870C89: __dlerror_main_freeres (dlerror.c:239)
==70==    by 0x4B59711: __libc_freeres (in /usr/lib/x86_64-linux-gnu/libc-2.29.so)
==70==    by 0x482E19E: _vgnU_freeres (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_core-amd64-linux.so)
==70==    by 0x4A0A3A9: __run_exit_handlers (exit.c:132)
==70==    by 0x4A0A3D9: exit (exit.c:139)
==70==    by 0x49E9B71: (below main) (libc-start.c:342)
==70==  Address 0x4f6a570 is 0 bytes inside a block of size 312 alloc'd
==70==    at 0x4838DBF: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==70==    by 0x303D6D: boost::detail::make_external_thread_data() (in /build-context/bin/debug/setmatch-tests)
==70==    by 0x305424: boost::detail::add_new_tss_node(void const*, boost::shared_ptr<boost::detail::tss_cleanup_function>, void*) (in /build-context/bin/debug/setmatch-tests)
==70==    by 0x3054ED: boost::detail::set_tss_data(void const*, 

[...]

==70== Invalid free() / delete / delete[] / realloc()
==70==    at 0x483997B: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==70==    by 0x4870BB4: free_key_mem (dlerror.c:223)
==70==    by 0x4870BB4: __dlerror_main_freeres (dlerror.c:239)
==70==    by 0x4B59711: __libc_freeres (in /usr/lib/x86_64-linux-gnu/libc-2.29.so)
==70==    by 0x482E19E: _vgnU_freeres (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_core-amd64-linux.so)
==70==    by 0x4A0A3A9: __run_exit_handlers (exit.c:132)
==70==    by 0x4A0A3D9: exit (exit.c:139)
==70==    by 0x49E9B71: (below main) (libc-start.c:342)
==70==  Address 0x4f6a570 is 0 bytes inside a block of size 312 free'd
==70==    at 0x483997B: free (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==70==    by 0x4870C89: check_free (dlerror.c:202)
==70==    by 0x4870C89: check_free (dlerror.c:186)
==70==    by 0x4870C89: free_key_mem (dlerror.c:221)
==70==    by 0x4870C89: __dlerror_main_freeres (dlerror.c:239)
==70==    by 0x4B59711: __libc_freeres (in /usr/lib/x86_64-linux-gnu/libc-2.29.so)
==70==    by 0x482E19E: _vgnU_freeres (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_core-amd64-linux.so)
==70==    by 0x4A0A3A9: __run_exit_handlers (exit.c:132)
==70==    by 0x4A0A3D9: exit (exit.c:139)
==70==    by 0x49E9B71: (below main) (libc-start.c:342)
==70==  Block was alloc'd at
==70==    at 0x4838DBF: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==70==    by 0x303D6D: boost::detail::make_external_thread_data() (in /build-context/bin/debug/setmatch-tests)
==70==    by 0x305424: boost::detail::add_new_tss_node(void const*, boost::shared_ptr<boost::detail::tss_cleanup_function>, void*) (in /build-context/bin/debug/setmatch-tests)
==70==    by 0x3054ED: boost::detail::set_tss_data(void const*, boost::shared_ptr<boost::detail::tss_cleanup_function>, void*, bool) (in /build-context/bin/debug/setmatch-tests)
==70==    by 0x188841: boost::thread_specific_ptr<burningmime::setmatch::MatchState>::reset(burningmime::setmatch::MatchState*) (tss.hpp:105)

[...]

==70== 24 bytes in 1 blocks are definitely lost in loss record 1 of 2
==70==    at 0x4838DBF: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==70==    by 0x303F50: boost::detail::make_external_thread_data() (in /build-context/bin/debug/setmatch-tests)
==70==    by 0x305424: boost::detail::add_new_tss_node(void const*, boost::shared_ptr<boost::detail::tss_cleanup_function>, void*) (in /build-context/bin/debug/setmatch-tests)
==70==    by 0x3054ED: boost::detail::set_tss_data(void const*, boost::shared_ptr<boost::detail::tss_cleanup_function>, void*, bool) (in /build-context/bin/debug/setmatch-tests)

[...]

看起来 boost 正在将其线程数据分配到 dlerror 已分配其自己的线程数据的同一位置。 A quick search points to a (slightly different?) version of dlerror here

快速浏览一下 bosot 的代码,我觉得它只是 allocating the TSS block on the heap

GCC 7.3.0 + Ubuntu 18(相同的 Boost 版本)不是问题

这里有人有见解吗?

编辑:Maybe it's the double-free that was fixed in this commit? Still I don't see why Boost would be using that at all.

【问题讨论】:

  • 有什么理由不使用最新的 Valgrind 3.15.0?

标签: c++ boost pthreads boost-thread thread-local


【解决方案1】:

请检查您使用过的所有工具的版本。这似乎存在一些版本兼容性问题。尝试使用 3.15.0 版本的 valgrind。

请参阅here 了解 valgrind 的用法。

【讨论】:

    【解决方案2】:

    如果我像这样修改pthread_setspecific 调用周围的glibc upstream test case(并使用g++ 编译它):

        void *ptr = new char;
        printf("Setting thread local to ptr.\n");
        if (pthread_setspecific(key, ptr) != 0) {
          perror("pthread_setspecific");
          exit(1);
        }
        delete ptr;
    

    在修复之前(在提交 5b06f538c5aee0389ed034f60d90a8884d6d54de 时,使用 glibc 构建树中的 ./testrun.sh --tool=valgrind /path/to/test)运行 glibc 时出现此错误:

    ==14143== Invalid read of size 8
    ==14143==    at 0x483B550: check_free (dlerror.c:188)
    ==14143==    by 0x483BA21: free_key_mem (dlerror.c:221)
    ==14143==    by 0x483BA21: __dlerror_main_freeres (dlerror.c:239)
    ==14143==    by 0x4D06AD1: __libc_freeres (in /home/fweimer/src/gnu/glibc/build/libc.so)
    ==14143==    by 0x48031DE: _vgnU_freeres (vg_preloaded.c:77)
    ==14143==    by 0x4BDD331: __run_exit_handlers (exit.c:132)
    ==14143==    by 0x4BDD3C9: exit (exit.c:139)
    ==14143==    by 0x4BC7E21: (below main) (libc-start.c:342)
    ==14143==  Address 0x4d750d8 is 23 bytes after a block of size 1 free'd
    ==14143==    at 0x480CEFC: operator delete(void*) (vg_replace_malloc.c:586)
    ==14143==    by 0x401344: main (t.c:93)
    ==14143==  Block was alloc'd at
    ==14143==    at 0x480BE86: operator new(unsigned long) (vg_replace_malloc.c:344)
    ==14143==    by 0x4012F4: main (t.c:87)
    ==14143== 
    ==14143== Invalid free() / delete / delete[] / realloc()
    ==14143==    at 0x480CA0C: free (vg_replace_malloc.c:540)
    ==14143==    by 0x483BA29: free_key_mem (dlerror.c:223)
    ==14143==    by 0x483BA29: __dlerror_main_freeres (dlerror.c:239)
    ==14143==    by 0x4D06AD1: __libc_freeres (in /home/fweimer/src/gnu/glibc/build/libc.so)
    ==14143==    by 0x48031DE: _vgnU_freeres (vg_preloaded.c:77)
    ==14143==    by 0x4BDD331: __run_exit_handlers (exit.c:132)
    ==14143==    by 0x4BDD3C9: exit (exit.c:139)
    ==14143==    by 0x4BC7E21: (below main) (libc-start.c:342)
    ==14143==  Address 0x4d750c0 is 0 bytes inside a block of size 1 free'd
    ==14143==    at 0x480CEFC: operator delete(void*) (vg_replace_malloc.c:586)
    ==14143==    by 0x401344: main (t.c:93)
    ==14143==  Block was alloc'd at
    ==14143==    at 0x480BE86: operator new(unsigned long) (vg_replace_malloc.c:344)
    ==14143==    by 0x4012F4: main (t.c:87)
    

    这与您遇到的错误几乎相同,只是减去了 Boost 中 operator new 分配的嵌套。所以看起来这两个错误确实是一样的。

    这是有道理的:由于bug 24476libdl 使用未初始化的pthread_key_t 值(之前没有调用pthread_key_create)。对于数据段(其中存储了libdl 的内部密钥0,未初始化意味着零,当然,正如您从测试中的诊断输出中看到的那样,测试分配的密钥(在您的情况下为 Boost)在事实关键 0:

    key = 0
    

    这个libdl 代码相当复杂,而我posted a patch which moves dlerror into libc(来自libdl)也完全避免使用POSIX 线程线程本地存储。

    总结一下:维护您使用的 glibc 版本的人需要将 upstream fix 反向移植到他们的源代码树中并发布更新。 We had to do this as well. 从好的方面来说,这个错误只会在你在 valgrind 和类似工具下运行应用程序时发生,因为在常规进程关闭期间,__libc_freeres 不会被调用:无论如何,进程将很快退出,内核会清理所有资源为我们。除非你在生产环境中使用 valgrind,否则这意味着你永远不会遇到这个 bug。当然,当你使用 valgrind 进行调试时,这仍然是一个烦人的问题。对此感到抱歉。

    【讨论】:

    • 谢谢!!很高兴听到有人真正研究过这些东西。
    • 我很害怕函数迁移到 glibc。 clock_gettime() 从 librt 迁移到 libc 在向后兼容性方面破坏了很多。
    • @RobertFraser 如果有问题,请提交错误或发布到 libc-help。
    【解决方案3】:

    也许你应该将 valgrind 版本升级到 3.15.0 ,它应该会有所帮助。

    我认为here 应该可以帮助你。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多