Skip to content

Commit 2e34637

Browse files
authored
Merge pull request github#3382 from jbj/escape-qualifier
C++: Addresses may escape through call qualifiers
2 parents 37f30d3 + 9b9f524 commit 2e34637

File tree

3 files changed

+41
-14
lines changed

3 files changed

+41
-14
lines changed

cpp/ql/src/semmle/code/cpp/dataflow/EscapesTree.qll

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,13 @@ private predicate referenceFromVariableAccess(VariableAccess va, Expr reference)
166166
)
167167
}
168168

169-
private predicate valueMayEscapeAt(Expr e) {
169+
private predicate addressMayEscapeAt(Expr e) {
170170
exists(Call call |
171171
e = call.getAnArgument().getFullyConverted() and
172172
not stdIdentityFunction(call.getTarget())
173+
or
174+
e = call.getQualifier().getFullyConverted() and
175+
e.getUnderlyingType() instanceof PointerType
173176
)
174177
or
175178
exists(AssignExpr assign | e = assign.getRValue().getFullyConverted())
@@ -187,8 +190,8 @@ private predicate valueMayEscapeAt(Expr e) {
187190
exists(AsmStmt asm | e = asm.getAChild().(Expr).getFullyConverted())
188191
}
189192

190-
private predicate valueMayEscapeMutablyAt(Expr e) {
191-
valueMayEscapeAt(e) and
193+
private predicate addressMayEscapeMutablyAt(Expr e) {
194+
addressMayEscapeAt(e) and
192195
exists(Type t | t = e.getType().getUnderlyingType() |
193196
exists(PointerType pt |
194197
pt = t
@@ -207,6 +210,22 @@ private predicate valueMayEscapeMutablyAt(Expr e) {
207210
)
208211
}
209212

213+
private predicate lvalueMayEscapeAt(Expr e) {
214+
// A call qualifier, like `q` in `q.f()`, is special in that the address of
215+
// `q` escapes even though `q` is not a pointer or a reference.
216+
exists(Call call |
217+
e = call.getQualifier().getFullyConverted() and
218+
e.getType().getUnspecifiedType() instanceof Class
219+
)
220+
}
221+
222+
private predicate lvalueMayEscapeMutablyAt(Expr e) {
223+
lvalueMayEscapeAt(e) and
224+
// A qualifier of a call to a const member function is converted to a const
225+
// class type.
226+
not e.getType().isConst()
227+
}
228+
210229
private predicate addressFromVariableAccess(VariableAccess va, Expr e) {
211230
pointerFromVariableAccess(va, e)
212231
or
@@ -253,8 +272,11 @@ private module EscapesTree_Cached {
253272
*/
254273
cached
255274
predicate variableAddressEscapesTree(VariableAccess va, Expr e) {
256-
valueMayEscapeAt(e) and
275+
addressMayEscapeAt(e) and
257276
addressFromVariableAccess(va, e)
277+
or
278+
lvalueMayEscapeAt(e) and
279+
lvalueFromVariableAccess(va, e)
258280
}
259281

260282
/**
@@ -283,8 +305,11 @@ private module EscapesTree_Cached {
283305
*/
284306
cached
285307
predicate variableAddressEscapesTreeNonConst(VariableAccess va, Expr e) {
286-
valueMayEscapeMutablyAt(e) and
308+
addressMayEscapeMutablyAt(e) and
287309
addressFromVariableAccess(va, e)
310+
or
311+
lvalueMayEscapeMutablyAt(e) and
312+
lvalueFromVariableAccess(va, e)
288313
}
289314

290315
/**

cpp/ql/src/semmle/code/cpp/exprs/Call.qll

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@ private import semmle.code.cpp.dataflow.EscapesTree
99
*/
1010
abstract class Call extends Expr, NameQualifiableElement {
1111
/**
12-
* Gets the number of actual parameters in this call; use
13-
* `getArgument(i)` with `i` between `0` and `result - 1` to
14-
* retrieve actuals.
12+
* Gets the number of arguments (actual parameters) of this call. The count
13+
* does _not_ include the qualifier of the call, if any.
1514
*/
1615
int getNumberOfArguments() { result = count(this.getAnArgument()) }
1716

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

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

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

4647
/**
47-
* Gets a sub expression of the argument at position `index`. If the
48+
* Gets a subexpression of the argument at position `index`. If the
4849
* argument itself contains calls, such calls will be considered
49-
* leafs in the expression tree.
50+
* leaves in the expression tree. The qualifier of the call, if any, is not
51+
* considered to be an argument.
5052
*
5153
* Example: the call `f(2, 3 + 4, g(4 + 5))` has sub expression(s)
5254
* `2` at index 0; `3`, `4`, and `3 + 4` at index 1; and `g(4 + 5)`

cpp/ql/test/library-tests/defuse/isAddressOfAccess.expected

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
| addressOf.cpp:38:20:38:20 | i | non-const address |
1212
| addressOf.cpp:40:15:40:15 | i | non-const address |
1313
| addressOf.cpp:42:19:42:22 | iref | non-const address |
14-
| addressOf.cpp:48:3:48:4 | f1 | |
14+
| addressOf.cpp:48:3:48:4 | f1 | const address |
1515
| addressOf.cpp:49:15:49:22 | captured | non-const address |
16-
| addressOf.cpp:50:3:50:4 | f2 | |
16+
| addressOf.cpp:50:3:50:4 | f2 | const address |
1717
| addressOf.cpp:51:10:51:17 | captured | |
1818
| addressOf.cpp:56:16:56:16 | i | |
1919
| addressOf.cpp:56:19:56:19 | i | |

0 commit comments

Comments
 (0)