Skip to content

Commit c1b91db

Browse files
committed
C++: Add more virtual dispatch tests.
1 parent f9f99a0 commit c1b91db

File tree

3 files changed

+149
-0
lines changed

3 files changed

+149
-0
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
struct Base {
2+
void f();
3+
virtual void virtual_f();
4+
};
5+
6+
struct Derived : Base {
7+
void f();
8+
void virtual_f();
9+
};
10+
11+
void test_simple() {
12+
Base b;
13+
b.f(); // $ target=2
14+
b.virtual_f(); // $ target=3
15+
16+
Derived d;
17+
d.f(); // $ target=7
18+
d.virtual_f(); // $ target=8
19+
20+
Base* b_ptr = &d;
21+
b_ptr->f(); // $ target=2
22+
b_ptr->virtual_f(); // $ target=8 SPURIOUS: target=3
23+
24+
Base& b_ref = d;
25+
b_ref.f(); // $ target=2
26+
b_ref.virtual_f(); // $ target=8 SPURIOUS: target=3
27+
28+
Base* b_null = nullptr;
29+
b_null->f(); // $ target=2
30+
b_null->virtual_f(); // $ target=3
31+
32+
Base* base_is_derived = new Derived();
33+
base_is_derived->f(); // $ target=2
34+
base_is_derived->virtual_f(); // $ target=8 SPURIOUS: target=3
35+
36+
Base* base_is_base = new Base();
37+
base_is_base->f(); // $ target=2
38+
base_is_base->virtual_f(); // $ target=3
39+
40+
Derived* derived_is_derived = new Derived();
41+
derived_is_derived->f(); // $ target=7
42+
derived_is_derived->virtual_f(); // $ target=8
43+
44+
Base& b_ref2 = b;
45+
b_ref2 = d;
46+
b_ref2.f(); // $ target=2
47+
b_ref2.virtual_f(); // $ target=3
48+
}
49+
50+
struct S {
51+
Base* b1;
52+
Base* b2;
53+
};
54+
55+
void test_fields() {
56+
S s;
57+
58+
s.b1 = new Base();
59+
s.b2 = new Derived();
60+
61+
s.b1->virtual_f(); // $ target=3
62+
s.b2->virtual_f(); // $ SPURIOUS: target=3 MISSING: target=8
63+
64+
s.b1 = new Derived();
65+
s.b2 = new Base();
66+
s.b1->virtual_f(); // $ MISSING: target=8 SPURIOUS: target=3 // type-tracking has no 'clearsContent' feature and C/C++ doesn't have field-based SSA
67+
s.b2->virtual_f(); // $ target=3 // type-tracking has no 'clearsContent' feature and C/C++ doesn't have field-based SSA
68+
}
69+
70+
Base* getDerived() {
71+
return new Derived();
72+
}
73+
74+
void test_getDerived() {
75+
Base* b = getDerived();
76+
b->virtual_f(); // $ target=8 SPURIOUS: target=3
77+
78+
Derived d = *(Derived*)getDerived();
79+
d.virtual_f(); // $ target=8
80+
}
81+
82+
void write_to_arg(Base* b) {
83+
*b = Derived();
84+
}
85+
86+
void write_to_arg_2(Base** b) {
87+
Derived* d = new Derived();
88+
*b = d;
89+
}
90+
91+
void test_write_to_arg() {
92+
{
93+
Base b;
94+
write_to_arg(&b);
95+
b.virtual_f(); // $ SPURIOUS: target=3 MISSING: target=8 // missing flow through the copy-constructor in write_to_arg
96+
}
97+
98+
{
99+
Base* b;
100+
write_to_arg_2(&b);
101+
b->virtual_f(); // $ target=8 SPURIOUS: target=3
102+
}
103+
}
104+
105+
Base* global_derived;
106+
107+
void set_global_to_derived() {
108+
global_derived = new Derived();
109+
}
110+
111+
void read_global() {
112+
global_derived->virtual_f(); // $ target=8 SPURIOUS: target=3
113+
}
114+
115+
Base* global_base_or_derived;
116+
117+
void set_global_base_or_derived_1() {
118+
global_base_or_derived = new Base();
119+
}
120+
121+
void set_global_base_or_derived_2() {
122+
global_base_or_derived = new Derived();
123+
}
124+
125+
void read_global_base_or_derived() {
126+
global_base_or_derived->virtual_f(); // $ target=3 target=8
127+
}

cpp/ql/test/library-tests/dataflow/dispatch/test.expected

Whitespace-only changes.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import cpp
2+
import utils.test.InlineExpectationsTest
3+
import semmle.code.cpp.ir.dataflow.internal.DataFlowDispatch
4+
import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
5+
6+
module ResolveDispatchTest implements TestSig {
7+
string getARelevantTag() { result = "target" }
8+
9+
predicate hasActualResult(Location location, string element, string tag, string value) {
10+
exists(DataFlowCall call, SourceCallable callable, MemberFunction mf |
11+
mf = callable.asSourceCallable() and
12+
not mf.isCompilerGenerated() and
13+
callable = viableCallable(call) and
14+
location = call.getLocation() and
15+
element = call.toString() and
16+
tag = "target" and
17+
value = callable.getLocation().getStartLine().toString()
18+
)
19+
}
20+
}
21+
22+
import MakeTest<ResolveDispatchTest>

0 commit comments

Comments
 (0)