 |
|
 |
|
| 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 |
| |
 |
|
 |
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