197 lines · cpp
1// RUN: %clang_analyze_cc1 \2// RUN: -analyzer-checker=unix.BlockInCriticalSection \3// RUN: -std=c++11 \4// RUN: -analyzer-output text \5// RUN: -verify %s6 7unsigned int sleep(unsigned int seconds) {return 0;}8namespace std {9// There are some standard library implementations where some mutex methods10// come from an implementation detail base class. We need to ensure that these11// are matched correctly.12class __mutex_base {13public:14 void lock();15};16class mutex : public __mutex_base{17public:18 void unlock();19 bool try_lock();20};21} // namespace std22 23void 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 33void no_false_positive_gh_104241() {34 std::mutex m;35 m.lock();36 // If inheritance not handled properly, this unlock might not match the lock37 // above because technically they act on different memory regions:38 // __mutex_base and mutex.39 m.unlock();40 sleep(10); // no-warning41}42 43struct TwoMutexes {44 std::mutex m1;45 std::mutex m2;46};47 48void 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 58struct MyMutexBase1 : std::mutex {59 void lock1() { lock(); }60 // expected-note@-1 {{Entering critical section here}}61 void unlock1() { unlock(); }62};63struct MyMutexBase2 : std::mutex {64 void lock2() { lock(); }65 void unlock2() { unlock(); }66};67struct MyMutex : MyMutexBase1, MyMutexBase2 {};68// MyMutex has two distinct std::mutex as base classes69 70void 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 79void custom_mutex_tn(MyMutexBase1 &mb) {80 mb.lock();81 mb.unlock();82 sleep(10);83}84 85void 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 94void 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 100void 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 111void two_custom_mutex_bases_tn(MyMutex &m) {112 m.lock1();113 m.unlock1();114 sleep(10);115}116 117void 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 127void 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 133struct MutexVirtBase1 : virtual std::mutex {134 void lock1() { lock(); }135 // expected-note@-1 {{Entering critical section here}}136 void unlock1() { unlock(); }137};138 139struct MutexVirtBase2 : virtual std::mutex {140 void lock2() { lock(); }141 void unlock2() { unlock(); }142};143 144struct CombinedVirtMutex : MutexVirtBase1, MutexVirtBase2 {};145 146void virt_inherited_mutexes_same_base_tn1(CombinedVirtMutex &cvt) {147 cvt.lock1();148 cvt.unlock1();149 sleep(10);150}151 152void 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 lock1155 sleep(10);156}157 158void 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 168namespace std {169template <class... MutexTypes> struct scoped_lock {170 explicit scoped_lock(MutexTypes&... m);171 ~scoped_lock();172};173template <class MutexType> class scoped_lock<MutexType> {174public:175 explicit scoped_lock(MutexType& m) : m(m) { m.lock(); }176 ~scoped_lock() { m.unlock(); }177private:178 MutexType& m;179};180} // namespace std181 182namespace gh_104241 {183int magic_number;184std::mutex m;185 186void 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 warning194 }195}196} // namespace gh_104241197