Skip to content

Commit 799b285

Browse files
committed
DataFlow: overlay-informed flow includes the diff
1 parent 41ef65e commit 799b285

File tree

2 files changed

+74
-9
lines changed

2 files changed

+74
-9
lines changed

shared/dataflow/codeql/dataflow/internal/DataFlowImplStage1.qll

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -144,19 +144,58 @@ module MakeImplStage1<LocationSig Location, InputSig<Location> Lang> {
144144
exists(node)
145145
}
146146

147+
/**
148+
* Holds if `node` comes from a file that was in the diff for which we
149+
* are producing results.
150+
*/
151+
overlay[global]
152+
private predicate isDiffFileNode(Node node) {
153+
exists(string filePath |
154+
node.getLocation().hasLocationInfo(filePath, _, _, _, _) and
155+
AlertFiltering::fileIsInDiff(filePath)
156+
)
157+
}
158+
147159
overlay[global]
148160
pragma[nomagic]
149161
private predicate isFilteredSource(Node source) {
150162
Config::isSource(source, _) and
151-
if Config::observeDiffInformedIncrementalMode()
152-
then AlertFiltering::filterByLocation(Config::getASelectedSourceLocation(source))
163+
// Data flow is always incremental in one of two ways.
164+
// 1. If the configuration is diff-informed and diff information is
165+
// available, we filter to only include nodes in the diff, which
166+
// gives the smallest set of nodes.
167+
// 2. If not, in global evaluation with overlay, we filter to only
168+
// include nodes from files in the overlay or the diff; flow from
169+
// other nodes will be added back later. There can be two reasons
170+
// why we are in this case:
171+
// 1. This could be the primary configuration for a query that
172+
// hasn't yet become diff-informed. In that case, the
173+
// `getASelectedSourceLocation` information is probably just the
174+
// default, and it's a fairly safe overapproximation to
175+
// effectively expand to all nodes in the file (via
176+
// `isDiffFileNode`).
177+
// 2. This could be a secondary configuration, like a helper
178+
// configuration for finding sources or sinks of a primary
179+
// configuration. In that case, the results of this configuration
180+
// are typically in the same file as the final alert.
181+
if
182+
Config::observeDiffInformedIncrementalMode() and
183+
AlertFiltering::diffInformationAvailable()
184+
then AlertFiltering::locationIsInDiff(Config::getASelectedSourceLocation(source))
153185
else (
154186
// If we are in base-only global evaluation, do not filter out any sources.
155187
not isEvaluatingInOverlay()
156188
or
157189
// If we are in global evaluation with an overlay present, restrict
158-
// sources to those visible in the overlay.
190+
// sources to those visible in the overlay or
159191
isOverlayNode(source)
192+
or
193+
// those from files in the diff. The diff is a subset of the overlay
194+
// in the common case, but this is not guaranteed. Including the diff here
195+
// ensures that we re-evaluate flow that passes from a file in the
196+
// diff (but in the base), through a file in the overlay with
197+
// possibly important changes, back to the base.
198+
isDiffFileNode(source)
160199
)
161200
}
162201

@@ -167,15 +206,17 @@ module MakeImplStage1<LocationSig Location, InputSig<Location> Lang> {
167206
Config::isSink(sink, _) or
168207
Config::isSink(sink)
169208
) and
170-
if Config::observeDiffInformedIncrementalMode()
171-
then AlertFiltering::filterByLocation(Config::getASelectedSinkLocation(sink))
209+
// See the comments in `isFilteredSource` for the reasoning behind the following.
210+
if
211+
Config::observeDiffInformedIncrementalMode() and
212+
AlertFiltering::diffInformationAvailable()
213+
then AlertFiltering::locationIsInDiff(Config::getASelectedSinkLocation(sink))
172214
else (
173-
// If we are in base-only global evaluation, do not filter out any sinks.
174215
not isEvaluatingInOverlay()
175216
or
176-
// If we are in global evaluation with an overlay present, restrict
177-
// sinks to those visible in the overlay.
178217
isOverlayNode(sink)
218+
or
219+
isDiffFileNode(sink)
179220
)
180221
}
181222

shared/util/codeql/util/AlertFiltering.qll

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,21 @@ module AlertFilteringImpl<LocationSig Location> {
8282
)
8383
}
8484

85+
/** Holds if diff information is available in this evaluation. */
86+
predicate diffInformationAvailable() {
87+
restrictAlertsTo(_, _, _) or restrictAlertsToExactLocation(_, _, _, _, _)
88+
}
89+
90+
/**
91+
* Holds if diff information is available, and `filePath` is in the diff
92+
* range.
93+
*/
94+
predicate fileIsInDiff(string filePath) {
95+
restrictAlertsTo(filePath, _, _)
96+
or
97+
restrictAlertsToExactLocation(filePath, _, _, _, _)
98+
}
99+
85100
/**
86101
* Holds if the given location intersects the diff range. When that is the
87102
* case, ensuring that alerts mentioning this location are included in the
@@ -103,8 +118,17 @@ module AlertFilteringImpl<LocationSig Location> {
103118
*/
104119
bindingset[location]
105120
predicate filterByLocation(Location location) {
106-
not restrictAlertsTo(_, _, _) and not restrictAlertsToExactLocation(_, _, _, _, _)
121+
not diffInformationAvailable()
107122
or
123+
locationIsInDiff(location)
124+
}
125+
126+
/**
127+
* Like `filterByLocation`, except that if there is no diff range, this
128+
* predicate never holds.
129+
*/
130+
bindingset[location]
131+
predicate locationIsInDiff(Location location) {
108132
exists(string filePath |
109133
restrictAlertsToEntireFile(filePath) and
110134
location.hasLocationInfo(filePath, _, _, _, _)

0 commit comments

Comments
 (0)