mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-10 03:13:34 +00:00
[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:
parent
ba46422694
commit
659949cb03
@ -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);
|
||||
|
30
compiler-rt/test/tsan/Darwin/libcxx-future.mm
Normal file
30
compiler-rt/test/tsan/Darwin/libcxx-future.mm
Normal 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.
|
Loading…
x
Reference in New Issue
Block a user