[cfe-commits] r86958 - in /cfe/trunk/lib/Analysis: CMakeLists.txt GRExprEngineExperimentalChecks.h PthreadLockChecker.cpp

Ted Kremenek kremenek at apple.com
Wed Nov 11 22:17:47 PST 2009


Author: kremenek
Date: Thu Nov 12 00:17:47 2009
New Revision: 86958

URL: http://llvm.org/viewvc/llvm-project?rev=86958&view=rev
Log:
Add most of the boilerplate logic for a simple pthread_mutux_lock() -> pthread_mutex_unlock() checker.  We need to add a visitor method to Checker for handling dead symbols in order to detect locks that are not unlocked.

Added:
    cfe/trunk/lib/Analysis/GRExprEngineExperimentalChecks.h
    cfe/trunk/lib/Analysis/PthreadLockChecker.cpp
Modified:
    cfe/trunk/lib/Analysis/CMakeLists.txt

Modified: cfe/trunk/lib/Analysis/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=86958&r1=86957&r2=86958&view=diff

==============================================================================
--- cfe/trunk/lib/Analysis/CMakeLists.txt (original)
+++ cfe/trunk/lib/Analysis/CMakeLists.txt Thu Nov 12 00:17:47 2009
@@ -16,7 +16,6 @@
   CallGraph.cpp
   CallInliner.cpp
   CastToStructChecker.cpp
-  CheckSizeofPointer.cpp
   CheckDeadStores.cpp
   CheckObjCDealloc.cpp
   CheckObjCInstMethSignature.cpp
@@ -41,6 +40,7 @@
   PathDiagnostic.cpp
   PointerArithChecker.cpp
   PointerSubChecker.cpp
+  PthreadLockChecker.cpp
   RangeConstraintManager.cpp
   RegionStore.cpp
   ReturnPointerRangeChecker.cpp

Added: cfe/trunk/lib/Analysis/GRExprEngineExperimentalChecks.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngineExperimentalChecks.h?rev=86958&view=auto

==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngineExperimentalChecks.h (added)
+++ cfe/trunk/lib/Analysis/GRExprEngineExperimentalChecks.h Thu Nov 12 00:17:47 2009
@@ -0,0 +1,25 @@
+//=-- GRExprEngineExperimentalChecks.h ------------------------------*- C++ -*-=
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines functions to instantiate and register experimental
+//  checks in GRExprEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GREXPRENGINE_EXPERIMENTAL_CHECKS
+#define LLVM_CLANG_GREXPRENGINE_EXPERIMENTAL_CHECKS
+
+namespace clang {
+
+class GRExprEngine;
+
+void RegisterPthreadLockChecker(GRExprEngine &Eng);
+
+} // end clang namespace
+#endif

Added: cfe/trunk/lib/Analysis/PthreadLockChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PthreadLockChecker.cpp?rev=86958&view=auto

==============================================================================
--- cfe/trunk/lib/Analysis/PthreadLockChecker.cpp (added)
+++ cfe/trunk/lib/Analysis/PthreadLockChecker.cpp Thu Nov 12 00:17:47 2009
@@ -0,0 +1,155 @@
+//===--- PthreadLockChecker.h - Undefined arguments checker ----*- C++ -*--===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines PthreadLockChecker, a simple lock -> unlock checker.  Eventually
+// this shouldn't be registered with GRExprEngineInternalChecks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/GRStateTrait.h"
+#include "GRExprEngineExperimentalChecks.h"
+#include "llvm/ADT/ImmutableSet.h"
+
+using namespace clang;
+
+namespace {
+class VISIBILITY_HIDDEN PthreadLockChecker
+  : public CheckerVisitor<PthreadLockChecker> {
+  BugType *BT;
+public:
+  PthreadLockChecker() : BT(0) {}
+  static void *getTag() {
+    static int x = 0;
+    return &x;
+  }
+  void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+  void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
+    
+  void AcquireLock(CheckerContext &C, const CallExpr *CE,
+                   SVal lock, bool isTryLock);
+    
+  void ReleaseLock(CheckerContext &C, const CallExpr *CE,
+                    SVal lock);
+
+};
+} // end anonymous namespace
+
+// GDM Entry for tracking lock state.
+namespace { class VISIBILITY_HIDDEN LockSet {}; }
+namespace clang {
+template <> struct GRStateTrait<LockSet> :
+  public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
+    static void* GDMIndex() { return PthreadLockChecker::getTag(); }
+};
+} // end clang namespace
+
+void clang::RegisterPthreadLockChecker(GRExprEngine &Eng) {
+  Eng.registerCheck(new PthreadLockChecker());
+}
+
+void PthreadLockChecker::PreVisitCallExpr(CheckerContext &C,
+                                          const CallExpr *CE) {
+  const GRState *state = C.getState();
+  const Expr *Callee = CE->getCallee();
+  const CodeTextRegion *R =
+    dyn_cast_or_null<CodeTextRegion>(state->getSVal(Callee).getAsRegion());
+  
+  if (!R)
+    return;
+  
+  llvm::StringRef FName = R->getDecl()->getName();
+
+  if (FName == "pthread_mutex_lock") {
+    if (CE->getNumArgs() != 1)
+      return;
+    AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false);
+  }
+  else if (FName == "pthread_mutex_trylock") {
+    if (CE->getNumArgs() != 1)
+      return;
+    AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true);
+  }
+}
+
+void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C,
+                                           const CallExpr *CE) {
+  const GRState *state = C.getState();
+  const Expr *Callee = CE->getCallee();
+  const CodeTextRegion *R =
+    dyn_cast_or_null<CodeTextRegion>(state->getSVal(Callee).getAsRegion());
+  
+  if (!R)
+    return;
+  
+  llvm::StringRef FName = R->getDecl()->getName();
+  
+  if (FName == "pthread_mutex_unlock") {
+    if (CE->getNumArgs() != 1)
+      return;
+    ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
+  }
+}
+
+void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
+                                     SVal lock, bool isTryLock) {
+  
+  const MemRegion *lockR = lock.getAsRegion();
+  if (!lockR)
+    return;
+  
+  const GRState *state = C.getState();
+  
+  SVal X = state->getSVal(CE);
+  if (X.isUnknownOrUndef())
+    return;
+  
+  DefinedSVal retVal = cast<DefinedSVal>(X);
+  const GRState *lockSucc = state;
+  
+  if (isTryLock) {
+      // Bifurcate the state, and allow a mode where the lock acquisition fails.
+    const GRState *lockFail;
+    llvm::tie(lockFail, lockSucc) = state->Assume(retVal);    
+    assert(lockFail && lockSucc);
+    C.addTransition(C.GenerateNode(CE, lockFail));
+  }
+  else {
+      // Assume that the return value was 0.
+    lockSucc = state->Assume(retVal, false);
+    assert(lockSucc);
+  }
+  
+    // Record that the lock was acquired.  
+  lockSucc = lockSucc->add<LockSet>(lockR);
+  
+  C.addTransition(lockSucc != state ? C.GenerateNode(CE, lockSucc) :
+                  C.getPredecessor());
+}
+
+void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
+                                     SVal lock) {
+
+  const MemRegion *lockR = lock.getAsRegion();
+  if (!lockR)
+    return;
+  
+  const GRState *state = C.getState();
+
+  // Record that the lock was released.  
+  // FIXME: Handle unlocking locks that were never acquired.  This may
+  // require IPA for wrappers.
+  const GRState *unlockState = state->remove<LockSet>(lockR);
+  
+  if (state == unlockState)
+    return;
+  
+  C.addTransition(C.GenerateNode(CE, unlockState));  
+}





More information about the cfe-commits mailing list