diff --git a/python/ql/src/Functions/ModificationOfParameterWithDefault.ql b/python/ql/src/Functions/ModificationOfParameterWithDefault.ql index 88b346fd2a0..3c601091694 100644 --- a/python/ql/src/Functions/ModificationOfParameterWithDefault.ql +++ b/python/ql/src/Functions/ModificationOfParameterWithDefault.ql @@ -13,11 +13,11 @@ import python import semmle.python.functions.ModificationOfParameterWithDefault -import DataFlow::PathGraph +import ModificationOfParameterWithDefault::Flow::PathGraph from - ModificationOfParameterWithDefault::Configuration config, DataFlow::PathNode source, - DataFlow::PathNode sink -where config.hasFlowPath(source, sink) + ModificationOfParameterWithDefault::Flow::PathNode source, + ModificationOfParameterWithDefault::Flow::PathNode sink +where ModificationOfParameterWithDefault::Flow::flowPath(source, sink) select sink.getNode(), source, sink, "This expression mutates a $@.", source.getNode(), "default value" diff --git a/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefault.qll b/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefault.qll index 24103a33ace..a0838772515 100644 --- a/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefault.qll +++ b/python/ql/src/semmle/python/functions/ModificationOfParameterWithDefault.qll @@ -16,9 +16,11 @@ module ModificationOfParameterWithDefault { import ModificationOfParameterWithDefaultCustomizations::ModificationOfParameterWithDefault /** + * DEPRECATED: Use `Flow` module instead. + * * A data-flow configuration for detecting modifications of a parameters default value. */ - class Configuration extends DataFlow::Configuration { + deprecated class Configuration extends DataFlow::Configuration { /** Record whether the default value being tracked is non-empty. */ boolean nonEmptyDefault; @@ -43,4 +45,33 @@ module ModificationOfParameterWithDefault { nonEmptyDefault = false and node instanceof MustBeNonEmpty } } + + private module Config implements DataFlow::StateConfigSig { + class FlowState = boolean; + + predicate isSource(DataFlow::Node source, FlowState state) { + source.(Source).isNonEmpty() = state + } + + predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + predicate isSink(DataFlow::Node sink, FlowState state) { + // dummy implementation since this predicate is required, but actual logic is in + // the predicate above. + none() + } + + predicate isBarrier(DataFlow::Node node, FlowState state) { + // if we are tracking a non-empty default, then it is ok to modify empty values, + // so our tracking ends at those. + state = true and node instanceof MustBeEmpty + or + // if we are tracking a empty default, then it is ok to modify non-empty values, + // so our tracking ends at those. + state = false and node instanceof MustBeNonEmpty + } + } + + /** Global data-flow for detecting modifications of a parameters default value. */ + module Flow = DataFlow::GlobalWithState; } diff --git a/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.ql b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.ql index 97a01fd4b5f..eaf935d573b 100644 --- a/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.ql +++ b/python/ql/test/query-tests/Functions/ModificationOfParameterWithDefault/test.ql @@ -8,7 +8,7 @@ module ModificationOfParameterWithDefaultTest implements TestSig { string getARelevantTag() { result = "modification" } private predicate relevant_node(DataFlow::Node sink) { - exists(ModificationOfParameterWithDefault::Configuration cfg | cfg.hasFlowTo(sink)) + ModificationOfParameterWithDefault::Flow::flowTo(sink) } predicate hasActualResult(Location location, string element, string tag, string value) {