clang-3.6 thread sanitizer complains on shared_ptr operations

I'm using clang 3.6 with boost 1.54
$ clang-3.6 --version
Ubuntu clang version 3.6.0-svn225356-1~exp1 (trunk) (based on LLVM 3.6.0)
Target: x86_64-pc-linux-gnu
Thread model: posix
Compiling the code here: http://pastebin.com/zh0SPz5n
$ clang++-3.6 -g main.cpp -lboost_system -lboost_thread -fsanitize=thread
I get at runtime:
==================
WARNING: ThreadSanitizer: data race (pid=5592)
Write of size 8 at 0x7d080000cfe8 by thread T2 (mutexes: write M18):
#0 operator delete(void*) <null> (a.out+0x00000045febb)
#1 ~sp_counted_impl_p /usr/include/boost/smart_ptr/detail/sp_counted_impl.hpp:53 (a.out+0x0000004d15c9)
#2 boost::detail::sp_counted_base::destroy() /usr/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:126 (a.out+0x0000004cb77c)
#3 boost::detail::sp_counted_base::weak_release() /usr/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:160 (a.out+0x0000004c773f)
#4 boost::detail::sp_counted_base::release() /usr/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:147 (a.out+0x0000004c75e8)
#5 ~shared_count /usr/include/boost/smart_ptr/detail/shared_count.hpp:371 (a.out+0x0000004c7550)
#6 ~shared_ptr /usr/include/boost/smart_ptr/shared_ptr.hpp:722 (a.out+0x0000004cef59)
#7 boost::shared_ptr<int>::operator=(boost::shared_ptr<int> const&) /usr/include/boost/smart_ptr/shared_ptr.hpp:507 (a.out+0x0000004cf1b7)
#8 Consumer::consume(boost::shared_ptr<int>) /home/kalman/boost_sp_test/main.cpp:9 (a.out+0x0000004ced61)
#9 Producer::operator()() /home/kalman/boost_sp_test/main.cpp:32 (a.out+0x0000004ceaba)
#10 boost::detail::thread_data

Gaetano Mendola wrote:
I'm using clang 3.6 with boost 1.54
$ clang-3.6 --version Ubuntu clang version 3.6.0-svn225356-1~exp1 (trunk) (based on LLVM 3.6.0) Target: x86_64-pc-linux-gnu Thread model: posix
Compiling the code here: http://pastebin.com/zh0SPz5n
$ clang++-3.6 -g main.cpp -lboost_system -lboost_thread -fsanitize=thread
I get at runtime:
================== WARNING: ThreadSanitizer: data race (pid=5592) Write of size 8 at 0x7d080000cfe8 by thread T2 (mutexes: write M18): #0 operator delete(void*) <null> (a.out+0x00000045febb) ...
I believe this is a false alarm indeed the two threads are working on their own shared_ptr copy and thePtr shared pointer write/read in the two threads is protected with a mutex.
I can't see anything wrong with your code; clang's thread sanitizer probably doesn't understand our homegrown atomic operations in sp_counted_base_gcc_x86.hpp because they use inline assembly. You should try the same with -DBOOST_SP_USE_STD_ATOMIC, which will use std::atomic. It's possible that the sanitizer understands standard atomics better. Failing that, next thing to try is -DBOOST_SP_USE_PTHREADS.

On 01/21/2015 01:07 AM, Peter Dimov wrote:
Gaetano Mendola wrote:
I'm using clang 3.6 with boost 1.54
$ clang-3.6 --version Ubuntu clang version 3.6.0-svn225356-1~exp1 (trunk) (based on LLVM 3.6.0) Target: x86_64-pc-linux-gnu Thread model: posix
Compiling the code here: http://pastebin.com/zh0SPz5n
$ clang++-3.6 -g main.cpp -lboost_system -lboost_thread -fsanitize=thread
I get at runtime:
================== WARNING: ThreadSanitizer: data race (pid=5592) Write of size 8 at 0x7d080000cfe8 by thread T2 (mutexes: write M18): #0 operator delete(void*) <null> (a.out+0x00000045febb) ...
I believe this is a false alarm indeed the two threads are working on their own shared_ptr copy and thePtr shared pointer write/read in the two threads is protected with a mutex.
I can't see anything wrong with your code; clang's thread sanitizer probably doesn't understand our homegrown atomic operations in sp_counted_base_gcc_x86.hpp because they use inline assembly.
You should try the same with -DBOOST_SP_USE_STD_ATOMIC, which will use std::atomic. It's possible that the sanitizer understands standard atomics better. Failing that, next thing to try is -DBOOST_SP_USE_PTHREADS.
Same issue with -DBOOST_SP_USE_STD_ATOMIC however with -DBOOST_SP_USE_PTHREADS the warning disappears. Annoying. -- cpp-today.blogspot.it --- This email is free from viruses and malware because avast! Antivirus protection is active. http://www.avast.com

Gaetano Mendola wrote:
Same issue with -DBOOST_SP_USE_STD_ATOMIC however with -DBOOST_SP_USE_PTHREADS the warning disappears.
Annoying.
If it persists when boost:: use is replaced with std::thread, std::mutex and std::shared_ptr, it should be obvious that it's not our fault. :-)

On 01/21/2015 07:38 PM, Peter Dimov wrote:
Gaetano Mendola wrote:
Same issue with -DBOOST_SP_USE_STD_ATOMIC however with -DBOOST_SP_USE_PTHREADS the warning disappears.
Annoying.
If it persists when boost:: use is replaced with std::thread, std::mutex and std::shared_ptr, it should be obvious that it's not our fault. :-)
Replaced all the boost with the "equivalent" in std: http://pastebin.com/X6u1rD0c compiled with: clang++-3.6 -std=c++11 -g main_std.cpp -fsanitize=thread and clang++ *doesn't* complain. So either is our fault or std is doing something different? -- cpp-today.blogspot.it --- This email is free from viruses and malware because avast! Antivirus protection is active. http://www.avast.com

Gaetano Mendola wrote:
Replaced all the boost with the "equivalent" in std:
compiled with:
clang++-3.6 -std=c++11 -g main_std.cpp -fsanitize=thread
and clang++ *doesn't* complain. So either is our fault or std is doing something different?
It's probably doing something different, but it would be nice to know what. What standard library are you using by default? The one coming with your g++ installation, I suppose, but which g++ is it?

Gaetano Mendola wrote:
Replaced all the boost with the "equivalent" in std:
compiled with:
clang++-3.6 -std=c++11 -g main_std.cpp -fsanitize=thread
and clang++ *doesn't* complain. So either is our fault or std is doing something different?
It's probably doing something different, but it would be nice to know what. What standard library are you using by default? The one coming with your g++ installation, I suppose, but which g++ is it?
Also, can you please post the output when using -DBOOST_SP_USE_STD_ATOMIC? It should be different from the one without.

On 01/22/2015 12:15 AM, Peter Dimov wrote:
Gaetano Mendola wrote:
Replaced all the boost with the "equivalent" in std:
compiled with:
clang++-3.6 -std=c++11 -g main_std.cpp -fsanitize=thread
and clang++ *doesn't* complain. So either is our fault or std is doing > something different?
It's probably doing something different, but it would be nice to know what. What standard library are you using by default? The one coming with your g++ installation, I suppose, but which g++ is it?
Also, can you please post the output when using -DBOOST_SP_USE_STD_ATOMIC? It should be different from the one without.
Yes you are right I'm using the std coming with my gcc 4.9.2: g++ (Ubuntu 4.9.2-0ubuntu1~14.04) 4.9.2 And I'm sorry to have stated that with BOOST_SP_USE_STD_ATOMIC still the issue is there, but it doesn't seems so, I believe in my earlier test I copied/pasted not the complete macro. So just to sum up: boost based version: http://pastebin.com/zh0SPz5n WARNING http://pastebin.com/zh0SPz5n + BOOST_SP_USE_STD_ATOMIC OK http://pastebin.com/zh0SPz5n + BOOST_SP_USE_PTHREADS OK std based version (std from gcc 4.9.2): http://pastebin.com/X6u1rD0c OK -- cpp-today.blogspot.it --- This email is free from viruses and malware because avast! Antivirus protection is active. http://www.avast.com

Gaetano Mendola wrote:
So just to sum up:
boost based version: http://pastebin.com/zh0SPz5n WARNING http://pastebin.com/zh0SPz5n + BOOST_SP_USE_STD_ATOMIC OK http://pastebin.com/zh0SPz5n + BOOST_SP_USE_PTHREADS OK
Thanks, that explains it, then. I should probably enable this by default, but we still might need to sort out a few configuration issues before that.

Gaetano Mendola wrote:
So just to sum up:
boost based version: http://pastebin.com/zh0SPz5n WARNING http://pastebin.com/zh0SPz5n + BOOST_SP_USE_STD_ATOMIC OK http://pastebin.com/zh0SPz5n + BOOST_SP_USE_PTHREADS OK
Thanks, that explains it, then. I should probably enable this by default, but we still might need to sort out a few configuration issues before that.
I've added a clang-specific implementation: https://github.com/boostorg/smart_ptr/commit/75de3dbcf1379119ee21a8029845c65... This should be warning-free with the thread sanitizer.

On 01/22/2015 12:47 AM, Gaetano Mendola wrote:
On 01/22/2015 12:15 AM, Peter Dimov wrote:
Gaetano Mendola wrote:
So just to sum up:
boost based version: http://pastebin.com/zh0SPz5n WARNING http://pastebin.com/zh0SPz5n + BOOST_SP_USE_STD_ATOMIC OK http://pastebin.com/zh0SPz5n + BOOST_SP_USE_PTHREADS OK
std based version (std from gcc 4.9.2): http://pastebin.com/X6u1rD0c OK
I tried tonight to see if the BOOST_SP_USE_STD_ATOMIC fixes the warning on my own real code but it doesn't.
Something wrong is going on, compiling again the version at:
http://pastebin.com/zh0SPz5n
without any define it gives:
$ clang++-3.6 -g main.cpp -lboost_thread -lboost_system -fsanitize=thread
$ ./a.out
==================
WARNING: ThreadSanitizer: data race (pid=26547)
Write of size 8 at 0x7d080000cfc8 by thread T2 (mutexes: write M18):
#0 operator delete(void*) <null> (a.out+0x00000045feab)
#1 ~sp_counted_impl_p /usr/include/boost/smart_ptr/detail/sp_counted_impl.hpp:53 (a.out+0x0000004d15b9)
#2 boost::detail::sp_counted_base::destroy() /usr/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:126 (a.out+0x0000004cb76c)
#3 boost::detail::sp_counted_base::weak_release() /usr/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:160 (a.out+0x0000004c772f)
#4 boost::detail::sp_counted_base::release() /usr/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:147 (a.out+0x0000004c75d8)
#5 ~shared_count /usr/include/boost/smart_ptr/detail/shared_count.hpp:371 (a.out+0x0000004c7540)
#6 ~shared_ptr /usr/include/boost/smart_ptr/shared_ptr.hpp:722 (a.out+0x0000004cef49)
#7 boost::shared_ptr<int>::operator=(boost::shared_ptr<int> const&) /usr/include/boost/smart_ptr/shared_ptr.hpp:507 (a.out+0x0000004cf1a7)
#8 Consumer::consume(boost::shared_ptr<int>) /home/kalman/boost_sp/main.cpp:9 (a.out+0x0000004ced51)
#9 Producer::operator()() /home/kalman/boost_sp/main.cpp:32 (a.out+0x0000004ceaaa)
#10 boost::detail::thread_data

Gaetano Mendola wrote:
I tried tonight to see if the BOOST_SP_USE_STD_ATOMIC fixes the warning on my own real code but it doesn't.
...
now defining BOOST_SP_USE_STD_ATOMIC:
...
#2 boost::detail::sp_counted_base::destroy() /usr/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:126 (a.out+0x0000004ca97c)
It uses sp_counted_base_gcc_x86.hpp, so the define didn't take hold. What probably happens is that you're using an older Boost version which doesn't have the support for std::atomic, so the define doesn't work. The tests that worked probably used a newer Boost. You wrote earlier:
I'm using clang 3.6 with boost 1.54
and sure enough, 1.54 didn't have BOOST_SP_USE_STD_ATOMIC:
https://github.com/boostorg/smart_ptr/blob/boost-1.54.0/include/boost/smart_...
1.56 does:
https://github.com/boostorg/smart_ptr/blob/boost-1.56.0/include/boost/smart_...
If you want to remain on 1.54, you can patch your sp_counted_base.hpp either
with the
#elif defined( BOOST_SP_USE_STD_ATOMIC )
# include

On 01/24/2015 08:35 PM, Peter Dimov wrote:
Gaetano Mendola wrote:
I tried tonight to see if the BOOST_SP_USE_STD_ATOMIC fixes the warning on my own real code but it doesn't.
...
now defining BOOST_SP_USE_STD_ATOMIC:
...
#2 boost::detail::sp_counted_base::destroy() /usr/include/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp:126 (a.out+0x0000004ca97c)
It uses sp_counted_base_gcc_x86.hpp, so the define didn't take hold. What probably happens is that you're using an older Boost version which doesn't have the support for std::atomic, so the define doesn't work. The tests that worked probably used a newer Boost.
You wrote earlier:
I'm using clang 3.6 with boost 1.54
and sure enough, 1.54 didn't have BOOST_SP_USE_STD_ATOMIC:
https://github.com/boostorg/smart_ptr/blob/boost-1.54.0/include/boost/smart_...
1.56 does:
https://github.com/boostorg/smart_ptr/blob/boost-1.56.0/include/boost/smart_...
If you want to remain on 1.54, you can patch your sp_counted_base.hpp either with the
#elif defined( BOOST_SP_USE_STD_ATOMIC ) # include
part (adding of course sp_counted_base_std_atomic.hpp), or with the new clang-specific version I referenced in my post:
ok, I see why then, may be is worth to open an issue with clang guys, after all boost 1.54 smart pointer as it is is not bugged, it's clang fault not recognizing the memory access.

Gaetano Mendola wrote:
Same issue with -DBOOST_SP_USE_STD_ATOMIC however with -DBOOST_SP_USE_PTHREADS the warning disappears.
One more thing to try, I suppose, is -DBOOST_SP_USE_STD_ATOMIC with libc++ instead of libstdc++. Thread sanitizer is supposed to understand the __c11 built-ins and I expect libc++'s std::atomic to use them. https://code.google.com/p/thread-sanitizer/wiki/AtomicOperations I was going to implement a version of sp_counted_base using the __c11 built-ins and make it default on Clang, but never got around to it.

Le 21/01/15 00:50, Gaetano Mendola a écrit :
I'm using clang 3.6 with boost 1.54
$ clang-3.6 --version Ubuntu clang version 3.6.0-svn225356-1~exp1 (trunk) (based on LLVM 3.6.0) Target: x86_64-pc-linux-gnu Thread model: posix
Compiling the code here: http://pastebin.com/zh0SPz5n
$ clang++-3.6 -g main.cpp -lboost_system -lboost_thread -fsanitize=thread
I get at runtime:
================== WARNING: ThreadSanitizer: data race (pid=5592) <snip> SUMMARY: ThreadSanitizer: data race ??:0 operator delete(void*) ==================
I believe this is a false alarm indeed the two threads are working on their own shared_ptr copy and thePtr shared pointer write/read in the two threads is protected with a mutex.
I will open a ticket with clang folks if you recognize that is a false alarm, unless they are right and we have issue in shared_ptr implementation.
Thanks for raising this issue. The Boost.Thread regression tests are showing this kind of issues since the testers were installed by Marshall. Your example seems to show that the issue is only related to boost::shared_ptr. In order we can concentrate only on Boost::SmartPtr, could you give a try replacing Boost.Thread by (std::thread/mutex/unique_lock)? Best, Vicente

On Wed, Jan 21, 2015 at 8:57 AM, Vicente J. Botet Escriba
Le 21/01/15 00:50, Gaetano Mendola a écrit :
I'm using clang 3.6 with boost 1.54
$ clang-3.6 --version Ubuntu clang version 3.6.0-svn225356-1~exp1 (trunk) (based on LLVM 3.6.0) Target: x86_64-pc-linux-gnu Thread model: posix
Compiling the code here: http://pastebin.com/zh0SPz5n
$ clang++-3.6 -g main.cpp -lboost_system -lboost_thread -fsanitize=thread
I get at runtime:
================== WARNING: ThreadSanitizer: data race (pid=5592) <snip> SUMMARY: ThreadSanitizer: data race ??:0 operator delete(void*) ==================
I believe this is a false alarm indeed the two threads are working on their own shared_ptr copy and thePtr shared pointer write/read in the two threads is protected with a mutex.
I will open a ticket with clang folks if you recognize that is a false alarm, unless they are right and we have issue in shared_ptr implementation.
Thanks for raising this issue. The Boost.Thread regression tests are showing this kind of issues since the testers were installed by Marshall.
Your example seems to show that the issue is only related to boost::shared_ptr. In order we can concentrate only on Boost::SmartPtr, could you give a try replacing Boost.Thread by (std::thread/mutex/unique_lock)?
This is not specific to Boost.SmartPtr. Any library that implements atomics, including Boost.Atomic and std::atomic, will likely be present in TSan reports. The problem is that TSan does not fully support C++ memory ordering arguments. See this thread: http://boost.2283326.n4.nabble.com/atomic-ThreadSanitizer-reports-a-data-rac...

Andrey Semashev wrote:
This is not specific to Boost.SmartPtr. Any library that implements atomics, including Boost.Atomic and std::atomic, will likely be present in TSan reports. The problem is that TSan does not fully support C++ memory ordering arguments.
In this specific case, it looks like TSan completely ignores the asm blocks and doesn't see the memory accesses there at all, which is why it reports a race between use_count() and the destructor, while these are separated by at least two decrements of the count. That's why it would be interesting to see what it has to say about the std::atomic case.
participants (4)
-
Andrey Semashev
-
Gaetano Mendola
-
Peter Dimov
-
Vicente J. Botet Escriba