zcov: / lib/Checker/PthreadLockChecker.cpp


Files: 1 Branches Taken: 13.2% 5 / 38
Generated: 2010-02-10 01:31 Branches Executed: 26.3% 10 / 38
Line Coverage: 29.1% 16 / 55


Programs: 1 Runs 2897


       1                 : //===--- PthreadLockChecker.h - Undefined arguments checker ----*- C++ -*--===//
       2                 : //
       3                 : //                     The LLVM Compiler Infrastructure
       4                 : //
       5                 : // This file is distributed under the University of Illinois Open Source
       6                 : // License. See LICENSE.TXT for details.
       7                 : //
       8                 : //===----------------------------------------------------------------------===//
       9                 : //
      10                 : // This defines PthreadLockChecker, a simple lock -> unlock checker.  Eventually
      11                 : // this shouldn't be registered with GRExprEngineInternalChecks.
      12                 : //
      13                 : //===----------------------------------------------------------------------===//
      14                 : 
      15                 : #include "clang/Checker/PathSensitive/CheckerVisitor.h"
      16                 : #include "clang/Checker/BugReporter/BugReporter.h"
      17                 : #include "clang/Checker/PathSensitive/GRStateTrait.h"
      18                 : #include "GRExprEngineExperimentalChecks.h"
      19                 : #include "llvm/ADT/ImmutableSet.h"
      20                 : 
      21                 : using namespace clang;
      22                 : 
      23                 : namespace {
      24                 : class PthreadLockChecker
                       10: branch 1 taken
                        0: branch 2 not taken
                        0: branch 5 not taken
                        0: branch 6 not taken
      25               10:   : public CheckerVisitor<PthreadLockChecker> {
      26                 :   BugType *BT;
      27                 : public:
      28               10:   PthreadLockChecker() : BT(0) {}
      29               10:   static void *getTag() {
      30                 :     static int x = 0;
      31               10:     return &x;
      32                 :   }
      33                 :   void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
      34                 :     
      35                 :   void AcquireLock(CheckerContext &C, const CallExpr *CE,
      36                 :                    SVal lock, bool isTryLock);
      37                 :     
      38                 :   void ReleaseLock(CheckerContext &C, const CallExpr *CE,
      39                 :                     SVal lock);
      40                 : 
      41                 : };
      42                 : } // end anonymous namespace
      43                 : 
      44                 : // GDM Entry for tracking lock state.
      45                 : namespace { class LockSet {}; }
      46                 : namespace clang {
      47                 : template <> struct GRStateTrait<LockSet> :
      48                 :   public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
      49                0:     static void* GDMIndex() { return PthreadLockChecker::getTag(); }
      50                 : };
      51                 : } // end clang namespace
      52                 : 
      53               10: void clang::RegisterPthreadLockChecker(GRExprEngine &Eng) {
      54               10:   Eng.registerCheck(new PthreadLockChecker());
      55               10: }
      56                 : 
      57                 : 
      58                 : void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C,
      59               14:                                            const CallExpr *CE) {
      60               14:   const GRState *state = C.getState();
      61               14:   const Expr *Callee = CE->getCallee();
      62                 :   const FunctionTextRegion *R =
      63               14:     dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
      64                 :   
                        0: branch 0 not taken
                       14: branch 1 taken
      65               14:   if (!R)
      66                0:     return;
      67                 :   
      68               14:   llvm::StringRef FName = R->getDecl()->getName();
      69                 :   
                        0: branch 2 not taken
                       14: branch 3 taken
      70               14:   if (FName == "pthread_mutex_lock") {
                        0: branch 1 not taken
                        0: branch 2 not taken
      71                0:     if (CE->getNumArgs() != 1)
      72                0:       return;
      73                0:     AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false);
      74                 :   }
                        0: branch 2 not taken
                       14: branch 3 taken
      75               14:   else if (FName == "pthread_mutex_trylock") {
                        0: branch 1 not taken
                        0: branch 2 not taken
      76                0:     if (CE->getNumArgs() != 1)
      77                0:       return;
      78                0:     AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true);
      79                 :   }  
                        0: branch 2 not taken
                       14: branch 3 taken
      80               14:   else if (FName == "pthread_mutex_unlock") {
                        0: branch 1 not taken
                        0: branch 2 not taken
      81                0:     if (CE->getNumArgs() != 1)
      82                0:       return;
      83                0:     ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
      84                 :   }
      85                 : }
      86                 : 
      87                 : void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
      88                0:                                      SVal lock, bool isTryLock) {
      89                 :   
      90                0:   const MemRegion *lockR = lock.getAsRegion();
                        0: branch 0 not taken
                        0: branch 1 not taken
      91                0:   if (!lockR)
      92                0:     return;
      93                 :   
      94                0:   const GRState *state = C.getState();
      95                 :   
      96                0:   SVal X = state->getSVal(CE);
                        0: branch 1 not taken
                        0: branch 2 not taken
      97                0:   if (X.isUnknownOrUndef())
      98                0:     return;
      99                 :   
     100                0:   DefinedSVal retVal = cast<DefinedSVal>(X);
     101                0:   const GRState *lockSucc = state;
     102                 :   
                        0: branch 0 not taken
                        0: branch 1 not taken
     103                0:   if (isTryLock) {
     104                 :       // Bifurcate the state, and allow a mode where the lock acquisition fails.
     105                 :     const GRState *lockFail;
     106                0:     llvm::tie(lockFail, lockSucc) = state->Assume(retVal);    
                        0: branch 0 not taken
                        0: branch 1 not taken
                        0: branch 2 not taken
                        0: branch 3 not taken
     107                0:     assert(lockFail && lockSucc);
     108                0:     C.addTransition(C.GenerateNode(CE, lockFail));
     109                 :   }
     110                 :   else {
     111                 :       // Assume that the return value was 0.
     112                0:     lockSucc = state->Assume(retVal, false);
                        0: branch 0 not taken
                        0: branch 1 not taken
     113                0:     assert(lockSucc);
     114                 :   }
     115                 :   
     116                 :     // Record that the lock was acquired.  
     117                0:   lockSucc = lockSucc->add<LockSet>(lockR);
     118                 :   
     119                 :   C.addTransition(lockSucc != state ? C.GenerateNode(CE, lockSucc) :
                        0: branch 0 not taken
                        0: branch 1 not taken
                        0: branch 7 not taken
                        0: branch 8 not taken
     120                0:                   C.getPredecessor());
     121                 : }
     122                 : 
     123                 : void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
     124                0:                                      SVal lock) {
     125                 : 
     126                0:   const MemRegion *lockR = lock.getAsRegion();
                        0: branch 0 not taken
                        0: branch 1 not taken
     127                0:   if (!lockR)
     128                0:     return;
     129                 :   
     130                0:   const GRState *state = C.getState();
     131                 : 
     132                 :   // Record that the lock was released.  
     133                 :   // FIXME: Handle unlocking locks that were never acquired.  This may
     134                 :   // require IPA for wrappers.
     135                0:   const GRState *unlockState = state->remove<LockSet>(lockR);
     136                 :   
                        0: branch 0 not taken
                        0: branch 1 not taken
     137                0:   if (state == unlockState)
     138                0:     return;
     139                 :   
     140                0:   C.addTransition(C.GenerateNode(CE, unlockState));  
     141                0: }

Generated: 2010-02-10 01:31 by zcov