C++: Rewrite flow test common to use inline expectation test module

This also rewrites all uses of flow test common to use `DataFlow::ConfigSig`.

Note that the removed deprecated aliases are 14 months old by now and, hence,
can be safely removed.
This commit is contained in:
Jeroen Ketema
2023-05-23 16:26:47 +02:00
parent ee36d32ef0
commit aeb6293757
13 changed files with 83 additions and 79 deletions

View File

@@ -16,18 +16,16 @@ private import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as IRDataFlow
private import semmle.code.cpp.dataflow.DataFlow::DataFlow as AstDataFlow
import TestUtilities.InlineExpectationsTest
class IRFlowTest extends InlineExpectationsTest {
IRFlowTest() { this = "IRFlowTest" }
module IRFlowTest<IRDataFlow::GlobalFlowSig Flow> implements TestSig {
string getARelevantTag() { result = "ir" }
override string getARelevantTag() { result = "ir" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(IRDataFlow::Node source, IRDataFlow::Node sink, IRDataFlow::Configuration conf, int n |
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(IRDataFlow::Node source, IRDataFlow::Node sink, int n |
tag = "ir" and
conf.hasFlow(source, sink) and
Flow::flow(source, sink) and
n =
strictcount(int line, int column |
conf.hasFlow(any(IRDataFlow::Node otherSource |
Flow::flow(any(IRDataFlow::Node otherSource |
otherSource.hasLocationInfo(_, line, column, _, _)
), sink)
) and
@@ -47,20 +45,16 @@ class IRFlowTest extends InlineExpectationsTest {
}
}
class AstFlowTest extends InlineExpectationsTest {
AstFlowTest() { this = "ASTFlowTest" }
module AstFlowTest<AstDataFlow::GlobalFlowSig Flow> implements TestSig {
string getARelevantTag() { result = "ast" }
override string getARelevantTag() { result = "ast" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(
AstDataFlow::Node source, AstDataFlow::Node sink, AstDataFlow::Configuration conf, int n
|
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(AstDataFlow::Node source, AstDataFlow::Node sink, int n |
tag = "ast" and
conf.hasFlow(source, sink) and
Flow::flow(source, sink) and
n =
strictcount(int line, int column |
conf.hasFlow(any(AstDataFlow::Node otherSource |
Flow::flow(any(AstDataFlow::Node otherSource |
otherSource.hasLocationInfo(_, line, column, _, _)
), sink)
) and
@@ -79,6 +73,3 @@ class AstFlowTest extends InlineExpectationsTest {
)
}
}
/** DEPRECATED: Alias for AstFlowTest */
deprecated class ASTFlowTest = AstFlowTest;

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -16,10 +16,8 @@ module AstTest {
}
/** Common data flow configuration to be used by tests. */
class AstTestAllocationConfig extends DataFlow::Configuration {
AstTestAllocationConfig() { this = "ASTTestAllocationConfig" }
override predicate isSource(DataFlow::Node source) {
module AstTestAllocationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
or
source.asParameter().getName().matches("source%")
@@ -32,18 +30,20 @@ module AstTest {
exists(source.asUninitialized())
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call |
call.getTarget().getName() = ["sink", "indirect_sink"] and
sink.asExpr() = call.getAnArgument()
)
}
override predicate isBarrier(DataFlow::Node barrier) {
predicate isBarrier(DataFlow::Node barrier) {
barrier.asExpr().(VariableAccess).getTarget().hasName("barrier") or
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getABarrierNode()
}
}
module AstFlow = DataFlow::Global<AstTestAllocationConfig>;
}
module IRTest {
@@ -67,10 +67,8 @@ module IRTest {
}
/** Common data flow configuration to be used by tests. */
class IRTestAllocationConfig extends DataFlow::Configuration {
IRTestAllocationConfig() { this = "IRTestAllocationConfig" }
override predicate isSource(DataFlow::Node source) {
module IRTestAllocationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
or
source.asIndirectExpr(1).(FunctionCall).getTarget().getName() = "indirect_source"
@@ -82,7 +80,7 @@ module IRTest {
exists(source.asUninitialized())
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call, Expr e | e = call.getAnArgument() |
call.getTarget().getName() = "sink" and
sink.asExpr() = e
@@ -92,7 +90,7 @@ module IRTest {
)
}
override predicate isBarrier(DataFlow::Node barrier) {
predicate isBarrier(DataFlow::Node barrier) {
exists(Expr barrierExpr | barrierExpr in [barrier.asExpr(), barrier.asIndirectExpr()] |
barrierExpr.(VariableAccess).getTarget().hasName("barrier")
)
@@ -102,4 +100,8 @@ module IRTest {
barrier = DataFlow::BarrierGuard<testBarrierGuard/3>::getAnIndirectBarrierNode()
}
}
module IRFlow = DataFlow::Global<IRTestAllocationConfig>;
}
import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>>

View File

@@ -1,10 +1,8 @@
private import semmle.code.cpp.dataflow.DataFlow
private import DataFlow
class AstConf extends Configuration {
AstConf() { this = "ASTFieldFlowConf" }
override predicate isSource(Node src) {
module AstConfig implements ConfigSig {
predicate isSource(Node src) {
src.asExpr() instanceof NewExpr
or
src.asExpr().(Call).getTarget().hasName("user_input")
@@ -15,14 +13,14 @@ class AstConf extends Configuration {
)
}
override predicate isSink(Node sink) {
predicate isSink(Node sink) {
exists(Call c |
c.getTarget().hasName("sink") and
c.getAnArgument() = sink.asExpr()
)
}
override predicate isAdditionalFlowStep(Node a, Node b) {
predicate isAdditionalFlowStep(Node a, Node b) {
b.asPartialDefinition() =
any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr())
.getQualifier()
@@ -31,5 +29,4 @@ class AstConf extends Configuration {
}
}
/** DEPRECATED: Alias for AstConf */
deprecated class ASTConf = AstConf;
module AstFlow = Global<AstConfig>;

View File

@@ -1,10 +1,8 @@
private import semmle.code.cpp.ir.dataflow.DataFlow
private import DataFlow
class IRConf extends Configuration {
IRConf() { this = "IRFieldFlowConf" }
override predicate isSource(Node src) {
module IRConfig implements ConfigSig {
predicate isSource(Node src) {
src.asExpr() instanceof NewExpr
or
src.asExpr().(Call).getTarget().hasName("user_input")
@@ -15,14 +13,14 @@ class IRConf extends Configuration {
)
}
override predicate isSink(Node sink) {
predicate isSink(Node sink) {
exists(Call c |
c.getTarget().hasName("sink") and
c.getAnArgument() = [sink.asExpr(), sink.asIndirectExpr(), sink.asConvertedExpr()]
)
}
override predicate isAdditionalFlowStep(Node a, Node b) {
predicate isAdditionalFlowStep(Node a, Node b) {
b.asPartialDefinition() =
any(Call c | c.getTarget().hasName("insert") and c.getAnArgument() = a.asExpr())
.getQualifier()
@@ -30,3 +28,5 @@ class IRConf extends Configuration {
b.asExpr().(AddressOfExpr).getOperand() = a.asExpr()
}
}
module IRFlow = Global<IRConfig>;

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -1,9 +1,11 @@
import TestUtilities.dataflow.FlowTestCommon
module AstTest {
private import ASTConfiguration
import ASTConfiguration
}
module IRTest {
private import IRConfiguration
import IRConfiguration
}
import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>>

View File

@@ -4,8 +4,8 @@
import semmle.code.cpp.ir.dataflow.DataFlow
import IRConfiguration
import DataFlow::PathGraph
import IRFlow::PathGraph
from DataFlow::PathNode src, DataFlow::PathNode sink, IRConf conf
where conf.hasFlowPath(src, sink)
from IRFlow::PathNode src, IRFlow::PathNode sink
where IRFlow::flowPath(src, sink)
select sink, src, sink, sink + " flows from $@", src, src.toString()

View File

@@ -4,8 +4,8 @@
import semmle.code.cpp.dataflow.DataFlow
import ASTConfiguration
import DataFlow::PathGraph
import AstFlow::PathGraph
from DataFlow::PathNode src, DataFlow::PathNode sink, AstConf conf
where conf.hasFlowPath(src, sink)
from AstFlow::PathNode src, AstFlow::PathNode sink
where AstFlow::flowPath(src, sink)
select sink, src, sink, sink + " flows from $@", src, src.toString()

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -3,37 +3,39 @@ import TestUtilities.dataflow.FlowTestCommon
module AstTest {
private import semmle.code.cpp.dataflow.TaintTracking
class AstSmartPointerTaintConfig extends TaintTracking::Configuration {
AstSmartPointerTaintConfig() { this = "ASTSmartPointerTaintConfig" }
override predicate isSource(DataFlow::Node source) {
module AstSmartPointerTaintConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call |
call.getTarget().getName() = "sink" and
sink.asExpr() = call.getAnArgument()
)
}
}
module AstFlow = TaintTracking::Global<AstSmartPointerTaintConfig>;
}
module IRTest {
private import semmle.code.cpp.ir.dataflow.TaintTracking
class IRSmartPointerTaintConfig extends TaintTracking::Configuration {
IRSmartPointerTaintConfig() { this = "IRSmartPointerTaintConfig" }
override predicate isSource(DataFlow::Node source) {
module IRSmartPointerTaintConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call |
call.getTarget().getName() = "sink" and
sink.asExpr() = call.getAnArgument()
)
}
}
module IRFlow = TaintTracking::Global<IRSmartPointerTaintConfig>;
}
import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>>

View File

@@ -0,0 +1,2 @@
failures
testFailures

View File

@@ -43,10 +43,8 @@ module AstTest {
private import semmle.code.cpp.models.interfaces.Taint
/** Common data flow configuration to be used by tests. */
class AstTestAllocationConfig extends TaintTracking::Configuration {
AstTestAllocationConfig() { this = "ASTTestAllocationConfig" }
override predicate isSource(DataFlow::Node source) {
module AstTestAllocationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
or
source.asParameter().getName().matches("source%")
@@ -60,17 +58,19 @@ module AstTest {
)
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call |
call.getTarget().getName() = "sink" and
sink.asExpr() = call.getAnArgument()
)
}
override predicate isSanitizer(DataFlow::Node barrier) {
predicate isBarrier(DataFlow::Node barrier) {
barrier.asExpr().(VariableAccess).getTarget().hasName("sanitizer")
}
}
module AstFlow = TaintTracking::Global<AstTestAllocationConfig>;
}
module IRTest {
@@ -78,10 +78,8 @@ module IRTest {
private import semmle.code.cpp.ir.dataflow.TaintTracking
/** Common data flow configuration to be used by tests. */
class TestAllocationConfig extends TaintTracking::Configuration {
TestAllocationConfig() { this = "TestAllocationConfig" }
override predicate isSource(DataFlow::Node source) {
module TestAllocationConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) {
source.asExpr().(FunctionCall).getTarget().getName() = "source"
or
source.asIndirectExpr().(FunctionCall).getTarget().getName() = "source"
@@ -94,21 +92,25 @@ module IRTest {
)
}
override predicate isSink(DataFlow::Node sink) {
predicate isSink(DataFlow::Node sink) {
exists(FunctionCall call |
call.getTarget().getName() = "sink" and
[sink.asExpr(), sink.asIndirectExpr()] = call.getAnArgument()
)
}
override predicate isSanitizer(DataFlow::Node barrier) {
predicate isBarrier(DataFlow::Node barrier) {
barrier.asExpr().(VariableAccess).getTarget().hasName("sanitizer")
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
// allow arbitrary reads at sinks
this.isSink(node) and
isSink(node) and
c.(DataFlow::FieldContent).getField().getDeclaringType() = node.getType().getUnspecifiedType()
}
}
module IRFlow = TaintTracking::Global<TestAllocationConfig>;
}
import MakeTest<MergeTests<AstFlowTest<AstTest::AstFlow>, IRFlowTest<IRTest::IRFlow>>>