Skip to content

Commit 5decd4c

Browse files
committed
new queries
1 parent c69756f commit 5decd4c

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* This query finds potential misuse of mutexes passed to threads by considering
3+
* cases where the underlying mutex is a local variable; such a variable would
4+
* go out of scope at the end of the calling function and thus would potentially
5+
* create issues for the thread depending on the mutex. This query is primarily
6+
* targeted at C usages since in the case of CPP, many more cases can be covered
7+
* via tracking of destructors. The main difference is that this query doesn't
8+
* expect an explicitly deleted call to be made.
9+
*
10+
* In order to safely destroy a dependent mutex, it is necessary both to not delete
11+
* it, but also if deletes do happen, one must wait for a thread to exit prior to
12+
* deleting it. We broadly model this by using standard language support for thread
13+
* synchronization.
14+
*/
15+
16+
import cpp
17+
import codingstandards.cpp.Customizations
18+
import codingstandards.cpp.Exclusions
19+
import codingstandards.cpp.Concurrency
20+
import semmle.code.cpp.dataflow.TaintTracking
21+
22+
abstract class DoNotAllowAMutexToGoOutOfScopeWhileLockedSharedQuery extends Query { }
23+
24+
Query getQuery() { result instanceof DoNotAllowAMutexToGoOutOfScopeWhileLockedSharedQuery }
25+
26+
query predicate problems(ThreadDependentMutex dm, string message) {
27+
not isExcluded(dm.asExpr(), getQuery()) and
28+
exists(LocalVariable lv |
29+
not isExcluded(lv, getQuery()) and
30+
not lv.isStatic() and
31+
TaintTracking::localTaint(dm.getAUsage(), DataFlow::exprNode(lv.getAnAssignedValue())) and
32+
// ensure that each dependent thread is followed by some sort of joining
33+
// behavior.
34+
exists(DataFlow::Node n | n = dm.getADependentThreadCreationExpr() |
35+
forall(ThreadWait tw | not tw = n.asExpr().getASuccessor*())
36+
) and
37+
message = "Mutex used by thread potentially destroyed while in use."
38+
)
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* This query finds potential misuse of mutexes passed to threads by considering
3+
* cases where the underlying mutex may be destroyed. The scope of this query is
4+
* that it performs this analysis both locally within the function but can also
5+
* look through to the called thread to identify mutexes it may not own.
6+
* query is that it considers this behavior locally within the procedure.
7+
*
8+
* In order to safely destroy a dependent mutex, it is necessary both to not delete
9+
* it, but also if deletes do happen, one must wait for a thread to exit prior to
10+
* deleting it. We broadly model this by using standard language support for thread
11+
* synchronization.
12+
*/
13+
14+
import cpp
15+
import codingstandards.cpp.Customizations
16+
import codingstandards.cpp.Exclusions
17+
import codingstandards.cpp.Concurrency
18+
import semmle.code.cpp.dataflow.TaintTracking
19+
20+
abstract class DoNotDestroyAMutexWhileItIsLockedSharedQuery extends Query { }
21+
22+
Query getQuery() { result instanceof DoNotDestroyAMutexWhileItIsLockedSharedQuery }
23+
24+
query predicate problems(
25+
ThreadDependentMutex dm, string message, MutexDestroyer md, string mdMessage
26+
) {
27+
not isExcluded(dm.asExpr(), getQuery()) and
28+
not isExcluded(md, getQuery()) and
29+
// find all instances where a usage of a dependent mutex flows into a
30+
// expression that will destroy it.
31+
TaintTracking::localTaint(dm.getAUsage(), DataFlow::exprNode(md.getMutexExpr())) and
32+
(
33+
// firstly, we assume it is never safe to destroy a global mutex, but it is
34+
// difficult to make assumptions about the intended control flow. Note that
35+
// this means the point at where the mutex is defined -- not where the variable
36+
// that contains it is scoped -- a `ThreadDependentMutex` is bound to the
37+
// function that creates an initialized mutex. For example, in `C`
38+
// `mtx_init` is called to initialize the mutex and in C++, the constructor
39+
// of std::mutex is called.
40+
not exists(dm.asExpr().getEnclosingFunction())
41+
or
42+
// secondly, we assume it is never safe to destroy a mutex created by
43+
// another function scope -- which includes trying to destroy a mutex that
44+
// was passed into a function.
45+
not md.getMutexExpr().getEnclosingFunction() = dm.asExpr().getEnclosingFunction()
46+
or
47+
// this leaves only destructions of mutexes locally near the thread that may
48+
// consume them. We allow this only if there has been some effort to
49+
// synchronize the threads prior to destroying the mutex.
50+
not exists(ThreadWait tw | tw = md.getAPredecessor*())
51+
) and
52+
message = "Mutex used by thread potentially $@ while in use." and
53+
mdMessage = "destroyed"
54+
}

0 commit comments

Comments
 (0)