Merge pull request #20386 from github/alexet/overlay-informed-dataflow

Dataflow: Overlay informed dataflow.
This commit is contained in:
Alexander Eyers-Taylor
2025-10-07 20:22:57 +01:00
committed by GitHub
8 changed files with 530 additions and 133 deletions

View File

@@ -10,6 +10,6 @@ import java
module DataFlow { module DataFlow {
private import semmle.code.java.dataflow.internal.DataFlowImplSpecific private import semmle.code.java.dataflow.internal.DataFlowImplSpecific
private import codeql.dataflow.DataFlow private import codeql.dataflow.DataFlow
import DataFlowMake<Location, JavaDataFlow> import DataFlowMakeOverlay<Location, JavaDataFlow>
import Public import Public
} }

View File

@@ -13,5 +13,5 @@ module TaintTracking {
private import semmle.code.java.dataflow.internal.DataFlowImplSpecific private import semmle.code.java.dataflow.internal.DataFlowImplSpecific
private import semmle.code.java.dataflow.internal.TaintTrackingImplSpecific private import semmle.code.java.dataflow.internal.TaintTrackingImplSpecific
private import codeql.dataflow.TaintTracking private import codeql.dataflow.TaintTracking
import TaintFlowMake<Location, JavaDataFlow, JavaTaintTracking> import TaintFlowMakeOverlay<Location, JavaDataFlow, JavaTaintTracking>
} }

View File

@@ -6,6 +6,7 @@ module;
private import semmle.code.Location private import semmle.code.Location
private import codeql.dataflow.DataFlow private import codeql.dataflow.DataFlow
private import semmle.code.java.Overlay
module Private { module Private {
import DataFlowPrivate import DataFlowPrivate
@@ -29,4 +30,6 @@ module JavaDataFlow implements InputSig<Location> {
predicate mayBenefitFromCallContext = Private::mayBenefitFromCallContext/1; predicate mayBenefitFromCallContext = Private::mayBenefitFromCallContext/1;
predicate viableImplInCallContext = Private::viableImplInCallContext/2; predicate viableImplInCallContext = Private::viableImplInCallContext/2;
predicate isEvaluatingInOverlay = isOverlay/0;
} }

View File

@@ -349,6 +349,18 @@ signature module InputSig<LocationSig Location> {
/** Holds if `fieldFlowBranchLimit` should be ignored for flow going into/out of `c`. */ /** Holds if `fieldFlowBranchLimit` should be ignored for flow going into/out of `c`. */
default predicate ignoreFieldFlowBranchLimit(DataFlowCallable c) { none() } default predicate ignoreFieldFlowBranchLimit(DataFlowCallable c) { none() }
/**
* Holds if the evaluator is currently evaluating with an overlay. The
* implementation of this predicate needs to be `overlay[local]`. For a
* language with no overlay support, `none()` is a valid implementation.
*
* When called from a local predicate, this predicate holds if we are in the
* overlay-only local evaluation. When called from a global predicate, this
* predicate holds if we are evaluating globally with overlay and base both
* visible.
*/
default predicate isEvaluatingInOverlay() { none() }
} }
module Configs<LocationSig Location, InputSig<Location> Lang> { module Configs<LocationSig Location, InputSig<Location> Lang> {
@@ -645,10 +657,8 @@ private module PathGraphSigMod {
} }
} }
module DataFlowMake<LocationSig Location, InputSig<Location> Lang> { private module DataFlowMakeCore<LocationSig Location, InputSig<Location> Lang> {
private import Lang private import Lang
private import internal.DataFlowImpl::MakeImpl<Location, Lang>
private import internal.DataFlowImplStage1::MakeImplStage1<Location, Lang>
import Configs<Location, Lang> import Configs<Location, Lang>
/** /**
@@ -691,59 +701,6 @@ module DataFlowMake<LocationSig Location, InputSig<Location> Lang> {
predicate flowToExpr(DataFlowExpr sink); predicate flowToExpr(DataFlowExpr sink);
} }
/**
* Constructs a global data flow computation.
*/
module Global<ConfigSig Config> implements GlobalFlowSig {
private module C implements FullStateConfigSig {
import DefaultState<Config>
import Config
predicate accessPathLimit = Config::accessPathLimit/0;
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
}
private module Stage1 = ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = Impl<C, Stage1::Stage1NoState>;
import Flow
}
/**
* Constructs a global data flow computation using flow state.
*/
module GlobalWithState<StateConfigSig Config> implements GlobalFlowSig {
private module C implements FullStateConfigSig {
import Config
predicate accessPathLimit = Config::accessPathLimit/0;
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate isAdditionalFlowStep(
Node node1, FlowState state1, Node node2, FlowState state2, string model
) {
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
}
}
private module Stage1 = ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = Impl<C, Stage1::Stage1WithState>;
import Flow
}
signature class PathNodeSig { signature class PathNodeSig {
/** Gets a textual representation of this element. */ /** Gets a textual representation of this element. */
string toString(); string toString();
@@ -1141,3 +1098,135 @@ module DataFlowMake<LocationSig Location, InputSig<Location> Lang> {
import PathGraph import PathGraph
} }
} }
module DataFlowMake<LocationSig Location, InputSig<Location> Lang> {
import DataFlowMakeCore<Location, Lang>
private import Lang
private import internal.DataFlowImpl::MakeImpl<Location, Lang>
private import internal.DataFlowImplStage1::MakeImplStage1<Location, Lang>
/**
* Constructs a global data flow computation.
*/
module Global<ConfigSig Config> implements GlobalFlowSig {
private module C implements FullStateConfigSig {
import DefaultState<Config>
import Config
predicate accessPathLimit = Config::accessPathLimit/0;
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() { none() }
}
private module Stage1 = ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = Impl<C, Stage1::Stage1NoState>;
import Flow
}
/**
* Constructs a global data flow computation using flow state.
*/
module GlobalWithState<StateConfigSig Config> implements GlobalFlowSig {
private module C implements FullStateConfigSig {
import Config
predicate accessPathLimit = Config::accessPathLimit/0;
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate isAdditionalFlowStep(
Node node1, FlowState state1, Node node2, FlowState state2, string model
) {
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() { none() }
}
private module Stage1 = ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = Impl<C, Stage1::Stage1WithState>;
import Flow
}
}
module DataFlowMakeOverlay<LocationSig Location, InputSig<Location> Lang> {
import DataFlowMake<Location, Lang>
private import Lang
private import internal.DataFlowImpl::MakeImpl<Location, Lang>
private import internal.DataFlowImplStage1::MakeImplStage1<Location, Lang>
/**
* Constructs a global data flow computation.
*/
module Global<ConfigSig Config> implements GlobalFlowSig {
private module C implements FullStateConfigSig {
import DefaultState<Config>
import Config
predicate accessPathLimit = Config::accessPathLimit/0;
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() {
not Config::observeDiffInformedIncrementalMode()
}
}
private module Stage1 = ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = OverlayImpl<C, Stage1::Stage1NoState>;
import Flow
}
/**
* Constructs a global data flow computation using flow state.
*/
module GlobalWithState<StateConfigSig Config> implements GlobalFlowSig {
private module C implements FullStateConfigSig {
import Config
predicate accessPathLimit = Config::accessPathLimit/0;
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate isAdditionalFlowStep(
Node node1, FlowState state1, Node node2, FlowState state2, string model
) {
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() {
not Config::observeDiffInformedIncrementalMode()
}
}
private module Stage1 = ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = OverlayImpl<C, Stage1::Stage1WithState>;
import Flow
}
}

View File

@@ -47,16 +47,16 @@ signature module InputSig<LocationSig Location, DF::InputSig<Location> Lang> {
/** /**
* Construct the modules for taint-tracking analyses. * Construct the modules for taint-tracking analyses.
*/ */
module TaintFlowMake< private module TaintFlowMakeCore<
LocationSig Location, DF::InputSig<Location> DataFlowLang, LocationSig Location, DF::InputSig<Location> DataFlowLang,
InputSig<Location, DataFlowLang> TaintTrackingLang> InputSig<Location, DataFlowLang> TaintTrackingLang>
{ {
private import TaintTrackingLang import TaintTrackingLang
private import DF::DataFlowMake<Location, DataFlowLang> as DataFlow import DF::DataFlowMake<Location, DataFlowLang> as DataFlow
private import MakeImpl<Location, DataFlowLang> as DataFlowInternal import MakeImpl<Location, DataFlowLang> as DataFlowInternal
private import MakeImplStage1<Location, DataFlowLang> as DataFlowInternalStage1 import MakeImplStage1<Location, DataFlowLang> as DataFlowInternalStage1
private module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements module AddTaintDefaults<DataFlowInternal::FullStateConfigSig Config> implements
DataFlowInternal::FullStateConfigSig DataFlowInternal::FullStateConfigSig
{ {
import Config import Config
@@ -83,71 +83,9 @@ module TaintFlowMake<
} }
} }
/**
* Constructs a global taint tracking computation.
*/
module Global<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import DataFlowInternal::DefaultState<Config>
import Config
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = DataFlowInternal::Impl<C, Stage1::Stage1NoState>;
import Flow
}
/**
* Constructs a global taint tracking computation using flow state.
*/
module GlobalWithState<DataFlow::StateConfigSig Config> implements DataFlow::GlobalFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import Config
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, FlowState state1, DataFlowLang::Node node2, FlowState state2,
string model
) {
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
}
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = DataFlowInternal::Impl<C, Stage1::Stage1WithState>;
import Flow
}
signature int speculationLimitSig(); signature int speculationLimitSig();
private module AddSpeculativeTaintSteps< module AddSpeculativeTaintSteps<
DataFlowInternal::FullStateConfigSig Config, speculationLimitSig/0 speculationLimit> implements DataFlowInternal::FullStateConfigSig Config, speculationLimitSig/0 speculationLimit> implements
DataFlowInternal::FullStateConfigSig DataFlowInternal::FullStateConfigSig
{ {
@@ -215,6 +153,79 @@ module TaintFlowMake<
state1.getState() = state2.getState() state1.getState() = state2.getState()
} }
} }
}
module TaintFlowMake<
LocationSig Location, DF::InputSig<Location> DataFlowLang,
InputSig<Location, DataFlowLang> TaintTrackingLang>
{
private import TaintFlowMakeCore<Location, DataFlowLang, TaintTrackingLang>
/**
* Constructs a global taint tracking computation.
*/
module Global<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import DataFlowInternal::DefaultState<Config>
import Config
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() { none() }
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = DataFlowInternal::Impl<C, Stage1::Stage1NoState>;
import Flow
}
/**
* Constructs a global taint tracking computation using flow state.
*/
module GlobalWithState<DataFlow::StateConfigSig Config> implements DataFlow::GlobalFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import Config
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, FlowState state1, DataFlowLang::Node node2, FlowState state2,
string model
) {
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() { none() }
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = DataFlowInternal::Impl<C, Stage1::Stage1WithState>;
import Flow
}
/** /**
* Constructs a global taint tracking computation that also allows a given * Constructs a global taint tracking computation that also allows a given
@@ -232,6 +243,8 @@ module TaintFlowMake<
) { ) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config" Config::isAdditionalFlowStep(node1, node2) and model = "Config"
} }
predicate observeOverlayInformedIncrementalMode() { none() }
} }
private module C implements DataFlowInternal::FullStateConfigSig { private module C implements DataFlowInternal::FullStateConfigSig {
@@ -270,6 +283,8 @@ module TaintFlowMake<
) { ) {
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config" Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
} }
predicate observeOverlayInformedIncrementalMode() { none() }
} }
private module C implements DataFlowInternal::FullStateConfigSig { private module C implements DataFlowInternal::FullStateConfigSig {
@@ -285,3 +300,157 @@ module TaintFlowMake<
import Flow import Flow
} }
} }
module TaintFlowMakeOverlay<
LocationSig Location, DF::InputSig<Location> DataFlowLang,
InputSig<Location, DataFlowLang> TaintTrackingLang>
{
private import TaintFlowMakeCore<Location, DataFlowLang, TaintTrackingLang>
/**
* Constructs a global taint tracking computation.
*/
module Global<DataFlow::ConfigSig Config> implements DataFlow::GlobalFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import DataFlowInternal::DefaultState<Config>
import Config
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() {
not Config::observeDiffInformedIncrementalMode()
}
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = DataFlowInternal::OverlayImpl<C, Stage1::Stage1NoState>;
import Flow
}
/**
* Constructs a global taint tracking computation using flow state.
*/
module GlobalWithState<DataFlow::StateConfigSig Config> implements DataFlow::GlobalFlowSig {
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import Config
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, FlowState state1, DataFlowLang::Node node2, FlowState state2,
string model
) {
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() {
not Config::observeDiffInformedIncrementalMode()
}
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<Config0>
}
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = DataFlowInternal::OverlayImpl<C, Stage1::Stage1WithState>;
import Flow
}
/**
* Constructs a global taint tracking computation that also allows a given
* maximum number of speculative taint steps.
*/
module SpeculativeGlobal<DataFlow::ConfigSig Config, speculationLimitSig/0 speculationLimit>
implements DataFlow::GlobalFlowSig
{
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import DataFlowInternal::DefaultState<Config>
import Config
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() {
not Config::observeDiffInformedIncrementalMode()
}
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<AddSpeculativeTaintSteps<Config0, speculationLimit/0>>
}
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = DataFlowInternal::OverlayImpl<C, Stage1::Stage1WithState>;
import Flow
}
/**
* Constructs a global taint tracking computation using flow state that also
* allows a given maximum number of speculative taint steps.
*/
module SpeculativeGlobalWithState<
DataFlow::StateConfigSig Config, speculationLimitSig/0 speculationLimit> implements
DataFlow::GlobalFlowSig
{
private module Config0 implements DataFlowInternal::FullStateConfigSig {
import Config
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, DataFlowLang::Node node2, string model
) {
Config::isAdditionalFlowStep(node1, node2) and model = "Config"
}
predicate isAdditionalFlowStep(
DataFlowLang::Node node1, FlowState state1, DataFlowLang::Node node2, FlowState state2,
string model
) {
Config::isAdditionalFlowStep(node1, state1, node2, state2) and model = "Config"
}
predicate observeOverlayInformedIncrementalMode() {
not Config::observeDiffInformedIncrementalMode()
}
}
private module C implements DataFlowInternal::FullStateConfigSig {
import AddTaintDefaults<AddSpeculativeTaintSteps<Config0, speculationLimit/0>>
}
private module Stage1 = DataFlowInternalStage1::ImplStage1<C>;
import Stage1::PartialFlow
private module Flow = DataFlowInternal::OverlayImpl<C, Stage1::Stage1WithState>;
import Flow
}
}

View File

@@ -143,6 +143,15 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
*/ */
predicate observeDiffInformedIncrementalMode(); predicate observeDiffInformedIncrementalMode();
/**
* Holds if sources and sinks should be filtered to only include those that
* may lead to a flow path with either a source or a sink in the overlay database.
* This only has an effect when running
* in overlay-informed incremental mode. This should be used in conjunction
* with the `OverlayImpl` implementation to merge the base results back in.
*/
predicate observeOverlayInformedIncrementalMode();
Location getASelectedSourceLocation(Node source); Location getASelectedSourceLocation(Node source);
Location getASelectedSinkLocation(Node sink); Location getASelectedSinkLocation(Node sink);
@@ -171,6 +180,56 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
} }
} }
/**
* Constructs a data flow computation given a full input configuration, and
* an initial stage 1 pruning with merging of overlay and base results.
*/
module OverlayImpl<FullStateConfigSig Config, Stage1Output<Config::FlowState> Stage1> {
private module Flow = Impl<Config, Stage1>;
import Flow
/**
* Holds if data can flow from `source` to `sink`.
*
* This is a local predicate that only has results local to the overlay/base database.
*/
private predicate flowLocal(Node source, Node sink) = forceLocal(Flow::flow/2)(source, sink)
/**
* Holds if data can flow from `source` to `sink`.
*/
predicate flow(Node source, Node sink) {
Flow::flow(source, sink)
or
// If we are overlay informed (i.e. we are not diff-informed), we
// merge in the local results which includes the base database results.
flowLocal(source, sink) and Config::observeOverlayInformedIncrementalMode()
}
/**
* Holds if data can flow from some source to `sink`.
* This is a local predicate that only has results local to the overlay/base database.
*/
predicate flowToLocal(Node sink) = forceLocal(Flow::flowTo/1)(sink)
/**
* Holds if data can flow from some source to `sink`.
*/
predicate flowTo(Node sink) {
Flow::flowTo(sink)
or
// If we are overlay informed (i.e. we are not diff-informed), we
// merge in the local results which includes the base database results.
flowToLocal(sink) and Config::observeOverlayInformedIncrementalMode()
}
/**
* Holds if data can flow from some source to `sink`.
*/
predicate flowToExpr(Lang::DataFlowExpr sink) { flowTo(exprNode(sink)) }
}
/** /**
* Constructs a data flow computation given a full input configuration, and * Constructs a data flow computation given a full input configuration, and
* an initial stage 1 pruning. * an initial stage 1 pruning.

View File

@@ -4,7 +4,7 @@
* Provides an implementation of a fast initial pruning of global * Provides an implementation of a fast initial pruning of global
* (interprocedural) data flow reachability (Stage 1). * (interprocedural) data flow reachability (Stage 1).
*/ */
overlay[local?] overlay[local?] // when this is removed, put `overlay[local?]` on `isOverlayNode`.
module; module;
private import codeql.util.Unit private import codeql.util.Unit
@@ -129,23 +129,76 @@ module MakeImplStage1<LocationSig Location, InputSig<Location> Lang> {
private module AlertFiltering = AlertFilteringImpl<Location>; private module AlertFiltering = AlertFilteringImpl<Location>;
/**
* Holds if the given node is visible in overlay-only local evaluation.
*
* This predicate needs to be `overlay[local?]`, either directly or
* through annotations from an outer scope. If `Node` is global for the
* language under analysis, then every node is considered an overlay
* node, which means there will effectively be no overlay-based
* filtering of sources and sinks.
*/
private predicate isOverlayNode(Node node) {
isEvaluatingInOverlay() and
// Any local node is an overlay node if we are evaluating in overlay mode
exists(node)
}
/**
* The filtering if we aren't meant to be diff-informed.
*
* Shared between sources and sinks.
*/
overlay[global]
pragma[inline]
private predicate nonDiffInformedFilter(Node node) {
// If we are in base-only global evaluation, do not filter out any sources/sinks.
not isEvaluatingInOverlay()
or
// If the configuration doesn't merge overlays, do not filter out any sources/sinks.
not Config::observeOverlayInformedIncrementalMode()
or
// If we are in global evaluation with an overlay present, restrict
// sources/sinks to those visible in the overlay.
isOverlayNode(node)
}
overlay[global]
pragma[nomagic] pragma[nomagic]
private predicate isFilteredSource(Node source) { private predicate isFilteredSource(Node source) {
Config::isSource(source, _) and Config::isSource(source, _) and
// Data flow is always incremental in one of two ways.
// 1. If the configuration is diff-informed, we filter to only include nodes in the diff,
// which gives the smallest set of nodes.
// If diff information is not available, we do not filter at all.
// 2. If not, in global evaluation with overlay, we filter to only
// include nodes from files in the overlay; flow from
// other nodes will be added back later.
// We start by seeing if we should be in case 1.
if Config::observeDiffInformedIncrementalMode() if Config::observeDiffInformedIncrementalMode()
then AlertFiltering::filterByLocation(Config::getASelectedSourceLocation(source)) then
else any() // Case 1: We are meant to be diff-informed.
// We still only filter if we have diff information.
AlertFiltering::diffInformationAvailable()
implies
AlertFiltering::locationIsInDiff(Config::getASelectedSourceLocation(source))
else nonDiffInformedFilter(source)
} }
overlay[global]
pragma[nomagic] pragma[nomagic]
private predicate isFilteredSink(Node sink) { private predicate isFilteredSink(Node sink) {
( (
Config::isSink(sink, _) or Config::isSink(sink, _) or
Config::isSink(sink) Config::isSink(sink)
) and ) and
// See the comments in `isFilteredSource` for the reasoning behind the following.
if Config::observeDiffInformedIncrementalMode() if Config::observeDiffInformedIncrementalMode()
then AlertFiltering::filterByLocation(Config::getASelectedSinkLocation(sink)) then
else any() AlertFiltering::diffInformationAvailable()
implies
AlertFiltering::locationIsInDiff(Config::getASelectedSinkLocation(sink))
else nonDiffInformedFilter(sink)
} }
private predicate hasFilteredSource() { isFilteredSource(_) } private predicate hasFilteredSource() { isFilteredSource(_) }

View File

@@ -82,6 +82,21 @@ module AlertFilteringImpl<LocationSig Location> {
) )
} }
/** Holds if diff information is available in this evaluation. */
predicate diffInformationAvailable() {
restrictAlertsTo(_, _, _) or restrictAlertsToExactLocation(_, _, _, _, _)
}
/**
* Holds if diff information is available, and `filePath` is in the diff
* range.
*/
predicate fileIsInDiff(string filePath) {
restrictAlertsTo(filePath, _, _)
or
restrictAlertsToExactLocation(filePath, _, _, _, _)
}
/** /**
* Holds if the given location is a match for one of the active filtering * Holds if the given location is a match for one of the active filtering
* predicates in this module, or if all filtering predicates are inactive * predicates in this module, or if all filtering predicates are inactive
@@ -92,8 +107,17 @@ module AlertFilteringImpl<LocationSig Location> {
*/ */
bindingset[location] bindingset[location]
predicate filterByLocation(Location location) { predicate filterByLocation(Location location) {
not restrictAlertsTo(_, _, _) and not restrictAlertsToExactLocation(_, _, _, _, _) not diffInformationAvailable()
or or
locationIsInDiff(location)
}
/**
* Like `filterByLocation`, except that if there is no diff range, this
* predicate never holds.
*/
bindingset[location]
predicate locationIsInDiff(Location location) {
exists(string filePath | exists(string filePath |
restrictAlertsToEntireFile(filePath) and restrictAlertsToEntireFile(filePath) and
location.hasLocationInfo(filePath, _, _, _, _) location.hasLocationInfo(filePath, _, _, _, _)