这段简单C++代码的数据竞态在哪?是否为误报?
ThreadSanitizer与UBSanitizer同时启用时的竞态警告是否为误报?
clang和g的Sanitizer针对以下简单C++代码均报告类似的数据竞态警告,仅当同时启用Thread Sanitizer和UB Sanitizer时才会出现此警告。请问这是否属于误报?问题出在哪里?
测试代码
#include <thread> struct A { void operator()() { } }; struct B { void operator()() { } }; int main(void) { // callable objects are created and moved into thread std::thread t1(A{}); std::thread t2(B{}); t1.join(); t2.join(); return 0; }
编译选项
-pthread -O0 -g -fsanitize=thread -fsanitize=undefined
g++的Sanitizer输出
================== WARNING: ThreadSanitizer: data race (pid=80173) Write of size 8 at 0x7b0400000800 by thread T2: #0 pipe ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1726 (libtsan.so.0+0x3ea28) #1 __sanitizer::IsAccessibleMemoryRange(unsigned long, unsigned long) ../../../../src/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp:276 (libubsan.so.1+0x20102) #2 std::thread::_State_impl<std::thread::_Invoker<std::tuple<B> > >::~_State_impl() /usr/include/c++/11/bits/std_thread.h:201 (a.out+0x5191) #3 <null> <null> (libstdc++.so.6+0xdc2cb) Previous write of size 8 at 0x7b0400000800 by thread T1: #0 pipe ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1726 (libtsan.so.0+0x3ea28) #1 __sanitizer::IsAccessibleMemoryRange(unsigned long, unsigned long) ../../../../src/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp:276 (libubsan.so.1+0x20102) #2 std::thread::_State_impl<std::thread::_Invoker<std::tuple<A> > >::~_State_impl() /usr/include/c++/11/bits/std_thread.h:201 (a.out+0x53a5) #3 <null> <null> (libstdc++.so.6+0xdc2cb) Thread T2 (tid=80176, running) created by main thread at: #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:969 (libtsan.so.0+0x605b8) #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xdc398) #2 main a.cpp:20 (a.out+0x3396) Thread T1 (tid=80175, finished) created by main thread at: #0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:969 (libtsan.so.0+0x605b8) #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xdc398) #2 main a.cpp:19 (a.out+0x3383) SUMMARY: ThreadSanitizer: data race ../../../../src/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp:276 in __sanitizer::IsAccessibleMemoryRange(unsigned long, unsigned long) ================== ThreadSanitizer: reported 1 warnings
解答
这属于工具组合使用导致的误报,问题根源在Sanitizer库内部:
- 当同时启用ThreadSanitizer(TSan)和UndefinedBehaviorSanitizer(UBSan)时,UBSan的
IsAccessibleMemoryRange函数会调用pipe系统调用,而TSan会追踪所有内存操作。 - 两个线程在销毁各自
std::thread的内部状态时,都会触发UBSan的内存可达性检查,进而调用pipe。TSan误将pipe内部的共享内存操作识别为用户代码的数据竞态,但实际上这是Sanitizer库自身的共享资源访问未做同步保护导致的,和用户编写的代码完全无关。 - 只有同时启用两个Sanitizer才会触发该警告,也进一步说明这是工具组合的内部问题,而非用户代码存在数据竞态。
内容的提问来源于stack exchange,提问作者Özgür Murat Sağdıçoğlu
相关产品推荐
相关产品推荐

