3
3
*
4
4
* Example for a test.ql:
5
5
* ```ql
6
- * import java
6
+ * import go
7
7
* import TestUtilities.InlineFlowTest
8
+ * import DefaultFlowTest
8
9
* ```
9
10
*
10
11
* To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files.
11
- * Example of the corresponding test file, e.g. Test.java
12
+ * Example of the corresponding test file, e.g. Test.go
12
13
* ```go
13
- * public class Test {
14
- *
15
- * Object source() { return null; }
16
- * String taint() { return null; }
17
- * void sink(Object o) { }
18
- *
19
- * public void test() {
20
- * Object s = source();
21
- * sink(s); //$hasValueFlow
22
- * String t = "foo" + taint();
23
- * sink(t); //$hasTaintFlow
24
- * }
14
+ * func source() string { return ""; }
15
+ * func taint() string { return ""; }
16
+ * func sink(s string) { }
25
17
*
18
+ * func test() {
19
+ * s := source()
20
+ * sink(s) // $ hasValueFlow="s"
21
+ * t := "foo" + taint()
22
+ * sink(t) // $ hasTaintFlow="t"
26
23
* }
27
24
* ```
28
25
*
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
- * ```
26
+ * If you are only interested in value flow, then instead of importing `DefaultFlowTest`, you can import
27
+ * `ValueFlowTest<DefaultFlowConfig>`. Similarly, if you are only interested in taint flow, then instead of
28
+ * importing `DefaultFlowTest`, you can import `TaintFlowTest<DefaultFlowConfig>`. In both cases
29
+ * `DefaultFlowConfig` can be replaced by another implementation of `DataFlow::ConfigSig`.
37
30
*
38
31
* If you need more fine-grained tuning, consider implementing a test using `InlineExpectationsTest`.
39
32
*/
@@ -47,57 +40,62 @@ private predicate defaultSource(DataFlow::Node source) {
47
40
)
48
41
}
49
42
50
- class DefaultValueFlowConf extends DataFlow:: Configuration {
51
- DefaultValueFlowConf ( ) { this = "qltest:defaultValueFlowConf" }
43
+ private predicate defaultSink ( DataFlow:: Node sink ) {
44
+ exists ( Function fn | fn .hasQualifiedName ( _, "sink" ) | sink = fn .getACall ( ) .getAnArgument ( ) )
45
+ }
46
+
47
+ module DefaultFlowConfig implements DataFlow:: ConfigSig {
48
+ predicate isSource ( DataFlow:: Node source ) { defaultSource ( source ) }
52
49
53
- override predicate isSource ( DataFlow:: Node source ) { defaultSource ( source ) }
50
+ predicate isSink ( DataFlow:: Node sink ) { defaultSink ( sink ) }
54
51
55
- override predicate isSink ( DataFlow:: Node sink ) {
56
- exists ( Function fn | fn .hasQualifiedName ( _, "sink" ) | sink = fn .getACall ( ) .getAnArgument ( ) )
57
- }
52
+ int fieldFlowBranchLimit ( ) { result = 1000 }
53
+ }
54
+
55
+ private module NoFlowConfig implements DataFlow:: ConfigSig {
56
+ predicate isSource ( DataFlow:: Node source ) { none ( ) }
58
57
59
- override int fieldFlowBranchLimit ( ) { result = 1000 }
58
+ predicate isSink ( DataFlow :: Node sink ) { none ( ) }
60
59
}
61
60
62
- class DefaultTaintFlowConf extends TaintTracking :: Configuration {
63
- DefaultTaintFlowConf ( ) { this = "qltest:defaultTaintFlowConf" }
61
+ module FlowTest < DataFlow :: ConfigSig ValueFlowConfig , DataFlow :: ConfigSig TaintFlowConfig > {
62
+ module ValueFlow = DataFlow :: Global < ValueFlowConfig > ;
64
63
65
- override predicate isSource ( DataFlow :: Node source ) { defaultSource ( source ) }
64
+ module TaintFlow = TaintTracking :: Global < TaintFlowConfig > ;
66
65
67
- override predicate isSink ( DataFlow:: Node sink ) {
68
- exists ( Function fn | fn .hasQualifiedName ( _, "sink" ) | sink = fn .getACall ( ) .getAnArgument ( ) )
66
+ private module InlineTest implements TestSig {
67
+ string getARelevantTag ( ) { result = [ "hasValueFlow" , "hasTaintFlow" ] }
68
+
69
+ predicate hasActualResult ( Location location , string element , string tag , string value ) {
70
+ tag = "hasValueFlow" and
71
+ exists ( DataFlow:: Node sink | ValueFlow:: flowTo ( sink ) |
72
+ sink .hasLocationInfo ( location .getFile ( ) .getAbsolutePath ( ) , location .getStartLine ( ) ,
73
+ location .getStartColumn ( ) , location .getEndLine ( ) , location .getEndColumn ( ) ) and
74
+ element = sink .toString ( ) and
75
+ value = "\"" + sink .toString ( ) + "\""
76
+ )
77
+ or
78
+ tag = "hasTaintFlow" and
79
+ exists ( DataFlow:: Node src , DataFlow:: Node sink |
80
+ TaintFlow:: flow ( src , sink ) and not ValueFlow:: flow ( src , sink )
81
+ |
82
+ sink .hasLocationInfo ( location .getFile ( ) .getAbsolutePath ( ) , location .getStartLine ( ) ,
83
+ location .getStartColumn ( ) , location .getEndLine ( ) , location .getEndColumn ( ) ) and
84
+ element = sink .toString ( ) and
85
+ value = "\"" + sink .toString ( ) + "\""
86
+ )
87
+ }
69
88
}
70
89
71
- override int fieldFlowBranchLimit ( ) { result = 1000 }
90
+ import MakeTest < InlineTest >
72
91
}
73
92
74
- class InlineFlowTest extends InlineExpectationsTest {
75
- InlineFlowTest ( ) { this = "HasFlowTest" }
76
-
77
- override string getARelevantTag ( ) { result = [ "hasValueFlow" , "hasTaintFlow" ] }
78
-
79
- override predicate hasActualResult ( Location location , string element , string tag , string value ) {
80
- tag = "hasValueFlow" and
81
- exists ( DataFlow:: Node sink | this .getValueFlowConfig ( ) .hasFlowTo ( sink ) |
82
- sink .hasLocationInfo ( location .getFile ( ) .getAbsolutePath ( ) , location .getStartLine ( ) ,
83
- location .getStartColumn ( ) , location .getEndLine ( ) , location .getEndColumn ( ) ) and
84
- element = sink .toString ( ) and
85
- value = "\"" + sink .toString ( ) + "\""
86
- )
87
- or
88
- tag = "hasTaintFlow" and
89
- exists ( DataFlow:: Node src , DataFlow:: Node sink |
90
- this .getTaintFlowConfig ( ) .hasFlow ( src , sink ) and
91
- not this .getValueFlowConfig ( ) .hasFlow ( src , sink )
92
- |
93
- sink .hasLocationInfo ( location .getFile ( ) .getAbsolutePath ( ) , location .getStartLine ( ) ,
94
- location .getStartColumn ( ) , location .getEndLine ( ) , location .getEndColumn ( ) ) and
95
- element = sink .toString ( ) and
96
- value = "\"" + sink .toString ( ) + "\""
97
- )
98
- }
93
+ module DefaultFlowTest = FlowTest< DefaultFlowConfig , DefaultFlowConfig > ;
99
94
100
- DataFlow:: Configuration getValueFlowConfig ( ) { result = any ( DefaultValueFlowConf config ) }
95
+ module ValueFlowTest< DataFlow:: ConfigSig ValueFlowConfig> {
96
+ import FlowTest< ValueFlowConfig , NoFlowConfig >
97
+ }
101
98
102
- DataFlow:: Configuration getTaintFlowConfig ( ) { result = any ( DefaultTaintFlowConf config ) }
99
+ module TaintFlowTest< DataFlow:: ConfigSig TaintFlowConfig> {
100
+ import FlowTest< NoFlowConfig , TaintFlowConfig >
103
101
}
0 commit comments