Skip to content

Conversation

@hvitved
Copy link
Contributor

@hvitved hvitved commented Dec 8, 2025

This PR adds general support for the Deref trait when resolving method calls, which means both supporting it when actually resolving method calls in the type inference library, but also inserting the implicit deref calls in data flow.

As usual, commit-by-commit review is encouraged.

Type inference

When resolving method calls, a set of candidate receiver types are constructed by repeatedly dereferencing the receiver using applicable Deref implementations. Before this PR, we had limited support, namely &(mut) T -> T and String -> str. In order to handle arbitrary chains of dereferences, we introduce a new class DerefChain, based on the shared UnboundList library, which records the chain of deref calls needed to resolve a method call.

After having resolved a method call, type information may also have to flow backwards through the chain of dereferences. Example:

use std::ops::Deref;
use std::ops::DerefMut;

struct S<T>(T);

impl<T> Deref for S<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

impl<T> DerefMut for S<T> {
    fn deref_mut(&mut self) -> &mut T {
        &mut self.0
    }
}

fn f() {
    let v = Vec::new();
    let mut s = S(v);
    s.push(0); // resolves to `Vec::push`, forces `v` to be of type `Vec<i32>`
}

Support for this is implemented in the inferMethodCallTypeSelf predicate, where the DerefChain is applied in reverse order, peeling off the top element until the chain becomes empty.

Data flow

A method call x.m() with an implicit dereference desugars to (*Deref::deref(&x)).m(), so we need to add data flow nodes for &x, Deref::deref(&x), and *Deref::deref(&x), as well as the implicit call to Deref::deref. This means we will have a reference store-step from x to &x and a reference read-step from Deref::deref(&x) to *Deref::deref(&x).

The three different data flow nodes are represented by a state called ImplicitDerefNodeState, and since we need to support arbitrary dereference chains, each synthetic node is additionally tagged with a DerefChain as well as an index into that chain.

A small, but important, performance improvement is made when the targeted deref method is one of the two built-in implementations; in this case, we can add a local flow step directly from x to Deref::deref(&x), which avoids the need for inter-procedural flow.

Evaluation

The changes on this PR resolve a lot of MISSING test expectations. DCA looks really great: Percentage of calls with call target increases by 2 % point, and as a consequence, we gain quite a lot of new results, all without regressing on performance. I also conducted a very positive QA experiment, which confirms the increase in alerts, e.g. 10 % more cleartext-logging results, 25 % more log-injection results, and a staggering 100 % more path-injection results.

@github-actions github-actions bot added the Rust Pull requests that update Rust code label Dec 8, 2025
Comment on lines 265 to 297
/**
* Index assignments like `a[i] = rhs` are treated as `*a.index_mut(i) = rhs`,
* so they should in principle be handled by `referenceAssignment`.
*
* However, this would require support for [generalized reverse flow][1], which
* is not yet implemented, so instead we simulate reverse flow where it would
* have applied via the model for `<_ as core::ops::index::IndexMut>::index_mut`.
*
* The same is the case for compound assignments like `a[i] += rhs`, which are
* treated as `(*a.index_mut(i)).add_assign(rhs)`.
*
* [1]: https://github.com/github/codeql/pull/18109
*/

Check warning

Code scanning / CodeQL

Predicate QLDoc style Warning

The QLDoc for a predicate without a result should start with 'Holds'.
@hvitved hvitved force-pushed the rust/type-inference-deref-trait branch 3 times, most recently from baba061 to 5dda9be Compare December 15, 2025 09:17
@hvitved hvitved force-pushed the rust/type-inference-deref-trait branch 2 times, most recently from eb1db27 to e269016 Compare December 16, 2025 13:44
pragma[nomagic]
Type getACandidateReceiverTypeAtSubstituteLookupTraits(
string derefChain, boolean borrow, TypePath path
Type getANonPseudoCandidateReceiverTypeAt(

Check warning

Code scanning / CodeQL

Missing QLDoc for parameter Warning

The QLDoc has no documentation for borrow, or derefChain, or path, but the QLDoc mentions unknown
@hvitved hvitved force-pushed the rust/type-inference-deref-trait branch from 8266451 to 14037e4 Compare December 16, 2025 14:38
@hvitved hvitved force-pushed the rust/type-inference-deref-trait branch from 14037e4 to 0c7b1d0 Compare December 17, 2025 10:42
)
)
}

Check warning

Code scanning / CodeQL

Omittable 'exists' variable Warning

This exists variable can be omitted by using a don't-care expression
in this argument
.
@hvitved hvitved force-pushed the rust/type-inference-deref-trait branch 2 times, most recently from 7880183 to be3a16a Compare December 17, 2025 12:40
@hvitved hvitved force-pushed the rust/type-inference-deref-trait branch 6 times, most recently from cc413c1 to adcbfc8 Compare December 18, 2025 13:42
@hvitved hvitved force-pushed the rust/type-inference-deref-trait branch from dd62164 to dc0c45b Compare December 18, 2025 16:18
@hvitved hvitved force-pushed the rust/type-inference-deref-trait branch 4 times, most recently from f3bad27 to c23d528 Compare December 19, 2025 15:02
@hvitved hvitved force-pushed the rust/type-inference-deref-trait branch 2 times, most recently from 60d9084 to de3a73e Compare January 5, 2026 13:25
@hvitved hvitved force-pushed the rust/type-inference-deref-trait branch 2 times, most recently from 5c70ae0 to 20ebba3 Compare January 5, 2026 14:04
@hvitved hvitved force-pushed the rust/type-inference-deref-trait branch 4 times, most recently from 9190142 to 00b243a Compare January 6, 2026 09:19
@hvitved hvitved force-pushed the rust/type-inference-deref-trait branch 3 times, most recently from 452da63 to 2d8da40 Compare January 6, 2026 14:18
}

private class ImplicitDerefOutNode extends ImplicitDerefNode, OutNode {
private DataFlowCall call;

Check warning

Code scanning / CodeQL

Dead code Warning

This code is never used, and it's not publicly exported.
@hvitved hvitved force-pushed the rust/type-inference-deref-trait branch from 2d8da40 to a446415 Compare January 7, 2026 09:50
@hvitved hvitved force-pushed the rust/type-inference-deref-trait branch from a446415 to dce21e5 Compare January 7, 2026 09:56
@hvitved hvitved marked this pull request as ready for review January 7, 2026 13:18
Copilot AI review requested due to automatic review settings January 7, 2026 13:18
@hvitved hvitved requested review from a team as code owners January 7, 2026 13:18
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

This PR adds comprehensive support for Rust's Deref trait in both type inference and data flow analysis. The implementation enables proper resolution of method calls through implicit dereference chains and inserts appropriate data flow nodes for such operations.

Key changes:

  • Introduces DerefChain class to track chains of implicit dereferences during type inference
  • Adds data flow support for implicit deref calls with synthetic nodes
  • Resolves numerous test expectations that were previously marked as MISSING

Reviewed changes

Copilot reviewed 33 out of 33 changed files in this pull request and generated no comments.

Show a summary per file
File Description
shared/util/codeql/util/UnboundList.qll Makes getElement public to support DerefChain implementation
shared/typeinference/codeql/typeinference/internal/TypeInference.qll Adds performance optimizations with new predicates and pragma annotations
rust/ql/lib/codeql/rust/internal/typeinference/DerefChain.qll New file implementing deref chain logic using UnboundList
Test expectation files Updates reflecting improved type inference and data flow (resolving MISSING cases)
Test source files Updates comments to reflect resolved test cases (removing MISSING markers)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Rust Pull requests that update Rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant