NoQ created this revision.

As usual, we need to invalidate mutex states when something may touch them. 
Implement this boilerplate for the thread lock checker.

The previous refactoring is handy for listing functions on which we don't need 
to invalidate mutex states because we model them instead.

Additionally, i don't invalidate mutex states when any system header function 
is called, unless the mutex is passed directly into it. The TODO here would be 
to model *all* system functions that may change mutex states, and then disable 
invalidation for the rest of them even if they take a mutex; that's what other 
checkers do.


https://reviews.llvm.org/D37812

Files:
  lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
  test/Analysis/Inputs/system-header-simulator-for-pthread-lock.h
  test/Analysis/pthreadlock.c

Index: test/Analysis/pthreadlock.c
===================================================================
--- test/Analysis/pthreadlock.c
+++ test/Analysis/pthreadlock.c
@@ -221,6 +221,27 @@
   lck_rw_unlock_exclusive(&rw); // no-warning
 }
 
+void escape_mutex(pthread_mutex_t *m);
+void ok30(void) {
+  pthread_mutex_t local_mtx;
+  pthread_mutex_init(&local_mtx, NULL);
+  pthread_mutex_lock(&local_mtx);
+  escape_mutex(&local_mtx);
+  pthread_mutex_lock(&local_mtx); // no-warning
+  pthread_mutex_unlock(&local_mtx);
+  pthread_mutex_destroy(&local_mtx);
+}
+
+void ok31(void) {
+  pthread_mutex_t local_mtx;
+  pthread_mutex_init(&local_mtx, NULL);
+  pthread_mutex_lock(&local_mtx);
+  fake_system_function_that_takes_a_mutex(&local_mtx);
+  pthread_mutex_lock(&local_mtx); // no-warning
+  pthread_mutex_unlock(&local_mtx);
+  pthread_mutex_destroy(&local_mtx);
+}
+
 void
 bad1(void)
 {
@@ -486,3 +507,9 @@
   lck_rw_lock_exclusive(&rw);
   lck_rw_unlock_shared(&rw); // FIXME: warn - should be exclusive?
 }
+
+void bad33(void) {
+  pthread_mutex_lock(pmtx);
+  fake_system_function();
+  pthread_mutex_lock(pmtx); // expected-warning{{This lock has already been acquired}}
+}
Index: test/Analysis/Inputs/system-header-simulator-for-pthread-lock.h
===================================================================
--- test/Analysis/Inputs/system-header-simulator-for-pthread-lock.h
+++ test/Analysis/Inputs/system-header-simulator-for-pthread-lock.h
@@ -3,6 +3,8 @@
 // should not invalidate regions of their arguments.
 #pragma clang system_header
 
+extern void fake_system_function();
+
 typedef struct {
   void *foo;
 } OpaqueThing;
@@ -12,6 +14,8 @@
 typedef OpaqueThing pthread_rwlock_t;
 typedef OpaqueThing pthread_mutexattr_t;
 
+extern void fake_system_function_that_takes_a_mutex(pthread_mutex_t *mtx);
+
 // XNU.
 typedef OpaqueThing lck_mtx_t;
 typedef OpaqueThing lck_rw_t;
Index: lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -66,8 +66,8 @@
   }
 };
 
-class PthreadLockChecker
-    : public Checker<check::PostCall, check::DeadSymbols> {
+class PthreadLockChecker : public Checker<check::PostCall, check::DeadSymbols,
+                                          check::RegionChanges> {
   mutable std::unique_ptr<BugType> BT_doublelock;
   mutable std::unique_ptr<BugType> BT_doubleunlock;
   mutable std::unique_ptr<BugType> BT_destroylock;
@@ -124,6 +124,11 @@
 
   void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
   void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
+  ProgramStateRef
+  checkRegionChanges(ProgramStateRef State, const InvalidatedSymbols *Symbols,
+                     ArrayRef<const MemRegion *> ExplicitRegions,
+                     ArrayRef<const MemRegion *> Regions,
+                     const LocationContext *LCtx, const CallEvent *Call) const;
   void printState(raw_ostream &Out, ProgramStateRef State,
                   const char *NL, const char *Sep) const override;
 };
@@ -567,6 +572,38 @@
   C.addTransition(State);
 }
 
+ProgramStateRef PthreadLockChecker::checkRegionChanges(
+    ProgramStateRef State, const InvalidatedSymbols *Symbols,
+    ArrayRef<const MemRegion *> ExplicitRegions,
+    ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
+    const CallEvent *Call) const {
+
+  bool IsLibraryFunction = false;
+  if (Call && Call->isGlobalCFunction()) {
+    // Avoid invalidating mutex state when a known supported function is called.
+    for (auto I : SupportedAPIs)
+      if (Call->isCalled(I.Name))
+        return State;
+    if (Call->isInSystemHeader())
+      IsLibraryFunction = true;
+  }
+
+  for (auto R : Regions) {
+    // We assume that system library function wouldn't touch the mutex unless
+    // it takes the mutex explicitly as an argument.
+    if (IsLibraryFunction &&
+        std::find(ExplicitRegions.begin(), ExplicitRegions.end(), R) ==
+            ExplicitRegions.end())
+      continue;
+
+    State = State->remove<LockMap>(R);
+    State = State->remove<DestroyRetVal>(R);
+    // TODO: Destroy the lock stack as well.
+  }
+
+  return State;
+}
+
 void ento::registerPthreadLockChecker(CheckerManager &mgr) {
   mgr.registerChecker<PthreadLockChecker>();
 }
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D37812: [analyzer]... Artem Dergachev via Phabricator via cfe-commits

Reply via email to