Skip to content

C++: Modernize MustFlow and fix allowInterproceduralFlow in the case of direct recursion#21331

Merged
jketema merged 7 commits intogithub:mainfrom
jketema:must-flow
Feb 17, 2026
Merged

C++: Modernize MustFlow and fix allowInterproceduralFlow in the case of direct recursion#21331
jketema merged 7 commits intogithub:mainfrom
jketema:must-flow

Conversation

@jketema
Copy link
Contributor

@jketema jketema commented Feb 16, 2026

Commit-by-commit review is recommended.

@github-actions github-actions bot added the C++ label Feb 16, 2026
@jketema jketema changed the title C++: Modernize MustFlow using parameterized modules C++: Modernize MustFlow and fix allowInterproceduralFlow in the case of direct recursion Feb 17, 2026
@jketema jketema marked this pull request as ready for review February 17, 2026 11:54
@jketema jketema requested a review from a team as a code owner February 17, 2026 11:54
Copilot AI review requested due to automatic review settings February 17, 2026 11:54
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Modernizes the C++ MustFlow CodeQL library to parameterized modules and fixes allowInterproceduralFlow behavior for direct recursion, updating dependent queries and adding a regression test.

Changes:

  • Reworked MustFlow into MustFlow::ConfigSig + MustFlow::Global<...> and updated queries to use module instances and instance-specific PathGraph.
  • Adjusted interprocedural stepping so allowInterproceduralFlow() { none() } blocks direct recursion.
  • Added a C++ test case covering direct recursion for return-of-stack-address analysis.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
cpp/ql/test/query-tests/Likely Bugs/Memory Management/ReturnStackAllocatedMemory/test.cpp Adds regression test for direct recursion case.
cpp/ql/src/Likely Bugs/OO/UnsafeUseOfThis.ql Migrates query to new MustFlow::Global module instantiation and updated path node types.
cpp/ql/src/Likely Bugs/Memory Management/UninitializedLocal.ql Migrates query to new MustFlow module API, including instance-specific PathGraph.
cpp/ql/src/Likely Bugs/Memory Management/ReturnStackAllocatedMemory.ql Migrates query to new MustFlow module API and updates path problem wiring.
cpp/ql/lib/semmle/code/cpp/ir/dataflow/MustFlow.qll Major refactor: introduces MustFlow::ConfigSig and MustFlow::Global, adjusts interprocedural recursion handling.
cpp/ql/lib/change-notes/2026-02-14-must-flow.md Documents the breaking API change for MustFlow.
cpp/ql/lib/change-notes/2026-02-14-must-flow-fix.md Documents the recursion-related fix in must-flow configs.

* The corresponding paths are generated from the end-points and the graph
* included in the module `PathGraph`.
*/
predicate flowPath(PathNode source, PathSink sink) {
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flowPath is exported but its signature exposes PathSink, which is a private class. This makes the public API awkward for consumers (they can’t name PathSink in their own type declarations). Consider changing flowPath to accept PathNode for the sink parameter and enforce sink instanceof PathSink in the body, or make PathSink non-private (and document it as part of the API).

Suggested change
predicate flowPath(PathNode source, PathSink sink) {
predicate flowPath(PathNode source, PathNode sink) {
sink instanceof PathSink and

Copilot uses AI. Check for mistakes.
Comment on lines +129 to +131
private class PathSink extends PathNode {
PathSink() { isSink(this.getInstruction().getAUse()) }
}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flowPath is exported but its signature exposes PathSink, which is a private class. This makes the public API awkward for consumers (they can’t name PathSink in their own type declarations). Consider changing flowPath to accept PathNode for the sink parameter and enforce sink instanceof PathSink in the body, or make PathSink non-private (and document it as part of the API).

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@geoffw0 geoffw0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeQL changes and DCA LGTM.

int x;
int* px = f_rec(&x); // GOOD
return p;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is a bit odd because it never returns, so of course it doesn't return stack allocated memory. I don't think that's the point of the test though - can we make it return, e.g. by adding an iteration count?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can change it, but do observe that it was producing an FP (366ebca) which is fixed by 4efbc6e

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that conditional stuff also means there is no longer a must-flow relation. So even before the changes from this PR the following does not produce an alert:

int* f_rec_n(int *p, int n) {
  int x;
  if (n != 0)
    int* px = f_rec(&x, n - 1);
  return p;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I think we should leave the test as-is, even though it looks "wrong".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I was a bit concerned about (1) readability and (2) if at some point we excluded dead code from the query, this test would no longer cover what it's supposed to (because return p is simply dead code). But given what you've said above, a fix for (2) is likely to make (1) worse.

Lets leave it as it is then.

@jketema jketema merged commit 61dc1d6 into github:main Feb 17, 2026
29 of 30 checks passed
@jketema jketema deleted the must-flow branch February 17, 2026 16:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MustFlowConfiguration::allowInterproceduralFlow doesn't work for recursive functions

2 participants