Skip to content

Commit 203bbdd

Browse files
authored
Merge pull request #4741 from criemen/port-dataflow-tests
C++: Port dataflow tests to inline expectations test library.
2 parents 7f485df + f3a7d87 commit 203bbdd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+1357
-3484
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ class Node extends TIRDataFlowNode {
9595
* Gets the uninitialized local variable corresponding to this node, if
9696
* any.
9797
*/
98-
LocalVariable asUninitialized() { none() }
98+
deprecated LocalVariable asUninitialized() { none() }
9999

100100
/**
101101
* Gets an upper bound on the type of this node.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#include "../shared.h"
2+
3+
using SinkFunction = void (*)(int);
4+
5+
void notSink(int notSinkParam);
6+
7+
void callsSink(int sinkParam) {
8+
sink(sinkParam); // $ ast,ir=31:28 ast,ir=32:31 ast,ir=34:22 MISSING: ast,ir=28
9+
}
10+
11+
struct {
12+
SinkFunction sinkPtr, notSinkPtr;
13+
} globalStruct;
14+
15+
union {
16+
SinkFunction sinkPtr, notSinkPtr;
17+
} globalUnion;
18+
19+
SinkFunction globalSinkPtr;
20+
21+
void assignGlobals() {
22+
globalStruct.sinkPtr = callsSink;
23+
globalUnion.sinkPtr = callsSink;
24+
globalSinkPtr = callsSink;
25+
};
26+
27+
void testStruct() {
28+
globalStruct.sinkPtr(atoi(getenv("TAINTED"))); // $ MISSING: ast,ir
29+
globalStruct.notSinkPtr(atoi(getenv("TAINTED"))); // clean
30+
31+
globalUnion.sinkPtr(atoi(getenv("TAINTED"))); // $ ast,ir
32+
globalUnion.notSinkPtr(atoi(getenv("TAINTED"))); // $ ast,ir
33+
34+
globalSinkPtr(atoi(getenv("TAINTED"))); // $ ast,ir
35+
}
36+
37+
class B {
38+
public:
39+
virtual void f(const char*) = 0;
40+
};
41+
42+
class D1 : public B {};
43+
44+
class D2 : public D1 {
45+
public:
46+
void f(const char* p) override {}
47+
};
48+
49+
class D3 : public D2 {
50+
public:
51+
void f(const char* p) override {
52+
sink(p); // $ ast,ir=58:10 ast,ir=60:17 ast,ir=61:28 ast,ir=62:29 ast,ir=63:33 SPURIOUS: ast,ir=73:30
53+
}
54+
};
55+
56+
void test_dynamic_cast() {
57+
B* b = new D3();
58+
b->f(getenv("VAR")); // $ ast,ir
59+
60+
((D2*)b)->f(getenv("VAR")); // $ ast,ir
61+
static_cast<D2*>(b)->f(getenv("VAR")); // $ ast,ir
62+
dynamic_cast<D2*>(b)->f(getenv("VAR")); // $ ast,ir
63+
reinterpret_cast<D2*>(b)->f(getenv("VAR")); // $ ast,ir
64+
65+
B* b2 = new D2();
66+
b2->f(getenv("VAR"));
67+
68+
((D2*)b2)->f(getenv("VAR"));
69+
static_cast<D2*>(b2)->f(getenv("VAR"));
70+
dynamic_cast<D2*>(b2)->f(getenv("VAR"));
71+
reinterpret_cast<D2*>(b2)->f(getenv("VAR"));
72+
73+
dynamic_cast<D3*>(b2)->f(getenv("VAR")); // $ SPURIOUS: ast,ir
74+
}

cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_path_to_sink/tainted.expected

Whitespace-only changes.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/**
2+
* This test provides the possibility to annotate elements when they are on a path of a taint flow to a sink.
3+
* This is different when compared to the tests in `../annotate_sink`, where only sink invocations are annotated.
4+
*/
5+
6+
import cpp
7+
import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking
8+
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
9+
import TestUtilities.InlineExpectationsTest
10+
11+
predicate isSink(Element sink) {
12+
exists(FunctionCall call |
13+
call.getTarget().getName() = "sink" and
14+
sink = call.getAnArgument()
15+
)
16+
}
17+
18+
predicate astTaint(Expr source, Element sink) { ASTTaintTracking::tainted(source, sink) }
19+
20+
predicate irTaint(Expr source, Element sink) { IRDefaultTaintTracking::tainted(source, sink) }
21+
22+
class IRDefaultTaintTrackingTest extends InlineExpectationsTest {
23+
IRDefaultTaintTrackingTest() { this = "IRDefaultTaintTrackingTest" }
24+
25+
override string getARelevantTag() { result = "ir" }
26+
27+
override predicate hasActualResult(Location location, string element, string tag, string value) {
28+
exists(Expr source, Element tainted, int n |
29+
tag = "ir" and
30+
irTaint(source, tainted) and
31+
(
32+
isSink(tainted)
33+
or
34+
exists(Element sink |
35+
isSink(sink) and
36+
irTaint(tainted, sink)
37+
)
38+
) and
39+
n = strictcount(Expr otherSource | irTaint(otherSource, tainted)) and
40+
(
41+
n = 1 and value = ""
42+
or
43+
// If there is more than one source for this sink
44+
// we specify the source location explicitly.
45+
n > 1 and
46+
value =
47+
source.getLocation().getStartLine().toString() + ":" +
48+
source.getLocation().getStartColumn()
49+
) and
50+
location = tainted.getLocation() and
51+
element = tainted.toString()
52+
)
53+
}
54+
}
55+
56+
class ASTTaintTrackingTest extends InlineExpectationsTest {
57+
ASTTaintTrackingTest() { this = "ASTTaintTrackingTest" }
58+
59+
override string getARelevantTag() { result = "ast" }
60+
61+
override predicate hasActualResult(Location location, string element, string tag, string value) {
62+
exists(Expr source, Element tainted, int n |
63+
tag = "ast" and
64+
astTaint(source, tainted) and
65+
(
66+
isSink(tainted)
67+
or
68+
exists(Element sink |
69+
isSink(sink) and
70+
astTaint(tainted, sink)
71+
)
72+
) and
73+
n = strictcount(Expr otherSource | astTaint(otherSource, tainted)) and
74+
(
75+
n = 1 and value = ""
76+
or
77+
// If there is more than one source for this sink
78+
// we specify the source location explicitly.
79+
n > 1 and
80+
value =
81+
source.getLocation().getStartLine().toString() + ":" +
82+
source.getLocation().getStartColumn()
83+
) and
84+
location = tainted.getLocation() and
85+
element = tainted.toString()
86+
)
87+
}
88+
}

cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/test_diff.cpp renamed to cpp/ql/test/library-tests/dataflow/DefaultTaintTracking/annotate_path_to_sink/test_diff.cpp

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#include "shared.h"
1+
#include "../shared.h"
22

33

44
struct S {
@@ -14,7 +14,7 @@ struct S {
1414
};
1515

1616
void calls_sink_with_argv(const char* a) {
17-
sink(a);
17+
sink(a); // $ ast,ir=96:26 ast,ir=98:18
1818
}
1919

2020
extern int i;
@@ -27,7 +27,7 @@ class BaseWithPureVirtual {
2727
class DerivedCallsSink : public BaseWithPureVirtual {
2828
public:
2929
void f(const char* p) override {
30-
sink(p);
30+
sink(p); // $ ir ast=108:10 SPURIOUS: ast=111:10
3131
}
3232
};
3333

@@ -39,7 +39,7 @@ class DerivedDoesNotCallSink : public BaseWithPureVirtual {
3939
class DerivedCallsSinkDiamond1 : virtual public BaseWithPureVirtual {
4040
public:
4141
void f(const char* p) override {
42-
sink(p);
42+
sink(p); // $ ast,ir
4343
}
4444
};
4545

@@ -65,7 +65,7 @@ class CRTP {
6565
class CRTPCallsSink : public CRTP<CRTPCallsSink> {
6666
public:
6767
void g(const char* p) {
68-
sink(p);
68+
sink(p); // $ ast,ir
6969
}
7070
};
7171

@@ -79,7 +79,7 @@ class Derived2 : public Derived1 {
7979
class Derived3 : public Derived2 {
8080
public:
8181
void f(const char* p) override {
82-
sink(p);
82+
sink(p); // $ ast,ir=124:19 ast,ir=126:43 ast,ir=128:44
8383
}
8484
};
8585

@@ -89,41 +89,41 @@ class CRTPDoesNotCallSink : public CRTP<CRTPDoesNotCallSink> {
8989
};
9090

9191
int main(int argc, char *argv[]) {
92-
sink(argv[0]);
92+
sink(argv[0]); // $ ast,ir
9393

94-
sink(reinterpret_cast<int>(argv));
94+
sink(reinterpret_cast<int>(argv)); // $ ast,ir
9595

96-
calls_sink_with_argv(argv[1]);
96+
calls_sink_with_argv(argv[1]); // $ ast,ir
9797

98-
char*** p = &argv;
98+
char*** p = &argv; // $ ast,ir
9999

100-
sink(*p[0]);
100+
sink(*p[0]); // $ ast,ir
101101

102-
calls_sink_with_argv(*p[i]);
102+
calls_sink_with_argv(*p[i]); // $ MISSING: ast,ir
103103

104-
sink(*(argv + 1));
104+
sink(*(argv + 1)); // $ ast,ir
105105

106106
BaseWithPureVirtual* b = new DerivedCallsSink;
107107

108-
b->f(argv[1]);
108+
b->f(argv[1]); // $ ast,ir
109109

110110
b = new DerivedDoesNotCallSink;
111-
b->f(argv[0]); // no flow [FALSE POSITIVE by AST]
111+
b->f(argv[0]); // $ SPURIOUS: ast
112112

113113
BaseWithPureVirtual* b2 = new DerivesMultiple;
114114

115-
b2->f(argv[i]);
115+
b2->f(argv[i]); // $ ast,ir
116116

117117
CRTP<CRTPDoesNotCallSink> crtp_not_call_sink;
118-
crtp_not_call_sink.f(argv[0]);
118+
crtp_not_call_sink.f(argv[0]); // clean
119119

120120
CRTP<CRTPCallsSink> crtp_calls_sink;
121-
crtp_calls_sink.f(argv[0]);
121+
crtp_calls_sink.f(argv[0]); // $ ast,ir
122122

123123
Derived1* calls_sink = new Derived3;
124-
calls_sink->f(argv[1]);
124+
calls_sink->f(argv[1]); // $ ast,ir
125125

126-
static_cast<Derived2*>(calls_sink)->f(argv[1]);
126+
static_cast<Derived2*>(calls_sink)->f(argv[1]); // $ ast,ir
127127

128-
dynamic_cast<Derived2*>(calls_sink)->f(argv[1]); // flow [NOT DETECTED by IR]
128+
dynamic_cast<Derived2*>(calls_sink)->f(argv[1]); // $ ast,ir
129129
}

0 commit comments

Comments
 (0)