Skip to content

Commit 0d1fd88

Browse files
authored
Merge pull request github#14050 from jketema/inline-6
Consolidate all `InlineFlowTest` libraries in the dataflow qlpack
2 parents 3343b78 + b550c06 commit 0d1fd88

File tree

139 files changed

+285
-699
lines changed

Some content is hidden

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

139 files changed

+285
-699
lines changed

csharp/ql/test/TestUtilities/InlineExpectationsTest.qll

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,6 @@
33
* See `shared/util/codeql/util/test/InlineExpectationsTest.qll`
44
*/
55

6-
private import csharp as CS
76
private import codeql.util.test.InlineExpectationsTest
8-
9-
private module Impl implements InlineExpectationsTestSig {
10-
/**
11-
* A class representing line comments in C# used by the InlineExpectations core code
12-
*/
13-
class ExpectationComment extends CS::SinglelineComment {
14-
/** Gets the contents of the given comment, _without_ the preceding comment marker (`//`). */
15-
string getContents() { result = this.getText() }
16-
}
17-
18-
class Location = CS::Location;
19-
}
20-
7+
private import internal.InlineExpectationsTestImpl
218
import Make<Impl>
Lines changed: 23 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,34 @@
11
/**
2-
* Provides a simple base test for flow-related tests using inline expectations.
3-
*
4-
* Example for a test.ql:
5-
* ```ql
6-
* import csharp
7-
* import TestUtilities.InlineFlowTest
8-
* import DefaultFlowTest
9-
* import PathGraph
10-
*
11-
* from PathNode source, PathNode sink
12-
* where flowPath(source, sink)
13-
* select sink, source, sink, "$@", source, source.toString()
14-
*
15-
* ```
16-
*
17-
* To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files.
18-
* Example of the corresponding test file, e.g. Test.cs
19-
* ```csharp
20-
* public class Test
21-
* {
22-
* object Source() { return null; }
23-
* string Taint() { return null; }
24-
* void Sink(object o) { }
25-
*
26-
* public void test()
27-
* {
28-
* var s = Source(1);
29-
* Sink(s); // $ hasValueFlow=1
30-
* var t = "foo" + Taint(2);
31-
* Sink(t); // $ hasTaintFlow=2
32-
* }
33-
* }
34-
* ```
35-
*
36-
* If you are only interested in value flow, then instead of importing `DefaultFlowTest`, you can import
37-
* `ValueFlowTest<DefaultFlowConfig>`. Similarly, if you are only interested in taint flow, then instead of
38-
* importing `DefaultFlowTest`, you can import `TaintFlowTest<DefaultFlowConfig>`. In both cases
39-
* `DefaultFlowConfig` can be replaced by another implementation of `DataFlow::ConfigSig`.
40-
*
41-
* If you need more fine-grained tuning, consider implementing a test using `InlineExpectationsTest`.
2+
* Inline flow tests for CSharp.
3+
* See `shared/util/codeql/dataflow/test/InlineFlowTest.qll`
424
*/
435

446
import csharp
45-
import TestUtilities.InlineExpectationsTest
46-
47-
private predicate defaultSource(DataFlow::Node source) {
48-
source.asExpr().(MethodCall).getTarget().getUndecoratedName() = ["Source", "Taint"]
49-
}
50-
51-
private predicate defaultSink(DataFlow::Node sink) {
52-
exists(MethodCall mc | mc.getTarget().hasUndecoratedName("Sink") |
53-
sink.asExpr() = mc.getAnArgument()
54-
)
55-
}
56-
57-
module DefaultFlowConfig implements DataFlow::ConfigSig {
58-
predicate isSource(DataFlow::Node source) { defaultSource(source) }
59-
60-
predicate isSink(DataFlow::Node sink) { defaultSink(sink) }
61-
62-
int fieldFlowBranchLimit() { result = 1000 }
63-
}
64-
65-
private module NoFlowConfig implements DataFlow::ConfigSig {
66-
predicate isSource(DataFlow::Node source) { none() }
67-
68-
predicate isSink(DataFlow::Node sink) { none() }
69-
}
70-
71-
private string getSourceArgString(DataFlow::Node src) {
72-
defaultSource(src) and
73-
src.asExpr().(MethodCall).getAnArgument().getValue() = result
74-
}
75-
76-
module FlowTest<DataFlow::ConfigSig ValueFlowConfig, DataFlow::ConfigSig TaintFlowConfig> {
77-
module ValueFlow = DataFlow::Global<ValueFlowConfig>;
78-
79-
module TaintFlow = TaintTracking::Global<TaintFlowConfig>;
80-
81-
private module InlineTest implements TestSig {
82-
string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] }
83-
84-
predicate hasActualResult(Location location, string element, string tag, string value) {
85-
tag = "hasValueFlow" and
86-
exists(DataFlow::Node src, DataFlow::Node sink | ValueFlow::flow(src, sink) |
87-
sink.getLocation() = location and
88-
element = sink.toString() and
89-
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
90-
)
91-
or
92-
tag = "hasTaintFlow" and
93-
exists(DataFlow::Node src, DataFlow::Node sink |
94-
TaintFlow::flow(src, sink) and not ValueFlow::flow(src, sink)
95-
|
96-
sink.getLocation() = location and
97-
element = sink.toString() and
98-
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
99-
)
100-
}
7+
private import codeql.dataflow.test.InlineFlowTest
8+
private import semmle.code.csharp.dataflow.internal.DataFlowImplSpecific
9+
private import semmle.code.csharp.dataflow.internal.TaintTrackingImplSpecific
10+
private import internal.InlineExpectationsTestImpl
11+
12+
private module FlowTestImpl implements InputSig<CsharpDataFlow> {
13+
predicate defaultSource(DataFlow::Node source) {
14+
source.asExpr().(MethodCall).getTarget().getUndecoratedName() = ["Source", "Taint"]
10115
}
10216

103-
import MakeTest<InlineTest>
104-
import DataFlow::MergePathGraph<ValueFlow::PathNode, TaintFlow::PathNode, ValueFlow::PathGraph, TaintFlow::PathGraph>
105-
106-
predicate flowPath(PathNode source, PathNode sink) {
107-
ValueFlow::flowPath(source.asPathNode1(), sink.asPathNode1()) or
108-
TaintFlow::flowPath(source.asPathNode2(), sink.asPathNode2())
17+
predicate defaultSink(DataFlow::Node sink) {
18+
exists(MethodCall mc | mc.getTarget().hasUndecoratedName("Sink") |
19+
sink.asExpr() = mc.getAnArgument()
20+
)
10921
}
110-
}
11122

112-
module DefaultFlowTest = FlowTest<DefaultFlowConfig, DefaultFlowConfig>;
23+
private string getSourceArgString(DataFlow::Node src) {
24+
defaultSource(src) and
25+
src.asExpr().(MethodCall).getAnArgument().getValue() = result
26+
}
11327

114-
module ValueFlowTest<DataFlow::ConfigSig ValueFlowConfig> {
115-
import FlowTest<ValueFlowConfig, NoFlowConfig>
28+
string getArgString(DataFlow::Node src, DataFlow::Node sink) {
29+
(if exists(getSourceArgString(src)) then result = getSourceArgString(src) else result = "") and
30+
exists(sink)
31+
}
11632
}
11733

118-
module TaintFlowTest<DataFlow::ConfigSig TaintFlowConfig> {
119-
import FlowTest<NoFlowConfig, TaintFlowConfig>
120-
}
34+
import InlineFlowTestMake<CsharpDataFlow, CsharpTaintTracking, Impl, FlowTestImpl>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
private import csharp as CS
2+
private import codeql.util.test.InlineExpectationsTest
3+
4+
module Impl implements InlineExpectationsTestSig {
5+
/**
6+
* A class representing line comments in C# used by the InlineExpectations core code
7+
*/
8+
class ExpectationComment extends CS::SinglelineComment {
9+
/** Gets the contents of the given comment, _without_ the preceding comment marker (`//`). */
10+
string getContents() { result = this.getText() }
11+
}
12+
13+
class Location = CS::Location;
14+
}

csharp/ql/test/library-tests/dataflow/fields/FieldFlow.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
failures
21
testFailures
32
edges
43
| A.cs:5:17:5:28 | call to method Source<C> : C | A.cs:6:24:6:24 | access to local variable c : C |

csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
failures
21
testFailures
32
edges
43
| Operator.cs:9:39:9:39 | x : C | Operator.cs:9:50:9:50 | access to parameter x : C |

csharp/ql/test/library-tests/dataflow/patterns/PatternFlow.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
failures
21
testFailures
32
edges
43
nodes

csharp/ql/test/library-tests/dataflow/tuples/Tuples.expected

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
failures
21
testFailures
32
edges
43
| Tuples.cs:7:18:7:34 | call to method Source<Object> : Object | Tuples.cs:10:21:10:22 | access to local variable o1 : Object |

go/ql/test/TestUtilities/InlineExpectationsTest.qll

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,6 @@
33
* See `shared/util/codeql/util/test/InlineExpectationsTest.qll`
44
*/
55

6-
private import go as G
76
private import codeql.util.test.InlineExpectationsTest
8-
9-
private module Impl implements InlineExpectationsTestSig {
10-
/**
11-
* A class representing line comments in the Go style, including the
12-
* preceding comment marker (`//`).
13-
*/
14-
class ExpectationComment extends G::Comment {
15-
/** Returns the contents of the given comment, _without_ the preceding comment marker (`//`). */
16-
string getContents() { result = this.getText() }
17-
}
18-
19-
class Location = G::Location;
20-
}
21-
7+
private import internal.InlineExpectationsTestImpl
228
import Make<Impl>
Lines changed: 19 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,29 @@
11
/**
2-
* Provides a simple base test for flow-related tests using inline expectations.
3-
*
4-
* Example for a test.ql:
5-
* ```ql
6-
* import go
7-
* import TestUtilities.InlineFlowTest
8-
* import DefaultFlowTest
9-
* import PathGraph
10-
*
11-
* from PathNode source, PathNode sink
12-
* where flowPath(source, sink)
13-
* select sink, source, sink, "$@", source, source.toString()
14-
* ```
15-
*
16-
* To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files.
17-
* Example of the corresponding test file, e.g. Test.go
18-
* ```go
19-
* func source() string { return ""; }
20-
* func taint() string { return ""; }
21-
* func sink(s string) { }
22-
*
23-
* func test() {
24-
* s := source()
25-
* sink(s) // $ hasValueFlow="s"
26-
* t := "foo" + taint()
27-
* sink(t) // $ hasTaintFlow="t"
28-
* }
29-
* ```
30-
*
31-
* If you are only interested in value flow, then instead of importing `DefaultFlowTest`, you can import
32-
* `ValueFlowTest<DefaultFlowConfig>`. Similarly, if you are only interested in taint flow, then instead of
33-
* importing `DefaultFlowTest`, you can import `TaintFlowTest<DefaultFlowConfig>`. In both cases
34-
* `DefaultFlowConfig` can be replaced by another implementation of `DataFlow::ConfigSig`.
35-
*
36-
* If you need more fine-grained tuning, consider implementing a test using `InlineExpectationsTest`.
2+
* Inline flow tests for Go.
3+
* See `shared/util/codeql/dataflow/test/InlineFlowTest.qll`
374
*/
385

396
import go
40-
import TestUtilities.InlineExpectationsTest
41-
42-
private predicate defaultSource(DataFlow::Node source) {
43-
exists(Function fn | fn.hasQualifiedName(_, ["source", "taint"]) |
44-
source = fn.getACall().getResult()
45-
)
46-
}
47-
48-
private predicate defaultSink(DataFlow::Node sink) {
49-
exists(Function fn | fn.hasQualifiedName(_, "sink") | sink = fn.getACall().getAnArgument())
50-
}
51-
52-
module DefaultFlowConfig implements DataFlow::ConfigSig {
53-
predicate isSource(DataFlow::Node source) { defaultSource(source) }
54-
55-
predicate isSink(DataFlow::Node sink) { defaultSink(sink) }
56-
57-
int fieldFlowBranchLimit() { result = 1000 }
58-
}
59-
60-
private module NoFlowConfig implements DataFlow::ConfigSig {
61-
predicate isSource(DataFlow::Node source) { none() }
62-
63-
predicate isSink(DataFlow::Node sink) { none() }
64-
}
65-
66-
module FlowTest<DataFlow::ConfigSig ValueFlowConfig, DataFlow::ConfigSig TaintFlowConfig> {
67-
module ValueFlow = DataFlow::Global<ValueFlowConfig>;
68-
69-
module TaintFlow = TaintTracking::Global<TaintFlowConfig>;
70-
71-
private module InlineTest implements TestSig {
72-
string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] }
73-
74-
predicate hasActualResult(Location location, string element, string tag, string value) {
75-
tag = "hasValueFlow" and
76-
exists(DataFlow::Node sink | ValueFlow::flowTo(sink) |
77-
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
78-
location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
79-
element = sink.toString() and
80-
value = "\"" + sink.toString() + "\""
81-
)
82-
or
83-
tag = "hasTaintFlow" and
84-
exists(DataFlow::Node src, DataFlow::Node sink |
85-
TaintFlow::flow(src, sink) and not ValueFlow::flow(src, sink)
86-
|
87-
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
88-
location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
89-
element = sink.toString() and
90-
value = "\"" + sink.toString() + "\""
91-
)
92-
}
7+
private import codeql.dataflow.test.InlineFlowTest
8+
private import semmle.go.dataflow.internal.DataFlowImplSpecific
9+
private import semmle.go.dataflow.internal.TaintTrackingImplSpecific
10+
private import internal.InlineExpectationsTestImpl
11+
12+
private module FlowTestImpl implements InputSig<GoDataFlow> {
13+
predicate defaultSource(DataFlow::Node source) {
14+
exists(Function fn | fn.hasQualifiedName(_, ["source", "taint"]) |
15+
source = fn.getACall().getResult()
16+
)
9317
}
9418

95-
import MakeTest<InlineTest>
96-
import DataFlow::MergePathGraph<ValueFlow::PathNode, TaintFlow::PathNode, ValueFlow::PathGraph, TaintFlow::PathGraph>
97-
98-
predicate flowPath(PathNode source, PathNode sink) {
99-
ValueFlow::flowPath(source.asPathNode1(), sink.asPathNode1()) or
100-
TaintFlow::flowPath(source.asPathNode2(), sink.asPathNode2())
19+
predicate defaultSink(DataFlow::Node sink) {
20+
exists(Function fn | fn.hasQualifiedName(_, "sink") | sink = fn.getACall().getAnArgument())
10121
}
102-
}
103-
104-
module DefaultFlowTest = FlowTest<DefaultFlowConfig, DefaultFlowConfig>;
10522

106-
module ValueFlowTest<DataFlow::ConfigSig ValueFlowConfig> {
107-
import FlowTest<ValueFlowConfig, NoFlowConfig>
23+
string getArgString(DataFlow::Node src, DataFlow::Node sink) {
24+
exists(src) and
25+
result = "\"" + sink.toString() + "\""
26+
}
10827
}
10928

110-
module TaintFlowTest<DataFlow::ConfigSig TaintFlowConfig> {
111-
import FlowTest<NoFlowConfig, TaintFlowConfig>
112-
}
29+
import InlineFlowTestMake<GoDataFlow, GoTaintTracking, Impl, FlowTestImpl>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
private import go as G
2+
private import codeql.util.test.InlineExpectationsTest
3+
4+
module Impl implements InlineExpectationsTestSig {
5+
/**
6+
* A class representing line comments in the Go style, including the
7+
* preceding comment marker (`//`).
8+
*/
9+
class ExpectationComment extends G::Comment {
10+
/** Returns the contents of the given comment, _without_ the preceding comment marker (`//`). */
11+
string getContents() { result = this.getText() }
12+
}
13+
14+
class Location = G::Location;
15+
}

0 commit comments

Comments
 (0)