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

Kostya Serebryany kcc at google.com
Tue Feb 18 00:37:13 PST 2014


Hi Ben,

Thanks for the test case!
You've hit this entry of our FAQ:
https://code.google.com/p/thread-sanitizer/wiki/CppManual#FAQ
==================

   - Q: I see what looks like a false report inside the libstdc++ (libc++)
   code.

This may happen in c++11 mode. We are not aware of any such case today, but
ThreadSanitizer is not heavily tested on code that uses c++11 threading. A
likely solution would be to rebuild libstdc++ (libc++) with ThreadSanitizer
(this might be tricky, and the process changes periodically; contact us for
details). It is also possible that libstdc++ (libc++) has a bug, we've seen
at least one such <http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59215>
 before.

==================
Apparently, we now know about one more such case and we'll need to update
the FAQ. :)
Good news is that this is very easy to fix: just rebuild libc++ with tsan
by changing the flags in projects/libcxx/lib/buildit.
I've just verified that using instrumented libc++ eliminates the tsan
reports.

If curious, this is happening because shared_ptr<int>::~shared_ptr has
atomic synchronization in it
and if tsan does not observe that synchronization it can not properly
reason about races.

hth,

--kcc







On Mon, Feb 17, 2014 at 6:51 PM, Ben Pope <benpope81 at gmail.com> wrote:

> 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
>
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20140218/caf7e4b1/attachment.html>


More information about the cfe-dev mailing list