Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

C++: Make node.asExpr() instanceof ArrayAggregateLiteral satisfiable #19511

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
Loading
from

Conversation

MathiasVP
Copy link
Contributor

@MathiasVP MathiasVP commented May 16, 2025

This PR fixes the same problem as #19501, but for ArrayAggregateLiterals. Unlike in the ArrayAggregateLiterals case we don't have a post-update node to use to represent the "fully initialized literal" since array writes aren't handled using post-update nodes. So we can't do quite the same in this case.

In #19501 I said that we should fix the ArrayAggregateLiterals by making use of post-update nodes for array writes. However, that's a really hard task that I don't actually feel like tackling right now 😅

However, we can do something that's almost as good: We can use the last Store instruction as the dataflow node for which node.asExpr() instanceof ArrayAggregateLiteral should hold. This is because, at this point, the literal has been fully initialized and the memory pointed to by the array will contain (among other things) the last expression that was written to it.

This gives us exactly the flow we want. Sadly, the location isn't quite right. In the below example I track flow from:

source.asExpr() instanceof AggregateLiteral

to

sink.asIndirectExpr() = any(Call call | call.getTarget().hasName("sink")).getAnArgument()

and as you can see the location of the source is the location of the last expression in the literal:

Screenshot 2025-05-16 at 20 15 51

I plan on fixing this as a follow-up. The problem is that we don't have the same logic in place to customize the behavior of Node.getLocation() as we do for Node.asExpr. Ideally, the result of Node.getLocation() should be location of Node.asExpr(), if any (as we do for Node.toString). But I'll leave that for a subsequent PR!

@github-actions github-actions bot added the C++ label May 16, 2025
@MathiasVP MathiasVP marked this pull request as ready for review May 16, 2025 23:02
@Copilot Copilot AI review requested due to automatic review settings May 16, 2025 23:02
@MathiasVP MathiasVP requested a review from a team as a code owner May 16, 2025 23:02
Copy link
Contributor

@Copilot 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

Adds support for treating the final store of an array aggregate literal as the expression node for dataflow, updates tests to expect the new {...} placeholder, and records the change in the release notes.

  • Introduce getRankedElementExpr and LastArrayAggregateStore in ExprNodes.qll to map the last store instruction back to its ArrayAggregateLiteral.
  • Update expected test outputs in several .expected files to include *{...} or asExpr={...} where the full aggregate literal is now recognized.
  • Add a change note documenting the fix to asExpr() for array aggregates.

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ExprNodes.qll Add helper to pick the last element store and a class to link it back to the array literal
cpp/ql/test/library-tests/dataflow/asExpr/test.cpp Update test cases to expect asExpr={...} for array aggregate literals
cpp/ql/test/query-tests/Security/CWE/CWE-319/UseOfHttp/UseOfHttp.expected Replace literal values with {...} in flows for array writes
cpp/ql/test/query-tests/Security/CWE/CWE-134/semmle/consts/NonConstantFormat.expected Replace intermediate nodes with {...} for array writes
cpp/ql/lib/change-notes/2025-05-16-array-aggregate-literals.md Document the fix for asExpr() on ArrayAggregateLiteral
Comments suppressed due to low confidence (1)

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/ExprNodes.qll:58

  • [nitpick] The field name aggr is abbreviated and may be unclear. Consider renaming it to arrayLiteral or aggregateLiteral to improve readability.
ArrayAggregateLiteral aggr;

Comment on lines +61 to +63
exists(int rnk |
this.getSourceValue().getUnconvertedResultExpression() = getRankedElementExpr(aggr, rnk) and
not exists(getRankedElementExpr(aggr, rnk + 1))
Copy link
Preview

Copilot AI May 16, 2025

Choose a reason for hiding this comment

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

Field aggr is used in the LastArrayAggregateStore constructor but never bound to a specific ArrayAggregateLiteral. As a result, getArrayAggregateLiteral() may return an uninitialized value. Consider capturing the literal in the exists predicate (e.g., exists(ArrayAggregateLiteral lit | ... and this.aggr = lit)) or otherwise assigning aggr explicitly.

Suggested change
exists(int rnk |
this.getSourceValue().getUnconvertedResultExpression() = getRankedElementExpr(aggr, rnk) and
not exists(getRankedElementExpr(aggr, rnk + 1))
exists(ArrayAggregateLiteral lit, int rnk |
this.aggr = lit and
this.getSourceValue().getUnconvertedResultExpression() = getRankedElementExpr(lit, rnk) and
not exists(getRankedElementExpr(lit, rnk + 1))

Copilot uses AI. Check for mistakes.

Positive FeedbackNegative Feedback
@@ -45,6 +45,28 @@ private module Cached {
)
}

Copy link
Preview

Copilot AI May 16, 2025

Choose a reason for hiding this comment

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

[nitpick] The purpose and behavior of getRankedElementExpr aren't documented. Adding a brief comment explaining how it selects and orders elements by index and position will aid future maintainers.

Suggested change
/**
* Retrieves the expression corresponding to the `rnk`-th ranked element
* in the given array aggregate literal `aggr`.
*
* The function selects elements using the `rank` construct, which ranks
* elements based on their index and position, and orders them by
* `elementIndex` and `position`.
*/

Copilot uses AI. Check for mistakes.

Positive FeedbackNegative Feedback
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.

1 participant
Morty Proxy This is a proxified and sanitized view of the page, visit original site.