From 3e97fc9c19dd3f1509bf7e50dc84d816f97b638c Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 16 Sep 2026 12:45:16 -0700 Subject: [PATCH 1/2] Improve localTaint predicate performance in STLContainer. Previous implementation was using nomagic to prevent bad joins from being introduced in localTaint. However, this forces the evaluator to construct the entire graph of local taint paths, which is about 25 million tuples on pandas. This blocks updating to new dataflow where the performance issues get worse. The evaluator creates `additionalTaintStep+`, a relation with 6.7 billion rows. This is done via a higher-order-predicate and is surprisingly fast (8sec). However, the next step takes the `+`-style transitive closure and tries to make the `*` version, by unioning the `+` version with a scan of all dataflow nodes n into tuples (n, n)`. I don't know why this union OOMs, to be honest, but the crash stack trace includes an "unsorted relation writer," which maybe indicates that the OOM comes from trying to sort the 6.7 billion values. In any case, I'm satisfied that we shouldn't be constructing a 6.7 billion relation here. Fixed by identifying the root candidate set of expressions that come from container function calls that we're interested in, which is 799 nodes on pandas, and then the transitive relation `containerTaint` is just 1765 rows on old dataflow. On new dataflow this is 701 sources and 5779 nodes in the transitive closure. --- .../cpp/standardlibrary/STLContainers.qll | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/standardlibrary/STLContainers.qll b/cpp/common/src/codingstandards/cpp/standardlibrary/STLContainers.qll index 64a1aee3b4..3e53fbba8e 100644 --- a/cpp/common/src/codingstandards/cpp/standardlibrary/STLContainers.qll +++ b/cpp/common/src/codingstandards/cpp/standardlibrary/STLContainers.qll @@ -312,9 +312,30 @@ abstract class ContainerAccess extends VariableAccess { abstract Variable getOwningContainer(); } -pragma[noinline, nomagic] -private predicate localTaint(DataFlow::Node n1, DataFlow::Node n2) { - TaintTracking::localTaint(n1, n2) +pragma[nomagic] +private predicate containerTaintSource(FunctionCall fc, DataFlow::Node n1) { + n1 = DataFlow::exprNode(fc) and + exists(STLContainer c | + fc = c.getACallToAFunction() and + // There are a few cases where the value is tainted + // but no actual link to the underlying container is established. + // For example, calling Vector.size() returns an int but the + // resulting variable doesn't depend on the underlying container + // anymore. + ( + fc.getTarget().getType() instanceof ReferenceType or + fc.getTarget().getType() instanceof PointerType or + fc.getTarget().getType() instanceof IteratorType + ) + ) +} + +pragma[nomagic] +private predicate containerTaint(FunctionCall fc, DataFlow::Node n2) { + exists(DataFlow::Node n1 | + containerTaintSource(fc, n1) and + TaintTracking::localTaint(n1, n2) + ) } /** @@ -326,19 +347,8 @@ class ContainerPointerOrReferenceAccess extends ContainerAccess { Variable owningContainer; ContainerPointerOrReferenceAccess() { - exists(STLContainer c, FunctionCall fc | - fc = c.getACallToAFunction() and - // There are a few cases where the value is tainted - // but no actual link to the underlying container is established. - // For example, calling Vector.size() returns an int but the - // resulting variable doesn't depend on the underlying container - // anymore. - ( - fc.getTarget().getType() instanceof ReferenceType or - fc.getTarget().getType() instanceof PointerType or - fc.getTarget().getType() instanceof IteratorType - ) and - localTaint(DataFlow::exprNode(fc), DataFlow::exprNode(this)) and + exists(FunctionCall fc | + containerTaint(fc, DataFlow::exprNode(this)) and (getUnderlyingType() instanceof ReferenceType or getUnderlyingType() instanceof PointerType) and fc.getQualifier().(VariableAccess).getTarget() = owningContainer and // Exclude cases where we see taint into the owning container From af9a3cb5e1eb56b4670ecf64e28cb3f83c155981 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 16 Sep 2026 14:31:46 -0700 Subject: [PATCH 2/2] Add changenote --- .../2026-09-16-improve-iterator-access-check-performance.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 change_notes/2026-09-16-improve-iterator-access-check-performance.md diff --git a/change_notes/2026-09-16-improve-iterator-access-check-performance.md b/change_notes/2026-09-16-improve-iterator-access-check-performance.md new file mode 100644 index 0000000000..b5f71a1d3b --- /dev/null +++ b/change_notes/2026-09-16-improve-iterator-access-check-performance.md @@ -0,0 +1,2 @@ + - All queries using `Iterators.qll` or `STLContainers.qll`: + - The means of detecting iterator and container accesses has been optimized to improve performance by avoiding construction of the full transitive closure of local taint paths. \ No newline at end of file