mirror of
https://github.com/github/codeql.git
synced 2025-12-24 12:46:34 +01:00
196 lines
5.5 KiB
Plaintext
196 lines
5.5 KiB
Plaintext
/**
|
|
* Utilities for analyzing synchronization primitives, such
|
|
* as mutexes and semaphores.
|
|
*/
|
|
|
|
import cpp
|
|
|
|
/**
|
|
* A type that acts as a mutex. This class is extended below and and may
|
|
* be extended in `Options.qll`.
|
|
*/
|
|
abstract class MutexType extends Type {
|
|
/**
|
|
* Holds if `fc` is a call that always locks mutex `arg`
|
|
* of this type.
|
|
*/
|
|
abstract predicate mustlockAccess(FunctionCall fc, Expr arg);
|
|
|
|
/**
|
|
* Holds if `fc` is a call that tries to lock mutex `arg`
|
|
* of this type, but may return without success.
|
|
*/
|
|
abstract predicate trylockAccess(FunctionCall fc, Expr arg);
|
|
|
|
/**
|
|
* Holds if `fc` is a call that unlocks mutex `arg` of this type.
|
|
*/
|
|
abstract predicate unlockAccess(FunctionCall fc, Expr arg);
|
|
|
|
/**
|
|
* Holds if `fc` is n call that locks or tries to lock mutex
|
|
* `arg` of this type.
|
|
*/
|
|
predicate lockAccess(FunctionCall fc, Expr arg) {
|
|
this.mustlockAccess(fc, arg) or
|
|
this.trylockAccess(fc, arg)
|
|
}
|
|
|
|
/**
|
|
* Gets a call that locks or tries to lock any mutex of this type.
|
|
*/
|
|
FunctionCall getLockAccess() {
|
|
result = this.getMustlockAccess() or
|
|
result = this.getTrylockAccess()
|
|
}
|
|
|
|
/**
|
|
* Gets a call that always locks any mutex of this type.
|
|
*/
|
|
FunctionCall getMustlockAccess() { this.mustlockAccess(result, _) }
|
|
|
|
/**
|
|
* Gets a call that tries to lock any mutex of this type,
|
|
* by may return without success.
|
|
*/
|
|
FunctionCall getTrylockAccess() { this.trylockAccess(result, _) }
|
|
|
|
/**
|
|
* Gets a call that unlocks any mutex of this type.
|
|
*/
|
|
FunctionCall getUnlockAccess() { this.unlockAccess(result, _) }
|
|
}
|
|
|
|
/**
|
|
* Gets a function that looks like a lock function.
|
|
*/
|
|
private Function mustlockCandidate() {
|
|
exists(string name | name = result.getName() |
|
|
name = "lock" or
|
|
name.matches("%mutex\\_lock")
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Gets a function that looks like a try-lock function.
|
|
*/
|
|
private Function trylockCandidate() {
|
|
exists(string name | name = result.getName() |
|
|
name = "try_lock" or
|
|
name.matches("%mutex\\_trylock")
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Gets a function that looks like an unlock function.
|
|
*/
|
|
private Function unlockCandidate() {
|
|
exists(string name | name = result.getName() |
|
|
name = "unlock" or
|
|
name.matches("%mutex\\_unlock")
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Gets a type that is a parameter to a function, or it's declaring type
|
|
* (i.e. it's `this`). If the function is a locking related function,
|
|
* these can be thought of as candidates for the mutex is it locking or
|
|
* unlocking. It is narrowed down in `DefaultMutexType` by requiring that
|
|
* it must be a class type with both a lock and an unlock function.
|
|
*/
|
|
private Class lockArgTypeCandidate(Function fcn) {
|
|
result = fcn.getDeclaringType() or
|
|
result = fcn.getAParameter().getType().stripType()
|
|
}
|
|
|
|
/**
|
|
* A class or struct type that has both a lock and an unlock function
|
|
* candidate, and is therefore a mutex.
|
|
*
|
|
* This excludes types like `std::weak_ptr` which has a lock
|
|
* method, but not an unlock method, and is not a mutex.)
|
|
*/
|
|
class DefaultMutexType extends MutexType {
|
|
DefaultMutexType() {
|
|
this = lockArgTypeCandidate(mustlockCandidate()) and
|
|
this = lockArgTypeCandidate(unlockCandidate())
|
|
}
|
|
|
|
private predicate lockArgType(FunctionCall fc, Expr arg) {
|
|
exists(int n |
|
|
arg = fc.getArgument(n) and
|
|
fc.getTarget().getParameter(n).getType().stripType() = this
|
|
)
|
|
or
|
|
fc.getTarget().getDeclaringType() = this and
|
|
arg = fc.getQualifier()
|
|
or
|
|
// if we're calling our own method with an implicit `this`,
|
|
// let `arg` be the function call, since we don't really have
|
|
// anything else to use.
|
|
fc.getTarget().getDeclaringType() = this and
|
|
not exists(fc.getQualifier()) and
|
|
arg = fc
|
|
}
|
|
|
|
override predicate mustlockAccess(FunctionCall fc, Expr arg) {
|
|
fc.getTarget() = mustlockCandidate() and
|
|
this.lockArgType(fc, arg)
|
|
}
|
|
|
|
override predicate trylockAccess(FunctionCall fc, Expr arg) {
|
|
fc.getTarget() = trylockCandidate() and
|
|
this.lockArgType(fc, arg)
|
|
}
|
|
|
|
override predicate unlockAccess(FunctionCall fc, Expr arg) {
|
|
fc.getTarget() = unlockCandidate() and
|
|
this.lockArgType(fc, arg)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Holds if `arg` is the mutex argument of a call to lock or unlock and
|
|
* `argType` is the type of the mutex.
|
|
*/
|
|
private predicate lockArg(Expr arg, MutexType argType, FunctionCall call) {
|
|
argType = arg.getUnderlyingType().stripType() and
|
|
(
|
|
arg = call.getQualifier() or
|
|
arg = call.getAnArgument()
|
|
)
|
|
// note: this seems to arbitrarily care about argument types, rather
|
|
// than parameter types as elsewhere. As a result `mustlockCall`,
|
|
// for example, has slightly different results from
|
|
// `MutexType.mustlockAccess`.
|
|
}
|
|
|
|
/**
|
|
* Holds if `call` is a call that locks or tries to lock its argument `arg`.
|
|
*/
|
|
predicate lockCall(Expr arg, FunctionCall call) {
|
|
exists(MutexType t | lockArg(arg, t, call) and call = t.getLockAccess())
|
|
}
|
|
|
|
/**
|
|
* Holds if `call` is a call that always locks its argument `arg`.
|
|
*/
|
|
predicate mustlockCall(Expr arg, FunctionCall call) {
|
|
exists(MutexType t | lockArg(arg, t, call) and call = t.getMustlockAccess())
|
|
}
|
|
|
|
/**
|
|
* Holds if `call` is a call that tries to lock its argument `arg`, but may
|
|
* return without success.
|
|
*/
|
|
predicate trylockCall(Expr arg, FunctionCall call) {
|
|
exists(MutexType t | lockArg(arg, t, call) and call = t.getTrylockAccess())
|
|
}
|
|
|
|
/**
|
|
* Holds if `call` is a call that unlocks its argument `arg`.
|
|
*/
|
|
predicate unlockCall(Expr arg, FunctionCall call) {
|
|
exists(MutexType t | lockArg(arg, t, call) and call = t.getUnlockAccess())
|
|
}
|