Skip to content

Commit 742eb8d

Browse files
committed
Java: Rewrite InlineFlowTest as a parameterized module
1 parent 853bf2a commit 742eb8d

File tree

148 files changed

+272
-225
lines changed

Some content is hidden

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

148 files changed

+272
-225
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
import java
22
import TestUtilities.InlineFlowTest
3+
import DefaultFlowTest

java/ql/test/TestUtilities/InlineFlowTest.qll

Lines changed: 54 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* ```ql
66
* import java
77
* import TestUtilities.InlineFlowTest
8+
* import DefaultFlowTest
89
* ```
910
*
1011
* To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files.
@@ -18,22 +19,18 @@
1819
*
1920
* public void test() {
2021
* Object s = source();
21-
* sink(s); //$hasValueFlow
22+
* sink(s); // $ hasValueFlow
2223
* String t = "foo" + taint();
23-
* sink(t); //$hasTaintFlow
24+
* sink(t); // $ hasTaintFlow
2425
* }
2526
*
2627
* }
2728
* ```
2829
*
29-
* If you're not interested in a specific flow type, you can disable either value or taint flow expectations as follows:
30-
* ```ql
31-
* class HasFlowTest extends InlineFlowTest {
32-
* override DataFlow::Configuration getTaintFlowConfig() { none() }
33-
*
34-
* override DataFlow::Configuration getValueFlowConfig() { none() }
35-
* }
36-
* ```
30+
* If you are only interested in value flow, then instead of importing `DefaultFlowTest`, you can import
31+
* `ValueFlowTest<DefaultFlowConfig>`. Similarly, if you are only interested in taint flow, then instead of
32+
* importing `DefaultFlowTest`, you can import `TaintFlowTest<DefaultFlowConfig>`. In both cases
33+
* `DefaultFlowConfig` can be replaced by another implementation of `DataFlow::ConfigSig`.
3734
*
3835
* If you need more fine-grained tuning, consider implementing a test using `InlineExpectationsTest`.
3936
*/
@@ -43,57 +40,69 @@ import semmle.code.java.dataflow.ExternalFlow
4340
import semmle.code.java.dataflow.TaintTracking
4441
import TestUtilities.InlineExpectationsTest
4542

46-
private predicate defaultSource(DataFlow::Node src) {
47-
src.asExpr().(MethodAccess).getMethod().getName() = ["source", "taint"]
43+
private predicate defaultSource(DataFlow::Node source) {
44+
source.asExpr().(MethodAccess).getMethod().getName() = ["source", "taint"]
45+
}
46+
47+
private predicate defaultSink(DataFlow::Node sink) {
48+
exists(MethodAccess ma | ma.getMethod().hasName("sink") | sink.asExpr() = ma.getAnArgument())
4849
}
4950

5051
module DefaultFlowConfig implements DataFlow::ConfigSig {
51-
predicate isSource(DataFlow::Node n) { defaultSource(n) }
52+
predicate isSource(DataFlow::Node source) { defaultSource(source) }
5253

53-
predicate isSink(DataFlow::Node n) {
54-
exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
55-
}
54+
predicate isSink(DataFlow::Node sink) { defaultSink(sink) }
5655

5756
int fieldFlowBranchLimit() { result = 1000 }
5857
}
5958

60-
private module DefaultValueFlow = DataFlow::Global<DefaultFlowConfig>;
59+
private module NoFlowConfig implements DataFlow::ConfigSig {
60+
predicate isSource(DataFlow::Node source) { none() }
6161

62-
private module DefaultTaintFlow = TaintTracking::Global<DefaultFlowConfig>;
62+
predicate isSink(DataFlow::Node sink) { none() }
63+
}
6364

6465
private string getSourceArgString(DataFlow::Node src) {
6566
defaultSource(src) and
6667
src.asExpr().(MethodAccess).getAnArgument().(StringLiteral).getValue() = result
6768
}
6869

69-
class InlineFlowTest extends InlineExpectationsTest {
70-
InlineFlowTest() { this = "HasFlowTest" }
71-
72-
override string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] }
73-
74-
override predicate hasActualResult(Location location, string element, string tag, string value) {
75-
tag = "hasValueFlow" and
76-
exists(DataFlow::Node src, DataFlow::Node sink | this.hasValueFlow(src, sink) |
77-
sink.getLocation() = location and
78-
element = sink.toString() and
79-
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
80-
)
81-
or
82-
tag = "hasTaintFlow" and
83-
exists(DataFlow::Node src, DataFlow::Node sink |
84-
this.hasTaintFlow(src, sink) and not this.hasValueFlow(src, sink)
85-
|
86-
sink.getLocation() = location and
87-
element = sink.toString() and
88-
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
89-
)
90-
}
70+
module FlowTest<DataFlow::ConfigSig ValueFlowConfig, DataFlow::ConfigSig TaintFlowConfig> {
71+
module ValueFlow = DataFlow::Global<ValueFlowConfig>;
9172

92-
predicate hasValueFlow(DataFlow::Node src, DataFlow::Node sink) {
93-
DefaultValueFlow::flow(src, sink)
94-
}
73+
module TaintFlow = TaintTracking::Global<TaintFlowConfig>;
74+
75+
private module InlineTest implements TestSig {
76+
string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] }
9577

96-
predicate hasTaintFlow(DataFlow::Node src, DataFlow::Node sink) {
97-
DefaultTaintFlow::flow(src, sink)
78+
predicate hasActualResult(Location location, string element, string tag, string value) {
79+
tag = "hasValueFlow" and
80+
exists(DataFlow::Node src, DataFlow::Node sink | ValueFlow::flow(src, sink) |
81+
sink.getLocation() = location and
82+
element = sink.toString() and
83+
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
84+
)
85+
or
86+
tag = "hasTaintFlow" and
87+
exists(DataFlow::Node src, DataFlow::Node sink |
88+
TaintFlow::flow(src, sink) and not ValueFlow::flow(src, sink)
89+
|
90+
sink.getLocation() = location and
91+
element = sink.toString() and
92+
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
93+
)
94+
}
9895
}
96+
97+
import MakeTest<InlineTest>
98+
}
99+
100+
module DefaultFlowTest = FlowTest<DefaultFlowConfig, DefaultFlowConfig>;
101+
102+
module ValueFlowTest<DataFlow::ConfigSig ValueFlowConfig> {
103+
import FlowTest<ValueFlowConfig, NoFlowConfig>
104+
}
105+
106+
module TaintFlowTest<DataFlow::ConfigSig TaintFlowConfig> {
107+
import FlowTest<NoFlowConfig, TaintFlowConfig>
99108
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
failures
2+
testFailures

java/ql/test/ext/TestModels/test.ql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
import java
22
import TestUtilities.InlineFlowTest
3+
import DefaultFlowTest

java/ql/test/kotlin/library-tests/dataflow/summaries/test.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
failures
2+
testFailures
13
| test.kt:28:14:28:21 | getSecond(...) | Unexpected result: hasTaintFlow=a |
24
| test.kt:35:14:35:27 | component1(...) | Unexpected result: hasTaintFlow=d |
35
| test.kt:41:14:41:22 | getSecond(...) | Unexpected result: hasTaintFlow=e |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
import java
22
import TestUtilities.InlineFlowTest
3+
import DefaultFlowTest
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
failures
2+
testFailures
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
import java
22
import TestUtilities.InlineFlowTest
3+
import DefaultFlowTest
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
failures
2+
testFailures
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import java
22
import semmle.code.java.dataflow.DataFlow
33
import TestUtilities.InlineFlowTest
4+
import DefaultFlowTest

0 commit comments

Comments
 (0)