From 0c827a55525e75ee3b164e7b65559b49e6de3f47 Mon Sep 17 00:00:00 2001 From: Kasper Svendsen Date: Mon, 23 Jun 2025 09:02:02 +0200 Subject: [PATCH 1/4] Java lib qlpack: Enable overlay compilation --- java/ql/lib/qlpack.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml index c7a6a045451e..c27a06994b2f 100644 --- a/java/ql/lib/qlpack.yml +++ b/java/ql/lib/qlpack.yml @@ -23,3 +23,4 @@ dataExtensions: - ext/generated/*.model.yml - ext/experimental/*.model.yml warnOnImplicitThis: true +compileForOverlayEval: true From 41ef65e4c76e18a70df0183aed559ed397ad3879 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 23 Jun 2025 14:54:26 +0200 Subject: [PATCH 2/4] DataFlow:Run overlay-informed if not diff-informed To ensure good performance, always run data flow overlay-informed unless the configuration has opted in to being diff-informed. This change affects only databases with an overlay and therefore has no immediate production consequences. --- .../internal/DataFlowImplSpecific.qll | 3 ++ shared/dataflow/codeql/dataflow/DataFlow.qll | 12 ++++++ .../dataflow/internal/DataFlowImplStage1.qll | 37 +++++++++++++++++-- 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplSpecific.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplSpecific.qll index 65034ee08b93..97f5020142e0 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplSpecific.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplSpecific.qll @@ -6,6 +6,7 @@ module; private import semmle.code.Location private import codeql.dataflow.DataFlow +private import semmle.code.java.Overlay module Private { import DataFlowPrivate @@ -29,4 +30,6 @@ module JavaDataFlow implements InputSig { predicate mayBenefitFromCallContext = Private::mayBenefitFromCallContext/1; predicate viableImplInCallContext = Private::viableImplInCallContext/2; + + predicate isEvaluatingInOverlay = isOverlay/0; } diff --git a/shared/dataflow/codeql/dataflow/DataFlow.qll b/shared/dataflow/codeql/dataflow/DataFlow.qll index 3483287e3b39..efcd54ff696d 100644 --- a/shared/dataflow/codeql/dataflow/DataFlow.qll +++ b/shared/dataflow/codeql/dataflow/DataFlow.qll @@ -349,6 +349,18 @@ signature module InputSig { /** Holds if `fieldFlowBranchLimit` should be ignored for flow going into/out of `c`. */ 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 Lang> { diff --git a/shared/dataflow/codeql/dataflow/internal/DataFlowImplStage1.qll b/shared/dataflow/codeql/dataflow/internal/DataFlowImplStage1.qll index c7883df0de18..d2ae1c41e662 100644 --- a/shared/dataflow/codeql/dataflow/internal/DataFlowImplStage1.qll +++ b/shared/dataflow/codeql/dataflow/internal/DataFlowImplStage1.qll @@ -4,7 +4,7 @@ * Provides an implementation of a fast initial pruning of global * (interprocedural) data flow reachability (Stage 1). */ -overlay[local?] +overlay[local?] // when this is removed, put `overlay[local?]` on `isOverlayNode`. module; private import codeql.util.Unit @@ -129,14 +129,38 @@ module MakeImplStage1 Lang> { private module AlertFiltering = AlertFilteringImpl; + /** + * 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) + } + + overlay[global] pragma[nomagic] private predicate isFilteredSource(Node source) { Config::isSource(source, _) and if Config::observeDiffInformedIncrementalMode() then AlertFiltering::filterByLocation(Config::getASelectedSourceLocation(source)) - else any() + else ( + // If we are in base-only global evaluation, do not filter out any sources. + not isEvaluatingInOverlay() + or + // If we are in global evaluation with an overlay present, restrict + // sources to those visible in the overlay. + isOverlayNode(source) + ) } + overlay[global] pragma[nomagic] private predicate isFilteredSink(Node sink) { ( @@ -145,7 +169,14 @@ module MakeImplStage1 Lang> { ) and if Config::observeDiffInformedIncrementalMode() then AlertFiltering::filterByLocation(Config::getASelectedSinkLocation(sink)) - else any() + else ( + // If we are in base-only global evaluation, do not filter out any sinks. + not isEvaluatingInOverlay() + or + // If we are in global evaluation with an overlay present, restrict + // sinks to those visible in the overlay. + isOverlayNode(sink) + ) } private predicate hasFilteredSource() { isFilteredSource(_) } From 799b2859fe3b00d4db5b078a23ae8e11ce213aba Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Mon, 30 Jun 2025 13:49:04 +0200 Subject: [PATCH 3/4] DataFlow: overlay-informed flow includes the diff --- .../dataflow/internal/DataFlowImplStage1.qll | 57 ++++++++++++++++--- shared/util/codeql/util/AlertFiltering.qll | 26 ++++++++- 2 files changed, 74 insertions(+), 9 deletions(-) diff --git a/shared/dataflow/codeql/dataflow/internal/DataFlowImplStage1.qll b/shared/dataflow/codeql/dataflow/internal/DataFlowImplStage1.qll index d2ae1c41e662..6e716b74bc33 100644 --- a/shared/dataflow/codeql/dataflow/internal/DataFlowImplStage1.qll +++ b/shared/dataflow/codeql/dataflow/internal/DataFlowImplStage1.qll @@ -144,19 +144,58 @@ module MakeImplStage1 Lang> { exists(node) } + /** + * Holds if `node` comes from a file that was in the diff for which we + * are producing results. + */ + overlay[global] + private predicate isDiffFileNode(Node node) { + exists(string filePath | + node.getLocation().hasLocationInfo(filePath, _, _, _, _) and + AlertFiltering::fileIsInDiff(filePath) + ) + } + overlay[global] pragma[nomagic] private predicate isFilteredSource(Node source) { Config::isSource(source, _) and - if Config::observeDiffInformedIncrementalMode() - then AlertFiltering::filterByLocation(Config::getASelectedSourceLocation(source)) + // Data flow is always incremental in one of two ways. + // 1. If the configuration is diff-informed and diff information is + // available, we filter to only include nodes in the diff, which + // gives the smallest set of nodes. + // 2. If not, in global evaluation with overlay, we filter to only + // include nodes from files in the overlay or the diff; flow from + // other nodes will be added back later. There can be two reasons + // why we are in this case: + // 1. This could be the primary configuration for a query that + // hasn't yet become diff-informed. In that case, the + // `getASelectedSourceLocation` information is probably just the + // default, and it's a fairly safe overapproximation to + // effectively expand to all nodes in the file (via + // `isDiffFileNode`). + // 2. This could be a secondary configuration, like a helper + // configuration for finding sources or sinks of a primary + // configuration. In that case, the results of this configuration + // are typically in the same file as the final alert. + if + Config::observeDiffInformedIncrementalMode() and + AlertFiltering::diffInformationAvailable() + then AlertFiltering::locationIsInDiff(Config::getASelectedSourceLocation(source)) else ( // If we are in base-only global evaluation, do not filter out any sources. not isEvaluatingInOverlay() or // If we are in global evaluation with an overlay present, restrict - // sources to those visible in the overlay. + // sources to those visible in the overlay or isOverlayNode(source) + or + // those from files in the diff. The diff is a subset of the overlay + // in the common case, but this is not guaranteed. Including the diff here + // ensures that we re-evaluate flow that passes from a file in the + // diff (but in the base), through a file in the overlay with + // possibly important changes, back to the base. + isDiffFileNode(source) ) } @@ -167,15 +206,17 @@ module MakeImplStage1 Lang> { Config::isSink(sink, _) or Config::isSink(sink) ) and - if Config::observeDiffInformedIncrementalMode() - then AlertFiltering::filterByLocation(Config::getASelectedSinkLocation(sink)) + // See the comments in `isFilteredSource` for the reasoning behind the following. + if + Config::observeDiffInformedIncrementalMode() and + AlertFiltering::diffInformationAvailable() + then AlertFiltering::locationIsInDiff(Config::getASelectedSinkLocation(sink)) else ( - // If we are in base-only global evaluation, do not filter out any sinks. not isEvaluatingInOverlay() or - // If we are in global evaluation with an overlay present, restrict - // sinks to those visible in the overlay. isOverlayNode(sink) + or + isDiffFileNode(sink) ) } diff --git a/shared/util/codeql/util/AlertFiltering.qll b/shared/util/codeql/util/AlertFiltering.qll index bfc9d901b2fa..aabd42c7dbb2 100644 --- a/shared/util/codeql/util/AlertFiltering.qll +++ b/shared/util/codeql/util/AlertFiltering.qll @@ -82,6 +82,21 @@ module AlertFilteringImpl { ) } + /** 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 intersects the diff range. When that is the * case, ensuring that alerts mentioning this location are included in the @@ -103,8 +118,17 @@ module AlertFilteringImpl { */ bindingset[location] predicate filterByLocation(Location location) { - not restrictAlertsTo(_, _, _) and not restrictAlertsToExactLocation(_, _, _, _, _) + not diffInformationAvailable() 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 | restrictAlertsToEntireFile(filePath) and location.hasLocationInfo(filePath, _, _, _, _) From 19acc8dfe7302ed28e8656ea2049ca3bce2de9a8 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Fri, 4 Jul 2025 10:18:05 +0200 Subject: [PATCH 4/4] TEMP: DataFlow: Java-only flow including base This won't work for other languages until we can annotate a `forceLocal` call with `local?`. --- .../codeql/dataflow/internal/DataFlowImpl.qll | 63 ++++++++++++++++++- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll b/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll index a7e0736432ac..f06faafcf964 100644 --- a/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll +++ b/shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll @@ -3376,24 +3376,81 @@ module MakeImpl Lang> { import S6 /** - * Holds if data can flow from `source` to `sink`. + * Holds if data can flow from `source` to `sink`. When running in overlay + * incremental mode on a supported language, this predicate only has + * results where either the source or sink is in the overlay database. */ - predicate flow(Node source, Node sink) { + private predicate flowIncremental(Node source, Node sink) { exists(PathNode source0, PathNode sink0 | flowPath(source0, sink0) and source0.getNode() = source and sink0.getNode() = sink ) } + overlay[local] + private predicate flowLocal(Node source, Node sink) = + forceLocal(flowIncremental/2)(source, sink) + + /** + * Holds if data can flow from `source` to `sink`. + */ + predicate flow(Node source, Node sink) { + flowIncremental(source, sink) + or + flowLocal(source, sink) + } + + /** + * Holds if data can flow from some source to `sink`. When running in + * overlay incremental mode on a supported language, this predicate only + * has results where either the source or sink is in the overlay database. + */ + private predicate flowToIncremental(Node sink) { + exists(PathNode n | n.isSink() and n.getNode() = sink) + } + + overlay[local] + private predicate flowToLocal(Node sink) = forceLocal(flowToIncremental/1)(sink) + /** * Holds if data can flow from some source to `sink`. */ - predicate flowTo(Node sink) { exists(PathNode n | n.isSink() and n.getNode() = sink) } + predicate flowTo(Node sink) { + flowToIncremental(sink) + or + flowToLocal(sink) + } /** * Holds if data can flow from some source to `sink`. */ predicate flowToExpr(Expr sink) { flowTo(exprNode(sink)) } + /** + * Holds if data can flow from `source` to some sink. When running in + * overlay incremental mode on a supported language, this predicate only + * has results where either the source or sink is in the overlay database. + */ + private predicate flowFromIncremental(Node source) { + exists(PathNode n | n.isSource() and n.getNode() = source) + } + + overlay[local] + private predicate flowFromLocal(Node source) = forceLocal(flowFromIncremental/1)(source) + + /** + * Holds if data can flow from `source` to some sink. + */ + predicate flowFrom(Node source) { + flowFromIncremental(source) + or + flowFromLocal(source) + } + + /** + * Holds if data can flow from `source` to some sink. + */ + predicate flowFromExpr(Expr source) { flowFrom(exprNode(source)) } + /** * INTERNAL: Only for debugging. * pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy