44 * Example for a test.ql:
55 * ```ql
66 * import TestUtilities.InlineFlowTest
7+ * import DefaultFlowTest
78 * import PathGraph
89 *
9- * from DataFlow ::PathNode source, DataFlow ::PathNode sink, DefaultValueFlowConf conf
10- * where conf.hasFlowPath (source, sink)
10+ * from ValueFlow ::PathNode source, ValueFlow ::PathNode sink
11+ * where ValueFlow::flowPath (source, sink)
1112 * select sink, source, sink, "$@", source, source.toString()
1213 * ```
1314 *
2021 * sink(t); // $ hasTaintFlow=2
2122 * ```
2223 *
23- * If you're not interested in a specific flow type, you can disable either value or taint flow expectations as follows:
24- * ```ql
25- * class HasFlowTest extends InlineFlowTest {
26- * override DataFlow::Configuration getTaintFlowConfig() { none() }
27- *
28- * override DataFlow::Configuration getValueFlowConfig() { none() }
29- * }
30- * ```
24+ * If you are only interested in value flow, then instead of importing `DefaultFlowTest`, you can import
25+ * `ValueFlowTest<DefaultFlowConfig>`. Similarly, if you are only interested in taint flow, then instead of
26+ * importing `DefaultFlowTest`, you can import `TaintFlowTest<DefaultFlowConfig>`. In both cases
27+ * `DefaultFlowConfig` can be replaced by another implementation of `DataFlow::ConfigSig`.
3128 *
3229 * If you need more fine-grained tuning, consider implementing a test using `InlineExpectationsTest`.
3330 */
@@ -38,72 +35,62 @@ import codeql.ruby.TaintTracking
3835import TestUtilities.InlineExpectationsTest
3936import TestUtilities.InlineFlowTestUtil
4037
41- class DefaultValueFlowConf extends DataFlow:: Configuration {
42- DefaultValueFlowConf ( ) { this = "qltest:defaultValueFlowConf" }
43-
44- override predicate isSource ( DataFlow:: Node n ) { defaultSource ( n ) }
38+ module DefaultFlowConfig implements DataFlow:: ConfigSig {
39+ predicate isSource ( DataFlow:: Node source ) { defaultSource ( source ) }
4540
46- override predicate isSink ( DataFlow:: Node n ) { defaultSink ( n ) }
41+ predicate isSink ( DataFlow:: Node sink ) { defaultSink ( sink ) }
4742
48- override int fieldFlowBranchLimit ( ) { result = 1000 }
43+ int fieldFlowBranchLimit ( ) { result = 1000 }
4944}
5045
51- class DefaultTaintFlowConf extends TaintTracking :: Configuration {
52- DefaultTaintFlowConf ( ) { this = "qltest:defaultTaintFlowConf" }
46+ private module NoFlowConfig implements DataFlow :: ConfigSig {
47+ predicate isSource ( DataFlow :: Node source ) { none ( ) }
5348
54- override predicate isSource ( DataFlow:: Node n ) { defaultSource ( n ) }
55-
56- override predicate isSink ( DataFlow:: Node n ) { defaultSink ( n ) }
57-
58- override int fieldFlowBranchLimit ( ) { result = 1000 }
49+ predicate isSink ( DataFlow:: Node sink ) { none ( ) }
5950}
6051
61- class InlineFlowTest extends InlineExpectationsTest {
62- InlineFlowTest ( ) { this = "HasFlowTest" }
63-
64- override string getARelevantTag ( ) { result = [ "hasValueFlow" , "hasTaintFlow" ] }
65-
66- override predicate hasActualResult ( Location location , string element , string tag , string value ) {
67- tag = "hasValueFlow" and
68- exists ( DataFlow:: Node src , DataFlow:: Node sink | this .getValueFlowConfig ( ) .hasFlow ( src , sink ) |
69- sink .getLocation ( ) = location and
70- element = sink .toString ( ) and
71- if exists ( getSourceArgString ( src ) ) then value = getSourceArgString ( src ) else value = ""
72- )
73- or
74- tag = "hasTaintFlow" and
75- exists ( DataFlow:: Node src , DataFlow:: Node sink |
76- this .getTaintFlowConfig ( ) .hasFlow ( src , sink ) and
77- not this .getValueFlowConfig ( ) .hasFlow ( src , sink )
78- |
79- sink .getLocation ( ) = location and
80- element = sink .toString ( ) and
81- if exists ( getSourceArgString ( src ) ) then value = getSourceArgString ( src ) else value = ""
82- )
52+ module FlowTest< DataFlow:: ConfigSig ValueFlowConfig, DataFlow:: ConfigSig TaintFlowConfig> {
53+ module ValueFlow = DataFlow:: Global< ValueFlowConfig > ;
54+
55+ module TaintFlow = TaintTracking:: Global< TaintFlowConfig > ;
56+
57+ private module InlineTest implements TestSig {
58+ string getARelevantTag ( ) { result = [ "hasValueFlow" , "hasTaintFlow" ] }
59+
60+ predicate hasActualResult ( Location location , string element , string tag , string value ) {
61+ tag = "hasValueFlow" and
62+ exists ( DataFlow:: Node src , DataFlow:: Node sink | ValueFlow:: flow ( src , sink ) |
63+ sink .getLocation ( ) = location and
64+ element = sink .toString ( ) and
65+ if exists ( getSourceArgString ( src ) ) then value = getSourceArgString ( src ) else value = ""
66+ )
67+ or
68+ tag = "hasTaintFlow" and
69+ exists ( DataFlow:: Node src , DataFlow:: Node sink |
70+ TaintFlow:: flow ( src , sink ) and not ValueFlow:: flow ( src , sink )
71+ |
72+ sink .getLocation ( ) = location and
73+ element = sink .toString ( ) and
74+ if exists ( getSourceArgString ( src ) ) then value = getSourceArgString ( src ) else value = ""
75+ )
76+ }
8377 }
8478
85- DataFlow:: Configuration getValueFlowConfig ( ) { result = any ( DefaultValueFlowConf config ) }
86-
87- DataFlow:: Configuration getTaintFlowConfig ( ) { result = any ( DefaultTaintFlowConf config ) }
88- }
89-
90- module PathGraph {
91- private import DataFlow:: PathGraph as PG
79+ import MakeTest< InlineTest >
80+ import DataFlow:: MergePathGraph< ValueFlow:: PathNode , TaintFlow:: PathNode , ValueFlow:: PathGraph , TaintFlow:: PathGraph >
9281
93- private class PathNode extends DataFlow:: PathNode {
94- PathNode ( ) {
95- this .getConfiguration ( ) =
96- [ any ( InlineFlowTest t ) .getValueFlowConfig ( ) , any ( InlineFlowTest t ) .getTaintFlowConfig ( ) ]
97- }
82+ predicate flowPath ( PathNode source , PathNode sink ) {
83+ ValueFlow:: flowPath ( source .asPathNode1 ( ) , sink .asPathNode1 ( ) ) or
84+ TaintFlow:: flowPath ( source .asPathNode2 ( ) , sink .asPathNode2 ( ) )
9885 }
86+ }
9987
100- /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
101- query predicate edges ( PathNode a , PathNode b ) { PG:: edges ( a , b ) }
88+ module DefaultFlowTest = FlowTest< DefaultFlowConfig , DefaultFlowConfig > ;
10289
103- /** Holds if `n` is a node in the graph of data flow path explanations. */
104- query predicate nodes ( PathNode n , string key , string val ) { PG:: nodes ( n , key , val ) }
90+ module ValueFlowTest< DataFlow:: ConfigSig ValueFlowConfig> {
91+ import FlowTest< ValueFlowConfig , NoFlowConfig >
92+ }
10593
106- query predicate subpaths ( PathNode arg , PathNode par , PathNode ret , PathNode out ) {
107- PG:: subpaths ( arg , par , ret , out )
108- }
94+ module TaintFlowTest< DataFlow:: ConfigSig TaintFlowConfig> {
95+ import FlowTest< NoFlowConfig , TaintFlowConfig >
10996}
0 commit comments