I am debugging A segfault reported by TSAN in the CI of Boost.Beast.
I strongly believe it to be a false positive, but I don't know what to look for in order to suppress it.
It seems to me from the stack trace that the code is correctly instrumented.
The code passes all other tests, inclding valgrind, ubsan, etc.
I'm hoping some kind expert may put me out of my misery.
Here is the output:
====== BEGIN OUTPUT ======
beast.http.read
ThreadSanitizer:DEADLYSIGNAL
==132842==ERROR: ThreadSanitizer: SEGV on unknown address 0x7ff5d9cff000 (pc 0x7ff5dceba0d0 bp 0x000000000000 sp 0x7ff5d9c3d910 T132844)
==132842==The signal is caused by a READ memory access.
#0 __sanitizer::StackDepotBase<__sanitizer::StackDepotNode, 1, 20>::Put(__sanitizer::StackTrace, bool*) <null> (libtsan.so.2+0xba0d0)
#1 __tsan::CurrentStackId(__tsan::ThreadState*, unsigned long) <null> (libtsan.so.2+0x8c48f)
#2 __sanitizer::DD::MutexInit(__sanitizer::DDCallback*, __sanitizer::DDMutex*) <null> (libtsan.so.2+0xac534)
#3 __tsan::DDMutexInit(__tsan::ThreadState*, unsigned long, __tsan::SyncVar*) <null> (libtsan.so.2+0x9a3f8)
#4 __tsan::MetaMap::GetSync(__tsan::ThreadState*, unsigned long, unsigned long, bool, bool) <null> (libtsan.so.2+0xa85dc)
#5 __tsan_atomic32_fetch_add <null> (libtsan.so.2+0x783e9)
#6 __gnu_cxx::__exchange_and_add(int volatile*, int) /usr/include/c++/12/ext/atomicity.h:66 (read+0x4188f8)
#7 __gnu_cxx::__exchange_and_add_dispatch(int*, int) /usr/include/c++/12/ext/atomicity.h:101 (read+0x4188f8)
#8 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release_last_use() /usr/include/c++/12/bits/shared_ptr_base.h:187 (read+0x4188f8)
#9 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/12/bits/shared_ptr_base.h:361 (read+0x40c592)
#10 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/12/bits/shared_ptr_base.h:1071 (read+0x418fee)
#11 std::__shared_ptr<boost::asio::detail::strand_executor_service::strand_impl, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/12/bits/shared_ptr_base.h:1524 (read+0x420f83)
#12 std::shared_ptr<boost::asio::detail::strand_executor_service::strand_impl>::~shared_ptr() /usr/include/c++/12/bits/shared_ptr.h:175 (read+0x420faf)
#13 boost::asio::detail::strand_executor_service::invoker<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> const, void>::~invoker() <null> (read+0x471f5f)
#14 boost::asio::detail::executor_op<boost::asio::detail::strand_executor_service::invoker<boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> const, void>, boost::asio::detail::recycling_allocator<void, boost::asio::detail::thread_info_base::default_tag>, boost::asio::detail::scheduler_operation>::do_complete(void*, boost::asio::detail::scheduler_operation*, boost::system::error_code const&, unsigned long) <null> (read+0x48b0ac)
#15 boost::asio::detail::scheduler_operation::complete(void*, boost::system::error_code const&, unsigned long) boost/asio/detail/scheduler_operation.hpp:40 (read+0x4fa38e)
#16 boost::asio::detail::scheduler::do_run_one(boost::asio::detail::conditionally_enabled_mutex::scoped_lock&, boost::asio::detail::scheduler_thread_info&, boost::system::error_code const&) boost/asio/detail/impl/scheduler.ipp:492 (read+0x4e8835)
#17 boost::asio::detail::scheduler::run(boost::system::error_code&) boost/asio/detail/impl/scheduler.ipp:210 (read+0x4e74fb)
#18 boost::asio::io_context::run() boost/asio/impl/io_context.ipp:63 (read+0x4dc122)
#19 boost::beast::test::enable_yield_to::enable_yield_to(unsigned long)::{lambda()#1}::operator()() const <null> (read+0x412363)
#20 void std::__invoke_impl<void, boost::beast::test::enable_yield_to::enable_yield_to(unsigned long)::{lambda()#1}>(std::__invoke_other, boost::beast::test::enable_yield_to::enable_yield_to(unsigned long)::{lambda()#1}&&) <null> (read+0x4a1f92)
#21 std::__invoke_result<boost::beast::test::enable_yield_to::enable_yield_to(unsigned long)::{lambda()#1}>::type std::__invoke<boost::beast::test::enable_yield_to::enable_yield_to(unsigned long)::{lambda()#1}>(boost::beast::test::enable_yield_to::enable_yield_to(unsigned long)::{lambda()#1}&&) <null> (read+0x49f9dc)
#22 void std::thread::_Invoker<std::tuple<boost::beast::test::enable_yield_to::enable_yield_to(unsigned long)::{lambda()#1}> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) <null> (read+0x49c90a)
#23 std::thread::_Invoker<std::tuple<boost::beast::test::enable_yield_to::enable_yield_to(unsigned long)::{lambda()#1}> >::operator()() <null> (read+0x49941e)
#24 std::thread::_State_impl<std::thread::_Invoker<std::tuple<boost::beast::test::enable_yield_to::enable_yield_to(unsigned long)::{lambda()#1}> > >::_M_run() <null> (read+0x494c2a)
#25 execute_native_thread_routine <null> (libstdc++.so.6+0xdbb72)
#26 __tsan_thread_start_func <null> (libtsan.so.2+0x393ef)
#27 start_thread <null> (libc.so.6+0x8ce2c)
#28 clone3 <null> (libc.so.6+0x1121af)
ThreadSanitizer can not provide additional info.
SUMMARY: ThreadSanitizer: SEGV (/lib64/libtsan.so.2+0xba0d0) in __sanitizer::StackDepotBase<__sanitizer::StackDepotNode, 1, 20>::Put(__sanitizer::StackTrace, bool*)
==132842==ABORTING
The code being tested is latest master branch.
Command line to reproduce:
$ ./b2 toolset=gcc thread-sanitizer=norecover link=static variant=debug libs/beast/test -q -d+2 -j1
My compiler info:
$ gcc --version
gcc (GCC) 12.1.1 20220507 (Red Hat 12.1.1-1)
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
My OS is Fedora 36. But we see this happen on Ubuntu as well.
Using the b2 line I could repro the SEGV on linux using master (00293a6adb5 from the superproject).
I started with a - to me - more convenient setup based on CMake. I modified the CMake to use thread,undefined sanitizers instead of address,undefined for VARIANT=ubasan.
Interestingly, it doesn't segfault. It does however seem to have a legit TSAN violation in basic_stream.cpp, where the effective flags are:
{
"directory": "/backup/cloudbackup/custom_ex/superboost/libs/beast/build/test/beast/core",
"command": "/home/sehe/bin/g++-10 -DBOOST_ALL_STATIC_LINK=1 -DBOOST_ASIO_DISABLE_BOOST_ARRAY=1 -DBOOST_ASIO_DISABLE_BOOST_BIND=1 -DBOOST_ASIO_DISABLE_BOOST_DATE_TIME=1 -DBOOST_ASIO_DISABLE_BOOST_REGEX=1 -DBOOST_ASIO_NO_DEPRECATED=1 -DBOOST_ASIO_SEPARATE_COMPILATION=1 -DBOOST_BEAST_ALLOW_DEPRECATED -DBOOST_BEAST_SEPARATE_COMPILATION=1 -DBOOST_BEAST_TESTS -DBOOST_COROUTINES_NO_DEPRECATION_WARNING=1 -I/backup/cloudbackup/custom_ex/superboost/libs/beast/include -I/backup/cloudbackup/custom_ex/superboost/libs/beast/. -I/backup/cloudbackup/custom_ex/superboost/libs/beast/test/./extern -I/backup/cloudbackup/custom_ex/superboost/libs/beast/test/./extras/include -isystem /backup/cloudbackup/custom_ex/superboost -std=c++11 -Wall -Wextra -Wpedantic -Wno-unused-parameter -DBOOST_BEAST_NO_SLOW_TESTS=1 -msse4.2 -funsigned-char -fno-omit-frame-pointer -fsanitize=thread,undefined -O2 -g -DNDEBUG -pthread -o CMakeFiles/tests-beast-core.dir/basic_stream.cpp.o -c /backup/cloudbackup/custom_ex/superboost/libs/beast/test/beast/core/basic_stream.cpp",
"file": "/backup/cloudbackup/custom_ex/superboost/libs/beast/test/beast/core/basic_stream.cpp"
},
Breaking it down for readability:
g++-10
-DBOOST_ALL_STATIC_LINK=1
-DBOOST_ASIO_DISABLE_BOOST_ARRAY=1
-DBOOST_ASIO_DISABLE_BOOST_BIND=1
-DBOOST_ASIO_DISABLE_BOOST_DATE_TIME=1
-DBOOST_ASIO_DISABLE_BOOST_REGEX=1
-DBOOST_ASIO_NO_DEPRECATED=1
-DBOOST_ASIO_SEPARATE_COMPILATION=1
-DBOOST_BEAST_ALLOW_DEPRECATED
-DBOOST_BEAST_SEPARATE_COMPILATION=1
-DBOOST_BEAST_TESTS
-DBOOST_COROUTINES_NO_DEPRECATION_WARNING=1
-I/superboost/libs/beast/include
-I/superboost/libs/beast/.
-I/superboost/libs/beast/test/./extern
-I/superboost/libs/beast/test/./extras/include
-isystem /superboost
-std=c++11
-Wall
-Wextra
-Wpedantic
-Wno-unused-parameter
-DBOOST_BEAST_NO_SLOW_TESTS=1
-msse4.2
-funsigned-char
-fno-omit-frame-pointer
-fsanitize=thread,undefined
-O2 -g
-DNDEBUG
-pthread
-o CMakeFiles/tests-beast-core.dir/basic_stream.cpp.o
-c /superboost/libs/beast/test/beast/core/basic_stream.cpp
The reported diagnostic: https://paste.ubuntu.com/p/6SKjmZ9wFT/ (lines truncated for SO):
beast.core.basic_stream
==================
WARNING: ThreadSanitizer: data race (pid=24051)
Write of size 8 at 0x7b0400000030 by thread T1:
#0 pipe ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1726 (libtsan.so.0+0x3e574)
#1 __sanitizer::IsAccessibleMemoryRange(unsigned long, unsigned long) ../../../../src/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp:281 (libu...
#2 operator() /superboost/libs/beast/test/beast/core/basic_stream.cpp:228 (tests-beast-core+0x4f0271)
#3 operator() /superboost/boost/asio/detail/bind_handler.hpp:171 (tests-beast-core+0x4f0271)
#4 invoke<boost::asio::detail::binder1<boost::beast::(anonymous namespace)::test_server::test_server(boost::beast::string_view, boost::asio::ip::tcp::end...
#5 complete<boost::asio::detail::binder1<boost::beast::(anonymous namespace)::test_server::test_server(boost::beast::string_view, boost::asio::ip::tcp::e...
#6 do_complete /superboost/boost/asio/detail/reactive_socket_accept_op.hpp:150 (tests-beast-core+0x4f0271)
#7 boost::asio::detail::scheduler_operation::complete(void*, boost::system::error_code const&, unsigned long) /superboost/boost/asio/detail/scheduler_ope...
#8 boost::asio::detail::epoll_reactor::descriptor_state::do_complete(void*, boost::asio::detail::scheduler_operation*, boost::system::error_code const&, ...
#9 boost::asio::detail::scheduler_operation::complete(void*, boost::system::error_code const&, unsigned long) /superboost/boost/asio/detail/scheduler_ope...
#10 boost::asio::detail::scheduler::do_run_one(boost::asio::detail::conditionally_enabled_mutex::scoped_lock&, boost::asio::detail::scheduler_thread_info...
#11 boost::asio::detail::scheduler::run(boost::system::error_code&) /superboost/boost/asio/detail/impl/scheduler.ipp:210 (tests-beast-core+0x90d424)
#12 boost::asio::io_context::run() /superboost/boost/asio/impl/io_context.ipp:63 (tests-beast-core+0x91bf39)
#13 operator() /superboost/libs/beast/test/beast/core/basic_stream.cpp:234 (tests-beast-core+0x4cf1f9)
#14 __invoke_impl<void, boost::beast::(anonymous namespace)::test_server::test_server(boost::beast::string_view, boost::asio::ip::tcp::endpoint, std::ost...
#15 __invoke<boost::beast::(anonymous namespace)::test_server::test_server(boost::beast::string_view, boost::asio::ip::tcp::endpoint, std::ostream&)::<la...
#16 _M_invoke<0> /usr/include/c++/10/thread:264 (tests-beast-core+0x4cf1f9)
#17 operator() /usr/include/c++/10/thread:271 (tests-beast-core+0x4cf1f9)
#18 _M_run /usr/include/c++/10/thread:215 (tests-beast-core+0x4cf1f9)
#19 execute_native_thread_routine ../../../../../src/libstdc++-v3/src/c++11/thread.cc:82 (libstdc++.so.6+0xd44bf)
Previous write of size 8 at 0x7b0400000030 by main thread:
#0 pipe ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:1726 (libtsan.so.0+0x3e574)
#1 __sanitizer::IsAccessibleMemoryRange(unsigned long, unsigned long) ../../../../src/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp:281 (libu...
#2 void boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul> >::initiate_async_...
#3 void boost::asio::detail::completion_handler_async_result<boost::beast::basic_stream<boost::asio::ip::tcp, boost::asio::io_context::basic_executor_typ...
#4 boost::asio::constraint<boost::asio::detail::async_result_has_initiate_memfn<boost::beast::basic_stream<boost::asio::ip::tcp, boost::asio::io_context:...
#5 decltype ((async_initiate<boost::beast::basic_stream<boost::asio::ip::tcp, boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul>, bo...
#6 boost::beast::basic_stream<boost::asio::ip::tcp, boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul>, boost::beast::unlimited_rate...
#7 boost::beast::basic_stream<boost::asio::ip::tcp, boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul>, boost::beast::unlimited_rate...
#8 boost::beast::basic_stream<boost::asio::ip::tcp, boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul>, boost::beast::unlimited_rate...
#9 void boost::beast::basic_stream<boost::asio::ip::tcp, boost::asio::io_context::basic_executor_type<std::allocator<void>, 0ul>, boost::beast::unlimited...
#10 void boost::asio::detail::completion_handler_async_result<boost::beast::basic_stream_test::handler, void (boost::system::error_code, unsigned long)>:...
#11 boost::asio::constraint<boost::asio::detail::async_result_has_initiate_memfn<boost::beast::basic_stream_test::handler, void (boost::system::error_cod...
#12 boost::asio::async_result<std::decay<boost::beast::basic_stream_test::handler>::type, void (boost::system::error_code, unsigned long)>::return_type b...
#13 boost::beast::basic_stream_test::testRead() /superboost/libs/beast/test/beast/core/basic_stream.cpp:488 (tests-beast-core+0x678b01)
#14 boost::beast::basic_stream_test::run() /superboost/libs/beast/test/beast/core/basic_stream.cpp:1401 (tests-beast-core+0x70b193)
#15 void boost::beast::unit_test::suite::run<void>(boost::beast::unit_test::runner&) /superboost/libs/beast/include/boost/beast/_experimental/unit_test/s...
#16 void boost::beast::unit_test::suite::operator()<void>(boost::beast::unit_test::runner&) /superboost/libs/beast/include/boost/beast/_experimental/unit...
#17 boost::beast::unit_test::make_suite_info<boost::beast::basic_stream_test>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<cha...
#18 void std::__invoke_impl<void, boost::beast::unit_test::make_suite_info<boost::beast::basic_stream_test>(std::__cxx11::basic_string<char, std::char_tr...
#19 std::enable_if<std::__and_<std::is_void<void>, std::__is_invocable<boost::beast::unit_test::make_suite_info<boost::beast::basic_stream_test>(std::__c...
#20 std::_Function_handler<void (boost::beast::unit_test::runner&), boost::beast::unit_test::make_suite_info<boost::beast::basic_stream_test>(std::__cxx1...
#21 std::function<void (boost::beast::unit_test::runner&)>::operator()(boost::beast::unit_test::runner&) const /usr/include/c++/10/bits/std_function.h:62...
#22 boost::beast::unit_test::suite_info::run(boost::beast::unit_test::runner&) const /superboost/libs/beast/include/boost/beast/_experimental/unit_test/s...
#23 bool boost::beast::unit_test::runner::run<void>(boost::beast::unit_test::suite_info const&) /superboost/libs/beast/include/boost/beast/_experimental/...
#24 bool boost::beast::unit_test::runner::run_each<boost::beast::unit_test::suite_list>(boost::beast::unit_test::suite_list const&) /superboost/libs/beas...
#25 main /superboost/libs/beast/include/boost/beast/_experimental/unit_test/main.ipp:82 (tests-beast-core+0x4cc1d3)
Thread T1 (tid=24054, running) created by main thread at:
#0 pthread_create ../../../../src/libsanitizer/tsan/tsan_interceptors_posix.cpp:969 (libtsan.so.0+0x5fe84)
#1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) /build/gcc-11-YRKbe7/gcc-11-...
#2 boost::beast::basic_stream_test::testRead() /superboost/libs/beast/test/beast/core/basic_stream.cpp:484 (tests-beast-core+0x67891b)
#3 boost::beast::basic_stream_test::run() /superboost/libs/beast/test/beast/core/basic_stream.cpp:1401 (tests-beast-core+0x70b193)
#4 void boost::beast::unit_test::suite::run<void>(boost::beast::unit_test::runner&) /superboost/libs/beast/include/boost/beast/_experimental/unit_test/su...
#5 void boost::beast::unit_test::suite::operator()<void>(boost::beast::unit_test::runner&) /superboost/libs/beast/include/boost/beast/_experimental/unit_...
#6 boost::beast::unit_test::make_suite_info<boost::beast::basic_stream_test>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char...
#7 void std::__invoke_impl<void, boost::beast::unit_test::make_suite_info<boost::beast::basic_stream_test>(std::__cxx11::basic_string<char, std::char_tra...
#8 std::enable_if<std::__and_<std::is_void<void>, std::__is_invocable<boost::beast::unit_test::make_suite_info<boost::beast::basic_stream_test>(std::__cx...
#9 std::_Function_handler<void (boost::beast::unit_test::runner&), boost::beast::unit_test::make_suite_info<boost::beast::basic_stream_test>(std::__cxx11...
#10 std::function<void (boost::beast::unit_test::runner&)>::operator()(boost::beast::unit_test::runner&) const /usr/include/c++/10/bits/std_function.h:62...
#11 boost::beast::unit_test::suite_info::run(boost::beast::unit_test::runner&) const /superboost/libs/beast/include/boost/beast/_experimental/unit_test/s...
#12 bool boost::beast::unit_test::runner::run<void>(boost::beast::unit_test::suite_info const&) /superboost/libs/beast/include/boost/beast/_experimental/...
#13 bool boost::beast::unit_test::runner::run_each<boost::beast::unit_test::suite_list>(boost::beast::unit_test::suite_list const&) /superboost/libs/beas...
#14 main /superboost/libs/beast/include/boost/beast/_experimental/unit_test/main.ipp:82 (tests-beast-core+0x4cc1d3)
SUMMARY: ThreadSanitizer: data race ../../../../src/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cpp:281 in __sanitizer::IsAccessibleMemoryRange(uns...
==================
559ms, 1 suite, 1 case, 217 tests total, 0 failures
ThreadSanitizer: reported 1 warnings
Given this observation, I thought to see whether excluding the offending TU (basic_stream.cpp) from the b2 build removes the SEGV. No such luck.
On the contrary, the SEGV manfifest with the following TUs:
module
TU
test/beast/core
buffered_read_stream.cpp
test/beast/http
read.cpp
test/beast/http
write.cpp
test/beast/websocket
close.cpp
test/beast/websocket
handshake.cpp
test/beast/websocket
ping.cpp
test/beast/websocket
read2.cpp
test/beast/websocket
write.cpp
test/doc
http_examples.cpp
Dropping these TUs from their respective test/**/Jamfile allows all remaining tests to pass TSAN under b2. Now, I did some soul searching and e.g. unique include diving using a script like:
#!/bin/bash -i
alias PP='find build/ -name *.cpp.i'
PP -delete
make -C build/test/beast/core buffered_read_stream.i
make -C build/test/beast/http read.i
make -C build/test/beast/http write.i
make -C build/test/beast/websocket close.i
make -C build/test/beast/websocket handshake.i
make -C build/test/beast/websocket ping.i
make -C build/test/beast/websocket read2.i
make -C build/test/beast/websocket write.i
make -C build/test/doc http_examples.i
PP | nl
n=$(PP | wc -l)
set -x
export LANG=C
PP -exec sort -b {} \+ | uniq -dc | grep -wP "^\s*$n # 1" | grep -P '1( 3 4)?$' | nl
Which uncovers a common subset of includes of 854 includes. 40 of the beast headers are in that consistent set, but 208 are asio headers.
Questions from here:
why is SEGV not happening in the CMake build?
are there headers in the common subset that do not appear in the TUs that don't trip TSAN up?
is a recent change in Asio relevant?
Choosing to address these 3., 1., 2. (optimizing for return-on-effort)
3. Is a recent Asio change involved? [YES]
Doing the b2 test with only Asio reverted to 1.79.0 (e929e5cf Merge asio from 'develop') passes all the tests cleanly.
Just to check that no compiler flags were harmed in the process e.g. buffered_read_stream.cpp showed the same exact commands:
gcc.compile.c++ bin.v2/libs/beast/test/beast/core/buffered_read_stream.test/gcc-10.0/debug/link-static/thread-sanitizer-norecover/threading-multi/visibility-hidden/buffered_read_stream.o
"g++-10" -fvisibility-inlines-hidden -fsanitize=thread -fno-sanitize-recover=thread -fno-omit-frame-pointer -m64 -pthread -O0 -fno-inline -Wall -g -fvisibility=hidden -DBOOST_ALL_NO_LIB=1 -DBOOST_ASIO_DISABLE_BOOST_ARRAY=1 -DBOOST_ASIO_DISABLE_BOOST_BIND=1 -DBOOST_ASIO_DISABLE_BOOST_DATE_TIME=1 -DBOOST_ASIO_DISABLE_BOOST_REGEX=1 -DBOOST_ASIO_NO_DEPRECATED=1 -DBOOST_ASIO_SEPARATE_COMPILATION -DBOOST_ATOMIC_STATIC_LINK=1 -DBOOST_BEAST_ALLOW_DEPRECATED -DBOOST_BEAST_SEPARATE_COMPILATION -DBOOST_BEAST_TESTS -DBOOST_COROUTINES_NO_DEPRECATION_WARNING=1 -DBOOST_FILESYSTEM_STATIC_LINK=1 -D_GNU_SOURCE=1 -D_XOPEN_SOURCE=600 -I"." -I"libs/beast" -I"libs/beast/test/extern" -I"libs/beast/test/extras/include" -c -o "bin.v2/libs/beast/test/beast/core/buffered_read_stream.test/gcc-10.0/debug/link-static/thread-sanitizer-norecover/threading-multi/visibility-hidden/buffered_read_stream.o" "libs/beast/test/beast/core/buffered_read_stream.cpp"
gcc.link bin.v2/libs/beast/test/beast/core/buffered_read_stream.test/gcc-10.0/debug/link-static/thread-sanitizer-norecover/threading-multi/visibility-hidden/buffered_read_stream
"g++-10" -o "bin.v2/libs/beast/test/beast/core/buffered_read_stream.test/gcc-10.0/debug/link-static/thread-sanitizer-norecover/threading-multi/visibility-hidden/buffered_read_stream" -Wl,--start-group "bin.v2/libs/beast/test/beast/core/buffered_read_stream.test/gcc-10.0/debug/link-static/thread-sanitizer-norecover/threading-multi/visibility-hidden/buffered_read_stream.o" "bin.v2/libs/beast/test/gcc-10.0/debug/link-static/thread-sanitizer-norecover/threading-multi/visibility-hidden/lib-test.a" "bin.v2/libs/beast/gcc-10.0/debug/link-static/thread-sanitizer-norecover/threading-multi/visibility-hidden/lib-asio.a" "bin.v2/libs/beast/gcc-10.0/debug/link-static/thread-sanitizer-norecover/threading-multi/visibility-hidden/lib-beast.a" "bin.v2/libs/coroutine/build/gcc-10.0/debug/link-static/thread-sanitizer-norecover/threading-multi/visibility-hidden/libboost_coroutine.a" "bin.v2/libs/context/build/gcc-10.0/debug/link-static/thread-sanitizer-norecover/threading-multi/visibility-hidden/libboost_context.a" "bin.v2/libs/filesystem/build/gcc-10.0/debug/link-static/thread-sanitizer-norecover/threading-multi/visibility-hidden/libboost_filesystem.a" "bin.v2/libs/atomic/build/gcc-10.0/debug/link-static/thread-sanitizer-norecover/threading-multi/visibility-hidden/libboost_atomic.a" -Wl,-Bstatic -Wl,-Bdynamic -lrt -Wl,--end-group -m64 -pthread -g -fvisibility=hidden -fvisibility-inlines-hidden -fsanitize=thread -fno-sanitize-recover=thread -fno-omit-frame-pointer
So, now we know that something inside the 208 Asio headers must be involved.
1. Why is SEGV not happening in the CMake build?
Surely, here we should be able to spot difference in compilation flags? Ever-so-slightly redacted to remove spelling differences (left = CMake, right = b2):
I used the process of elimination, figured out that the culprit is -fno-inline -O0. Somehow it leads to recursive TSAN errors:
beast.core.buffered_read_stream
ThreadSanitizer:DEADLYSIGNAL
==2827==ERROR: ThreadSanitizer: SEGV on unknown address 0x60000212fff8 (pc 0x7f319a938bfc bp 0x7f3196fbe1c0 sp 0x7f3196fbe1a8 T2829)
==2827==The signal is caused by a WRITE memory access.
ThreadSanitizer:DEADLYSIGNAL
ThreadSanitizer: nested bug in the same thread, aborting.
Observations without -fno-inline:
from -O2 the symptoms go away
at -O1 the symptoms go away if NDEBUG is defined
at -O0 the symptom is there regardless
This suggests that a NDEBUG-sensitive piece of code could be involved. This might be a lead to guide minimization.
Comparing preprocessed sources may highlight specific possible causes. My main suspicions are the revamped spawned_thread_base in asio/spawn.hpp, source-locations and or cancellation slots.
As a courtesy, here's the preprocessed-buffered-stream-reader.zip containing 4 files (/home/sehe/{with,without}-NDEBUG.i.asio1.{79,80}.0).
Thanks everyone who chipped in on this.
I was was able to get some help from the legendary Chris Kohlhoff, author of the Asio library.
Quoting:
It seems that thread-sanitizer does not correctly handle coroutine/fiber stacks that migrate between threads. This would either be considered a bug in thread-sanitizer, or perhaps a feature request for it.
The issue is in the thread sanitiser library itself.
The workaround in this case is to restructure the code so that the initiation of the fiber takes place on the same thread as the one in which it makes progress.
Here's the old (correct but not TSAN-compatible) code:
template<class F0, class... FN>
inline
void
enable_yield_to::
spawn(F0&& f, FN&&... fn)
{
asio::spawn(ioc_,
[&](yield_context yield)
{
f(yield);
std::lock_guard<std::mutex> lock{m_};
if(--running_ == 0)
cv_.notify_all();
}
, boost::coroutines::attributes(2 * 1024 * 1024));
spawn(fn...);
}
And here's the code with the workaround:
template<class F0, class... FN>
inline
void
enable_yield_to::
spawn(F0&& f, FN&&... fn)
{
// dispatch of spawn is a workaround for
// https://github.com/boostorg/beast/issues/2499
asio::dispatch(ioc_,
[&]
{
asio::spawn(ioc_,
[&](yield_context yield)
{
f(yield);
std::lock_guard<std::mutex> lock{m_};
if(--running_ == 0)
cv_.notify_all();
}
, boost::coroutines::attributes(2 * 1024 * 1024));
});
spawn(fn...);
}
I have a C++ program in Code::Block with gcc and wxWidgets.
After my working thread throws a wxThreadEvent with a struct as payload my program crashes (actually not at the throw, but at the moment I want to get the payload in the main).
Does anyone have an idea what is wrong?
The working thread part:
wxThread::ExitCode NavigationThread::Entry()
{
wxThreadEvent event(wxEVT_THREAD, ID_REFRESH_DIRECTION);
position_variables positionPayload;
positionPayload.latitude = latDouble;
positionPayload.longitude = lonDouble;
positionPayload.direction = direction;
event.SetPayload(&positionPayload);
m_parent->GetEventHandler()->AddPendingEvent(event);
}
The struct:
struct position_variables{
double latitude;
double longitude;
wxString direction;
};
class NavigationThread : public wxThread
{
...
}
The main.cpp
WindowsDgpsGUIFrame::WindowsDgpsGUIFrame(wxWindow* parent,wxWindowID id)
{
Bind(wxEVT_THREAD, &WindowsDgpsGUIFrame::onRefreshDirections, this, ID_REFRESH_DIRECTION);
}
void WindowsDgpsGUIFrame::onRefreshDirections(wxThreadEvent& event)
{
position_variables answerDirections = event.GetPayload<position_variables>(); //Here it crashes
}
When the crash occurs in normal "run" mode, a windows opens saying the program stopped working. In debug mode there is a small window in Code::blocks saying something about SIGSEGV, segmentation fault (or something like that) and this is the Call Stack:
#0 00877A54 std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >::basic_string(std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > const&) () (??:??)
#1 04A1E550 ?? () (??:??)
#2 007ED139 position_variables::position_variables(this=0x4a1e588) (D:/WindowsDgps/WindowsDgpsGUI/NavigationThread.h:54)
#3 00851B54 wxAny::As<position_variables>(this=0x4c6fe70) (C:/wxWidgets-3.0.2/include/wx/any.h:979)
#4 0084E70C wxEventAnyPayloadMixin::GetPayload<position_variables>(this=0x4c6fe58) (C:/wxWidgets-3.0.2/include/wx/event.h:1219)
#5 0043320E WindowsDgpsGUIFrame::onRefreshDirections(this=0x4be2a68, event=...) (D:\WindowsDgps\WindowsDgpsGUI\WindowsDgpsGUIMain.cpp:440)
#6 0063AA48 wxAppConsoleBase::HandleEvent (this=0x4b2bde0, handler=0x4be2a68, func=(void (wxEvtHandler::*)(wxEvtHandler * const, wxEvent &) (../../src/common/appbase.cpp:611)
#7 0063AAD9 wxAppConsoleBase::CallEventHandler(this=0x4b2bde0, handler=0x4be2a68, functor=..., event=...) (../../src/common/appbase.cpp:623)
#8 0062DEA1 wxEvtHandler::ProcessEventIfMatchesId(entry=..., handler=0x4be2a68, event=...) (../../src/common/event.cpp:1392)
#9 0062EB3A wxEvtHandler::SearchDynamicEventTable(this=0x4be2a68, event=...) (../../src/common/event.cpp:1751)
#10 0062E318 wxEvtHandler::TryHereOnly(this=0x4be2a68, event=...) (../../src/common/event.cpp:1585)
#11 007C50A0 wxEvtHandler::TryBeforeAndHere(this=0x4be2a68, event=...) (../../include/wx/event.h:3671)
#12 0062E157 wxEvtHandler::ProcessEventLocally(this=0x4be2a68, event=...) (../../src/common/event.cpp:1522)
#13 0062E0FF wxEvtHandler::ProcessEvent(this=0x4be2a68, event=...) (../../src/common/event.cpp:1495)
#14 0062DCEC wxEvtHandler::ProcessPendingEvents(this=0x4be2a68) (../../src/common/event.cpp:1359)
#15 0063A69C wxAppConsoleBase::ProcessPendingEvents(this=0x4b2bde0) (../../src/common/appbase.cpp:520)
#16 007F0883 wxIdleWakeUpModule::MsgHookProc(nCode=0, wParam=1, lParam=77720172) (../../src/msw/window.cpp:7454)
#17 746BE1A1 USER32!TrackMouseEvent() (C:\WINDOWS\SysWOW64\user32.dll:??)
#18 ?? ?? () (??:??)
with #2 highlighted red.
Maybe it has something to do with the Clone() part in SetPayload()? Though I don't quite get how I should use it or why my accessing of the payload would be problematic...
You can't use a pointer to a local variable, which will be destroyed as soon as you exit the function containing it, thus making the pointer invalid, as the payload. Use the object itself, not a pointer to it, instead.
Having asked this before I tried out a lot of things and found out that the problem has to do with glutInit. Take the following code examples:
main.cpp
#include <iostream>
#include <memory>
#include<GL/glut.h>
using namespace std;
int main(int argcp, char **argv)
{
shared_ptr<double> abc;
glutInit(&argcp,argv);
cout<<"Hello!"<<endl;
return 0;
}
compiled with:
g++ -std=c++11 -g -Wall -o appx main.cpp -lGL -lGLU -lglut
cause the executable to instantly crash (no "Hello!" output) with segfault using g++ 5.2.1, ubuntu 15.10
Just commenting out the line
shared_ptr<double> abc;
will fix the crash.
Since i want to use shared_ptr and glut in a project I would like to know how this can be fixed or what causes the crash.
Edit 1:
GDB trace:
#0 0x0000000000000000 in ?? ()
#1 0x00007ffff33fb6fd in init () at dlerror.c:177
#2 _dlerror_run (operate=operate#entry=0x7ffff33fb0e0 <dlsym_doit>,args=args#entry=0x7fffffffde00) at dlerror.c:129
#3 0x00007ffff33fb148 in __dlsym (handle=<optimized out>, name=optimized out>) at dlsym.c:70
#4 0x00007ffff6fa2e1e in ?? () from /usr/lib/nvidia-352/libGL.so.1
#5 0x00007ffff6f4db47 in ?? () from /usr/lib/nvidia-352/libGL.so.1
#6 0x00007ffff7de957d in call_init (l=0x7ffff7fc59c8,argc=argc#entry=1, argv=argv#entry=0x7fffffffdf58, env=env#entry=0x7fffffffdf68)at dl-init.c:58
#7 0x00007ffff7de96cb in call_init (env=<optimized out>, argv=<optimized out>, argc=<optimized out>, l=<optimized out>) at dl-init.c:30
#8 _dl_init (main_map=0x7ffff7ffe188, argc=1, argv=0x7fffffffdf58, env=0x7fffffffdf68) at dl-init.c:120
#9 0x00007ffff7dd9d0a in _dl_start_user () from /lib64/ld-linux-x86-64.so.2
#10 0x0000000000000001 in ?? ()
#11 0x00007fffffffe2c8 in ?? ()
#12 0x0000000000000000 in ?? ()
As posted in the comments the problem was similar to the problem posted here.
The solution is adding:
-lpthread
to the compiler flags!
Thanks a lot!
I am having a problem with Gcc's thread sanitizer that I cannot find on their bugzilla or on stackoverflow so I am unsure if I am missing something or if this really is a bug. If I create a main.cpp file containing:
#include <thread>
int main(){
std::thread t([](){});
t.join();
return 0;}
Now if I compile it using:
g++-4.9.2 -std=c++1y -fsanitize=thread -fPIE -pie -o TestProgram main.cpp
Running the resulting executable does not yield any problem. Yet if I add the debug info flag:
g++-4.9.2 -std=c++1y -fsanitize=thread -g -fPIE -pie -o TestProgram main.cpp
then the thread sanitizer detects a data race:
WARNING: ThreadSanitizer: data race (pid=22683)
Write of size 8 at 0x7d0c0000efd8 by thread T1:
#0 operator delete(void*) ../../../../gcc-4.9.2/libsanitizer/tsan/tsan_interceptors.cc:592 (libtsan.so.0+0x000000049490)
#1 deallocate /usr/local/include/c++/4.9.2/ext/new_allocator.h:110 (TestProgram+0x000000002089)
#2 deallocate /usr/local/include/c++/4.9.2/bits/alloc_traits.h:383 (TestProgram+0x000000001f78)
#3 _M_destroy /usr/local/include/c++/4.9.2/bits/shared_ptr_base.h:535 (TestProgram+0x0000000026f4)
#4 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /home/UserG/Compile/objdir/x86_64-unknown-linux-gnu/libstdc++-v3/include/bits/shared_ptr_base.h:166 (libstdc++.so.6+0x0000000b5c51)
#5 ~__shared_count /home/UserG/Compile/objdir/x86_64-unknown-linux-gnu/libstdc++-v3/include/bits/shared_ptr_base.h:666 (libstdc++.so.6+0x0000000b5c51)
#6 ~__shared_ptr /home/UserG/Compile/objdir/x86_64-unknown-linux-gnu/libstdc++-v3/include/bits/shared_ptr_base.h:914 (libstdc++.so.6+0x0000000b5c51)
#7 ~shared_ptr /home/UserG/Compile/objdir/x86_64-unknown-linux-gnu/libstdc++-v3/include/bits/shared_ptr.h:93 (libstdc++.so.6+0x0000000b5c51)
#8 execute_native_thread_routine ../../../../../gcc-4.9.2/libstdc++-v3/src/c++11/thread.cc:95 (libstdc++.so.6+0x0000000b5c51)
Previous atomic write of size 4 at 0x7d0c0000efd8 by main thread:
#0 __tsan_atomic32_fetch_add ../../../../gcc-4.9.2/libsanitizer/tsan/tsan_interface_atomic.cc:468 (libtsan.so.0+0x0000000206ce)
#1 __exchange_and_add /usr/local/include/c++/4.9.2/ext/atomicity.h:49 (TestProgram+0x0000000014a0)
#2 __exchange_and_add_dispatch /usr/local/include/c++/4.9.2/ext/atomicity.h:82 (TestProgram+0x000000001557)
#3 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/local/include/c++/4.9.2/bits/shared_ptr_base.h:146 (TestProgram+0x000000002ceb)
#4 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/local/include/c++/4.9.2/bits/shared_ptr_base.h:666 (TestProgram+0x000000002cb6)
#5 std::__shared_ptr<std::thread::_Impl_base, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/local/include/c++/4.9.2/bits/shared_ptr_base.h:914 (TestProgram+0x000000002bc1)
#6 std::shared_ptr<std::thread::_Impl_base>::~shared_ptr() /usr/local/include/c++/4.9.2/bits/shared_ptr.h:93 (TestProgram+0x000000002bed)
#7 thread<main()::<lambda()> > /usr/local/include/c++/4.9.2/thread:135 (TestProgram+0x0000000016f1)
#8 main /home/UserG/main.cpp:3 (TestProgram+0x0000000015af)
Location is heap block of size 48 at 0x7d0c0000efd0 allocated by main thread:
#0 operator new(unsigned long) ../../../../gcc-4.9.2/libsanitizer/tsan/tsan_interceptors.cc:560 (libtsan.so.0+0x0000000496d2)
#1 allocate /usr/local/include/c++/4.9.2/ext/new_allocator.h:104 (TestProgram+0x000000001fe9)
#2 allocate /usr/local/include/c++/4.9.2/bits/alloc_traits.h:357 (TestProgram+0x000000001ecd)
#3 __shared_count<std::thread::_Impl<std::_Bind_simple<main()::<lambda()>()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<main()::<lambda()>()> > >, std::_Bind_simple<main()::<lambda()>()> > /usr/local/include/c++/4.9.2/bits/shared_ptr_base.h:616 (TestProgram+0x000000001d99)
#4 __shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<main()::<lambda()>()> > >, std::_Bind_simple<main()::<lambda()>()> > /usr/local/include/c++/4.9.2/bits/shared_ptr_base.h:1090 (TestProgram+0x000000001ccb)
#5 shared_ptr<std::allocator<std::thread::_Impl<std::_Bind_simple<main()::<lambda()>()> > >, std::_Bind_simple<main()::<lambda()>()> > /usr/local/include/c++/4.9.2/bits/shared_ptr.h:316 (TestProgram+0x000000001c5f)
#6 allocate_shared<std::thread::_Impl<std::_Bind_simple<main()::<lambda()>()> >, std::allocator<std::thread::_Impl<std::_Bind_simple<main()::<lambda()>()> > >, std::_Bind_simple<main()::<lambda()>()> > /usr/local/include/c++/4.9.2/bits/shared_ptr.h:588 (TestProgram+0x000000001bf0)
#7 make_shared<std::thread::_Impl<std::_Bind_simple<main()::<lambda()>()> >, std::_Bind_simple<main()::<lambda()>()> > /usr/local/include/c++/4.9.2/bits/shared_ptr.h:604 (TestProgram+0x000000001ab0)
#8 _M_make_routine<std::_Bind_simple<main()::<lambda()>()> > /usr/local/include/c++/4.9.2/thread:193 (TestProgram+0x000000001919)
#9 thread<main()::<lambda()> > /usr/local/include/c++/4.9.2/thread:135 (TestProgram+0x0000000016bf)
#10 main /home/UserG/main.cpp:3 (TestProgram+0x0000000015af)
Thread T1 (tid=22685, running) created by main thread at:
#0 pthread_create ../../../../gcc-4.9.2/libsanitizer/tsan/tsan_interceptors.cc:877 (libtsan.so.0+0x000000047c03)
#1 __gthread_create /home/UserG/Compile/objdir/x86_64-unknown-linux-gnu/libstdc++-v3/include/x86_64-unknown-linux-gnu/bits/gthr-default.h:662 (libstdc++.so.6+0x0000000b5d00)
#2 std::thread::_M_start_thread(std::shared_ptr<std::thread::_Impl_base>) ../../../../../gcc-4.9.2/libstdc++-v3/src/c++11/thread.cc:142 (libstdc++.so.6+0x0000000b5d00)
#3 main /home/UserG/main.cpp:3 (TestProgram+0x0000000015af)
SUMMARY: ThreadSanitizer: data race /usr/local/include/c++/4.9.2/ext/new_allocator.h:110 deallocate
==================
ThreadSanitizer: reported 1 warnings
Now the exact same code compiled with clang++ (version 3.6.0 (trunk 221144)) does not detect a data race:
clang++ -std=c++1y -fsanitize=thread -g -fPIE -pie -o TestProgram main.cpp
I am a bit quizzical about this behavior from gcc as:
1) passing an empty lambda function as an argument to a thread seems licit to me
2) gcc's behavior depends on the -g flag which doesn't strike me as having much to do with the thread sanitizer
3) under similar circumstances clang adopts a behavior that I would consider correct
Many thanks,
You mean this bug? It was reported for 4.8, but a similar report exists for 4.9.2.
Clang has the -fsanitize-blacklist compile switch to suppress warnings from the ThreadSanitizer. Unfortunately, I cannot get it to work.
Here is an example that I want to suppress:
WARNING: ThreadSanitizer: data race (pid=21502)
Read of size 8 at 0x7f0dcf5b31a8 by thread T6:
#0 tbb::interface6::internal::auto_partition_type_base<tbb::interface6::internal::auto_partition_type>::check_being_stolen(tbb::task&) /usr/include/tbb/partitioner.h:305 (exe+0x000000388b38)
#1 <null> <null>:0 (libtbb.so.2+0x0000000224d9)
Previous write of size 8 at 0x7f0dcf5b31a8 by thread T1:
#0 auto_partition_type_base /usr/include/tbb/partitioner.h:299 (exe+0x000000388d9a)
#1 <null> <null>:0 (libtbb.so.2+0x0000000224d9)
#2 GhostSearch::Ghost3Search::SearchTask::execute_impl() /home/phil/ghost/search/ghost3/ghost3_search_alg.cpp:1456 (exe+0x000000387a8a)
#3 <null> <null>:0 (libtbb.so.2+0x0000000224d9)
#4 GhostSearch::Ghost3Search::Ghost3SearchAlg::NullWindowSearch(int, MOVE, int, std::vector<MOVE, std::allocator<MOVE> >&) /home/phil/ghost/search/ghost3/ghost3_search_alg.cpp:1640 (exe+0x000000388310)
#5 GhostSearch::PureMTDSearchAlg::FullWindowSearch(GhostSearch::SearchWindow, GhostSearch::SearchWindow, MOVE, int, std::vector<MOVE, std::allocator<MOVE> >&) /home/phil/ghost/search/pure_mtd_search_alg.cpp:41 (exe+0x000000370e3f)
#6 GhostSearch::PureSearchAlgWrapper::RequestHandlerThread::EnterHandlerMainLoop() /home/phil/ghost/search/pure_search_alg_wrapper.cpp:124 (exe+0x000000372d1b)
#7 operator() /home/phil/ghost/search/pure_search_alg_wrapper.cpp:94 (exe+0x000000374683)
#8 execute_native_thread_routine /home/phil/tmp/gcc/src/gcc-4.8-20130725/libstdc++-v3/src/c++11/thread.cc:84 (libstdc++.so.6+0x0000000b26cf)
Thread T6 (tid=21518, running) created by thread T3 at:
#0 pthread_create ??:0 (exe+0x0000002378e1)
#1 <null> <null>:0 (libtbb.so.2+0x0000000198c0)
Thread T1 (tid=21513, running) created by main thread at:
#0 pthread_create ??:0 (exe+0x0000002378e1)
#1 __gthread_create /home/phil/tmp/gcc/src/gcc-build/x86_64-unknown-linux-gnu/libstdc++-v3/include/x86_64-unknown-linux-gnu/bits/gthr-default.h:662 (libstdc++.so.6+0x0000000b291e)
#2 GhostSearch::PureSearchAlgWrapper::StartRequestHandlerThread() /home/phil/ghost/search/pure_search_alg_wrapper.cpp:77 (exe+0x0000003715c3)
#3 GhostSearch::Search::ExecuteSearch(GhostSearch::SEARCH_SETTINGS const&) /home/phil/ghost/search.cpp:243 (exe+0x00000033063f)
#4 GhostSearch::Search::StartSearch(GhostSearch::SEARCH_SETTINGS const&, UserBoard const&, GhostInterfaces::UserInterface*) /home/phil/ghost/search.cpp:176 (exe+0x00000033037a)
#5 GhostInterfaces::UserInterface::StartSearch(GhostSearch::SEARCH_SETTINGS const&, UserBoard const&) /home/phil/ghost/interface.cpp:1072 (exe+0x0000002ea220)
#6 GhostInterfaces::UserInterface::MainLoop() /home/phil/ghost/interface.cpp:576 (exe+0x0000002e9464)
#7 GhostInterfaces::Command_Analyze::Execute(GhostInterfaces::UserInterfaceData&) /home/phil/ghost/commands.cpp:1005 (exe+0x00000028756c)
#8 GhostInterfaces::UserInterface::FinishNextCommand() /home/phil/ghost/interface.cpp:1161 (exe+0x0000002e9ed0)
#9 GhostInterfaces::UserInterface::MainLoop() /home/phil/ghost/interface.cpp:571 (exe+0x0000002e9447)
#10 main /home/phil/ghost/ghost.cpp:54 (exe+0x000000274efd)
SUMMARY: ThreadSanitizer: data race /usr/include/tbb/partitioner.h:305 tbb::interface6::internal::auto_partition_type_base<tbb::interface6::internal::auto_partition_type>::check_being_stolen(tbb::task&)
My tries for the suppression file so far (but it does not work):
# TBB
fun:tbb::*
src:/usr/include/tbb/partitioner.h
Do you know why it does not work?
(By the way, I would be happy to suppress all warnings from the TBB library.)
Finally, I got it working.
According to the documentation, each line must start with a valid "suppression_type" (race, thread, mutex, signal, deadlock, or called_from_lib).
In my example, the correct suppression_type is race.
Here is an example file called "sanitizer-thread-suppressions.txt", which suppresses two functions, which are known to contain data races:
race:Function1
race:MyNamespace::Function2
To test the suppress file, set the TSAN_OPTIONS environment variable and call the application (compiled with -fsanitize=thread):
$ TSAN_OPTIONS="suppressions=sanitizer-thread-suppressions.txt" ./myapp
If that works, you can apply the settings at compile time:
-fsanitize=thread -fsanitize-blacklist=sanitizer-thread-suppressions.txt