Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion rust/ql/.generated.list

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion rust/ql/.gitattributes

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 13 additions & 3 deletions rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -404,10 +404,20 @@ module RustDataFlow implements InputSig<Location> {

/** Gets a viable implementation of the target of the given `Call`. */
DataFlowCallable viableCallable(DataFlowCall call) {
Copy link

Copilot AI Jun 26, 2025

Choose a reason for hiding this comment

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

[nitpick] The viableCallable definition contains deeply nested exists and or expressions; extracting the trait-dispatch logic into a helper predicate could improve readability and maintenance.

Copilot uses AI. Check for mistakes.
exists(Callable target | target = call.asCallCfgNode().getCall().getStaticTarget() |
target = result.asCfgScope()
exists(Call c | c = call.asCallCfgNode().getCall() |
result.asCfgScope() = c.getARuntimeTarget()
or
target = result.asSummarizedCallable()
exists(SummarizedCallable sc, Function staticTarget |
staticTarget = c.getStaticTarget() and
sc = result.asSummarizedCallable()
|
sc = staticTarget
or
// only apply trait models to concrete implementations when they are not
// defined in source code
staticTarget.implements(sc) and
not staticTarget.fromSource()
)
)
}

Expand Down
6 changes: 6 additions & 0 deletions rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
* - `Field[t(i)]`: position `i` inside the variant/struct with canonical path `v`, for example
* `Field[core::option::Option::Some(0)]`.
* - `Field[i]`: the `i`th element of a tuple.
* - `Reference`: the referenced value.
* - `Future`: the value being computed asynchronously.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good spot. 👍

* 3. The `kind` column is a tag that can be referenced from QL to determine to
* which classes the interpreted elements should be added. For example, for
* sources `"remote"` indicates a default remote flow source, and for summaries
Expand Down Expand Up @@ -211,6 +213,10 @@ private class SummarizedCallableFromModel extends SummarizedCallable::Range {
this.getCanonicalPath() = path
}

override predicate hasProvenance(Provenance provenance) {
summaryModel(path, _, _, _, provenance, _)
}

override predicate propagatesFlow(
string input, string output, boolean preservesValue, string model
) {
Expand Down
17 changes: 15 additions & 2 deletions rust/ql/lib/codeql/rust/elements/internal/AssocItemImpl.qll
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// generated by codegen, remove this comment if you wish to edit this file
/**
* This module provides a hand-modifiable wrapper around the generated class `AssocItem`.
*
Expand All @@ -12,6 +11,10 @@ private import codeql.rust.elements.internal.generated.AssocItem
* be referenced directly.
*/
module Impl {
private import rust
private import codeql.rust.internal.PathResolution

// the following QLdoc is generated: if you need to edit it, do it in the schema file
/**
* An associated item in a `Trait` or `Impl`.
*
Expand All @@ -21,5 +24,15 @@ module Impl {
* // ^^^^^^^^^^^^^
* ```
*/
class AssocItem extends Generated::AssocItem { }
class AssocItem extends Generated::AssocItem {
/** Holds if this item implements trait item `other`. */
pragma[nomagic]
predicate implements(AssocItem other) {
exists(TraitItemNode t, ImplItemNode i, string name |
other = t.getAssocItem(pragma[only_bind_into](name)) and
t = i.resolveTraitTy() and
this = i.getAssocItem(pragma[only_bind_into](name))
)
}
}
}
11 changes: 11 additions & 0 deletions rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,17 @@ module Impl {
not exists(TypeInference::resolveMethodCallTarget(this)) and
result = this.(CallExpr).getStaticTarget()
}

/** Gets a runtime target of this call, if any. */
pragma[nomagic]
Function getARuntimeTarget() {
result.hasImplementation() and
(
result = this.getStaticTarget()
or
result.implements(this.getStaticTarget())
)
}
}

/** Holds if the call expression dispatches to a trait method. */
Expand Down
7 changes: 7 additions & 0 deletions rust/ql/lib/codeql/rust/internal/PathResolution.qll
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,13 @@ abstract class ImplOrTraitItemNode extends ItemNode {
/** Gets an associated item belonging to this trait or `impl` block. */
abstract AssocItemNode getAnAssocItem();

/** Gets the associated item named `name` belonging to this trait or `impl` block. */
pragma[nomagic]
AssocItemNode getAssocItem(string name) {
result = this.getAnAssocItem() and
result.getName() = name
}

/** Holds if this trait or `impl` block declares an associated item named `name`. */
pragma[nomagic]
predicate hasAssocItem(string name) { name = this.getAnAssocItem().getName() }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
multipleCallTargets
| main.rs:225:14:225:29 | ...::deref(...) |
| main.rs:272:14:272:29 | ...::deref(...) |
Loading
Loading