Skip to content

Commit fd79e79

Browse files
committed
C++: Add tests demonstrating differences between AST virtual dispatch analysis and IR virtual dispatch analysis
1 parent 8c00671 commit fd79e79

3 files changed

Lines changed: 174 additions & 0 deletions

File tree

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
void sink(const char *);
2+
void sink(int);
3+
4+
struct S {
5+
void(*f)(const char*);
6+
7+
void apply(char* p) {
8+
f(p);
9+
}
10+
11+
void (*get())(const char*) {
12+
return f;
13+
}
14+
};
15+
16+
void calls_sink_with_argv(const char* a) {
17+
sink(a);
18+
}
19+
20+
extern int i;
21+
22+
class BaseWithPureVirtual {
23+
public:
24+
virtual void f(const char*) = 0;
25+
};
26+
27+
class DerivedCallsSink : public BaseWithPureVirtual {
28+
public:
29+
void f(const char* p) override {
30+
sink(p);
31+
}
32+
};
33+
34+
class DerivedDoesNotCallSink : public BaseWithPureVirtual {
35+
public:
36+
void f(const char* p) override {}
37+
};
38+
39+
class DerivedCallsSinkDiamond1 : virtual public BaseWithPureVirtual {
40+
public:
41+
void f(const char* p) override {
42+
sink(p);
43+
}
44+
};
45+
46+
class DerivedDoesNotCallSinkDiamond2 : virtual public BaseWithPureVirtual {
47+
public:
48+
void f(const char* p) override {}
49+
};
50+
51+
class DerivesMultiple : public DerivedCallsSinkDiamond1, public DerivedDoesNotCallSinkDiamond2 {
52+
void f(const char* p) override {
53+
DerivedCallsSinkDiamond1::f(p);
54+
}
55+
};
56+
57+
template<typename T>
58+
class CRTP {
59+
public:
60+
void f(const char* p) {
61+
static_cast<T*>(this)->g(p);
62+
}
63+
};
64+
65+
class CRTPCallsSink : public CRTP<CRTPCallsSink> {
66+
public:
67+
void g(const char* p) {
68+
sink(p);
69+
}
70+
};
71+
72+
class Derived1 : public BaseWithPureVirtual {};
73+
74+
class Derived2 : public Derived1 {
75+
public:
76+
void f(const char* p) override {}
77+
};
78+
79+
class Derived3 : public Derived2 {
80+
public:
81+
void f(const char* p) override {
82+
sink(p);
83+
}
84+
};
85+
86+
class CRTPDoesNotCallSink : public CRTP<CRTPDoesNotCallSink> {
87+
public:
88+
void g(const char* p) {}
89+
};
90+
91+
int main(int argc, char *argv[]) {
92+
sink(argv[0]);
93+
94+
sink(reinterpret_cast<int>(argv));
95+
96+
calls_sink_with_argv(argv[1]);
97+
98+
char*** p = &argv;
99+
100+
sink(*p[0]);
101+
102+
calls_sink_with_argv(*p[i]);
103+
104+
sink(*(argv + 1)); // flow [NOT DECTED by AST]
105+
106+
BaseWithPureVirtual* b = new DerivedCallsSink;
107+
108+
b->f(argv[1]); // flow [NOT DETECTED by IR]
109+
110+
b = new DerivedDoesNotCallSink;
111+
b->f(argv[0]); // no flow [FALSE POSITIVE by AST]
112+
113+
BaseWithPureVirtual* b2 = new DerivesMultiple;
114+
115+
b2->f(argv[i]); // flow [NOT DETECTED]
116+
117+
CRTP<CRTPDoesNotCallSink> crtp_not_call_sink;
118+
crtp_not_call_sink.f(argv[0]);
119+
120+
CRTP<CRTPCallsSink> crtp_calls_sink;
121+
crtp_calls_sink.f(argv[0]); // flow [NOT DETECTED]
122+
123+
Derived1* calls_sink = new Derived3;
124+
calls_sink->f(argv[1]); // flow [NOT DETECTED by AST]
125+
126+
static_cast<Derived2*>(calls_sink)->f(argv[1]); // flow [NOT DETECTED]
127+
128+
dynamic_cast<Derived2*>(calls_sink)->f(argv[1]); // flow [NOT DETECTED by IR]
129+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:9:11:9:20 | p#0 | IR only |
2+
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:14 | call to _strdup | IR only |
3+
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | defaulttainttracking.cpp:16:8:16:29 | (const char *)... | IR only |
4+
| defaulttainttracking.cpp:16:16:16:21 | call to getenv | test_diff.cpp:1:11:1:20 | p#0 | IR only |
5+
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:3:21:3:22 | s1 | AST only |
6+
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:21:8:21:10 | buf | AST only |
7+
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:22:15:22:17 | buf | AST only |
8+
| defaulttainttracking.cpp:22:20:22:25 | call to getenv | defaulttainttracking.cpp:24:8:24:10 | buf | AST only |
9+
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:31:40:31:53 | dotted_address | AST only |
10+
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:36:39:61 | (const char *)... | AST only |
11+
| defaulttainttracking.cpp:38:25:38:30 | call to getenv | defaulttainttracking.cpp:39:51:39:61 | env_pointer | AST only |
12+
| test_diff.cpp:104:12:104:15 | argv | test_diff.cpp:104:11:104:20 | (...) | IR only |
13+
| test_diff.cpp:108:10:108:13 | argv | test_diff.cpp:36:24:36:24 | p | AST only |
14+
| test_diff.cpp:111:10:111:13 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | AST only |
15+
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:1:11:1:20 | p#0 | AST only |
16+
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:29:24:29:24 | p | AST only |
17+
| test_diff.cpp:111:10:111:13 | argv | test_diff.cpp:30:14:30:14 | p | AST only |
18+
| test_diff.cpp:124:19:124:22 | argv | test_diff.cpp:76:24:76:24 | p | IR only |
19+
| test_diff.cpp:128:44:128:47 | argv | defaulttainttracking.cpp:9:11:9:20 | p#0 | AST only |
20+
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:1:11:1:20 | p#0 | AST only |
21+
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:81:24:81:24 | p | AST only |
22+
| test_diff.cpp:128:44:128:47 | argv | test_diff.cpp:82:14:82:14 | p | AST only |
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import cpp
2+
import semmle.code.cpp.security.Security
3+
import semmle.code.cpp.security.TaintTracking as ASTTaintTracking
4+
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
5+
6+
predicate astFlow(Expr source, Element sink) {
7+
ASTTaintTracking::tainted(source, sink)
8+
}
9+
10+
predicate irFlow(Expr source, Element sink) {
11+
IRDefaultTaintTracking::tainted(source, sink)
12+
}
13+
14+
from Expr source, Element sink, string note
15+
where
16+
astFlow(source, sink) and
17+
not irFlow(source, sink) and
18+
note = "AST only"
19+
or
20+
irFlow(source, sink) and
21+
not astFlow(source, sink) and
22+
note = "IR only"
23+
select source, sink, note

0 commit comments

Comments
 (0)