[tsan] Add interceptor for libcxx __shared_count::__release_shared()

We already have an interceptor for __shared_weak_count::__release_shared, this patch handles __shared_count::__release_shared in the same way. This should get rid of TSan false positives when using std::future.

Differential Revision: https://reviews.llvm.org/D27797

llvm-svn: 289831
This commit is contained in:
Kuba Mracek 2016-12-15 16:45:28 +00:00
parent ba46422694
commit 659949cb03
2 changed files with 49 additions and 3 deletions

View File

@ -297,18 +297,20 @@ struct fake_shared_weak_count {
};
} // namespace
// This adds a libc++ interceptor for:
// The following code adds libc++ interceptors for:
// void __shared_weak_count::__release_shared() _NOEXCEPT;
// bool __shared_count::__release_shared() _NOEXCEPT;
// Shared and weak pointers in C++ maintain reference counts via atomics in
// libc++.dylib, which are TSan-invisible, and this leads to false positives in
// destructor code. This interceptor re-implements the whole function so that
// destructor code. These interceptors re-implements the whole functions so that
// the mo_acq_rel semantics of the atomic decrement are visible.
//
// Unfortunately, this interceptor cannot simply Acquire/Release some sync
// Unfortunately, the interceptors cannot simply Acquire/Release some sync
// object and call the original function, because it would have a race between
// the sync and the destruction of the object. Calling both under a lock will
// not work because the destructor can invoke this interceptor again (and even
// in a different thread, so recursive locks don't help).
STDCXX_INTERCEPTOR(void, _ZNSt3__119__shared_weak_count16__release_sharedEv,
fake_shared_weak_count *o) {
if (!flags()->shared_ptr_interceptor)
@ -327,6 +329,20 @@ STDCXX_INTERCEPTOR(void, _ZNSt3__119__shared_weak_count16__release_sharedEv,
}
}
STDCXX_INTERCEPTOR(bool, _ZNSt3__114__shared_count16__release_sharedEv,
fake_shared_weak_count *o) {
if (!flags()->shared_ptr_interceptor)
return REAL(_ZNSt3__114__shared_count16__release_sharedEv)(o);
SCOPED_TSAN_INTERCEPTOR(_ZNSt3__114__shared_count16__release_sharedEv, o);
if (__tsan_atomic64_fetch_add(&o->shared_owners, -1, mo_release) == 0) {
Acquire(thr, pc, (uptr)&o->shared_owners);
o->on_zero_shared();
return true;
}
return false;
}
namespace {
struct call_once_callback_args {
void (*orig_func)(void *arg);

View File

@ -0,0 +1,30 @@
// RUN: %clangxx_tsan %s -o %t
// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
#include <iostream>
#include <future>
#include <vector>
int main(int argc, const char *argv[]) {
fprintf(stderr, "Hello world.\n");
auto my_task = [] { return 42; };
std::vector<std::thread> threads;
for (int i = 0; i < 1000; i++) {
std::packaged_task<int(void)> task(my_task);
std::future<int> future = task.get_future();
threads.push_back(std::thread(std::move(task)));
}
for (auto &t : threads) {
t.join();
}
fprintf(stderr, "Done.\n");
}
// CHECK: Hello world.
// CHECK-NOT: WARNING: ThreadSanitizer
// CHECK: Done.