1515import cpp
1616import codingstandards.cpp.cert
1717import codingstandards.cpp.Concurrency
18+ import semmle.code.cpp.controlflow.Dominance
1819
1920/**
2021 * Gets a pair of locks guarding a `LockProtectedControlFlowNode` in an order
@@ -27,7 +28,8 @@ predicate getAnOrderedLockPair(
2728 lock1 = node .coveredByLock ( ) and
2829 lock2 = node .coveredByLock ( ) and
2930 not lock1 = lock2 and
30- lock1 .getFile ( ) = lock2 .getFile ( ) and
31+ lock1 .getEnclosingFunction ( ) = lock2 .getEnclosingFunction ( ) and
32+ node .( Expr ) .getEnclosingFunction ( ) = lock1 .getEnclosingFunction ( ) and
3133 exists ( Location l1Loc , Location l2Loc |
3234 l1Loc = lock1 .getLocation ( ) and
3335 l2Loc = lock2 .getLocation ( )
@@ -53,15 +55,30 @@ predicate getAnOrderedLockPair(
5355 * same time that are invoked from a thread.
5456 */
5557
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+ )
66+ }
67+
68+ predicate isSerializedLock ( LockingOperation lock ) { not isUnSerializedLock ( lock ) }
69+
5670from LockProtectedControlFlowNode node , Function f , FunctionCall lock1 , FunctionCall lock2
5771where
5872 not isExcluded ( node , ConcurrencyPackage:: deadlockByLockingInPredefinedOrderQuery ( ) ) and
5973 // we can get into trouble when we get into a situation where there may be two
6074 // locks in the same threaded function active at the same time.
61- // simple ordering
62- // lock1 = node.coveredByLock() and
63- // lock2 = node.coveredByLock() and
75+ // simple ordering is applied here for presentation purposes.
6476 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
6582 // To reduce the noise (and increase usefulness) we alert the user at the
6683 // level of the function, which is the unit the synchronization should be
6784 // performed.
0 commit comments