rust-lang / rust-lang/rust

implied bounds from projections in function signatures can be unsound

Open
#129,005 7 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

A-associated-items I-unsound P-medium T-types
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

edit: we've fixed the non-higher ranked version for FnDef to FnPtr casts in #129021. However, we're aware that keeping the target of the function pointer cast higher-ranked, it's still possible to exploit this

trait ToArg<T> {
    type Arg;
}
impl<T, U> ToArg<T> for U {
    type Arg = T;
}

fn extend_inner<'a, 'b>(x: &'a str) -> <&'b &'a () as ToArg<&'b str>>::Arg { x }
fn extend<'a, 'b>(x: &'a str) -> &'b str  {
    (extend_inner as for<'hr> fn(&'hr str) -> &'b str)(x)
}

fn main() {
    let y = extend(&String::from("Hello World"));
    println!("{}", y);
}

Fixing this properly is blocked on properly tracking implied bounds on binders


Related to #100051, but the underlying reason is slightly different. The full fix will be the same however and is blocked on the new trait solver.

trait ToArg<T> {
    type Arg;
}
impl<T, U> ToArg<T> for U {
    type Arg = T;
}

fn extend_inner<'a, 'b>(x: &'a str) -> <&'b &'a () as ToArg<&'b str>>::Arg { x }
fn extend<'a, 'b>(x: &'a str) -> &'b str  {
    (extend_inner as fn(_) -> _)(x)
}

fn main() {
    let y = extend(&String::from("Hello World"));
    println!("{}", y);
}

Introduced by #99217. The idea of that PR was that we check that the unnormalized function signature is well-formed when calling a function. We previously only checked the normalized signature, causing another unsoundness #98543 by having an associated type which we're able to normalize in the definition, but not the use. Checking that the unnormalized signature is well-formed, without assuming that it is well-formed, resulted in breaking changes. Because of this, we changed it to both check, and assume, that the unnormalized function signature is well-formed. This would be sound, except that we can first cast the function to a function pointer, discarding its unnormalized signature, and then call it.

We may be able to partially fix this by checking that the unnormalized signature is well-formed when casting function definitions to function pointers. This still leaves us with the general set of unsound higher-ranked implied bounds, cc #100051 #84591 #25860, which can only really be fixed by supporting implications in the type systems. cc @rust-lang/types

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the two Rust reproducers using extend_inner and extend, then read the discussion of #129021, #100051, #84591 and #25860. Investigate how the new trait solver can track implied bounds on binders; done means the demonstrated function-pointer casts no longer permit the reported unsound behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.