Open
Description
This bug is originally reported in google/sanitizer. But the original code is in llvm-project. So the ticket is referred to llvm for further analyzing and fix.
This bug is already reported by:
google/sanitizers#814
google/sanitizers#1419
To reproduce the bug:
Build and run the follow code with thread sanitizer.
#include <thread>
#include <mutex>
#include <atomic>
std::mutex m1;
std::mutex m2;
std::mutex m3;
std::atomic<int> counter {0};
void foo(){
std::unique_lock<std::mutex> lock1(m1);
std::unique_lock<std::mutex> lock2(m2);
}
void xoo(){
foo();
std::unique_lock<std::mutex> lock2(m2);
std::unique_lock<std::mutex> lock3(m3);
}
void yoo(){
std::unique_lock<std::mutex> lock3(m3);
std::unique_lock<std::mutex> lock1(m1);
}
int main(){
std::thread th1([]{
while(true){
xoo();
if(counter>10){
break;
}
}
});
std::thread th2([]{
while(true){
yoo();
counter++;
if(counter>10){
break;
}
}
});
th1.join();
th2.join();
}
mkdir build
clang++ -g -fsanitize=thread -o build/sanitizerDemo main.cpp
./build/sanitizerDemo
Expected behavior:
No warning and error
Observed behavior:
Get warning:
==================
WARNING: ThreadSanitizer: lock-order-inversion (potential deadlock) (pid=2961)
Cycle in lock order graph: M0 (0x55efb72306a8) => M1 (0x55efb72306d0) => M2 (0x55efb72306f8) => M0
Mutex M1 acquired here while holding mutex M0 in thread T1:
#0 pthread_mutex_lock <null> (sanitizerDemo+0x6cfaa) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#1 __gthread_mutex_lock(pthread_mutex_t*) /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/x86_64-linux-gnu/c++/11/bits/gthr-default.h:749:12 (sanitizerDemo+0xd0903) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#2 std::mutex::lock() /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_mutex.h:100:17 (sanitizerDemo+0xd1715) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#3 std::unique_lock<std::mutex>::lock() /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/unique_lock.h:139:17 (sanitizerDemo+0xd16a5) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#4 std::unique_lock<std::mutex>::unique_lock(std::mutex&) /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/unique_lock.h:69:2 (sanitizerDemo+0xd1457) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#5 foo() /home/jcq/workspace/ThreadSanitizerBugCandidate/main.cpp:13:32 (sanitizerDemo+0xd03d5) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#6 xoo() /home/jcq/workspace/ThreadSanitizerBugCandidate/main.cpp:17:3 (sanitizerDemo+0xd0465) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#7 main::$_0::operator()() const /home/jcq/workspace/ThreadSanitizerBugCandidate/main.cpp:30:7 (sanitizerDemo+0xd0de1) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#8 void std::__invoke_impl<void, main::$_0>(std::__invoke_other, main::$_0&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/invoke.h:61:14 (sanitizerDemo+0xd0d9d) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#9 std::__invoke_result<main::$_0>::type std::__invoke<main::$_0>(main::$_0&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/invoke.h:96:14 (sanitizerDemo+0xd0ced) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#10 void std::thread::_Invoker<std::tuple<main::$_0> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_thread.h:253:13 (sanitizerDemo+0xd0c95) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#11 std::thread::_Invoker<std::tuple<main::$_0> >::operator()() /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_thread.h:260:11 (sanitizerDemo+0xd0c35) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#12 std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::$_0> > >::_M_run() /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_thread.h:211:13 (sanitizerDemo+0xd0b49) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#13 <null> <null> (libstdc++.so.6+0xdc2c2) (BuildId: 725ef5da52ee6d881f9024d8238a989903932637)
Hint: use TSAN_OPTIONS=second_deadlock_stack=1 to get more informative warning message
Mutex M2 acquired here while holding mutex M1 in thread T1:
#0 pthread_mutex_lock <null> (sanitizerDemo+0x6cfaa) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#1 __gthread_mutex_lock(pthread_mutex_t*) /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/x86_64-linux-gnu/c++/11/bits/gthr-default.h:749:12 (sanitizerDemo+0xd0903) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#2 std::mutex::lock() /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_mutex.h:100:17 (sanitizerDemo+0xd1715) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#3 std::unique_lock<std::mutex>::lock() /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/unique_lock.h:139:17 (sanitizerDemo+0xd16a5) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#4 std::unique_lock<std::mutex>::unique_lock(std::mutex&) /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/unique_lock.h:69:2 (sanitizerDemo+0xd1457) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#5 xoo() /home/jcq/workspace/ThreadSanitizerBugCandidate/main.cpp:19:32 (sanitizerDemo+0xd048f) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#6 main::$_0::operator()() const /home/jcq/workspace/ThreadSanitizerBugCandidate/main.cpp:30:7 (sanitizerDemo+0xd0de1) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#7 void std::__invoke_impl<void, main::$_0>(std::__invoke_other, main::$_0&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/invoke.h:61:14 (sanitizerDemo+0xd0d9d) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#8 std::__invoke_result<main::$_0>::type std::__invoke<main::$_0>(main::$_0&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/invoke.h:96:14 (sanitizerDemo+0xd0ced) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#9 void std::thread::_Invoker<std::tuple<main::$_0> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_thread.h:253:13 (sanitizerDemo+0xd0c95) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#10 std::thread::_Invoker<std::tuple<main::$_0> >::operator()() /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_thread.h:260:11 (sanitizerDemo+0xd0c35) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#11 std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::$_0> > >::_M_run() /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_thread.h:211:13 (sanitizerDemo+0xd0b49) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#12 <null> <null> (libstdc++.so.6+0xdc2c2) (BuildId: 725ef5da52ee6d881f9024d8238a989903932637)
Mutex M0 acquired here while holding mutex M2 in thread T2:
#0 pthread_mutex_lock <null> (sanitizerDemo+0x6cfaa) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#1 __gthread_mutex_lock(pthread_mutex_t*) /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/x86_64-linux-gnu/c++/11/bits/gthr-default.h:749:12 (sanitizerDemo+0xd0903) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#2 std::mutex::lock() /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_mutex.h:100:17 (sanitizerDemo+0xd1715) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#3 std::unique_lock<std::mutex>::lock() /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/unique_lock.h:139:17 (sanitizerDemo+0xd16a5) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#4 std::unique_lock<std::mutex>::unique_lock(std::mutex&) /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/unique_lock.h:69:2 (sanitizerDemo+0xd1457) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#5 yoo() /home/jcq/workspace/ThreadSanitizerBugCandidate/main.cpp:24:32 (sanitizerDemo+0xd0535) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#6 main::$_1::operator()() const /home/jcq/workspace/ThreadSanitizerBugCandidate/main.cpp:39:7 (sanitizerDemo+0xd1301) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#7 void std::__invoke_impl<void, main::$_1>(std::__invoke_other, main::$_1&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/invoke.h:61:14 (sanitizerDemo+0xd12bd) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#8 std::__invoke_result<main::$_1>::type std::__invoke<main::$_1>(main::$_1&&) /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/invoke.h:96:14 (sanitizerDemo+0xd120d) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#9 void std::thread::_Invoker<std::tuple<main::$_1> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_thread.h:253:13 (sanitizerDemo+0xd11b5) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#10 std::thread::_Invoker<std::tuple<main::$_1> >::operator()() /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_thread.h:260:11 (sanitizerDemo+0xd1155) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#11 std::thread::_State_impl<std::thread::_Invoker<std::tuple<main::$_1> > >::_M_run() /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_thread.h:211:13 (sanitizerDemo+0xd1069) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#12 <null> <null> (libstdc++.so.6+0xdc2c2) (BuildId: 725ef5da52ee6d881f9024d8238a989903932637)
Thread T1 (tid=2963, running) created by main thread at:
#0 pthread_create <null> (sanitizerDemo+0x4f41d) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xdc398) (BuildId: 725ef5da52ee6d881f9024d8238a989903932637)
#2 main /home/jcq/workspace/ThreadSanitizerBugCandidate/main.cpp:28:15 (sanitizerDemo+0xd05cd) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
Thread T2 (tid=2964, running) created by main thread at:
#0 pthread_create <null> (sanitizerDemo+0x4f41d) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
#1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xdc398) (BuildId: 725ef5da52ee6d881f9024d8238a989903932637)
#2 main /home/jcq/workspace/ThreadSanitizerBugCandidate/main.cpp:37:15 (sanitizerDemo+0xd05df) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813)
SUMMARY: ThreadSanitizer: lock-order-inversion (potential deadlock) (/home/jcq/workspace/ThreadSanitizerBugCandidate/build/sanitizerDemo+0x6cfaa) (BuildId: c8889fc1fcd8a23e72c8e9304e3bd86a01df3813) in pthread_mutex_lock
==================
ThreadSanitizer: reported 1 warnings
Environment
Ubuntu 22.04 + clang-14(installed by apt)
$ uname -a
Linux ubuntu 5.15.0-25-generic #25-Ubuntu SMP Wed Mar 30 15:54:22 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
$ clang++ --version
Ubuntu clang version 14.0.0-1ubuntu1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin