[cfe-dev] TSAN shows data race in ~std::shared_ptr

Ben Pope benpope81 at gmail.com
Mon Feb 17 18:51:46 PST 2014


Does the following code have a race or is it a false positive?  If it's 
a false positive, can I teach TSAN about it?

#include <memory>
#include <thread>
#include <iostream>

int main()
{
    int v1 = 0;
    int v2 = 0;
    std::thread t1;
    std::thread t2;

    {
       auto thingy = std::make_shared<int>(1);
       t1 = std::thread([thingy, &v1] { v1 = *thingy; });
       t2 = std::thread([thingy, &v2] { v2 = *thingy; });
    }

    t1.join();
    t2.join();
    std::cout << v1 << "\n" << v2 << "\n";
}

Compiled with:
clang++ -std=c++11 -stdlib=libc++ -pthread -lc++abi -fsanitize=thread 
shared_ptr_thread_safety.cpp -o shared_ptr_thread_safety

clang version 3.4 (tags/RELEASE_34/final)

==================
WARNING: ThreadSanitizer: data race (pid=567)
   Write of size 8 at 0x7d080000efd8 by thread T2:
     #0 operator delete(void*) 
/home/ben/development/llvm/trunk/llvm/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:581 
(shared_ptr_thread_safety+0x0000000483eb)
     #1 std::__1::allocator<std::__1::__shared_ptr_emplace<int, 
std::__1::allocator<int> > 
 >::deallocate(std::__1::__shared_ptr_emplace<int, 
std::__1::allocator<int> >*, unsigned long) 
/usr/include/c++/v1/memory:1632 (shared_ptr_thread_safety+0x0000000adb77)
     #2 std::__1::__shared_ptr_emplace<int, std::__1::allocator<int> 
 >::__on_zero_shared_weak() /usr/include/c++/v1/memory:3744 
(shared_ptr_thread_safety+0x0000000adb77)
     #3 std::__1::shared_ptr<int>::~shared_ptr() 
/usr/include/c++/v1/memory:4448 (shared_ptr_thread_safety+0x0000000a6f1f)
     #4 main::$_1::~$_1() 
/home/ben/development/test/shared_ptr_thread_safety.cpp:15 
(shared_ptr_thread_safety+0x0000000a56d0)
     #5 std::__1::__tuple_leaf<0ul, main::$_1, false>::~__tuple_leaf() 
/usr/include/c++/v1/tuple:173 (shared_ptr_thread_safety+0x0000000a5fd0)
     #6 std::__1::__tuple_impl<std::__1::__tuple_indices<0ul>, 
main::$_1>::~__tuple_impl() /usr/include/c++/v1/tuple:385 
(shared_ptr_thread_safety+0x0000000a5f83)
     #7 std::__1::tuple<main::$_1>::~tuple() 
/usr/include/c++/v1/tuple:488 (shared_ptr_thread_safety+0x0000000a5f30)
     #8 std::__1::default_delete<std::__1::tuple<main::$_1> 
 >::operator()(std::__1::tuple<main::$_1>*) const 
/usr/include/c++/v1/memory:2426 (shared_ptr_thread_safety+0x0000000a5e2f)
     #9 std::__1::unique_ptr<std::__1::tuple<main::$_1>, 
std::__1::default_delete<std::__1::tuple<main::$_1> > 
 >::reset(std::__1::tuple<main::$_1>*) /usr/include/c++/v1/memory:2625 
(shared_ptr_thread_safety+0x0000000a5e2f)
     #10 ~unique_ptr /usr/include/c++/v1/memory:2593 
(shared_ptr_thread_safety+0x0000000a5e2f)
     #11 void* std::__1::__thread_proxy<std::__1::tuple<main::$_1> 
 >(void*) /usr/include/c++/v1/thread:343 
(shared_ptr_thread_safety+0x0000000a5e2f)

   Previous read of size 4 at 0x7d080000efd8 by thread T1:
     #0 main::$_0::operator()() const 
/home/ben/development/test/shared_ptr_thread_safety.cpp:14 
(shared_ptr_thread_safety+0x0000000a6c45)
     #1 
_ZNSt3__18__invokeIZ4mainE3$_0JEEEDTclclsr3std3__1E7forwardIT_Efp_Espclsr3std3__1E7forwardIT0_Efp0_EEEOS2_DpOS3_ 
/usr/include/c++/v1/__functional_base:413:12 
(shared_ptr_thread_safety+0x0000000a6775)
     #2 void 
std::__1::__thread_execute<main::$_0>(std::__1::tuple<main::$_0>&, 
std::__1::__tuple_indices<>) /usr/include/c++/v1/thread:332 
(shared_ptr_thread_safety+0x0000000a6775)
     #3 void* std::__1::__thread_proxy<std::__1::tuple<main::$_0> 
 >(void*) /usr/include/c++/v1/thread:342 
(shared_ptr_thread_safety+0x0000000a6775)

   Location is heap block of size 32 at 0x7d080000efc0 allocated by main 
thread:
     #0 operator new(unsigned long) 
/home/ben/development/llvm/trunk/llvm/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:549 
(shared_ptr_thread_safety+0x000000047e7d)
     #1 std::__1::allocator<std::__1::__shared_ptr_emplace<int, 
std::__1::allocator<int> > >::allocate(unsigned long, void const*) 
/usr/include/c++/v1/memory:1630 (shared_ptr_thread_safety+0x0000000abe69)
     #2 std::__1::shared_ptr<int> 
std::__1::shared_ptr<int>::make_shared<int>(int&&) 
/usr/include/c++/v1/memory:4270 (shared_ptr_thread_safety+0x0000000abe69)
     #3 int&& 
std::__1::forward<int>(std::__1::remove_reference<int>::type&) 
/usr/include/c++/v1/type_traits:1549 
(shared_ptr_thread_safety+0x0000000a3176)
     #4 
_ZNSt3__111make_sharedIiJiEEENS_9enable_ifIXntsr8is_arrayIT_EE5valueENS_10shared_ptrIS2_EEE4typeEDpOT0_ 
/usr/include/c++/v1/memory:4630 (shared_ptr_thread_safety+0x0000000a3176)
     #5 main /home/ben/development/test/shared_ptr_thread_safety.cpp:13 
(shared_ptr_thread_safety+0x0000000a3176)

   Thread T2 (tid=570, running) created by main thread at:
     #0 pthread_create 
/home/ben/development/llvm/trunk/llvm/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:865 
(shared_ptr_thread_safety+0x00000004b331)
     #1 std::__1::thread::thread<main::$_1, , void>(main::$_1&&) 
/usr/include/c++/v1/thread:354 (shared_ptr_thread_safety+0x0000000a4e77)
     #2 main /home/ben/development/test/shared_ptr_thread_safety.cpp:15 
(shared_ptr_thread_safety+0x0000000a3578)

   Thread T1 (tid=569, finished) created by main thread at:
     #0 pthread_create 
/home/ben/development/llvm/trunk/llvm/projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:865 
(shared_ptr_thread_safety+0x00000004b331)
     #1 std::__1::thread::thread<main::$_0, , void>(main::$_0&&) 
/usr/include/c++/v1/thread:354 (shared_ptr_thread_safety+0x0000000a3f57)
     #2 main /home/ben/development/test/shared_ptr_thread_safety.cpp:14 
(shared_ptr_thread_safety+0x0000000a32fc)

SUMMARY: ThreadSanitizer: data race /usr/include/c++/v1/memory:1632 
std::__1::allocator<std::__1::__shared_ptr_emplace<int, 
std::__1::allocator<int> > 
 >::deallocate(std::__1::__shared_ptr_emplace<int, 
std::__1::allocator<int> >*, unsigned long)
==================
1
1
ThreadSanitizer: reported 1 warnings


I get the same result with clang version 3.5 (trunk 201540)

Thanks,

Ben




More information about the cfe-dev mailing list