malhar1995 created this revision.

I am currently working on to avoid false positives which currently occur as the 
return values of mutex functions like pthread_mutex_destroy() are not taken 
into consideration.

The precise description of the bug can be found here: 
https://bugs.llvm.org/show_bug.cgi?id=32455

Dr. Devin and Dr. Artem have been guiding me to fix PthreadLockChecker to avoid 
such false positives. The patch I'm attaching is not 100% correct and hence I 
need your advice to proceed further.

Thank you.


Repository:
  rL LLVM

https://reviews.llvm.org/D32449

Files:
  lib/.DS_Store
  lib/StaticAnalyzer/.DS_Store
  lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp

Index: lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -18,6 +18,7 @@
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include <iostream>
 
 using namespace clang;
 using namespace ento;
@@ -25,7 +26,7 @@
 namespace {
 
 struct LockState {
-  enum Kind { Destroyed, Locked, Unlocked } K;
+  enum Kind { Destroyed, Locked, Unlocked, SchrodingerLocked, SchrodingerUnlocked } K;
 
 private:
   LockState(Kind K) : K(K) {}
@@ -34,6 +35,8 @@
   static LockState getLocked() { return LockState(Locked); }
   static LockState getUnlocked() { return LockState(Unlocked); }
   static LockState getDestroyed() { return LockState(Destroyed); }
+  static LockState getSchrodingerLocked() { return LockState(SchrodingerLocked); }
+  static LockState getSchrodingerUnlocked() { return LockState(SchrodingerUnlocked); }
 
   bool operator==(const LockState &X) const {
     return K == X.K;
@@ -42,13 +45,15 @@
   bool isLocked() const { return K == Locked; }
   bool isUnlocked() const { return K == Unlocked; }
   bool isDestroyed() const { return K == Destroyed; }
+  bool isSchrodingerLocked() const { return K == SchrodingerLocked; }
+  bool isSchrodingerUnlocked() const { return K == SchrodingerUnlocked; }
 
   void Profile(llvm::FoldingSetNodeID &ID) const {
     ID.AddInteger(K);
   }
 };
 
-class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > {
+class PthreadLockChecker : public Checker< check::PostStmt<CallExpr>, check::DeadSymbols > {
   mutable std::unique_ptr<BugType> BT_doublelock;
   mutable std::unique_ptr<BugType> BT_doubleunlock;
   mutable std::unique_ptr<BugType> BT_destroylock;
@@ -61,6 +66,7 @@
   };
 public:
   void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+  void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
 
   void AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock,
                    bool isTryLock, enum LockingSemantics semantics) const;
@@ -76,6 +82,7 @@
 REGISTER_LIST_WITH_PROGRAMSTATE(LockSet, const MemRegion *)
 
 REGISTER_MAP_WITH_PROGRAMSTATE(LockMap, const MemRegion *, LockState)
+REGISTER_MAP_WITH_PROGRAMSTATE(DestroyRetVal, const MemRegion *, SymbolRef)
 
 void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
                                        CheckerContext &C) const {
@@ -126,10 +133,30 @@
 
   const MemRegion *lockR = lock.getAsRegion();
   if (!lockR)
-    return;
+    return; 
 
   ProgramStateRef state = C.getState();
 
+  // CHECK THIS
+  const SymbolRef* sym = state->get<DestroyRetVal>(lockR);
+  if(sym){
+    const LockState* lstate = state->get<LockMap>(lockR);
+    if(lstate){
+      ConstraintManager &CMgr = state->getConstraintManager();
+      ConditionTruthVal retZero = CMgr.isNull(state, *sym);
+      if(retZero.isConstrainedFalse()){
+        if(lstate->isSchrodingerLocked())
+          state = state->set<LockMap>(lockR, LockState::getLocked());
+        else if(lstate->isSchrodingerUnlocked())
+          state = state->set<LockMap>(lockR, LockState::getUnlocked());
+      }
+      else{
+        if(!lstate || lstate->isSchrodingerLocked() || lstate->isSchrodingerUnlocked())
+          state = state->set<LockMap>(lockR, LockState::getDestroyed());
+      }
+    }
+  }
+
   SVal X = state->getSVal(CE, C.getLocationContext());
   if (X.isUnknownOrUndef())
     return;
@@ -198,6 +225,26 @@
 
   ProgramStateRef state = C.getState();
 
+  // CHECK THIS
+  const SymbolRef* sym = state->get<DestroyRetVal>(lockR);
+  if(sym){
+    const LockState* lstate = state->get<LockMap>(lockR);
+    if(lstate){
+      ConstraintManager &CMgr = state->getConstraintManager();
+      ConditionTruthVal retZero = CMgr.isNull(state, *sym);
+      if(retZero.isConstrainedFalse()){
+        if(lstate->isSchrodingerLocked())
+          state = state->set<LockMap>(lockR, LockState::getLocked());
+        else if(lstate->isSchrodingerUnlocked())
+          state = state->set<LockMap>(lockR, LockState::getUnlocked());
+      }
+      else{
+        if(!lstate || lstate->isSchrodingerLocked() || lstate->isSchrodingerUnlocked())
+          state = state->set<LockMap>(lockR, LockState::getDestroyed());
+      }
+    }
+  }
+
   if (const LockState *LState = state->get<LockMap>(lockR)) {
     if (LState->isUnlocked()) {
       if (!BT_doubleunlock)
@@ -253,9 +300,50 @@
 
   ProgramStateRef State = C.getState();
 
+  // CHECK THIS
+  const SymbolRef* sym = State->get<DestroyRetVal>(LockR);
+  if(sym){
+    const LockState* lstate = State->get<LockMap>(LockR);
+    if(lstate){
+      ConstraintManager &CMgr = State->getConstraintManager();
+      ConditionTruthVal retZero = CMgr.isNull(State, *sym);
+      if(retZero.isConstrainedFalse()){
+        if(lstate->isSchrodingerLocked())
+          State = State->set<LockMap>(LockR, LockState::getLocked());
+        else if(lstate->isSchrodingerUnlocked())
+          State = State->set<LockMap>(LockR, LockState::getUnlocked());
+      }
+      else{
+        if(!lstate || lstate->isSchrodingerLocked() || lstate->isSchrodingerUnlocked())
+          State = State->set<LockMap>(LockR, LockState::getDestroyed());
+      }
+    }
+  }
+
+  // CHECK THIS
   const LockState *LState = State->get<LockMap>(LockR);
-  if (!LState || LState->isUnlocked()) {
-    State = State->set<LockMap>(LockR, LockState::getDestroyed());
+  if(!LState){
+    SVal X = State->getSVal(CE, C.getLocationContext());
+    if (X.isUnknownOrUndef()){
+      return;
+    }
+
+    DefinedSVal retVal = X.castAs<DefinedSVal>();
+    retVal.dump();
+    SymbolRef sym = retVal.getAsSymbol();
+    State = State->set<DestroyRetVal>(LockR, sym);
+    C.addTransition(State);
+    return;
+  }
+  if (LState->isUnlocked()) {
+    SVal X = State->getSVal(CE, C.getLocationContext());
+    if (X.isUnknownOrUndef())
+      return;
+
+    DefinedSVal retVal = X.castAs<DefinedSVal>();
+    SymbolRef sym = retVal.getAsSymbol();
+    State = State->set<DestroyRetVal>(LockR, sym);
+    State = State->set<LockMap>(LockR, LockState::getSchrodingerUnlocked());
     C.addTransition(State);
     return;
   }
@@ -327,6 +415,37 @@
   Report->addRange(CE->getArg(0)->getSourceRange());
   C.emitReport(std::move(Report));
 }
+void PthreadLockChecker::checkDeadSymbols(SymbolReaper &SymReaper,
+                                           CheckerContext &C) const {
+  ProgramStateRef State = C.getState();
+  ConstraintManager &CMgr = State->getConstraintManager();
+
+  DestroyRetValTy TrackedSymbols = State->get<DestroyRetVal>();
+  for (DestroyRetValTy::iterator I = TrackedSymbols.begin(),
+                             E = TrackedSymbols.end(); I != E; ++I) {
+    SymbolRef Sym = I->second;
+    const MemRegion* lockR = I->first;
+    bool IsSymDead = SymReaper.isDead(Sym);
+    const LockState* LState = State->get<LockMap>(lockR); 
+    // Remove the dead symbol from the return value symbols map.
+    if (IsSymDead){
+      ConditionTruthVal retZero = CMgr.isNull(State, Sym);
+      if(retZero.isConstrainedFalse()){
+        if(LState && LState->isSchrodingerLocked())
+          State = State->set<LockMap>(lockR, LockState::getLocked());
+        else if(LState && LState->isSchrodingerUnlocked())
+          State = State->set<LockMap>(lockR, LockState::getUnlocked());
+      }
+      else{
+        // IS THIS CORRECT?
+        if(!LState || LState->isSchrodingerUnlocked() || LState->isSchrodingerLocked())
+          State = State->set<LockMap>(lockR, LockState::getDestroyed());
+      }
+      State = State->remove<DestroyRetVal>(lockR);
+    }
+  }
+  C.addTransition(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

Reply via email to