Skip to content

Commit 012ac3d

Browse files
committed
Create temporary copies of parts of the concurrency library
These use the new dataflow library
1 parent 8529fbb commit 012ac3d

File tree

4 files changed

+555
-0
lines changed

4 files changed

+555
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import cpp
2+
import semmle.code.cpp.dataflow.new.TaintTracking
3+
import codingstandards.cpp.concurrency.Atomic
4+
import codingstandards.cpp.concurrency.CConditionOperation
5+
import codingstandards.cpp.concurrency.ControlFlow
6+
import codingstandards.cpp.concurrency.ConditionalWait
7+
import codingstandards.cpp.concurrency.LockingOperationNew
8+
import codingstandards.cpp.concurrency.LockProtectedControlFlow
9+
import codingstandards.cpp.concurrency.MutexDestroyer
10+
import codingstandards.cpp.concurrency.ThreadCreation
11+
import codingstandards.cpp.concurrency.ThreadedFunction
12+
import codingstandards.cpp.concurrency.ThreadDependentMutexNew
13+
import codingstandards.cpp.concurrency.ThreadSpecificStorageNew
14+
import codingstandards.cpp.concurrency.ThreadWaitDetach
15+
import codingstandards.cpp.concurrency.Types
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
import cpp
2+
import semmle.code.cpp.dataflow.new.TaintTracking
3+
4+
abstract class LockingOperation extends FunctionCall {
5+
/**
6+
* Returns the target of the lock underlying this RAII-style lock.
7+
*/
8+
abstract Variable getLock();
9+
10+
/**
11+
* Returns the lock underlying this RAII-style lock.
12+
*/
13+
abstract Expr getLockExpr();
14+
15+
/**
16+
* Holds if this is a lock operation
17+
*/
18+
abstract predicate isLock();
19+
20+
/**
21+
* Holds if this is an unlock operation
22+
*/
23+
abstract predicate isUnlock();
24+
25+
/**
26+
* Holds if this locking operation is really a locking operation within a
27+
* designated locking operation. This library assumes the underlying locking
28+
* operations are implemented correctly in that calling a `LockingOperation`
29+
* results in the creation of a singular lock.
30+
*/
31+
predicate isLockingOperationWithinLockingOperation(LockingOperation inner) {
32+
exists(LockingOperation outer | outer.getTarget() = inner.getEnclosingFunction())
33+
}
34+
}
35+
36+
/**
37+
* Common base class providing an interface into function call
38+
* based mutex locks.
39+
*/
40+
abstract class MutexFunctionCall extends LockingOperation {
41+
abstract predicate isRecursive();
42+
43+
abstract predicate isSpeculativeLock();
44+
45+
abstract predicate unlocks(MutexFunctionCall fc);
46+
}
47+
48+
/**
49+
* Models calls to various mutex types found in CPP.
50+
*/
51+
class CPPMutexFunctionCall extends MutexFunctionCall {
52+
VariableAccess var;
53+
54+
CPPMutexFunctionCall() {
55+
getTarget()
56+
.(MemberFunction)
57+
.getDeclaringType()
58+
.hasQualifiedName("std",
59+
["mutex", "timed_mutex", "shared_timed_mutex", "recursive_mutex", "recursive_timed_mutex"]) and
60+
var = getQualifier()
61+
}
62+
63+
/**
64+
* Holds if this mutex is a recursive mutex.
65+
*/
66+
override predicate isRecursive() {
67+
getTarget()
68+
.(MemberFunction)
69+
.getDeclaringType()
70+
.hasQualifiedName("std", ["recursive_mutex", "recursive_timed_mutex"])
71+
}
72+
73+
/**
74+
* Holds if this `CPPMutexFunctionCall` is a lock.
75+
*/
76+
override predicate isLock() {
77+
not isLockingOperationWithinLockingOperation(this) and
78+
getTarget().getName() = "lock"
79+
}
80+
81+
/**
82+
* Holds if this `CPPMutexFunctionCall` is a speculative lock, defined as calling
83+
* one of the speculative locking functions such as `try_lock`.
84+
*/
85+
override predicate isSpeculativeLock() {
86+
getTarget().getName() in [
87+
"try_lock", "try_lock_for", "try_lock_until", "try_lock_shared_for", "try_lock_shared_until"
88+
]
89+
}
90+
91+
/**
92+
* Returns the lock to which this `CPPMutexFunctionCall` refers to.
93+
*/
94+
override Variable getLock() { result = getQualifier().(VariableAccess).getTarget() }
95+
96+
/**
97+
* Returns the qualifier for this `CPPMutexFunctionCall`.
98+
*/
99+
override Expr getLockExpr() { result = var }
100+
101+
/**
102+
* Holds if this is a `unlock` and *may* unlock the previously locked `MutexFunctionCall`.
103+
* This predicate does not check that the mutex is currently locked.
104+
*/
105+
override predicate unlocks(MutexFunctionCall fc) {
106+
isUnlock() and
107+
fc.getQualifier().(VariableAccess).getTarget() = getQualifier().(VariableAccess).getTarget()
108+
}
109+
110+
/**
111+
* Holds if this is an unlock call.
112+
*/
113+
override predicate isUnlock() { getTarget().getName() = "unlock" }
114+
}
115+
116+
/**
117+
* Models calls to various mutex types specialized to C code.
118+
*/
119+
class CMutexFunctionCall extends MutexFunctionCall {
120+
Expr arg;
121+
122+
CMutexFunctionCall() {
123+
// the non recursive kinds
124+
getTarget().getName() = ["mtx_lock", "mtx_unlock", "mtx_timedlock", "mtx_trylock"] and
125+
arg = getArgument(0)
126+
}
127+
128+
/**
129+
* Holds if this mutex is a recursive mutex.
130+
*/
131+
override predicate isRecursive() { none() }
132+
133+
/**
134+
* Holds if this `CMutexFunctionCall` is a lock.
135+
*/
136+
override predicate isLock() {
137+
not isLockingOperationWithinLockingOperation(this) and
138+
getTarget().getName() = ["mtx_lock", "mtx_timedlock", "mtx_trylock"]
139+
}
140+
141+
/**
142+
* Holds if this `CMutexFunctionCall` is a speculative lock, defined as calling
143+
* one of the speculative locking functions such as `try_lock`.
144+
*/
145+
override predicate isSpeculativeLock() {
146+
getTarget().getName() in ["mtx_timedlock", "mtx_trylock"]
147+
}
148+
149+
/**
150+
* Returns the `Variable` to which this `CMutexFunctionCall` refers to. For this
151+
* style of lock it can reference a number of different variables.
152+
*/
153+
override Variable getLock() {
154+
exists(VariableAccess va |
155+
TaintTracking::localTaint(DataFlow::exprNode(va), DataFlow::exprNode(getLockExpr())) and
156+
result = va.getTarget()
157+
)
158+
}
159+
160+
/**
161+
* Returns the expression for this `CMutexFunctionCall`.
162+
*/
163+
override Expr getLockExpr() { result = arg }
164+
165+
/**
166+
* Holds if this is a `unlock` and *may* unlock the previously locked `CMutexFunctionCall`.
167+
* This predicate does not check that the mutex is currently locked.
168+
*/
169+
override predicate unlocks(MutexFunctionCall fc) {
170+
isUnlock() and
171+
fc.getLock() = getLock()
172+
}
173+
174+
/**
175+
* Holds if this is an unlock call.
176+
*/
177+
override predicate isUnlock() { getTarget().getName() = "mtx_unlock" }
178+
}
179+
180+
/**
181+
* Models a RAII-Style lock.
182+
*/
183+
class RAIIStyleLock extends LockingOperation {
184+
VariableAccess lock;
185+
186+
RAIIStyleLock() {
187+
(
188+
getTarget().getDeclaringType().hasQualifiedName("std", "lock_guard") or
189+
getTarget().getDeclaringType().hasQualifiedName("std", "unique_lock") or
190+
getTarget().getDeclaringType().hasQualifiedName("std", "scoped_lock")
191+
) and
192+
(
193+
lock = getArgument(0).getAChild*()
194+
or
195+
this instanceof DestructorCall and
196+
exists(RAIIStyleLock constructor |
197+
constructor = getQualifier().(VariableAccess).getTarget().getInitializer().getExpr() and
198+
lock = constructor.getArgument(0).getAChild*()
199+
)
200+
)
201+
}
202+
203+
/**
204+
* Holds if this is a lock operation
205+
*/
206+
override predicate isLock() {
207+
not isLockingOperationWithinLockingOperation(this) and
208+
this instanceof ConstructorCall and
209+
lock = getArgument(0).getAChild*() and
210+
// defer_locks don't cause a lock
211+
not exists(Expr exp |
212+
exp = getArgument(1) and
213+
exp.(VariableAccess)
214+
.getTarget()
215+
.getUnderlyingType()
216+
.(Class)
217+
.hasQualifiedName("std", "defer_lock_t")
218+
)
219+
}
220+
221+
/**
222+
* Holds if this is an unlock operation
223+
*/
224+
override predicate isUnlock() { this instanceof DestructorCall }
225+
226+
/**
227+
* Returns the target of the lock underlying this RAII-style lock.
228+
*/
229+
override Variable getLock() { result = lock.getTarget() }
230+
231+
/**
232+
* Returns the lock underlying this RAII-style lock.
233+
*/
234+
override Expr getLockExpr() { result = lock }
235+
}

0 commit comments

Comments
 (0)