forked from github/codeql-coding-standards
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathInvalidOperationOnUnlockedMutex.ql
More file actions
67 lines (59 loc) · 2.46 KB
/
InvalidOperationOnUnlockedMutex.ql
File metadata and controls
67 lines (59 loc) · 2.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/**
* @id c/misra/invalid-operation-on-unlocked-mutex
* @name RULE-22-17: No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked
* @description No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it
* has not locked before.
* @kind problem
* @precision high
* @problem.severity error
* @tags external/misra/id/rule-22-17
* correctness
* concurrency
* external/misra/c/2012/amendment4
* external/misra/obligation/required
*/
import cpp
import codingstandards.c.misra
import codingstandards.c.SubObjects
import codingstandards.cpp.Concurrency
import codingstandards.cpp.dominance.BehavioralSet
/* A call to mtx_unlock() or cnd_wait() or cnd_timedwait(), which require a locked mutex */
class RequiresLockOperation extends FunctionCall {
SubObject mutex;
RequiresLockOperation() {
exists(CMutexFunctionCall mutexCall | this = mutexCall |
mutexCall.isUnlock() and
mutex.getAnAddressOfExpr() = mutexCall.getLockExpr()
)
or
exists(CConditionOperation condOp | this = condOp |
mutex.getAnAddressOfExpr() = condOp.getMutexExpr()
)
}
SubObject getMutex() { result = mutex }
}
/* A config to search for a dominating set that locks the mutex before the operation */
module LockDominatingSetConfig implements DominatingSetConfigSig<RequiresLockOperation> {
predicate isTargetBehavior(ControlFlowNode node, RequiresLockOperation op) {
exists(CMutexFunctionCall mutexCall | node = mutexCall |
mutexCall.isLock() and
mutexCall.getLockExpr() = op.getMutex().getAnAddressOfExpr()
)
}
predicate isBlockingBehavior(ControlFlowNode node, RequiresLockOperation op) {
// If we find a branch that explicitly unlocks the mutex, we should not look for an earlier
// call to lock that mutex.
exists(CMutexFunctionCall mutexCall | node = mutexCall |
mutexCall.isUnlock() and
mutexCall.getLockExpr() = op.getMutex().getAnAddressOfExpr()
)
}
}
import DominatingBehavioralSet<RequiresLockOperation, LockDominatingSetConfig> as DominatingSet
from RequiresLockOperation operation, SubObject mutex
where
not isExcluded(operation, Concurrency9Package::invalidOperationOnUnlockedMutexQuery()) and
mutex = operation.getMutex() and
not DominatingSet::isDominatedByBehavior(operation)
select operation, "Invalid operation on mutex '$@' not locked by the current thread.",
mutex.getRootIdentity(), mutex.toString()