Skip to content

Commit 09e7d31

Browse files
committed
refactor query
1 parent 2b4a46a commit 09e7d31

File tree

1 file changed

+5
-79
lines changed

1 file changed

+5
-79
lines changed

cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder.ql

Lines changed: 5 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -14,84 +14,10 @@
1414

1515
import cpp
1616
import codingstandards.cpp.cert
17-
import codingstandards.cpp.Concurrency
18-
import semmle.code.cpp.controlflow.Dominance
17+
import codingstandards.cpp.rules.preventdeadlockbylockinginpredefinedorder.PreventDeadlockByLockingInPredefinedOrder
1918

20-
/**
21-
* Gets a pair of locks guarding a `LockProtectedControlFlowNode` in an order
22-
* specified by the locking function's call site.
23-
*/
24-
pragma[inline]
25-
predicate getAnOrderedLockPair(
26-
FunctionCall lock1, FunctionCall lock2, LockProtectedControlFlowNode node
27-
) {
28-
lock1 = node.coveredByLock() and
29-
lock2 = node.coveredByLock() and
30-
not lock1 = lock2 and
31-
lock1.getEnclosingFunction() = lock2.getEnclosingFunction() and
32-
node.(Expr).getEnclosingFunction() = lock1.getEnclosingFunction() and
33-
exists(Location l1Loc, Location l2Loc |
34-
l1Loc = lock1.getLocation() and
35-
l2Loc = lock2.getLocation()
36-
|
37-
l1Loc.getEndLine() < l2Loc.getStartLine()
38-
or
39-
l1Loc.getStartLine() = l2Loc.getEndLine() and
40-
l1Loc.getEndColumn() < l2Loc.getStartColumn()
41-
)
42-
}
43-
44-
/*
45-
* There are two ways to safely avoid deadlock. One involves doing the locking
46-
* in a specific order that is guaranteed to be the same across all thread
47-
* invocations. This is especially hard to check and thus we adopt an
48-
* alternative viewpoint wherein we view a "safe" usage of multiple locks to be
49-
* one that uses the built in `std::lock` functionality which avoids this
50-
* problem.
51-
*
52-
* To properly deadlock, a thread must have at least two different locks (i.e.,
53-
* mutual exclusion) which are used in an order that causes a problem. Thus we
54-
* look for functions with CFNs wherein there may be two locks active at the
55-
* same time that are invoked from a thread.
56-
*/
57-
58-
predicate isUnSerializedLock(LockingOperation lock) {
59-
exists(VariableAccess va |
60-
va = lock.getArgument(0).getAChild().(VariableAccess) and
61-
not exists(Assignment assn |
62-
assn = va.getTarget().getAnAssignment() and
63-
not bbDominates(assn.getBasicBlock(), lock.getBasicBlock())
64-
)
65-
)
19+
class DeadlockByLockingInPredefinedOrderQuery extends PreventDeadlockByLockingInPredefinedOrderSharedQuery {
20+
DeadlockByLockingInPredefinedOrderQuery() {
21+
this = ConcurrencyPackage::deadlockByLockingInPredefinedOrderQuery()
22+
}
6623
}
67-
68-
predicate isSerializedLock(LockingOperation lock) { not isUnSerializedLock(lock) }
69-
70-
from LockProtectedControlFlowNode node, Function f, FunctionCall lock1, FunctionCall lock2
71-
where
72-
not isExcluded(node, ConcurrencyPackage::deadlockByLockingInPredefinedOrderQuery()) and
73-
// we can get into trouble when we get into a situation where there may be two
74-
// locks in the same threaded function active at the same time.
75-
// simple ordering is applied here for presentation purposes.
76-
getAnOrderedLockPair(lock1, lock2, node) and
77-
// it is difficult to determine if the ordering applied to the locks is "safe"
78-
// so here we simply look to see that there exists at least one other program
79-
// path that would yield different argument values to the lock functions
80-
// perhaps arising from some logic that applies an ordering to the locking.
81-
not (isSerializedLock(lock1) and isSerializedLock(lock2)) and
82-
// To reduce the noise (and increase usefulness) we alert the user at the
83-
// level of the function, which is the unit the synchronization should be
84-
// performed.
85-
f = node.getEnclosingStmt().getEnclosingFunction() and
86-
// Because `std::lock` isn't included in our definition of a 'lock'
87-
// it is not necessary to check to see if it is in fact what is protecting
88-
// these CNFs.
89-
// However, to reduce noise, we shall require that the function we are
90-
// reporting makes some sort of locking call since this is likely where the
91-
// user intends to perform the locking operations. Our implementation will
92-
// currently look into all of these nodes which is less helpful for the user
93-
// but useful for our analysis.
94-
any(LockingOperation l).getEnclosingFunction() = f
95-
select f,
96-
"Threaded function may be called from a context that uses $@ and $@ which may lead to deadlocks.",
97-
lock1, "lock 1", lock2, "lock 2"

0 commit comments

Comments
 (0)