@@ -26,6 +26,7 @@ using namespace ento;
26
26
namespace {
27
27
class PthreadLockChecker : public Checker < check::PostStmt<CallExpr> > {
28
28
mutable std::unique_ptr<BugType> BT_doublelock;
29
+ mutable std::unique_ptr<BugType> BT_doubleunlock;
29
30
mutable std::unique_ptr<BugType> BT_lor;
30
31
enum LockingSemantics {
31
32
NotApplicable = 0 ,
@@ -45,6 +46,7 @@ class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > {
45
46
// GDM Entry for tracking lock state.
46
47
REGISTER_LIST_WITH_PROGRAMSTATE (LockSet, const MemRegion *)
47
48
49
+ REGISTER_SET_WITH_PROGRAMSTATE(UnlockSet, const MemRegion *)
48
50
49
51
void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
50
52
CheckerContext &C) const {
@@ -144,6 +146,7 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
144
146
145
147
// Record that the lock was acquired.
146
148
lockSucc = lockSucc->add <LockSet>(lockR);
149
+ lockSucc = lockSucc->remove <UnlockSet>(lockR);
147
150
C.addTransition (lockSucc);
148
151
}
149
152
@@ -155,32 +158,48 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
155
158
return ;
156
159
157
160
ProgramStateRef state = C.getState ();
158
- LockSetTy LS = state->get <LockSet>();
159
161
160
- // FIXME: Better analysis requires IPA for wrappers.
161
- // FIXME: check for double unlocks
162
- if (LS.isEmpty ())
163
- return ;
164
-
165
- const MemRegion *firstLockR = LS.getHead ();
166
- if (firstLockR != lockR) {
167
- if (!BT_lor)
168
- BT_lor.reset (new BugType (this , " Lock order reversal" , " Lock checker" ));
162
+ if (state->contains <UnlockSet>(lockR)) {
163
+ if (!BT_doubleunlock)
164
+ BT_doubleunlock.reset (new BugType (this , " Double unlocking" ,
165
+ " Lock checker" ));
169
166
ExplodedNode *N = C.generateSink ();
170
167
if (!N)
171
168
return ;
172
- BugReport *report = new BugReport (*BT_lor,
173
- " This was not the most "
174
- " recently acquired lock. "
175
- " Possible lock order "
176
- " reversal" , N);
177
- report->addRange (CE->getArg (0 )->getSourceRange ());
178
- C.emitReport (report);
169
+ BugReport *Report = new BugReport (*BT_doubleunlock,
170
+ " This lock has already been unlocked" ,
171
+ N);
172
+ Report->addRange (CE->getArg (0 )->getSourceRange ());
173
+ C.emitReport (Report);
179
174
return ;
180
175
}
181
176
177
+ LockSetTy LS = state->get <LockSet>();
178
+
179
+ // FIXME: Better analysis requires IPA for wrappers.
180
+
181
+ if (!LS.isEmpty ()) {
182
+ const MemRegion *firstLockR = LS.getHead ();
183
+ if (firstLockR != lockR) {
184
+ if (!BT_lor)
185
+ BT_lor.reset (new BugType (this , " Lock order reversal" , " Lock checker" ));
186
+ ExplodedNode *N = C.generateSink ();
187
+ if (!N)
188
+ return ;
189
+ BugReport *report = new BugReport (*BT_lor,
190
+ " This was not the most recently "
191
+ " acquired lock. Possible lock order "
192
+ " reversal" ,
193
+ N);
194
+ report->addRange (CE->getArg (0 )->getSourceRange ());
195
+ C.emitReport (report);
196
+ return ;
197
+ }
198
+ }
199
+
182
200
// Record that the lock was released.
183
201
state = state->set <LockSet>(LS.getTail ());
202
+ state = state->add <UnlockSet>(lockR);
184
203
C.addTransition (state);
185
204
}
186
205
0 commit comments