<html>
<head>
<base href="https://llvm.org/bugs/" />
</head>
<body><table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Bug ID</th>
<td><a class="bz_bug_link
bz_status_NEW "
title="NEW --- - libcxx: racy use-after-free on condition_variable"
href="https://llvm.org/bugs/show_bug.cgi?id=23293">23293</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>libcxx: racy use-after-free on condition_variable
</td>
</tr>
<tr>
<th>Product</th>
<td>libc++
</td>
</tr>
<tr>
<th>Version</th>
<td>unspecified
</td>
</tr>
<tr>
<th>Hardware</th>
<td>PC
</td>
</tr>
<tr>
<th>OS</th>
<td>Linux
</td>
</tr>
<tr>
<th>Status</th>
<td>NEW
</td>
</tr>
<tr>
<th>Severity</th>
<td>release blocker
</td>
</tr>
<tr>
<th>Priority</th>
<td>P
</td>
</tr>
<tr>
<th>Component</th>
<td>All Bugs
</td>
</tr>
<tr>
<th>Assignee</th>
<td>unassignedclangbugs@nondot.org
</td>
</tr>
<tr>
<th>Reporter</th>
<td>dvyukov@google.com
</td>
</tr>
<tr>
<th>CC</th>
<td>llvmbugs@cs.uiuc.edu, mclow.lists@gmail.com
</td>
</tr>
<tr>
<th>Classification</th>
<td>Unclassified
</td>
</tr></table>
<p>
<div>
<pre>clang version 3.7.0 (trunk 235293)
Target: x86_64-unknown-linux-gnu
The program is:
#include <iostream>
#include <memory>
#include <future>
#include <atomic>
std::atomic<int> _counter;
int main()
{
_counter = 1;
auto f = std::async(std::launch::async,
[]{
_counter += 2;
return true;
});
std::cout << "Result: " << std::boolalpha << f.get() << "\n";
return 0;
}
ThreadSanitizer says:
==================
WARNING: ThreadSanitizer: data race (pid=19479)
Write of size 8 at 0x7d200000bfc0 by main thread:
#0 pthread_cond_destroy
/ssd/src/llvm/build/../projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:1153
(a.out+0x00000044aa8c)
#1 std::__1::condition_variable::~condition_variable()
build/../projects/libcxx/src/condition_variable.cpp:23:5
(libc++.so.1+0x00000008cb69)
#2 std::__1::__assoc_sub_state::~__assoc_sub_state()
build/bin/../include/c++/v1/future:515:24 (a.out+0x00000049999a)
#3 std::__1::__async_assoc_state<bool, std::__1::__async_func<main::$_0>
<span class="quote">>::~__async_assoc_state() build/bin/../include/c++/v1/future:940:7</span >
(a.out+0x0000004992d5)
#4 std::__1::__assoc_state<bool>::__on_zero_shared()
build/bin/../include/c++/v1/future:635:5 (a.out+0x000000499a63)
#5 std::__1::__async_assoc_state<bool, std::__1::__async_func<main::$_0>
<span class="quote">>::__on_zero_shared() build/bin/../include/c++/v1/future:990:5</span >
(a.out+0x00000049930d)
#6 std::__1::__shared_count::__release_shared()
build/../projects/libcxx/src/memory.cpp:63:9 (libc++.so.1+0x00000008eb20)
#7 std::__1::__release_shared_count::operator()(std::__1::__shared_count*)
build/bin/../include/c++/v1/future:1155:41 (a.out+0x00000049a155)
#8 std::__1::unique_ptr<std::__1::__shared_count,
std::__1::__release_shared_count>::reset(std::__1::__shared_count*)
build/bin/../include/c++/v1/memory:2669:13 (a.out+0x0000004996bd)
#9 std::__1::unique_ptr<std::__1::__shared_count,
std::__1::__release_shared_count>::~unique_ptr()
build/bin/../include/c++/v1/memory:2637 (a.out+0x0000004996bd)
#10 std::__1::future<bool>::get() build/bin/../include/c++/v1/future:1173
(a.out+0x0000004996bd)
#11 main /tmp/shared_ptr.cc:17:50 (a.out+0x000000498f62)
Previous read of size 8 at 0x7d200000bfc0 by thread T1:
#0 pthread_cond_broadcast
/ssd/src/llvm/build/../projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:1146
(a.out+0x000000447e40)
#1 std::__1::condition_variable::notify_all()
build/../projects/libcxx/src/condition_variable.cpp:35:5
(libc++.so.1+0x00000008cbc9)
#2 void std::__1::__assoc_state<bool>::set_value<bool>(bool&&)
build/bin/../include/c++/v1/future:655:5 (a.out+0x000000499c01)
#3 std::__1::__async_assoc_state<bool, std::__1::__async_func<main::$_0>
<span class="quote">>::__execute() build/bin/../include/c++/v1/future:975:9 (a.out+0x00000049934e)</span >
#4
_ZNSt3__18__invokeIMNS_19__async_assoc_stateIbNS_12__async_funcIZ4mainE3$_0JEEEEEFvvEPS5_JEvEEDTcldsdeclsr3std3__1E7forwardIT0_Efp0_Efp_spclsr3std3__1E7forwardIT1_Efp1_EEEOT_OS9_DpOSA_
build/bin/../include/c++/v1/__functional_base:382:12 (a.out+0x0000004994a1)
#5 void std::__1::__thread_execute<void
(std::__1::__async_assoc_state<bool, std::__1::__async_func<main::$_0> >::*)(),
std::__1::__async_assoc_state<bool, std::__1::__async_func<main::$_0> >*,
1ul>(std::__1::tuple<void (std::__1::__async_assoc_state<bool,
std::__1::__async_func<main::$_0> >::*)(), std::__1::__async_assoc_state<bool,
std::__1::__async_func<main::$_0> >*>&, std::__1::__tuple_indices<1ul>)
build/bin/../include/c++/v1/thread:337 (a.out+0x0000004994a1)
#6 void* std::__1::__thread_proxy<std::__1::tuple<void
(std::__1::__async_assoc_state<bool, std::__1::__async_func<main::$_0> >::*)(),
std::__1::__async_assoc_state<bool, std::__1::__async_func<main::$_0> >*>
<span class="quote">>(void*) build/bin/../include/c++/v1/thread:347 (a.out+0x0000004994a1)</span >
Location is heap block of size 120 at 0x7d200000bf80 allocated by main
thread:
#0 operator new(unsigned long)
/ssd/src/llvm/build/../projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:615
(a.out+0x00000043e08f)
#1 std::__1::future<bool> std::__1::__make_async_assoc_state<bool,
std::__1::__async_func<main::$_0> >(std::__1::__async_func<main::$_0>&&)
build/bin/../include/c++/v1/future:2312:13 (a.out+0x000000499035)
#2
std::__1::future<std::__1::__invoke_of<std::__1::decay<main::$_0>::type>::type>
std::__1::async<main::$_0>(std::__1::launch, main::$_0&&)
build/bin/../include/c++/v1/future:2361:16 (a.out+0x000000498fce)
#3 main /tmp/shared_ptr.cc:12:14 (a.out+0x000000498f0d)
Thread T1 (tid=19481, finished) created by main thread at:
#0 pthread_create
/ssd/src/llvm/build/../projects/compiler-rt/lib/tsan/rtl/tsan_interceptors.cc:951
(a.out+0x000000447123)
#1 std::__1::thread::thread<void (std::__1::__async_assoc_state<bool,
std::__1::__async_func<main::$_0> >::*)(), std::__1::__async_assoc_state<bool,
std::__1::__async_func<main::$_0> >*, void>(void
(std::__1::__async_assoc_state<bool, std::__1::__async_func<main::$_0>
<span class="quote">>::*&&)(), std::__1::__async_assoc_state<bool,</span >
std::__1::__async_func<main::$_0> >*&&)
build/bin/../include/c++/v1/thread:359:16 (a.out+0x000000499282)
#2 std::__1::future<bool> std::__1::__make_async_assoc_state<bool,
std::__1::__async_func<main::$_0> >(std::__1::__async_func<main::$_0>&&)
build/bin/../include/c++/v1/future:2313:5 (a.out+0x0000004990a4)
#3
std::__1::future<std::__1::__invoke_of<std::__1::decay<main::$_0>::type>::type>
std::__1::async<main::$_0>(std::__1::launch, main::$_0&&)
build/bin/../include/c++/v1/future:2361:16 (a.out+0x000000498fce)
#4 main /tmp/shared_ptr.cc:12:14 (a.out+0x000000498f0d)
SUMMARY: ThreadSanitizer: data race
build/../projects/libcxx/src/condition_variable.cpp:23:5 in
std::__1::condition_variable::~condition_variable()
==================
The program was built as:
clang++ test.cc -fsanitize=thread -std=c++14 -stdlib=libc++ -lc++abi -Wall -g
-O1
with tsan-instrumented libcxx (see instructions here
<a href="https://code.google.com/p/memory-sanitizer/wiki/LibcxxHowTo">https://code.google.com/p/memory-sanitizer/wiki/LibcxxHowTo</a>).
The problem is here:
__assoc_state<_Rp>::set_value(_Arg&& __arg)
{
unique_lock<mutex> __lk(this->__mut_);
#ifndef _LIBCPP_NO_EXCEPTIONS
if (this->__has_value())
throw
future_error(make_error_code(future_errc::promise_already_satisfied));
#endif
::new(&__value_) _Rp(_VSTD::forward<_Arg>(__arg));
this->__state_ |= base::__constructed | base::ready;
__lk.unlock();
__cv_.notify_all();
}
The function first unlocks the mutex and after than signals the cond var. But
once the mutex is unlocked the object can be destroyed as it is in ready state.</pre>
</div>
</p>
<hr>
<span>You are receiving this mail because:</span>
<ul>
<li>You are on the CC list for the bug.</li>
</ul>
</body>
</html>