44 * Example for a test.ql:
55 * ```ql
66 * import csharp
7- * import DefaultValueFlow::PathGraph
87 * import TestUtilities.InlineFlowTest
8+ * import DefaultFlowTest
9+ * import PathGraph
910 *
10- * from DefaultValueFlow:: PathNode source, DefaultValueFlow:: PathNode sink
11- * where DefaultValueFlow:: flowPath(source, sink)
11+ * from PathNode source, PathNode sink
12+ * where flowPath(source, sink)
1213 * select sink, source, sink, "$@", source, source.toString()
1314 *
1415 * ```
3233 * }
3334 * ```
3435 *
35- * If you're not interested in a specific flow type, you can disable either value or taint flow expectations as follows:
36- * ```ql
37- * class HasFlowTest extends InlineFlowTest {
38- * override DataFlow::Configuration getTaintFlowConfig() { none() }
39- *
40- * override DataFlow::Configuration getValueFlowConfig() { none() }
41- * }
42- * ```
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`.
4340 *
4441 * If you need more fine-grained tuning, consider implementing a test using `InlineExpectationsTest`.
4542 */
4643
4744import csharp
4845import TestUtilities.InlineExpectationsTest
4946
50- private predicate defaultSource ( DataFlow:: Node src ) {
51- src .asExpr ( ) .( MethodCall ) .getTarget ( ) .getUndecoratedName ( ) = [ "Source" , "Taint" ]
47+ private predicate defaultSource ( DataFlow:: Node source ) {
48+ source .asExpr ( ) .( MethodCall ) .getTarget ( ) .getUndecoratedName ( ) = [ "Source" , "Taint" ]
5249}
5350
5451private predicate defaultSink ( DataFlow:: Node sink ) {
@@ -58,42 +55,66 @@ private predicate defaultSink(DataFlow::Node sink) {
5855}
5956
6057module DefaultFlowConfig implements DataFlow:: ConfigSig {
61- predicate isSource ( DataFlow:: Node n ) { defaultSource ( n ) }
58+ predicate isSource ( DataFlow:: Node source ) { defaultSource ( source ) }
6259
63- predicate isSink ( DataFlow:: Node n ) { defaultSink ( n ) }
60+ predicate isSink ( DataFlow:: Node sink ) { defaultSink ( sink ) }
6461
6562 int fieldFlowBranchLimit ( ) { result = 1000 }
6663}
6764
68- module DefaultValueFlow = DataFlow:: Global< DefaultFlowConfig > ;
65+ private module NoFlowConfig implements DataFlow:: ConfigSig {
66+ predicate isSource ( DataFlow:: Node source ) { none ( ) }
6967
70- module DefaultTaintFlow = TaintTracking:: Global< DefaultFlowConfig > ;
68+ predicate isSink ( DataFlow:: Node sink ) { none ( ) }
69+ }
7170
7271private string getSourceArgString ( DataFlow:: Node src ) {
7372 defaultSource ( src ) and
7473 src .asExpr ( ) .( MethodCall ) .getAnArgument ( ) .getValue ( ) = result
7574}
7675
77- class InlineFlowTest extends InlineExpectationsTest {
78- InlineFlowTest ( ) { this = "HasFlowTest" }
79-
80- override string getARelevantTag ( ) { result = [ "hasValueFlow" , "hasTaintFlow" ] }
81-
82- override predicate hasActualResult ( Location location , string element , string tag , string value ) {
83- tag = "hasValueFlow" and
84- exists ( DataFlow:: Node src , DataFlow:: Node sink | DefaultValueFlow:: flow ( src , sink ) |
85- sink .getLocation ( ) = location and
86- element = sink .toString ( ) and
87- if exists ( getSourceArgString ( src ) ) then value = getSourceArgString ( src ) else value = ""
88- )
89- or
90- tag = "hasTaintFlow" and
91- exists ( DataFlow:: Node src , DataFlow:: Node sink |
92- DefaultTaintFlow:: flow ( src , sink ) and not DefaultValueFlow:: flow ( src , sink )
93- |
94- sink .getLocation ( ) = location and
95- element = sink .toString ( ) and
96- if exists ( getSourceArgString ( src ) ) then value = getSourceArgString ( src ) else value = ""
97- )
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+ }
98101 }
102+
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 ( ) )
109+ }
110+ }
111+
112+ module DefaultFlowTest = FlowTest< DefaultFlowConfig , DefaultFlowConfig > ;
113+
114+ module ValueFlowTest< DataFlow:: ConfigSig ValueFlowConfig> {
115+ import FlowTest< ValueFlowConfig , NoFlowConfig >
116+ }
117+
118+ module TaintFlowTest< DataFlow:: ConfigSig TaintFlowConfig> {
119+ import FlowTest< NoFlowConfig , TaintFlowConfig >
99120}
0 commit comments