[Bug sanitizer/78755] New: Thread sanitizer reports race with std::promise with -O0, works with -O{1,2,3}
csaba_22 at yahoo dot co.uk
gcc-bugzilla@gcc.gnu.org
Fri Dec 9 16:55:00 GMT 2016
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78755
Bug ID: 78755
Summary: Thread sanitizer reports race with std::promise with
-O0, works with -O{1,2,3}
Product: gcc
Version: 6.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: sanitizer
Assignee: unassigned at gcc dot gnu.org
Reporter: csaba_22 at yahoo dot co.uk
CC: dodji at gcc dot gnu.org, dvyukov at gcc dot gnu.org,
jakub at gcc dot gnu.org, kcc at gcc dot gnu.org
Target Milestone: ---
Hand-built GCC on Ubuntu 14.04LTS.
$ g++-620 -v
Using built-in specs.
COLLECT_GCC=g++-620
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-pc-linux-gnu/6.2.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: ../gcc-6.2.0/configure --program-suffix=-620
--enable-version-specific-runtime-libs --enable-languages=c,c++,lto
Thread model: posix
gcc version 6.2.0 (GCC)
Source:
#include <thread>
#include <future>
#include <atomic>
#include <memory>
#include <iostream>
class SD {
public:
~SD()
{
stop();
}
//
void start();
void stop();
void operator()();
private:
std::unique_ptr<std::thread> thread_; ///< The thread object.
std::promise<void> promise_; ///< The synchronization
promise.
std::atomic_bool bored_{false}; ///< Loop exit flag
};
void SD::start()
{
thread_.reset(new std::thread{std::ref(*this)});
// Indicating that the thread_ object can be used.
promise_.set_value(); // data race: write
}
void SD::stop()
{
if (thread_) { // it's running
bored_ = true; // tell it to stop
thread_->join(); // wait for it to stop
}
}
void SD::operator ()()
{
// Making sure that the thread_ object has been set properly.
promise_.get_future().wait(); // data race: read
while (!bored_) {
std::cout << (bored_ ? " " : "not") << " bored\n";
std::this_thread::sleep_for(std::chrono::seconds{1});
}
}
int main()
{
SD s;
std::cout << "Thread created\n";
s.start();
std::cout << "Thread is running\n";
std::this_thread::sleep_for(std::chrono::seconds{2});
std::cout << "Goodbye\n";
}
$ g++-620 -fsanitize=thread -g -O0 -pthread -std=gnu++0x -Wall -pedantic
-Wextra -Wformat=2 -I ~/workspace/zarquon -o "promise" "promise-std.cc"
-lboost_thread -lboost_system -save-temps
(no errors)
$ ./promise
Thread created
Thread is running
==================
WARNING: ThreadSanitizer: data race (pid=23398)
Read of size 8 at 0x7d0c0000efe8 by thread T1:
#0 std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter>::get() const
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/bits/unique_ptr.h:305
(promise+0x000000405d59)
#1 std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter>::operator*() const
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/bits/unique_ptr.h:291
(promise+0x000000404334)
#2 std::__future_base::_State_baseV2::wait()
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/future:329
(promise+0x00000040343b)
#3 std::__basic_future<void>::wait() const
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/future:662
(promise+0x0000004056b4)
#4 SD::operator()() /tmp/promise-std.cc:41 (promise+0x0000004024f5)
#5 void std::__invoke_impl<void, SD&>(std::__invoke_other, SD&)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/functional:218
(promise+0x0000004091f7)
#6 std::result_of<SD& ()>::type std::__invoke<SD&>(SD&)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/functional:260
(promise+0x0000004091a6)
#7 std::result_of<SD& ()>::type std::reference_wrapper<SD>::operator()<>()
const /usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/functional:474
(promise+0x000000409108)
#8 void std::_Bind_simple<std::reference_wrapper<SD>
()>::_M_invoke<>(std::_Index_tuple<>)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/functional:1400
(promise+0x0000004090b8)
#9 std::_Bind_simple<std::reference_wrapper<SD> ()>::operator()()
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/functional:1389
(promise+0x000000408f91)
#10 std::thread::_State_impl<std::_Bind_simple<std::reference_wrapper<SD>
()> >::_M_run()
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/thread:196
(promise+0x000000408ed8)
#11 execute_native_thread_routine
../../../../../gcc-6.1.0/libstdc++-v3/src/c++11/thread.cc:83
(libstdc++.so.6+0x0000000b8901)
Previous write of size 8 at 0x7d0c0000efe8 by main thread:
#0
std::enable_if<std::__and_<std::is_move_constructible<std::__future_base::_Result_base*>,
std::is_move_assignable<std::__future_base::_Result_base*> >::value,
void>::type
std::swap<std::__future_base::_Result_base*>(std::__future_base::_Result_base*&,
std::__future_base::_Result_base*&)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/bits/move.h:191
(promise+0x000000407f6e)
#1 std::_Tuple_impl<0ul, std::__future_base::_Result_base*,
std::__future_base::_Result_base::_Deleter>::_M_swap(std::_Tuple_impl<0ul,
std::__future_base::_Result_base*,
std::__future_base::_Result_base::_Deleter>&)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/tuple:331
(promise+0x000000407bd4)
#2 std::tuple<std::__future_base::_Result_base*,
std::__future_base::_Result_base::_Deleter>::swap(std::tuple<std::__future_base::_Result_base*,
std::__future_base::_Result_base::_Deleter>&)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/tuple:1215
(promise+0x0000004070aa)
#3 void std::swap<std::__future_base::_Result_base*,
std::__future_base::_Result_base::_Deleter>(std::tuple<std::__future_base::_Result_base*,
std::__future_base::_Result_base::_Deleter>&,
std::tuple<std::__future_base::_Result_base*,
std::__future_base::_Result_base::_Deleter>&)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/tuple:1548
(promise+0x000000405fd2)
#4 std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter>::swap(std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter>&)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/bits/unique_ptr.h:352
(promise+0x0000004048fa)
#5
std::__future_base::_State_baseV2::_M_do_set(std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/future:538
(promise+0x000000403885)
#6 void std::__invoke_impl<void, void (std::__future_base::_State_baseV2::*
const&)(std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*),
std::__future_base::_State_baseV2*,
std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*,
bool*>(std::__invoke_memfun_deref, void (std::__future_base::_State_baseV2::*
const&)(std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*),
std::__future_base::_State_baseV2*&&,
std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/functional:235
(promise+0x000000408771)
#7 std::result_of<void (std::__future_base::_State_baseV2::*
const&(std::__future_base::_State_baseV2*&&,
std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*&&,
bool*&&))(std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*)>::type
std::__invoke<void (std::__future_base::_State_baseV2::*
const&)(std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*),
std::__future_base::_State_baseV2*,
std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*>(void
(std::__future_base::_State_baseV2::*
const&)(std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*),
std::__future_base::_State_baseV2*&&,
std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/functional:260
(promise+0x0000004081fb)
#8 decltype (__invoke((*this)._M_pmf,
(forward<std::__future_base::_State_baseV2*>)({parm#1}),
(forward<std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*>)({parm#1}),
(forward<bool*>)({parm#1}))) std::_Mem_fn_base<void
(std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*),
true>::operator()<std::__future_base::_State_baseV2*,
std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*,
bool*>(std::__future_base::_State_baseV2*&&,
std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&) const
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/functional:613
(promise+0x000000407ecf)
#9 void std::_Bind_simple<std::_Mem_fn<void
(std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*)>
(std::__future_base::_State_baseV2*,
std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*)>::_M_invoke<0ul, 1ul,
2ul>(std::_Index_tuple<0ul, 1ul, 2ul>)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/functional:1400
(promise+0x000000407b6a)
#10 std::_Bind_simple<std::_Mem_fn<void
(std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*)>
(std::__future_base::_State_baseV2*,
std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*)>::operator()()
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/functional:1389
(promise+0x000000407057)
#11 void std::__once_call_impl<std::_Bind_simple<std::_Mem_fn<void
(std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*)>
(std::__future_base::_State_baseV2*,
std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*)> >()
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/mutex:587
(promise+0x000000405f82)
#12 pthread_once
../../../../gcc-6.1.0/libsanitizer/tsan/tsan_interceptors.cc:1304
(libtsan.so.0+0x0000000294af)
#13 __gthread_once
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/x86_64-pc-linux-gnu/bits/gthr-default.h:699
(promise+0x000000402190)
#14 void std::call_once<void
(std::__future_base::_State_baseV2::*)(std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*),
std::__future_base::_State_baseV2*,
std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*>(std::once_flag&, void
(std::__future_base::_State_baseV2::*&&)(std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*, bool*),
std::__future_base::_State_baseV2*&&,
std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>*&&, bool*&&)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/mutex:619
(promise+0x00000040471a)
#15
std::__future_base::_State_baseV2::_M_set_result(std::function<std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter> ()>, bool)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/future:393
(promise+0x00000040353c)
#16 std::promise<void>::set_value()
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/future:1308
(promise+0x000000403d82)
#17 SD::start() /tmp/promise-std.cc:27 (promise+0x000000402411)
#18 main /tmp/promise-std.cc:53 (promise+0x0000004025f7)
Location is heap block of size 48 at 0x7d0c0000efd0 allocated by main thread:
#0 operator new(unsigned long)
../../../../gcc-6.1.0/libsanitizer/tsan/tsan_new_delete.cc:43
(libtsan.so.0+0x000000065833)
#1
__gnu_cxx::new_allocator<std::_Sp_counted_ptr_inplace<std::__future_base::_State_baseV2,
std::allocator<std::__future_base::_State_baseV2>, (__gnu_cxx::_Lock_policy)2>
>::allocate(unsigned long, void const*)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/ext/new_allocator.h:104
(promise+0x000000408a1f)
#2
std::allocator_traits<std::allocator<std::_Sp_counted_ptr_inplace<std::__future_base::_State_baseV2,
std::allocator<std::__future_base::_State_baseV2>, (__gnu_cxx::_Lock_policy)2>
>
>::allocate(std::allocator<std::_Sp_counted_ptr_inplace<std::__future_base::_State_baseV2,
std::allocator<std::__future_base::_State_baseV2>, (__gnu_cxx::_Lock_policy)2>
>&, unsigned long)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/bits/alloc_traits.h:416
(promise+0x0000004087e5)
#3
std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<std::__future_base::_State_baseV2,
std::allocator<std::__future_base::_State_baseV2>, (__gnu_cxx::_Lock_policy)2>
> >
std::__allocate_guarded<std::allocator<std::_Sp_counted_ptr_inplace<std::__future_base::_State_baseV2,
std::allocator<std::__future_base::_State_baseV2>, (__gnu_cxx::_Lock_policy)2>
>
>(std::allocator<std::_Sp_counted_ptr_inplace<std::__future_base::_State_baseV2,
std::allocator<std::__future_base::_State_baseV2>, (__gnu_cxx::_Lock_policy)2>
>&)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/bits/allocated_ptr.h:103
(promise+0x000000408307)
#4
std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<std::__future_base::_State_baseV2,
std::allocator<std::__future_base::_State_baseV2>>(std::_Sp_make_shared_tag,
std::__future_base::_State_baseV2*,
std::allocator<std::__future_base::_State_baseV2> const&)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/bits/shared_ptr_base.h:613
(promise+0x00000040806f)
#5 std::__shared_ptr<std::__future_base::_State_baseV2,
(__gnu_cxx::_Lock_policy)2>::__shared_ptr<std::allocator<std::__future_base::_State_baseV2>>(std::_Sp_make_shared_tag,
std::allocator<std::__future_base::_State_baseV2> const&)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/bits/shared_ptr_base.h:1100
(promise+0x000000407c54)
#6
std::shared_ptr<std::__future_base::_State_baseV2>::shared_ptr<std::allocator<std::__future_base::_State_baseV2>>(std::_Sp_make_shared_tag,
std::allocator<std::__future_base::_State_baseV2> const&)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/bits/shared_ptr.h:319
(promise+0x000000407136)
#7 std::shared_ptr<std::__future_base::_State_baseV2>
std::allocate_shared<std::__future_base::_State_baseV2,
std::allocator<std::__future_base::_State_baseV2>>(std::allocator<std::__future_base::_State_baseV2>
const&)
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/bits/shared_ptr.h:620
(promise+0x0000004060ec)
#8 std::shared_ptr<std::__future_base::_State_baseV2>
std::make_shared<std::__future_base::_State_baseV2>()
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/bits/shared_ptr.h:636
(promise+0x000000404b2a)
#9 std::promise<void>::promise()
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/future:1223
(promise+0x000000403ac2)
#10 SD::SD() /tmp/promise-std.cc:7 (promise+0x000000403fbc)
#11 main /tmp/promise-std.cc:51 (promise+0x0000004025dc)
Thread T1 (tid=23400, running) created by main thread at:
#0 pthread_create
../../../../gcc-6.1.0/libsanitizer/tsan/tsan_interceptors.cc:876
(libtsan.so.0+0x000000027bfd)
#1 __gthread_create
/home/csabaraduly/workspace/GCC61/__build_with_isl/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/gthr-default.h:662
(libstdc++.so.6+0x0000000b8bf4)
#2 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State,
std::default_delete<std::thread::_State> >, void (*)())
../../../../../gcc-6.1.0/libstdc++-v3/src/c++11/thread.cc:163
(libstdc++.so.6+0x0000000b8bf4)
#3 SD::start() /tmp/promise-std.cc:25 (promise+0x0000004023f2)
#4 main /tmp/promise-std.cc:53 (promise+0x0000004025f7)
SUMMARY: ThreadSanitizer: data race
/usr/local/lib/gcc/x86_64-pc-linux-gnu/6.2.0/include/c++/bits/unique_ptr.h:305
in std::unique_ptr<std::__future_base::_Result_base,
std::__future_base::_Result_base::_Deleter>::get() const
==================
not bored
not bored
Goodbye
ThreadSanitizer: reported 1 warnings
If compiled with -O1 or higher, the program runs without a complaint.
More information about the Gcc-bugs
mailing list