Index: lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp	(revision 131078)
+++ lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp	(working copy)
@@ -18,15 +18,30 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
 #include "llvm/ADT/ImmutableSet.h"
+#include "llvm/ADT/SmallVector.h"
 
 using namespace clang;
 using namespace ento;
 
+// GDM Entry for tracking lock state.
+namespace { class LockSet {}; }
+namespace clang {
+namespace ento {
+template <> struct GRStateTrait<LockSet> :
+  public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
+    static void* GDMIndex() { static int x = 0; return &x; }
+};
+} // end GR namespace
+} // end clang namespace
+
 namespace {
-class PthreadLockChecker
-  : public Checker< check::PostStmt<CallExpr> > {
+class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > {
+  mutable llvm::OwningPtr<BugType> BT;
+  mutable llvm::SmallVector<const MemRegion *, 5> lockHistory;
 public:
+  void reportBug(CheckerContext &C, const char *msg) const;
   void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
     
   void AcquireLock(CheckerContext &C, const CallExpr *CE,
@@ -38,17 +53,16 @@
 };
 } // end anonymous namespace
 
-// GDM Entry for tracking lock state.
-namespace { class LockSet {}; }
-namespace clang {
-namespace ento {
-template <> struct GRStateTrait<LockSet> :
-  public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
-    static void* GDMIndex() { static int x = 0; return &x; }
-};
-} // end GR namespace
-} // end clang namespace
+void PthreadLockChecker::reportBug(CheckerContext &C,
+				   const char *msg) const {
 
+    ExplodedNode *N = C.generateSink();
+    if (!N)
+      return;
+    BT.reset(new BuiltinBug(msg));
+    EnhancedBugReport *report = new EnhancedBugReport(*BT, BT->getName(), N);
+    C.EmitReport(report);
+}
 
 void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
                                        CheckerContext &C) const {
@@ -65,17 +79,30 @@
     return;
   llvm::StringRef FName = II->getName();
   
-  if (FName == "pthread_mutex_lock") {
+  if (FName == "pthread_mutex_lock" ||
+      FName == "pthread_rwlock_rdlock" ||
+      FName == "pthread_rwlock_wrlock" ||
+      FName == "lck_mtx_lock" ||
+      FName == "lck_rw_lock_exclusive" ||
+      FName == "lck_rw_lock_shared") {
     if (CE->getNumArgs() != 1)
       return;
     AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false);
   }
-  else if (FName == "pthread_mutex_trylock") {
+  else if (FName == "pthread_mutex_trylock" ||
+           FName == "pthread_rwlock_tryrdlock" ||
+           FName == "pthread_rwlock_tryrwlock" ||
+           FName == "lck_mtx_try_lock" ||
+           FName == "lck_rw_try_lock_exclusive" ||
+           FName == "lck_rw_try_lock_shared") {
     if (CE->getNumArgs() != 1)
       return;
     AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true);
   }  
-  else if (FName == "pthread_mutex_unlock") {
+  else if (FName == "pthread_mutex_unlock" ||
+           FName == "pthread_rwlock_unlock" ||
+           FName == "lck_mtx_unlock" ||
+           FName == "lck_rw_done") {
     if (CE->getNumArgs() != 1)
       return;
     ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
@@ -97,6 +124,11 @@
   
   DefinedSVal retVal = cast<DefinedSVal>(X);
   const GRState *lockSucc = state;
+
+  if (state->contains<LockSet>(lockR)) {
+    reportBug(C, "Locking an already locked lock");
+    return;
+  }
   
   if (isTryLock) {
       // Bifurcate the state, and allow a mode where the lock acquisition fails.
@@ -113,7 +145,9 @@
   
     // Record that the lock was acquired.  
   lockSucc = lockSucc->add<LockSet>(lockR);
-  
+
+  lockHistory.push_back(lockR);
+
   C.addTransition(lockSucc != state ? C.generateNode(CE, lockSucc) :
                   C.getPredecessor());
 }
@@ -128,13 +162,20 @@
   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.
+  // FIXME: Better analysis require IPA for wrappers.
   const GRState *unlockState = state->remove<LockSet>(lockR);
   
-  if (state == unlockState)
+  if (state == unlockState) {
+    reportBug(C, "Unlocked an unlocked lock");
     return;
-  
+  }
+
+  if (!lockHistory.empty() &&
+      lockHistory.pop_back_val() != lockR) {
+    reportBug(C, "Lock Order Reversal");
+    return;
+  }
+
   C.addTransition(C.generateNode(CE, unlockState));  
 }
 
