Check WF of source type's signature on fn pointer cast by compiler-errors · Pull Request #129021 · rust-lang/rust (original) (raw)

Conversation

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters

[ Show hidden characters]({{ revealButtonHref }})

compiler-errors

bors added a commit to rust-lang-ci/rust that referenced this pull request

Aug 12, 2024

@bors

…=

Check WF of source type's signature on fn pointer cast

TODO: description

r? lcnr

compiler-errors

compiler-errors

@bors bors added S-waiting-on-bors

Status: Waiting on bors to run and complete tests. Bors will change the label on completion.

and removed S-waiting-on-review

Status: Awaiting review from the assignee but also interested parties.

labels

Sep 5, 2024

workingjubilee added a commit to workingjubilee/rustc that referenced this pull request

Sep 6, 2024

@workingjubilee

… r=lcnr

Check WF of source type's signature on fn pointer cast

This PR patches the implied bounds holes slightly for rust-lang#129005, rust-lang#25860.

Like most implied bounds related unsoundness fixes, this isn't complete w.r.t. higher-ranked function signatures, but I believe it implements a pretty good heuristic for now.

What does this do?

This PR makes a partial patch for a soundness hole in a FnDef -> FnPtr "reifying" pointer cast where we were never checking that the signature we are casting from is actually well-formed. Because of this, and because FnDef doesn't require its signature to be well-formed (just its predicates must hold), we are essentially allowed to "cast away" implied bounds that are assumed within the body of the FnDef:

fn foo<'a, 'b, T>(_: &'a &'b (), v: &'b T) -> &'a T { v }

fn bad<'short, T>(x: &'short T) -> &'static T {
    let f: fn(_, &'short T) -> &'static T = foo;
    f(&&(), x)
}

In this example, subtyping ends up casting the _ type (which should be &'static &'short ()) to some other type that no longer serves as a "witness" to the lifetime relationship 'short: 'static which would otherwise be required for this call to be WF. This happens regardless of if foo's lifetimes are early- or late-bound.

This PR implements two checks:

  1. We check that the signature of the FnDef is well-formed before casting it. This ensures that there is at least one point in the MIR where we ensure that the FnDef's implied bounds are actually satisfied by the caller.
  2. Implements a special case where if we're casting from a higher-ranked FnDef to a non-higher-ranked, we instantiate the binder of the FnDef with infer vars and ensure that it is a supertype of the target of the cast.

The (2.) is necessary to validate that these pointer casts are valid for higher-ranked FnDef. Otherwise, the example above would still pass even if help's 'a lifetime were late-bound.

Further work

The WF checks for function calls are scattered all over the MIR. We check the WF of args in call terminators, we check the WF of FnDef when we create a const operand referencing it, and we check the WF of the return type in rust-lang#115538, to name a few.

One way to make this a bit cleaner is to simply extend rust-lang#115538 to always check that the signature is WF for FnDef types. I may do this as a follow-up, but I wanted to keep this simple since this leads to some pretty bad NLL diagnostics regressions, and AFAICT this solution is complete enough.

Crater triage

Done here: rust-lang#129021 (comment)

r? lcnr

workingjubilee added a commit to workingjubilee/rustc that referenced this pull request

Sep 6, 2024

@workingjubilee

… r=lcnr

Check WF of source type's signature on fn pointer cast

This PR patches the implied bounds holes slightly for rust-lang#129005, rust-lang#25860.

Like most implied bounds related unsoundness fixes, this isn't complete w.r.t. higher-ranked function signatures, but I believe it implements a pretty good heuristic for now.

What does this do?

This PR makes a partial patch for a soundness hole in a FnDef -> FnPtr "reifying" pointer cast where we were never checking that the signature we are casting from is actually well-formed. Because of this, and because FnDef doesn't require its signature to be well-formed (just its predicates must hold), we are essentially allowed to "cast away" implied bounds that are assumed within the body of the FnDef:

fn foo<'a, 'b, T>(_: &'a &'b (), v: &'b T) -> &'a T { v }

fn bad<'short, T>(x: &'short T) -> &'static T {
    let f: fn(_, &'short T) -> &'static T = foo;
    f(&&(), x)
}

In this example, subtyping ends up casting the _ type (which should be &'static &'short ()) to some other type that no longer serves as a "witness" to the lifetime relationship 'short: 'static which would otherwise be required for this call to be WF. This happens regardless of if foo's lifetimes are early- or late-bound.

This PR implements two checks:

  1. We check that the signature of the FnDef is well-formed before casting it. This ensures that there is at least one point in the MIR where we ensure that the FnDef's implied bounds are actually satisfied by the caller.
  2. Implements a special case where if we're casting from a higher-ranked FnDef to a non-higher-ranked, we instantiate the binder of the FnDef with infer vars and ensure that it is a supertype of the target of the cast.

The (2.) is necessary to validate that these pointer casts are valid for higher-ranked FnDef. Otherwise, the example above would still pass even if help's 'a lifetime were late-bound.

Further work

The WF checks for function calls are scattered all over the MIR. We check the WF of args in call terminators, we check the WF of FnDef when we create a const operand referencing it, and we check the WF of the return type in rust-lang#115538, to name a few.

One way to make this a bit cleaner is to simply extend rust-lang#115538 to always check that the signature is WF for FnDef types. I may do this as a follow-up, but I wanted to keep this simple since this leads to some pretty bad NLL diagnostics regressions, and AFAICT this solution is complete enough.

Crater triage

Done here: rust-lang#129021 (comment)

r? lcnr

bors added a commit to rust-lang-ci/rust that referenced this pull request

Sep 6, 2024

@bors

bors added a commit to rust-lang-ci/rust that referenced this pull request

Sep 6, 2024

@bors

…iaskrgr

Rollup of 6 pull requests

Successful merges:

r? @ghost @rustbot modify labels: rollup

rust-timer added a commit to rust-lang-ci/rust that referenced this pull request

Sep 6, 2024

@rust-timer

Rollup merge of rust-lang#129021 - compiler-errors:ptr-cast-outlives, r=lcnr

Check WF of source type's signature on fn pointer cast

This PR patches the implied bounds holes slightly for rust-lang#129005, rust-lang#25860.

Like most implied bounds related unsoundness fixes, this isn't complete w.r.t. higher-ranked function signatures, but I believe it implements a pretty good heuristic for now.

What does this do?

This PR makes a partial patch for a soundness hole in a FnDef -> FnPtr "reifying" pointer cast where we were never checking that the signature we are casting from is actually well-formed. Because of this, and because FnDef doesn't require its signature to be well-formed (just its predicates must hold), we are essentially allowed to "cast away" implied bounds that are assumed within the body of the FnDef:

fn foo<'a, 'b, T>(_: &'a &'b (), v: &'b T) -> &'a T { v }

fn bad<'short, T>(x: &'short T) -> &'static T {
    let f: fn(_, &'short T) -> &'static T = foo;
    f(&&(), x)
}

In this example, subtyping ends up casting the _ type (which should be &'static &'short ()) to some other type that no longer serves as a "witness" to the lifetime relationship 'short: 'static which would otherwise be required for this call to be WF. This happens regardless of if foo's lifetimes are early- or late-bound.

This PR implements two checks:

  1. We check that the signature of the FnDef is well-formed before casting it. This ensures that there is at least one point in the MIR where we ensure that the FnDef's implied bounds are actually satisfied by the caller.
  2. Implements a special case where if we're casting from a higher-ranked FnDef to a non-higher-ranked, we instantiate the binder of the FnDef with infer vars and ensure that it is a supertype of the target of the cast.

The (2.) is necessary to validate that these pointer casts are valid for higher-ranked FnDef. Otherwise, the example above would still pass even if help's 'a lifetime were late-bound.

Further work

The WF checks for function calls are scattered all over the MIR. We check the WF of args in call terminators, we check the WF of FnDef when we create a const operand referencing it, and we check the WF of the return type in rust-lang#115538, to name a few.

One way to make this a bit cleaner is to simply extend rust-lang#115538 to always check that the signature is WF for FnDef types. I may do this as a follow-up, but I wanted to keep this simple since this leads to some pretty bad NLL diagnostics regressions, and AFAICT this solution is complete enough.

Crater triage

Done here: rust-lang#129021 (comment)

r? lcnr

This was referenced

Sep 19, 2024

Bright-Shard added a commit to Speykious/cve-rs that referenced this pull request

Oct 22, 2024

@Bright-Shard

cve-rs does not compile in nightly due to rust-lang/rust#129021 and this change will be landed in Rust 1.83. This PR fixes it.

wip-sync pushed a commit to NetBSD/pkgsrc-wip that referenced this pull request

Nov 30, 2024

@he32

Pkgsrc changes compared to rust182:

TODO:

Upstream changes:

Version 1.83.0 (2024-11-28)

Language

Compiler

Refer to Rust's [platform support page][platform-support-doc] for more information on Rust's tiered platform support.

Libraries

Stabilized APIs

These APIs are now stable in const contexts:

Cargo

Rustdoc

Compatibility Notes

tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request

Dec 5, 2024

@tmeijn

This MR contains the following updates:

Package Update Change
rust minor 1.82.0 -> 1.83.0

MR created with the help of el-capitano/tools/renovate-bot.

Proposed changes to behavior should be submitted there as MRs.


Release Notes

rust-lang/rust (rust)

v1.83.0

Compare Source

==========================

Language

Compiler

Refer to Rust's [platform support page][platform-support-doc] for more information on Rust's tiered platform support.

Libraries

Stabilized APIs

These APIs are now stable in const contexts:

Cargo

Rustdoc

Compatibility Notes


Configuration

📅 Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this MR and you won't be reminded about this update again.



This MR has been generated by Renovate Bot.

@lcnr lcnr mentioned this pull request

Dec 18, 2024

netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this pull request

Feb 24, 2025

@he32

Pkgsrc changes:

Upstream changes:

Version 1.83.0 (2024-11-28)

Language

Compiler

Refer to Rust's [platform support page][platform-support-doc] for more information on Rust's tiered platform support.

Libraries

Stabilized APIs

These APIs are now stable in const contexts:

Cargo

Rustdoc

Compatibility Notes