mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge pull request #14050 from jketema/inline-6
Consolidate all `InlineFlowTest` libraries in the dataflow qlpack
This commit is contained in:
@@ -3,19 +3,6 @@
|
||||
* See `shared/util/codeql/util/test/InlineExpectationsTest.qll`
|
||||
*/
|
||||
|
||||
private import csharp as CS
|
||||
private import codeql.util.test.InlineExpectationsTest
|
||||
|
||||
private module Impl implements InlineExpectationsTestSig {
|
||||
/**
|
||||
* A class representing line comments in C# used by the InlineExpectations core code
|
||||
*/
|
||||
class ExpectationComment extends CS::SinglelineComment {
|
||||
/** Gets the contents of the given comment, _without_ the preceding comment marker (`//`). */
|
||||
string getContents() { result = this.getText() }
|
||||
}
|
||||
|
||||
class Location = CS::Location;
|
||||
}
|
||||
|
||||
private import internal.InlineExpectationsTestImpl
|
||||
import Make<Impl>
|
||||
|
||||
@@ -1,120 +1,34 @@
|
||||
/**
|
||||
* Provides a simple base test for flow-related tests using inline expectations.
|
||||
*
|
||||
* Example for a test.ql:
|
||||
* ```ql
|
||||
* import csharp
|
||||
* import TestUtilities.InlineFlowTest
|
||||
* import DefaultFlowTest
|
||||
* import PathGraph
|
||||
*
|
||||
* from PathNode source, PathNode sink
|
||||
* where flowPath(source, sink)
|
||||
* select sink, source, sink, "$@", source, source.toString()
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files.
|
||||
* Example of the corresponding test file, e.g. Test.cs
|
||||
* ```csharp
|
||||
* public class Test
|
||||
* {
|
||||
* object Source() { return null; }
|
||||
* string Taint() { return null; }
|
||||
* void Sink(object o) { }
|
||||
*
|
||||
* public void test()
|
||||
* {
|
||||
* var s = Source(1);
|
||||
* Sink(s); // $ hasValueFlow=1
|
||||
* var t = "foo" + Taint(2);
|
||||
* Sink(t); // $ hasTaintFlow=2
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* If you are only interested in value flow, then instead of importing `DefaultFlowTest`, you can import
|
||||
* `ValueFlowTest<DefaultFlowConfig>`. Similarly, if you are only interested in taint flow, then instead of
|
||||
* importing `DefaultFlowTest`, you can import `TaintFlowTest<DefaultFlowConfig>`. In both cases
|
||||
* `DefaultFlowConfig` can be replaced by another implementation of `DataFlow::ConfigSig`.
|
||||
*
|
||||
* If you need more fine-grained tuning, consider implementing a test using `InlineExpectationsTest`.
|
||||
* Inline flow tests for CSharp.
|
||||
* See `shared/util/codeql/dataflow/test/InlineFlowTest.qll`
|
||||
*/
|
||||
|
||||
import csharp
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
private import codeql.dataflow.test.InlineFlowTest
|
||||
private import semmle.code.csharp.dataflow.internal.DataFlowImplSpecific
|
||||
private import semmle.code.csharp.dataflow.internal.TaintTrackingImplSpecific
|
||||
private import internal.InlineExpectationsTestImpl
|
||||
|
||||
private predicate defaultSource(DataFlow::Node source) {
|
||||
source.asExpr().(MethodCall).getTarget().getUndecoratedName() = ["Source", "Taint"]
|
||||
}
|
||||
|
||||
private predicate defaultSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc | mc.getTarget().hasUndecoratedName("Sink") |
|
||||
sink.asExpr() = mc.getAnArgument()
|
||||
)
|
||||
}
|
||||
|
||||
module DefaultFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { defaultSource(source) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { defaultSink(sink) }
|
||||
|
||||
int fieldFlowBranchLimit() { result = 1000 }
|
||||
}
|
||||
|
||||
private module NoFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
private string getSourceArgString(DataFlow::Node src) {
|
||||
defaultSource(src) and
|
||||
src.asExpr().(MethodCall).getAnArgument().getValue() = result
|
||||
}
|
||||
|
||||
module FlowTest<DataFlow::ConfigSig ValueFlowConfig, DataFlow::ConfigSig TaintFlowConfig> {
|
||||
module ValueFlow = DataFlow::Global<ValueFlowConfig>;
|
||||
|
||||
module TaintFlow = TaintTracking::Global<TaintFlowConfig>;
|
||||
|
||||
private module InlineTest implements TestSig {
|
||||
string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasValueFlow" and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink | ValueFlow::flow(src, sink) |
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
|
||||
)
|
||||
or
|
||||
tag = "hasTaintFlow" and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
TaintFlow::flow(src, sink) and not ValueFlow::flow(src, sink)
|
||||
|
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
|
||||
)
|
||||
}
|
||||
private module FlowTestImpl implements InputSig<CsharpDataFlow> {
|
||||
predicate defaultSource(DataFlow::Node source) {
|
||||
source.asExpr().(MethodCall).getTarget().getUndecoratedName() = ["Source", "Taint"]
|
||||
}
|
||||
|
||||
import MakeTest<InlineTest>
|
||||
import DataFlow::MergePathGraph<ValueFlow::PathNode, TaintFlow::PathNode, ValueFlow::PathGraph, TaintFlow::PathGraph>
|
||||
predicate defaultSink(DataFlow::Node sink) {
|
||||
exists(MethodCall mc | mc.getTarget().hasUndecoratedName("Sink") |
|
||||
sink.asExpr() = mc.getAnArgument()
|
||||
)
|
||||
}
|
||||
|
||||
predicate flowPath(PathNode source, PathNode sink) {
|
||||
ValueFlow::flowPath(source.asPathNode1(), sink.asPathNode1()) or
|
||||
TaintFlow::flowPath(source.asPathNode2(), sink.asPathNode2())
|
||||
private string getSourceArgString(DataFlow::Node src) {
|
||||
defaultSource(src) and
|
||||
src.asExpr().(MethodCall).getAnArgument().getValue() = result
|
||||
}
|
||||
|
||||
string getArgString(DataFlow::Node src, DataFlow::Node sink) {
|
||||
(if exists(getSourceArgString(src)) then result = getSourceArgString(src) else result = "") and
|
||||
exists(sink)
|
||||
}
|
||||
}
|
||||
|
||||
module DefaultFlowTest = FlowTest<DefaultFlowConfig, DefaultFlowConfig>;
|
||||
|
||||
module ValueFlowTest<DataFlow::ConfigSig ValueFlowConfig> {
|
||||
import FlowTest<ValueFlowConfig, NoFlowConfig>
|
||||
}
|
||||
|
||||
module TaintFlowTest<DataFlow::ConfigSig TaintFlowConfig> {
|
||||
import FlowTest<NoFlowConfig, TaintFlowConfig>
|
||||
}
|
||||
import InlineFlowTestMake<CsharpDataFlow, CsharpTaintTracking, Impl, FlowTestImpl>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
private import csharp as CS
|
||||
private import codeql.util.test.InlineExpectationsTest
|
||||
|
||||
module Impl implements InlineExpectationsTestSig {
|
||||
/**
|
||||
* A class representing line comments in C# used by the InlineExpectations core code
|
||||
*/
|
||||
class ExpectationComment extends CS::SinglelineComment {
|
||||
/** Gets the contents of the given comment, _without_ the preceding comment marker (`//`). */
|
||||
string getContents() { result = this.getText() }
|
||||
}
|
||||
|
||||
class Location = CS::Location;
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
failures
|
||||
testFailures
|
||||
edges
|
||||
| A.cs:5:17:5:28 | call to method Source<C> : C | A.cs:6:24:6:24 | access to local variable c : C |
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
failures
|
||||
testFailures
|
||||
edges
|
||||
| Operator.cs:9:39:9:39 | x : C | Operator.cs:9:50:9:50 | access to parameter x : C |
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
failures
|
||||
testFailures
|
||||
edges
|
||||
nodes
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
failures
|
||||
testFailures
|
||||
edges
|
||||
| Tuples.cs:7:18:7:34 | call to method Source<Object> : Object | Tuples.cs:10:21:10:22 | access to local variable o1 : Object |
|
||||
|
||||
@@ -3,20 +3,6 @@
|
||||
* See `shared/util/codeql/util/test/InlineExpectationsTest.qll`
|
||||
*/
|
||||
|
||||
private import go as G
|
||||
private import codeql.util.test.InlineExpectationsTest
|
||||
|
||||
private module Impl implements InlineExpectationsTestSig {
|
||||
/**
|
||||
* A class representing line comments in the Go style, including the
|
||||
* preceding comment marker (`//`).
|
||||
*/
|
||||
class ExpectationComment extends G::Comment {
|
||||
/** Returns the contents of the given comment, _without_ the preceding comment marker (`//`). */
|
||||
string getContents() { result = this.getText() }
|
||||
}
|
||||
|
||||
class Location = G::Location;
|
||||
}
|
||||
|
||||
private import internal.InlineExpectationsTestImpl
|
||||
import Make<Impl>
|
||||
|
||||
@@ -1,112 +1,29 @@
|
||||
/**
|
||||
* Provides a simple base test for flow-related tests using inline expectations.
|
||||
*
|
||||
* Example for a test.ql:
|
||||
* ```ql
|
||||
* import go
|
||||
* import TestUtilities.InlineFlowTest
|
||||
* import DefaultFlowTest
|
||||
* import PathGraph
|
||||
*
|
||||
* from PathNode source, PathNode sink
|
||||
* where flowPath(source, sink)
|
||||
* select sink, source, sink, "$@", source, source.toString()
|
||||
* ```
|
||||
*
|
||||
* To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files.
|
||||
* Example of the corresponding test file, e.g. Test.go
|
||||
* ```go
|
||||
* func source() string { return ""; }
|
||||
* func taint() string { return ""; }
|
||||
* func sink(s string) { }
|
||||
*
|
||||
* func test() {
|
||||
* s := source()
|
||||
* sink(s) // $ hasValueFlow="s"
|
||||
* t := "foo" + taint()
|
||||
* sink(t) // $ hasTaintFlow="t"
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* If you are only interested in value flow, then instead of importing `DefaultFlowTest`, you can import
|
||||
* `ValueFlowTest<DefaultFlowConfig>`. Similarly, if you are only interested in taint flow, then instead of
|
||||
* importing `DefaultFlowTest`, you can import `TaintFlowTest<DefaultFlowConfig>`. In both cases
|
||||
* `DefaultFlowConfig` can be replaced by another implementation of `DataFlow::ConfigSig`.
|
||||
*
|
||||
* If you need more fine-grained tuning, consider implementing a test using `InlineExpectationsTest`.
|
||||
* Inline flow tests for Go.
|
||||
* See `shared/util/codeql/dataflow/test/InlineFlowTest.qll`
|
||||
*/
|
||||
|
||||
import go
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
private import codeql.dataflow.test.InlineFlowTest
|
||||
private import semmle.go.dataflow.internal.DataFlowImplSpecific
|
||||
private import semmle.go.dataflow.internal.TaintTrackingImplSpecific
|
||||
private import internal.InlineExpectationsTestImpl
|
||||
|
||||
private predicate defaultSource(DataFlow::Node source) {
|
||||
exists(Function fn | fn.hasQualifiedName(_, ["source", "taint"]) |
|
||||
source = fn.getACall().getResult()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate defaultSink(DataFlow::Node sink) {
|
||||
exists(Function fn | fn.hasQualifiedName(_, "sink") | sink = fn.getACall().getAnArgument())
|
||||
}
|
||||
|
||||
module DefaultFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { defaultSource(source) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { defaultSink(sink) }
|
||||
|
||||
int fieldFlowBranchLimit() { result = 1000 }
|
||||
}
|
||||
|
||||
private module NoFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
module FlowTest<DataFlow::ConfigSig ValueFlowConfig, DataFlow::ConfigSig TaintFlowConfig> {
|
||||
module ValueFlow = DataFlow::Global<ValueFlowConfig>;
|
||||
|
||||
module TaintFlow = TaintTracking::Global<TaintFlowConfig>;
|
||||
|
||||
private module InlineTest implements TestSig {
|
||||
string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasValueFlow" and
|
||||
exists(DataFlow::Node sink | ValueFlow::flowTo(sink) |
|
||||
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
|
||||
element = sink.toString() and
|
||||
value = "\"" + sink.toString() + "\""
|
||||
)
|
||||
or
|
||||
tag = "hasTaintFlow" and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
TaintFlow::flow(src, sink) and not ValueFlow::flow(src, sink)
|
||||
|
|
||||
sink.hasLocationInfo(location.getFile().getAbsolutePath(), location.getStartLine(),
|
||||
location.getStartColumn(), location.getEndLine(), location.getEndColumn()) and
|
||||
element = sink.toString() and
|
||||
value = "\"" + sink.toString() + "\""
|
||||
)
|
||||
}
|
||||
private module FlowTestImpl implements InputSig<GoDataFlow> {
|
||||
predicate defaultSource(DataFlow::Node source) {
|
||||
exists(Function fn | fn.hasQualifiedName(_, ["source", "taint"]) |
|
||||
source = fn.getACall().getResult()
|
||||
)
|
||||
}
|
||||
|
||||
import MakeTest<InlineTest>
|
||||
import DataFlow::MergePathGraph<ValueFlow::PathNode, TaintFlow::PathNode, ValueFlow::PathGraph, TaintFlow::PathGraph>
|
||||
predicate defaultSink(DataFlow::Node sink) {
|
||||
exists(Function fn | fn.hasQualifiedName(_, "sink") | sink = fn.getACall().getAnArgument())
|
||||
}
|
||||
|
||||
predicate flowPath(PathNode source, PathNode sink) {
|
||||
ValueFlow::flowPath(source.asPathNode1(), sink.asPathNode1()) or
|
||||
TaintFlow::flowPath(source.asPathNode2(), sink.asPathNode2())
|
||||
string getArgString(DataFlow::Node src, DataFlow::Node sink) {
|
||||
exists(src) and
|
||||
result = "\"" + sink.toString() + "\""
|
||||
}
|
||||
}
|
||||
|
||||
module DefaultFlowTest = FlowTest<DefaultFlowConfig, DefaultFlowConfig>;
|
||||
|
||||
module ValueFlowTest<DataFlow::ConfigSig ValueFlowConfig> {
|
||||
import FlowTest<ValueFlowConfig, NoFlowConfig>
|
||||
}
|
||||
|
||||
module TaintFlowTest<DataFlow::ConfigSig TaintFlowConfig> {
|
||||
import FlowTest<NoFlowConfig, TaintFlowConfig>
|
||||
}
|
||||
import InlineFlowTestMake<GoDataFlow, GoTaintTracking, Impl, FlowTestImpl>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
private import go as G
|
||||
private import codeql.util.test.InlineExpectationsTest
|
||||
|
||||
module Impl implements InlineExpectationsTestSig {
|
||||
/**
|
||||
* A class representing line comments in the Go style, including the
|
||||
* preceding comment marker (`//`).
|
||||
*/
|
||||
class ExpectationComment extends G::Comment {
|
||||
/** Returns the contents of the given comment, _without_ the preceding comment marker (`//`). */
|
||||
string getContents() { result = this.getText() }
|
||||
}
|
||||
|
||||
class Location = G::Location;
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
failures
|
||||
edges
|
||||
| test.go:9:9:9:11 | selection of c [collection] | test.go:9:7:9:11 | <-... |
|
||||
| test.go:13:16:13:16 | definition of s [pointer, c, collection] | test.go:16:2:16:2 | s [pointer, c, collection] |
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
failures
|
||||
invalidModelRow
|
||||
testFailures
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
failures
|
||||
invalidModelRow
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
failures
|
||||
edges
|
||||
| test.go:14:8:14:15 | call to source | test.go:15:34:15:35 | fi |
|
||||
| test.go:15:2:15:44 | ... := ...[0] | test.go:16:7:16:12 | header |
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import go
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
module ValueFlow = DataFlow::Global<DefaultFlowConfig>;
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -3,40 +3,6 @@
|
||||
* See `shared/util/codeql/util/test/InlineExpectationsTest.qll`
|
||||
*/
|
||||
|
||||
private import java as J
|
||||
private import codeql.util.test.InlineExpectationsTest
|
||||
|
||||
private module Impl implements InlineExpectationsTestSig {
|
||||
/**
|
||||
* A class representing line comments in Java, which is simply Javadoc restricted
|
||||
* to EOL comments, with an extra accessor used by the InlineExpectations core code
|
||||
*/
|
||||
abstract class ExpectationComment extends J::Top {
|
||||
/** Gets the contents of the given comment, _without_ the preceding comment marker (`//`). */
|
||||
abstract string getContents();
|
||||
}
|
||||
|
||||
private class JavadocExpectationComment extends J::Javadoc, ExpectationComment {
|
||||
JavadocExpectationComment() { isEolComment(this) }
|
||||
|
||||
override string getContents() { result = this.getChild(0).toString() }
|
||||
}
|
||||
|
||||
private class KtExpectationComment extends J::KtComment, ExpectationComment {
|
||||
KtExpectationComment() { this.isEolComment() }
|
||||
|
||||
override string getContents() { result = this.getText().suffix(2).trim() }
|
||||
}
|
||||
|
||||
private class XmlExpectationComment extends ExpectationComment instanceof J::XmlComment {
|
||||
override string getContents() { result = super.getText().trim() }
|
||||
|
||||
override Location getLocation() { result = J::XmlComment.super.getLocation() }
|
||||
|
||||
override string toString() { result = J::XmlComment.super.toString() }
|
||||
}
|
||||
|
||||
class Location = J::Location;
|
||||
}
|
||||
|
||||
private import internal.InlineExpectationsTestImpl
|
||||
import Make<Impl>
|
||||
|
||||
@@ -1,119 +1,33 @@
|
||||
/**
|
||||
* Provides a simple base test for flow-related tests using inline expectations.
|
||||
*
|
||||
* Example for a test.ql:
|
||||
* ```ql
|
||||
* import java
|
||||
* import TestUtilities.InlineFlowTest
|
||||
* import DefaultFlowTest
|
||||
* import PathGraph
|
||||
*
|
||||
* from PathNode source, PathNode sink
|
||||
* where flowPath(source, sink)
|
||||
* select sink, source, sink, "$@", source, source.toString()
|
||||
* ```
|
||||
*
|
||||
* To declare expectations, you can use the $hasTaintFlow or $hasValueFlow comments within the test source files.
|
||||
* Example of the corresponding test file, e.g. Test.java
|
||||
* ```java
|
||||
* public class Test {
|
||||
*
|
||||
* Object source() { return null; }
|
||||
* String taint() { return null; }
|
||||
* void sink(Object o) { }
|
||||
*
|
||||
* public void test() {
|
||||
* Object s = source();
|
||||
* sink(s); // $ hasValueFlow
|
||||
* String t = "foo" + taint();
|
||||
* sink(t); // $ hasTaintFlow
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* If you are only interested in value flow, then instead of importing `DefaultFlowTest`, you can import
|
||||
* `ValueFlowTest<DefaultFlowConfig>`. Similarly, if you are only interested in taint flow, then instead of
|
||||
* importing `DefaultFlowTest`, you can import `TaintFlowTest<DefaultFlowConfig>`. In both cases
|
||||
* `DefaultFlowConfig` can be replaced by another implementation of `DataFlow::ConfigSig`.
|
||||
*
|
||||
* If you need more fine-grained tuning, consider implementing a test using `InlineExpectationsTest`.
|
||||
* Inline flow tests for Java.
|
||||
* See `shared/util/codeql/dataflow/test/InlineFlowTest.qll`
|
||||
*/
|
||||
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.ExternalFlow
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
private import codeql.dataflow.test.InlineFlowTest
|
||||
private import semmle.code.java.dataflow.internal.DataFlowImplSpecific
|
||||
private import semmle.code.java.dataflow.internal.TaintTrackingImplSpecific
|
||||
private import internal.InlineExpectationsTestImpl
|
||||
|
||||
private predicate defaultSource(DataFlow::Node source) {
|
||||
source.asExpr().(MethodAccess).getMethod().getName() = ["source", "taint"]
|
||||
}
|
||||
|
||||
private predicate defaultSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma | ma.getMethod().hasName("sink") | sink.asExpr() = ma.getAnArgument())
|
||||
}
|
||||
|
||||
module DefaultFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { defaultSource(source) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { defaultSink(sink) }
|
||||
|
||||
int fieldFlowBranchLimit() { result = 1000 }
|
||||
}
|
||||
|
||||
private module NoFlowConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { none() }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { none() }
|
||||
}
|
||||
|
||||
private string getSourceArgString(DataFlow::Node src) {
|
||||
defaultSource(src) and
|
||||
src.asExpr().(MethodAccess).getAnArgument().(StringLiteral).getValue() = result
|
||||
}
|
||||
|
||||
module FlowTest<DataFlow::ConfigSig ValueFlowConfig, DataFlow::ConfigSig TaintFlowConfig> {
|
||||
module ValueFlow = DataFlow::Global<ValueFlowConfig>;
|
||||
|
||||
module TaintFlow = TaintTracking::Global<TaintFlowConfig>;
|
||||
|
||||
private module InlineTest implements TestSig {
|
||||
string getARelevantTag() { result = ["hasValueFlow", "hasTaintFlow"] }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasValueFlow" and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink | ValueFlow::flow(src, sink) |
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
|
||||
)
|
||||
or
|
||||
tag = "hasTaintFlow" and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink |
|
||||
TaintFlow::flow(src, sink) and not ValueFlow::flow(src, sink)
|
||||
|
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
if exists(getSourceArgString(src)) then value = getSourceArgString(src) else value = ""
|
||||
)
|
||||
}
|
||||
private module FlowTestImpl implements InputSig<JavaDataFlow> {
|
||||
predicate defaultSource(DataFlow::Node source) {
|
||||
source.asExpr().(MethodAccess).getMethod().getName() = ["source", "taint"]
|
||||
}
|
||||
|
||||
import MakeTest<InlineTest>
|
||||
import DataFlow::MergePathGraph<ValueFlow::PathNode, TaintFlow::PathNode, ValueFlow::PathGraph, TaintFlow::PathGraph>
|
||||
predicate defaultSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess ma | ma.getMethod().hasName("sink") | sink.asExpr() = ma.getAnArgument())
|
||||
}
|
||||
|
||||
predicate flowPath(PathNode source, PathNode sink) {
|
||||
ValueFlow::flowPath(source.asPathNode1(), sink.asPathNode1()) or
|
||||
TaintFlow::flowPath(source.asPathNode2(), sink.asPathNode2())
|
||||
private string getSourceArgString(DataFlow::Node src) {
|
||||
defaultSource(src) and
|
||||
src.asExpr().(MethodAccess).getAnArgument().(StringLiteral).getValue() = result
|
||||
}
|
||||
|
||||
string getArgString(DataFlow::Node src, DataFlow::Node sink) {
|
||||
(if exists(getSourceArgString(src)) then result = getSourceArgString(src) else result = "") and
|
||||
exists(sink)
|
||||
}
|
||||
}
|
||||
|
||||
module DefaultFlowTest = FlowTest<DefaultFlowConfig, DefaultFlowConfig>;
|
||||
|
||||
module ValueFlowTest<DataFlow::ConfigSig ValueFlowConfig> {
|
||||
import FlowTest<ValueFlowConfig, NoFlowConfig>
|
||||
}
|
||||
|
||||
module TaintFlowTest<DataFlow::ConfigSig TaintFlowConfig> {
|
||||
import FlowTest<NoFlowConfig, TaintFlowConfig>
|
||||
}
|
||||
import InlineFlowTestMake<JavaDataFlow, JavaTaintTracking, Impl, FlowTestImpl>
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
private import java as J
|
||||
private import codeql.util.test.InlineExpectationsTest
|
||||
|
||||
module Impl implements InlineExpectationsTestSig {
|
||||
/**
|
||||
* A class representing line comments in Java, which is simply Javadoc restricted
|
||||
* to EOL comments, with an extra accessor used by the InlineExpectations core code
|
||||
*/
|
||||
abstract class ExpectationComment extends J::Top {
|
||||
/** Gets the contents of the given comment, _without_ the preceding comment marker (`//`). */
|
||||
abstract string getContents();
|
||||
}
|
||||
|
||||
private class JavadocExpectationComment extends J::Javadoc, ExpectationComment {
|
||||
JavadocExpectationComment() { isEolComment(this) }
|
||||
|
||||
override string getContents() { result = this.getChild(0).toString() }
|
||||
}
|
||||
|
||||
private class KtExpectationComment extends J::KtComment, ExpectationComment {
|
||||
KtExpectationComment() { this.isEolComment() }
|
||||
|
||||
override string getContents() { result = this.getText().suffix(2).trim() }
|
||||
}
|
||||
|
||||
private class XmlExpectationComment extends ExpectationComment instanceof J::XmlComment {
|
||||
override string getContents() { result = super.getText().trim() }
|
||||
|
||||
override Location getLocation() { result = J::XmlComment.super.getLocation() }
|
||||
|
||||
override string toString() { result = J::XmlComment.super.toString() }
|
||||
}
|
||||
|
||||
class Location = J::Location;
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
failures
|
||||
testFailures
|
||||
| test.kt:28:14:28:21 | getSecond(...) | Unexpected result: hasTaintFlow=a |
|
||||
| test.kt:35:14:35:27 | component1(...) | Unexpected result: hasTaintFlow=d |
|
||||
| test.kt:41:14:41:22 | getSecond(...) | Unexpected result: hasTaintFlow=e |
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
invalidModelRow
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.ExternalFlow
|
||||
import TestUtilities.InlineFlowTest
|
||||
import DefaultFlowTest
|
||||
import ModelValidation
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
valueOf
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.ExternalFlow
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
module OkHttpFlowConfig implements DataFlow::ConfigSig {
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import java
|
||||
import semmle.code.java.dataflow.DataFlow
|
||||
import semmle.code.java.dataflow.ExternalFlow
|
||||
import TestUtilities.InlineFlowTest
|
||||
|
||||
module FlowConfig implements DataFlow::ConfigSig {
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
failures
|
||||
testFailures
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user