Disable an exception-throw stress test for DistributedMutex under TSAN
Summary: This test inexplicably aborts when ran under TSAN. TSAN reports a read-write race where the exception is freed by the lock-holder / combiner thread and read concurrently by the thread that requested the combine operation. TSAN reports a similar read-write race for this code as well https://gist.github.com/aary/a14ae8d008e1d48a0f2d61582209f217 (copied below). Which is easier to verify as being correct. Though this does not conclusively prove that this test and implementation are race-free, the above repro combined with error-free stress runs of this test under other modes (optimized builds with and without both ASAN and UBSAN) give us a high signal at TSAN's error being a false-negative. So disabling it for now until some point in the future where TSAN stops reporting this as a false-negative ``` namespace { struct Storage { std::atomic<std::uint64_t> futex_{0}; std::atomic<std::uint64_t> next_; std::aligned_storage_t<48, 8> storage_; }; template <typename Waiter> void transferCurrentException(Waiter* waiter) { assert(std::current_exception()); new (&waiter->storage_) std::exception_ptr{std::current_exception()}; waiter->futex_.store(1, std::memory_order_release); } template <template <typename> class Atom = std::atomic> void concurrentExceptionPropagationStress( int, std::chrono::milliseconds) { auto exceptions = std::vector<std::unique_ptr<Storage>>{}; exceptions.resize(1000000); for (auto i = std::size_t{0}; i < exceptions.size(); ++i) { exceptions[i] = std::make_unique<Storage>(); } auto throwing = std::function<void(std::uint64_t)>{[&](auto counter) { if (counter % 2) { throw std::runtime_error{folly::to<std::string>(counter)}; } }}; std::cout << "Started test" << std::endl; auto writer = std::thread{[&]() { for (auto i = std::size_t{0}; i < exceptions.size(); ++i) { try { std::this_thread::yield(); throwing(i); } catch (...) { transferCurrentException(exceptions.at(i).get()); continue; } exceptions.at(i)->futex_.store(2, std::memory_order_release); } }}; auto reader = std::thread{[&]() { for (auto i = std::size_t{0}; i < exceptions.size(); ++i) { auto value = std::uint64_t{}; while (!(value = exceptions.at(i)->futex_.load(std::memory_order_acquire))) {} if (value == 1) { try { auto buf = reinterpret_cast<std::exception_ptr*>(&exceptions.at(i)->storage_); auto ex = folly::launder(buf); auto copy = std::move(*ex); ex->exception_ptr::~exception_ptr(); std::rethrow_exception(std::move(copy)); } catch (std::exception& exc) { assert(folly::to<std::uint64_t>(exc.what()) == i); } } } }}; reader.join(); writer.join(); } } // namespace ``` Reviewed By: yfeldblum Differential Revision: D24653383 fbshipit-source-id: 3ce166766eb42b22ec7b8cfaf8d31ca53580ff9e
Showing
Please register or sign in to comment