brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.5 KiB · 4b674e0 Raw
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