TSAN False Negative With try_lock

15 views
Skip to first unread message

Joseph Prince

unread,
4:39 AM (12 hours ago) 4:39 AM
to thread-sanitizer

Hello, I am writing a wrapper for a std::mutex (called ObservableMutex) that collects stats on various things including the number of contentions on the mutex. As part of that implementation, I have some code that behaves like the following:


void ObservableMutex::lock() {

if (!_mutex.try_lock()) {

            _contentions.fetchAndAddRelaxed(1);

            _mutex.lock();

        }

}


When using this mutex wrapper, I see what looks like TSAN false negatives. Consider this test which demonstrates a simple lock order inversion:


TEST(ObservableMutexTsanTest, LockOrderInversion) {

    ObservableMutex<std::mutex> m1;

    ObservableMutex<std::mutex> m2;

    std::thread t1([&] {

        std::lock_guard lg(m1);

        std::lock_guard lg2(m2);

    });


    t1.join();

    std::thread t2([&] {

        std::lock_guard lg(m2);

        std::lock_guard lg2(m1);

    });

    t2.join();

}


When I use the ObservableMutex, the test passes with no TSAN errors. However, if I switch the ObservableMutex to just a plain std::mutex, TSAN correctly reports a lock order inversion error. Also, deleting the if condition in ObservableMutex::lock and unconditionally calling into the body causes TSAN to identify the error. 


So a try_lock check guarding a call to lock appears to trick TSAN into outputting a false negative. Is this issue known, and if not is this something that the TSAN team could investigate/fix? 


For reference, I am using TSAN from llvm 19.1.7


Thanks,

Joseph Prince

Dmitry Vyukov

unread,
4:46 AM (12 hours ago) 4:46 AM
to Joseph Prince, thread-sanitizer, ccot...@bloomberg.net
Hi Joseph,

Yes, this is a known limitation. TSAN is a dynamic tool and only
observes and detects bugs that happen in the concrete execution. There
are also tons of false nehative race reports for this reason. It's not
static analysis.

You either need a stress test that actually exposes the inversion, or
perhaps Chris' new delay injection feature may help to trigger such
bugs:
https://github.com/llvm/llvm-project/pull/178836
(it's only in newer clang versions, and require manual enabling with
TSAN_OPTIONS).
Reply all
Reply to author
Forward
0 new messages