From a0e8271acaf49781430bc5439462d08fbcca617c Mon Sep 17 00:00:00 2001 From: Dennis Klein Date: Tue, 9 Jun 2026 21:57:08 +0200 Subject: [PATCH] test: suppress libzmq-induced thread-sanitizer false positives - libzmq is not tsan-instrumented, so tsan cannot see the happens-before its queues establish between user threads and libzmq I/O threads, producing false-positive data races on message buffers - add test/thread_sanitizer_suppressions.txt and point TSAN_OPTIONS at it via the sanitizers job env so it reaches the tests and their device subprocesses - suppress: accesses made directly from libzmq, the zero-copy message deleters libzmq runs from msg_t::close, shmem receive-side metadata reads, and std::regex/locale lazy-init races in libstdc++ --- .github/workflows/ci.yml | 2 ++ test/thread_sanitizer_suppressions.txt | 32 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 test/thread_sanitizer_suppressions.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a27ff92..7c663c98 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,6 +68,8 @@ jobs: if: github.repository == 'FairRootGroup/FairMQ' name: ${{ matrix.sanitizer.name }} runs-on: ubuntu-24.04 + env: + TSAN_OPTIONS: suppressions=${{ github.workspace }}/test/thread_sanitizer_suppressions.txt strategy: fail-fast: false matrix: diff --git a/test/thread_sanitizer_suppressions.txt b/test/thread_sanitizer_suppressions.txt new file mode 100644 index 00000000..153fbba7 --- /dev/null +++ b/test/thread_sanitizer_suppressions.txt @@ -0,0 +1,32 @@ +# ThreadSanitizer suppressions for FairMQ. +# +# libzmq is not built with -fsanitize=thread, so tsan cannot observe the +# happens-before that its inproc/socket queues establish between the user +# threads and libzmq's I/O threads. This produces false-positive data races +# on message buffers handed across that boundary. The proper fix is to build +# libzmq with tsan as well; until then these races are suppressed. + +# Racy access made directly from libzmq (encoder/decoder memcpy, +# signaler/epoll, recv). +called_from_lib:libzmq.so + +# Zero-copy message deleters that libzmq runs from msg_t::close once it is +# done with a buffer; the happens-before with the buffer's producer runs +# through libzmq's queue. +race:zmq::msg_t::close +race:fair::mq::TransportFactory::SimpleMsgCleanup + +# shmem message metadata read on the user side after delivery through libzmq +# (the shmem transport ships its metadata over a zeromq channel). +race:fair::mq::shmem::Message::Message +race:fair::mq::shmem::Socket::Receive +race:fair::mq::shmem::ShmHeader + +# Multipart message buffers written by the sending thread and read back by the +# receiving thread after delivery through libzmq's inproc queue; the +# happens-before runs through that non-instrumented queue. +race:RunMultiThreadedMultipart + +# std::regex / std::locale facet lazy-init races inside libstdc++. +race:fair::mq::Channel::Validate +race:fair::mq::tools::ToString