Skip to content

Commit 22e1715

Browse files
authored
Merge pull request #1900 from jbj/dataflow-this-by-ref
C++: Fix flow out of `this` by reference
2 parents 26490bd + 10b6935 commit 22e1715

File tree

3 files changed

+99
-1
lines changed

3 files changed

+99
-1
lines changed

cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowUtil.qll

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ private newtype TNode =
1919
TInstanceParameterNode(MemberFunction f) { exists(f.getBlock()) and not f.isStatic() } or
2020
TPreConstructorInitThis(ConstructorFieldInit cfi) or
2121
TPostConstructorInitThis(ConstructorFieldInit cfi) or
22+
TThisArgumentPostUpdate(ThisExpr ta) {
23+
exists(Call c, int i |
24+
ta = c.getArgument(i) and
25+
not c.getTarget().getParameter(i).getUnderlyingType().(PointerType).getBaseType().isConst()
26+
)
27+
} or
2228
TUninitializedNode(LocalVariable v) { not v.hasInitializer() }
2329

2430
/**
@@ -268,7 +274,7 @@ abstract class PostUpdateNode extends Node {
268274
override Location getLocation() { result = getPreUpdateNode().getLocation() }
269275
}
270276

271-
class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode {
277+
private class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode {
272278
PartialDefinition pd;
273279

274280
PartialDefinitionNode() { this = TPartialDefinitionNode(pd) }
@@ -282,6 +288,16 @@ class PartialDefinitionNode extends PostUpdateNode, TPartialDefinitionNode {
282288
override string toString() { result = getPreUpdateNode().toString() + " [post update]" }
283289
}
284290

291+
private class ThisArgumentPostUpdateNode extends PostUpdateNode, TThisArgumentPostUpdate {
292+
ThisExpr thisExpr;
293+
294+
ThisArgumentPostUpdateNode() { this = TThisArgumentPostUpdate(thisExpr) }
295+
296+
override Node getPreUpdateNode() { result.asExpr() = thisExpr }
297+
298+
override string toString() { result = "ref arg this" }
299+
}
300+
285301
/**
286302
* A node representing the temporary value of an object that was just
287303
* constructed by a constructor call or an aggregate initializer. This is only
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
void sink(void *o);
2+
void *user_input(void);
3+
4+
struct S {
5+
void *a;
6+
7+
/*
8+
* Setters
9+
*/
10+
11+
friend void nonMemberSetA(struct S *s, void *value) {
12+
s->a = value;
13+
}
14+
15+
void setDirectly(void *value) {
16+
this->a = value;
17+
}
18+
19+
void setIndirectly(void *value) {
20+
this->setDirectly(value);
21+
}
22+
23+
void setThroughNonMember(void *value) {
24+
nonMemberSetA(this, value);
25+
}
26+
27+
/*
28+
* Getters
29+
*/
30+
31+
friend void *nonMemberGetA(const struct S *s) {
32+
return s->a;
33+
}
34+
35+
void* getDirectly() const {
36+
return this->a;
37+
}
38+
39+
void* getIndirectly() const {
40+
return this->getDirectly();
41+
}
42+
43+
void *getThroughNonMember() const {
44+
return nonMemberGetA(this);
45+
}
46+
};
47+
48+
void test_setDirectly() {
49+
S s;
50+
s.setDirectly(user_input());
51+
sink(s.getDirectly()); // flow
52+
}
53+
54+
void test_setIndirectly() {
55+
S s;
56+
s.setIndirectly(user_input());
57+
sink(s.getIndirectly()); // flow
58+
}
59+
60+
void test_setThroughNonMember() {
61+
S s;
62+
s.setThroughNonMember(user_input());
63+
sink(s.getThroughNonMember()); // flow
64+
}
65+
66+
void test_nonMemberSetA() {
67+
S s;
68+
nonMemberSetA(&s, user_input());
69+
sink(nonMemberGetA(&s)); // flow [NOT DETECTED due to lack of flow through &]
70+
}

cpp/ql/test/library-tests/dataflow/fields/flow.expected

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,15 @@ edges
142142
| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:92:3:92:23 | ... = ... |
143143
| aliasing.cpp:93:8:93:8 | w [s, m1] | aliasing.cpp:93:10:93:10 | s [m1] |
144144
| aliasing.cpp:93:10:93:10 | s [m1] | aliasing.cpp:93:12:93:13 | m1 |
145+
| by_reference.cpp:50:3:50:3 | s [post update] [a] | by_reference.cpp:51:8:51:8 | s [a] |
146+
| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | s [post update] [a] |
147+
| by_reference.cpp:51:8:51:8 | s [a] | by_reference.cpp:51:10:51:20 | call to getDirectly |
148+
| by_reference.cpp:56:3:56:3 | s [post update] [a] | by_reference.cpp:57:8:57:8 | s [a] |
149+
| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:56:3:56:3 | s [post update] [a] |
150+
| by_reference.cpp:57:8:57:8 | s [a] | by_reference.cpp:57:10:57:22 | call to getIndirectly |
151+
| by_reference.cpp:62:3:62:3 | s [post update] [a] | by_reference.cpp:63:8:63:8 | s [a] |
152+
| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:3:62:3 | s [post update] [a] |
153+
| by_reference.cpp:63:8:63:8 | s [a] | by_reference.cpp:63:10:63:28 | call to getThroughNonMember |
145154
| complex.cpp:34:15:34:15 | b [f, a_] | complex.cpp:44:8:44:8 | b [f, a_] |
146155
| complex.cpp:34:15:34:15 | b [f, b_] | complex.cpp:45:8:45:8 | b [f, b_] |
147156
| complex.cpp:44:8:44:8 | b [f, a_] | complex.cpp:44:10:44:10 | f [a_] |
@@ -233,6 +242,9 @@ edges
233242
| aliasing.cpp:30:11:30:12 | m1 | aliasing.cpp:13:10:13:19 | call to user_input | aliasing.cpp:30:11:30:12 | m1 | m1 flows from $@ | aliasing.cpp:13:10:13:19 | call to user_input | call to user_input |
234243
| aliasing.cpp:62:14:62:15 | m1 | aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:62:14:62:15 | m1 | m1 flows from $@ | aliasing.cpp:60:11:60:20 | call to user_input | call to user_input |
235244
| aliasing.cpp:93:12:93:13 | m1 | aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:93:12:93:13 | m1 | m1 flows from $@ | aliasing.cpp:92:12:92:21 | call to user_input | call to user_input |
245+
| by_reference.cpp:51:10:51:20 | call to getDirectly | by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:51:10:51:20 | call to getDirectly | call to getDirectly flows from $@ | by_reference.cpp:50:17:50:26 | call to user_input | call to user_input |
246+
| by_reference.cpp:57:10:57:22 | call to getIndirectly | by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:57:10:57:22 | call to getIndirectly | call to getIndirectly flows from $@ | by_reference.cpp:56:19:56:28 | call to user_input | call to user_input |
247+
| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:63:10:63:28 | call to getThroughNonMember | call to getThroughNonMember flows from $@ | by_reference.cpp:62:25:62:34 | call to user_input | call to user_input |
236248
| complex.cpp:44:12:44:12 | call to a | complex.cpp:55:13:55:22 | call to user_input | complex.cpp:44:12:44:12 | call to a | call to a flows from $@ | complex.cpp:55:13:55:22 | call to user_input | call to user_input |
237249
| complex.cpp:44:12:44:12 | call to a | complex.cpp:57:13:57:22 | call to user_input | complex.cpp:44:12:44:12 | call to a | call to a flows from $@ | complex.cpp:57:13:57:22 | call to user_input | call to user_input |
238250
| complex.cpp:45:12:45:12 | call to b | complex.cpp:56:13:56:22 | call to user_input | complex.cpp:45:12:45:12 | call to b | call to b flows from $@ | complex.cpp:56:13:56:22 | call to user_input | call to user_input |

0 commit comments

Comments
 (0)