Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 30 additions & 5 deletions cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,13 @@ private predicate referenceFromVariableAccess(VariableAccess va, Expr reference)
)
}

private predicate valueMayEscapeAt(Expr e) {
private predicate addressMayEscapeAt(Expr e) {
exists(Call call |
e = call.getAnArgument().getFullyConverted() and
not stdIdentityFunction(call.getTarget())
or
e = call.getQualifier().getFullyConverted() and
e.getUnderlyingType() instanceof PointerType
)
or
exists(AssignExpr assign | e = assign.getRValue().getFullyConverted())
Expand All @@ -187,8 +190,8 @@ private predicate valueMayEscapeAt(Expr e) {
exists(AsmStmt asm | e = asm.getAChild().(Expr).getFullyConverted())
}

private predicate valueMayEscapeMutablyAt(Expr e) {
valueMayEscapeAt(e) and
private predicate addressMayEscapeMutablyAt(Expr e) {
addressMayEscapeAt(e) and
exists(Type t | t = e.getType().getUnderlyingType() |
exists(PointerType pt |
pt = t
Expand All @@ -207,6 +210,22 @@ private predicate valueMayEscapeMutablyAt(Expr e) {
)
}

private predicate lvalueMayEscapeAt(Expr e) {
// A call qualifier, like `q` in `q.f()`, is special in that the address of
// `q` escapes even though `q` is not a pointer or a reference.
exists(Call call |
e = call.getQualifier().getFullyConverted() and
e.getType().getUnspecifiedType() instanceof Class
)
}

private predicate lvalueMayEscapeMutablyAt(Expr e) {
lvalueMayEscapeAt(e) and
// A qualifier of a call to a const member function is converted to a const
// class type.
not e.getType().isConst()
}

private predicate addressFromVariableAccess(VariableAccess va, Expr e) {
pointerFromVariableAccess(va, e)
or
Expand Down Expand Up @@ -253,8 +272,11 @@ private module EscapesTree_Cached {
*/
cached
predicate variableAddressEscapesTree(VariableAccess va, Expr e) {
valueMayEscapeAt(e) and
addressMayEscapeAt(e) and
addressFromVariableAccess(va, e)
or
lvalueMayEscapeAt(e) and
lvalueFromVariableAccess(va, e)
}

/**
Expand Down Expand Up @@ -283,8 +305,11 @@ private module EscapesTree_Cached {
*/
cached
predicate variableAddressEscapesTreeNonConst(VariableAccess va, Expr e) {
valueMayEscapeMutablyAt(e) and
addressMayEscapeMutablyAt(e) and
addressFromVariableAccess(va, e)
or
lvalueMayEscapeMutablyAt(e) and
lvalueFromVariableAccess(va, e)
}

/**
Expand Down
16 changes: 9 additions & 7 deletions cpp/ql/src/semmle/code/cpp/exprs/Call.qll
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ private import semmle.code.cpp.dataflow.EscapesTree
*/
abstract class Call extends Expr, NameQualifiableElement {
/**
* Gets the number of actual parameters in this call; use
* `getArgument(i)` with `i` between `0` and `result - 1` to
* retrieve actuals.
* Gets the number of arguments (actual parameters) of this call. The count
* does _not_ include the qualifier of the call, if any.
*/
int getNumberOfArguments() { result = count(this.getAnArgument()) }

Expand All @@ -32,21 +31,24 @@ abstract class Call extends Expr, NameQualifiableElement {
Expr getQualifier() { result = this.getChild(-1) }

/**
* Gets an argument for this call.
* Gets an argument for this call. To get the qualifier of this call, if
* any, use `getQualifier()`.
*/
Expr getAnArgument() { exists(int i | result = this.getChild(i) and i >= 0) }

/**
* Gets the nth argument for this call.
*
* The range of `n` is from `0` to `getNumberOfArguments() - 1`.
* The range of `n` is from `0` to `getNumberOfArguments() - 1`. To get the
* qualifier of this call, if any, use `getQualifier()`.
*/
Expr getArgument(int n) { result = this.getChild(n) and n >= 0 }

/**
* Gets a sub expression of the argument at position `index`. If the
* Gets a subexpression of the argument at position `index`. If the
* argument itself contains calls, such calls will be considered
* leafs in the expression tree.
* leaves in the expression tree. The qualifier of the call, if any, is not
* considered to be an argument.
*
* Example: the call `f(2, 3 + 4, g(4 + 5))` has sub expression(s)
* `2` at index 0; `3`, `4`, and `3 + 4` at index 1; and `g(4 + 5)`
Expand Down
4 changes: 2 additions & 2 deletions cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
| addressOf.cpp:38:20:38:20 | i | non-const address |
| addressOf.cpp:40:15:40:15 | i | non-const address |
| addressOf.cpp:42:19:42:22 | iref | non-const address |
| addressOf.cpp:48:3:48:4 | f1 | |
| addressOf.cpp:48:3:48:4 | f1 | const address |
| addressOf.cpp:49:15:49:22 | captured | non-const address |
| addressOf.cpp:50:3:50:4 | f2 | |
| addressOf.cpp:50:3:50:4 | f2 | const address |
| addressOf.cpp:51:10:51:17 | captured | |
| addressOf.cpp:56:16:56:16 | i | |
| addressOf.cpp:56:19:56:19 | i | |
Expand Down