https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113244
Bug ID: 113244 Summary: Potential thread sanitizer false positive with future exception Product: gcc Version: 13.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: sanitizer Assignee: unassigned at gcc dot gnu.org Reporter: gcc-bugzilla at mhxnet dot de 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, marxin at gcc dot gnu.org Target Milestone: --- Created attachment 56994 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=56994&action=edit C++ code to reproduce the issue Using `g++-13 (Gentoo 13.2.1_p20230826 p7) 13.2.1 20230826` and compiling the attached program with g++-13 -std=c++20 -g -O2 -fsanitize=thread -fno-omit-frame-pointer -o packaged_task packaged_task.cpp Thread Sanitizer will likely, but not always, report several data races related to the exception stored in the future. The races are between reading from the exception object in the catch block on the main thread and destroying the exception as a result of packaged_task going out of scope in one of the worker threads. ================== WARNING: ThreadSanitizer: data race on vptr (ctor/dtor vs virtual call) (pid=7610) Write of size 8 at 0x7b2c00031460 by thread T9: #0 ~error_base /home/mhx/src/c++/test/packaged_task.cpp:12 (packaged_task+0x5574) #1 ~my_error /home/mhx/src/c++/test/packaged_task.cpp:22 (packaged_task+0x5574) #2 std::__exception_ptr::exception_ptr::_M_release() /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/gcc-13-20230826/libstdc++-v3/libsupc++/eh_ptr.cc:105 (libstdc++.so.6+0xb2f30) #3 std::__future_base::_Result<void>::_M_destroy() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/future:672 (packaged_task+0x5287) #4 std::__future_base::_Result_base::_Deleter::operator()(std::__future_base::_Result_base*) const /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/future:229 (packaged_task+0x5287) #5 std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>::~unique_ptr() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/unique_ptr.h:404 (packaged_task+0x5287) #6 std::__future_base::_State_baseV2::~_State_baseV2() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/future:344 (packaged_task+0x5287) #7 std::__future_base::_Task_state_base<void ()>::~_Task_state_base() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/future:1450 (packaged_task+0x5287) #8 ~_Task_state /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/future:1477 (packaged_task+0x5287) #9 destroy_at<std::__future_base::_Task_state<main()::<lambda()>, std::allocator<int>, void()> > /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/stl_construct.h:88 (packaged_task+0x5287) #10 destroy<std::__future_base::_Task_state<main()::<lambda()>, std::allocator<int>, void()> > /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/alloc_traits.h:559 (packaged_task+0x5287) #11 _M_dispose /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/shared_ptr_base.h:613 (packaged_task+0x5287) #12 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release_last_use() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/shared_ptr_base.h:175 (packaged_task+0x83bc) #13 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/shared_ptr_base.h:361 (packaged_task+0x83bc) #14 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/shared_ptr_base.h:1071 (packaged_task+0x83bc) #15 std::__shared_ptr<std::__future_base::_Task_state_base<void ()>, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/shared_ptr_base.h:1524 (packaged_task+0x83bc) #16 std::shared_ptr<std::__future_base::_Task_state_base<void ()> >::~shared_ptr() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/shared_ptr.h:175 (packaged_task+0x83bc) #17 std::packaged_task<void ()>::~packaged_task() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/future:1594 (packaged_task+0x83bc) #18 std::_Optional_payload_base<std::packaged_task<void ()> >::_M_destroy() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/optional:287 (packaged_task+0x645c) #19 std::_Optional_payload_base<std::packaged_task<void ()> >::_M_reset() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/optional:318 (packaged_task+0x645c) #20 std::_Optional_payload<std::packaged_task<void ()>, false, false, false>::~_Optional_payload() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/optional:439 (packaged_task+0x645c) #21 std::_Optional_base<std::packaged_task<void ()>, false, false>::~_Optional_base() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/optional:510 (packaged_task+0x645c) #22 std::optional<std::packaged_task<void ()> >::~optional() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/optional:705 (packaged_task+0x645c) #23 worker /home/mhx/src/c++/test/packaged_task.cpp:45 (packaged_task+0x645c) #24 void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/invoke.h:61 (packaged_task+0x6760) #25 std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/invoke.h:96 (packaged_task+0x6760) #26 void std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/std_thread.h:292 (packaged_task+0x6760) #27 std::thread::_Invoker<std::tuple<void (*)()> >::operator()() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/std_thread.h:299 (packaged_task+0x6760) #28 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/std_thread.h:244 (packaged_task+0x6760) #29 execute_native_thread_routine /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/gcc-13-20230826/libstdc++-v3/src/c++11/thread.cc:104 (libstdc++.so.6+0xe157e) Previous read of size 8 at 0x7b2c00031460 by main thread: #0 main /home/mhx/src/c++/test/packaged_task.cpp:96 (packaged_task+0x3c4a) Location is heap block of size 168 at 0x7b2c000313e0 allocated by thread T9: #0 malloc /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/gcc-13-20230826/libsanitizer/tsan/tsan_interceptors_posix.cpp:681 (libtsan.so.2+0x3a963) #1 __cxa_allocate_exception /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/gcc-13-20230826/libstdc++-v3/libsupc++/eh_alloc.cc:398 (libstdc++.so.6+0xb1fbf) #2 std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>::operator()() const /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/std_function.h:591 (packaged_task+0x6bbb) #3 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/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/future:589 (packaged_task+0x6bbb) #4 void std::__invoke_impl<void, 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::__invoke_memfun_deref, 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/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/invoke.h:74 (packaged_task+0x697a) #5 std::__invoke_result<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*>::type std::__invoke<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*>(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/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/invoke.h:96 (packaged_task+0x697a) #6 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*&&)::{lambda()#1}::operator()() const /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/mutex:900 (packaged_task+0x697a) #7 std::once_flag::_Prepare_execution::_Prepare_execution<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*&&)::{lambda()#1}>(void (std::__future_base::_State_baseV2::*&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*))::{lambda()#1}::operator()() const /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/mutex:836 (packaged_task+0x697a) #8 std::once_flag::_Prepare_execution::_Prepare_execution<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*&&)::{lambda()#1}>(void (std::__future_base::_State_baseV2::*&)(std::function<std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter> ()>*, bool*))::{lambda()#1}::_FUN() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/mutex:836 (packaged_task+0x697a) #9 pthread_once /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/gcc-13-20230826/libsanitizer/tsan/tsan_interceptors_posix.cpp:1551 (libtsan.so.2+0x5d742) #10 __gthread_once /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/x86_64-pc-linux-gnu/bits/gthr-default.h:700 (packaged_task+0x6f4e) #11 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/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/mutex:907 (packaged_task+0x6f4e) #12 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/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/future:428 (packaged_task+0x62d0) #13 _M_run /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/future:1494 (packaged_task+0x62d0) #14 std::packaged_task<void ()>::operator()() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/future:1628 (packaged_task+0x62d0) #15 worker /home/mhx/src/c++/test/packaged_task.cpp:44 (packaged_task+0x62d0) #16 void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/invoke.h:61 (packaged_task+0x6760) #17 std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/invoke.h:96 (packaged_task+0x6760) #18 void std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/std_thread.h:292 (packaged_task+0x6760) #19 std::thread::_Invoker<std::tuple<void (*)()> >::operator()() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/std_thread.h:299 (packaged_task+0x6760) #20 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/std_thread.h:244 (packaged_task+0x6760) #21 execute_native_thread_routine /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/gcc-13-20230826/libstdc++-v3/src/c++11/thread.cc:104 (libstdc++.so.6+0xe157e) Thread T9 (tid=7620, running) created by main thread at: #0 pthread_create /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/gcc-13-20230826/libsanitizer/tsan/tsan_interceptors_posix.cpp:1036 (libtsan.so.2+0x3b7c5) #1 __gthread_create /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/build/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/gthr-default.h:663 (libstdc++.so.6+0xe1644) #2 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/gcc-13-20230826/libstdc++-v3/src/c++11/thread.cc:172 (libstdc++.so.6+0xe1644) #3 std::thread& std::vector<std::thread, std::allocator<std::thread> >::emplace_back<void (&)()>(void (&)()) /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/vector.tcc:123 (packaged_task+0x4044) #4 start_workers /home/mhx/src/c++/test/packaged_task.cpp:58 (packaged_task+0x4044) #5 main /home/mhx/src/c++/test/packaged_task.cpp:74 (packaged_task+0x4044) SUMMARY: ThreadSanitizer: data race on vptr (ctor/dtor vs virtual call) /home/mhx/src/c++/test/packaged_task.cpp:12 in ~error_base ================== ================== WARNING: ThreadSanitizer: data race (pid=7610) Write of size 8 at 0x7b2c00031468 by thread T9: #0 free /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/gcc-13-20230826/libsanitizer/tsan/tsan_interceptors_posix.cpp:740 (libtsan.so.2+0x3ae4b) #1 std::__exception_ptr::exception_ptr::_M_release() /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/gcc-13-20230826/libstdc++-v3/libsupc++/eh_ptr.cc:107 (libstdc++.so.6+0xb2f38) #2 std::__exception_ptr::exception_ptr::_M_release() /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/gcc-13-20230826/libstdc++-v3/libsupc++/eh_ptr.cc:96 (libstdc++.so.6+0xb2f38) #3 std::__future_base::_Result<void>::_M_destroy() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/future:672 (packaged_task+0x5287) #4 std::__future_base::_Result_base::_Deleter::operator()(std::__future_base::_Result_base*) const /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/future:229 (packaged_task+0x5287) #5 std::unique_ptr<std::__future_base::_Result_base, std::__future_base::_Result_base::_Deleter>::~unique_ptr() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/unique_ptr.h:404 (packaged_task+0x5287) #6 std::__future_base::_State_baseV2::~_State_baseV2() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/future:344 (packaged_task+0x5287) #7 std::__future_base::_Task_state_base<void ()>::~_Task_state_base() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/future:1450 (packaged_task+0x5287) #8 ~_Task_state /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/future:1477 (packaged_task+0x5287) #9 destroy_at<std::__future_base::_Task_state<main()::<lambda()>, std::allocator<int>, void()> > /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/stl_construct.h:88 (packaged_task+0x5287) #10 destroy<std::__future_base::_Task_state<main()::<lambda()>, std::allocator<int>, void()> > /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/alloc_traits.h:559 (packaged_task+0x5287) #11 _M_dispose /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/shared_ptr_base.h:613 (packaged_task+0x5287) #12 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release_last_use() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/shared_ptr_base.h:175 (packaged_task+0x83bc) #13 std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/shared_ptr_base.h:361 (packaged_task+0x83bc) #14 std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/shared_ptr_base.h:1071 (packaged_task+0x83bc) #15 std::__shared_ptr<std::__future_base::_Task_state_base<void ()>, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/shared_ptr_base.h:1524 (packaged_task+0x83bc) #16 std::shared_ptr<std::__future_base::_Task_state_base<void ()> >::~shared_ptr() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/shared_ptr.h:175 (packaged_task+0x83bc) #17 std::packaged_task<void ()>::~packaged_task() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/future:1594 (packaged_task+0x83bc) #18 std::_Optional_payload_base<std::packaged_task<void ()> >::_M_destroy() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/optional:287 (packaged_task+0x645c) #19 std::_Optional_payload_base<std::packaged_task<void ()> >::_M_reset() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/optional:318 (packaged_task+0x645c) #20 std::_Optional_payload<std::packaged_task<void ()>, false, false, false>::~_Optional_payload() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/optional:439 (packaged_task+0x645c) #21 std::_Optional_base<std::packaged_task<void ()>, false, false>::~_Optional_base() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/optional:510 (packaged_task+0x645c) #22 std::optional<std::packaged_task<void ()> >::~optional() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/optional:705 (packaged_task+0x645c) #23 worker /home/mhx/src/c++/test/packaged_task.cpp:45 (packaged_task+0x645c) #24 void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/invoke.h:61 (packaged_task+0x6760) #25 std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/invoke.h:96 (packaged_task+0x6760) #26 void std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/std_thread.h:292 (packaged_task+0x6760) #27 std::thread::_Invoker<std::tuple<void (*)()> >::operator()() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/std_thread.h:299 (packaged_task+0x6760) #28 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run() /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/std_thread.h:244 (packaged_task+0x6760) #29 execute_native_thread_routine /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/gcc-13-20230826/libstdc++-v3/src/c++11/thread.cc:104 (libstdc++.so.6+0xe157e) Previous read of size 8 at 0x7b2c00031468 by main thread: #0 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_data() const /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/basic_string.h:223 (packaged_task+0x4f7d) #1 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::c_str() const /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/basic_string.h:2584 (packaged_task+0x4f7d) #2 what /home/mhx/src/c++/test/packaged_task.cpp:16 (packaged_task+0x4f7d) #3 main /home/mhx/src/c++/test/packaged_task.cpp:96 (packaged_task+0x3c5e) Thread T9 (tid=7620, running) created by main thread at: #0 pthread_create /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/gcc-13-20230826/libsanitizer/tsan/tsan_interceptors_posix.cpp:1036 (libtsan.so.2+0x3b7c5) #1 __gthread_create /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/build/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/gthr-default.h:663 (libstdc++.so.6+0xe1644) #2 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/gcc-13-20230826/libstdc++-v3/src/c++11/thread.cc:172 (libstdc++.so.6+0xe1644) #3 std::thread& std::vector<std::thread, std::allocator<std::thread> >::emplace_back<void (&)()>(void (&)()) /usr/lib/gcc/x86_64-pc-linux-gnu/13/include/g++-v13/bits/vector.tcc:123 (packaged_task+0x4044) #4 start_workers /home/mhx/src/c++/test/packaged_task.cpp:58 (packaged_task+0x4044) #5 main /home/mhx/src/c++/test/packaged_task.cpp:74 (packaged_task+0x4044) SUMMARY: ThreadSanitizer: data race /var/tmp/portage/sys-devel/gcc-13.2.1_p20230826/work/gcc-13-20230826/libstdc++-v3/libsupc++/eh_ptr.cc:107 in std::__exception_ptr::exception_ptr::_M_release() ================== errors: 20000 ThreadSanitizer: reported 2 warnings I believe what happens is that future::get() is called on the main thread, rethrowing the stored exception, before the packaged_task in the worker thread goes out of scope. Hence the exception_ptr refcount is 1 by the time packaged_task goes out of scope and the exception object is freed on the worker thread. I *think* the code and the behaviour are actually fine and the reported race is a false positive. This actually reproduces quite reliably on godbolt with both gcc-10 and gcc-13: https://gcc.godbolt.org/z/E97exx4MP