[LLVMbugs] [Bug 23293] New: libcxx: racy use-after-free on condition_variable

bugzilla-daemon at llvm.org bugzilla-daemon at llvm.org
Mon Apr 20 03:43:53 PDT 2015


https://llvm.org/bugs/show_bug.cgi?id=23293

            Bug ID: 23293
           Summary: libcxx: racy use-after-free on condition_variable
           Product: libc++
           Version: unspecified
          Hardware: PC
                OS: Linux
            Status: NEW
          Severity: release blocker
          Priority: P
         Component: All Bugs
          Assignee: unassignedclangbugs at nondot.org
          Reporter: dvyukov at google.com
                CC: llvmbugs at cs.uiuc.edu, mclow.lists at gmail.com
    Classification: Unclassified

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>
>::~__async_assoc_state() build/bin/../include/c++/v1/future:940:7
(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>
>::__on_zero_shared() build/bin/../include/c++/v1/future:990:5
(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>
>::__execute() build/bin/../include/c++/v1/future:975:9 (a.out+0x00000049934e)
    #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> >*>
>(void*) build/bin/../include/c++/v1/thread:347 (a.out+0x0000004994a1)

  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>
>::*&&)(), std::__1::__async_assoc_state<bool,
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
https://code.google.com/p/memory-sanitizer/wiki/LibcxxHowTo).

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.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20150420/785e1aa2/attachment.html>


More information about the llvm-bugs mailing list