1 // RUN: %clang_analyze_cc1 \ 2 // RUN: -analyzer-checker=unix.BlockInCriticalSection \ 3 // RUN: -std=c++11 \ 4 // RUN: -analyzer-output text \ 5 // RUN: -verify %s 6 7 unsigned int sleep(unsigned int seconds) {return 0;} 8 namespace std { 9 // There are some standard library implementations where some mutex methods 10 // come from an implementation detail base class. We need to ensure that these 11 // are matched correctly. 12 class __mutex_base { 13 public: 14 void lock(); 15 }; 16 class mutex : public __mutex_base{ 17 public: 18 void unlock(); 19 bool try_lock(); 20 }; 21 } // namespace std 22 23 void gh_99628() { 24 std::mutex m; 25 m.lock(); 26 // expected-note@-1 {{Entering critical section here}} 27 sleep(10); 28 // expected-warning@-1 {{Call to blocking function 'sleep' inside of critical section}} 29 // expected-note@-2 {{Call to blocking function 'sleep' inside of critical section}} 30 m.unlock(); 31 } 32 33 void no_false_positive_gh_104241() { 34 std::mutex m; 35 m.lock(); 36 // If inheritance not handled properly, this unlock might not match the lock 37 // above because technically they act on different memory regions: 38 // __mutex_base and mutex. 39 m.unlock(); 40 sleep(10); // no-warning 41 } 42 43 struct TwoMutexes { 44 std::mutex m1; 45 std::mutex m2; 46 }; 47 48 void two_mutexes_no_false_negative(TwoMutexes &tm) { 49 tm.m1.lock(); 50 // expected-note@-1 {{Entering critical section here}} 51 tm.m2.unlock(); 52 sleep(10); 53 // expected-warning@-1 {{Call to blocking function 'sleep' inside of critical section}} 54 // expected-note@-2 {{Call to blocking function 'sleep' inside of critical section}} 55 tm.m1.unlock(); 56 } 57 58 struct MyMutexBase1 : std::mutex { 59 void lock1() { lock(); } 60 // expected-note@-1 {{Entering critical section here}} 61 void unlock1() { unlock(); } 62 }; 63 struct MyMutexBase2 : std::mutex { 64 void lock2() { lock(); } 65 void unlock2() { unlock(); } 66 }; 67 struct MyMutex : MyMutexBase1, MyMutexBase2 {}; 68 // MyMutex has two distinct std::mutex as base classes 69 70 void custom_mutex_tp(MyMutexBase1 &mb) { 71 mb.lock(); 72 // expected-note@-1 {{Entering critical section here}} 73 sleep(10); 74 // expected-warning@-1 {{Call to blocking function 'sleep' inside of critical section}} 75 // expected-note@-2 {{Call to blocking function 'sleep' inside of critical section}} 76 mb.unlock(); 77 } 78 79 void custom_mutex_tn(MyMutexBase1 &mb) { 80 mb.lock(); 81 mb.unlock(); 82 sleep(10); 83 } 84 85 void custom_mutex_cast_tp(MyMutexBase1 &mb) { 86 static_cast<std::mutex&>(mb).lock(); 87 // expected-note@-1 {{Entering critical section here}} 88 sleep(10); 89 // expected-warning@-1 {{Call to blocking function 'sleep' inside of critical section}} 90 // expected-note@-2 {{Call to blocking function 'sleep' inside of critical section}} 91 static_cast<std::mutex&>(mb).unlock(); 92 } 93 94 void custom_mutex_cast_tn(MyMutexBase1 &mb) { 95 static_cast<std::mutex&>(mb).lock(); 96 static_cast<std::mutex&>(mb).unlock(); 97 sleep(10); 98 } 99 100 void two_custom_mutex_bases_tp(MyMutex &m) { 101 m.lock1(); 102 // expected-note@-1 {{Calling 'MyMutexBase1::lock1'}} 103 // expected-note@-2 {{Returning from 'MyMutexBase1::lock1'}} 104 m.unlock2(); 105 sleep(10); 106 // expected-warning@-1 {{Call to blocking function 'sleep' inside of critical section}} 107 // expected-note@-2 {{Call to blocking function 'sleep' inside of critical section}} 108 m.unlock1(); 109 } 110 111 void two_custom_mutex_bases_tn(MyMutex &m) { 112 m.lock1(); 113 m.unlock1(); 114 sleep(10); 115 } 116 117 void two_custom_mutex_bases_casts_tp(MyMutex &m) { 118 static_cast<MyMutexBase1&>(m).lock(); 119 // expected-note@-1 {{Entering critical section here}} 120 static_cast<MyMutexBase2&>(m).unlock(); 121 sleep(10); 122 // expected-warning@-1 {{Call to blocking function 'sleep' inside of critical section}} 123 // expected-note@-2 {{Call to blocking function 'sleep' inside of critical section}} 124 static_cast<MyMutexBase1&>(m).unlock(); 125 } 126 127 void two_custom_mutex_bases_casts_tn(MyMutex &m) { 128 static_cast<MyMutexBase1&>(m).lock(); 129 static_cast<MyMutexBase1&>(m).unlock(); 130 sleep(10); 131 } 132 133 struct MutexVirtBase1 : virtual std::mutex { 134 void lock1() { lock(); } 135 // expected-note@-1 {{Entering critical section here}} 136 void unlock1() { unlock(); } 137 }; 138 139 struct MutexVirtBase2 : virtual std::mutex { 140 void lock2() { lock(); } 141 void unlock2() { unlock(); } 142 }; 143 144 struct CombinedVirtMutex : MutexVirtBase1, MutexVirtBase2 {}; 145 146 void virt_inherited_mutexes_same_base_tn1(CombinedVirtMutex &cvt) { 147 cvt.lock1(); 148 cvt.unlock1(); 149 sleep(10); 150 } 151 152 void virt_inherited_mutexes_different_bases_tn(CombinedVirtMutex &cvt) { 153 cvt.lock1(); 154 cvt.unlock2(); // Despite a different name, unlock2 acts on the same mutex as lock1 155 sleep(10); 156 } 157 158 void virt_inherited_mutexes_different_bases_tp(CombinedVirtMutex &cvt) { 159 cvt.lock1(); 160 // expected-note@-1 {{Calling 'MutexVirtBase1::lock1'}} 161 // expected-note@-2 {{Returning from 'MutexVirtBase1::lock1'}} 162 sleep(10); 163 // expected-warning@-1 {{Call to blocking function 'sleep' inside of critical section}} 164 // expected-note@-2 {{Call to blocking function 'sleep' inside of critical section}} 165 cvt.unlock1(); 166 } 167 168 namespace std { 169 template <class... MutexTypes> struct scoped_lock { 170 explicit scoped_lock(MutexTypes&... m); 171 ~scoped_lock(); 172 }; 173 template <class MutexType> class scoped_lock<MutexType> { 174 public: 175 explicit scoped_lock(MutexType& m) : m(m) { m.lock(); } 176 ~scoped_lock() { m.unlock(); } 177 private: 178 MutexType& m; 179 }; 180 } // namespace std 181 182 namespace gh_104241 { 183 int magic_number; 184 std::mutex m; 185 186 void fixed() { 187 int current; 188 for (int items_processed = 0; items_processed < 100; ++items_processed) { 189 { 190 std::scoped_lock<std::mutex> guard(m); 191 current = magic_number; 192 } 193 sleep(current); // expected no warning 194 } 195 } 196 } // namespace gh_104241 197