Skip to content
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

Unsoundness due to where clauses not checked for well-formedness #98117

Closed
aliemjay opened this issue Jun 15, 2022 · 10 comments · Fixed by #124336
Closed

Unsoundness due to where clauses not checked for well-formedness #98117

aliemjay opened this issue Jun 15, 2022 · 10 comments · Fixed by #124336
Assignees
Labels
A-lifetimes Area: lifetime related C-bug Category: This is a bug. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness P-high High priority S-bug-has-test Status: This bug is tracked inside the repo by a `known-bug` test. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@aliemjay
Copy link
Member

aliemjay commented Jun 15, 2022

This code does pass: (playground)

trait Outlives<'a>: 'a {} // without `: 'a`, it fails as expected.

fn t_is_static<T>()
where
    &'static T: Outlives<'static>,
{
}

But according to RFC 1214 functions are responsible for checking the well-formedness of their own where clauses. So this should fail and require an explicit bound T: 'static.

Here is an exploit of this unsoundness: (playground)

trait Outlives<'a>: 'a {}
impl<'a, T> Outlives<'a> for &'a T {}

fn step2<T>(t: T) -> &'static str
where
    &'static T: Outlives<'static>,
    T: AsRef<str>,
{
    AsRef::as_ref(Box::leak(Box::new(t) as Box<dyn AsRef<str> + 'static>))
}

fn step1<T>(t: T) -> &'static str
where
    for<'a> &'a T: Outlives<'a>,
    T: AsRef<str>,
{
    step2(t)
}

fn main() {
    let s: &'static str = step1(&String::from("blah blah blah"));
    println!("{s}");
}

@rustbot label C-bug T-compiler T-types A-lifetimes I-unsound

@rustbot rustbot added A-lifetimes Area: lifetime related C-bug Category: This is a bug. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue. I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Jun 15, 2022
@steffahn
Copy link
Member

steffahn commented Jun 15, 2022

This works, too

use std::fmt::Display;

trait Static: 'static {}
impl<T> Static for &'static T {}

fn foo<T: Display>(x: T) -> Box<dyn Display>
where
    &'static T: Static,
{
    Box::new(x)
}

fn main() {
    let s = foo(&String::from("blah blah blah"));
    println!("{s}");
}

(playground)

@steffahn
Copy link
Member

steffahn commented Jun 15, 2022

Seems to compile since 1.14 (obviously without the dyn keyword, and without the naked "{s}").

@compiler-errors
Copy link
Member

compiler-errors commented Jun 15, 2022

@steffahn's minimized example is much easier to work with:

use std::fmt::Display;

trait Static: 'static {}
impl<T> Static for &'static T {}

fn foo<S: Display>(x: S) -> Box<dyn Display>
where
    &'static S: Static,
{
    Box::new(x)
}

fn main() {
    let s = foo(&String::from("blah blah blah"));
    println!("{}", s);
}

Somewhere we're throwing bounds on the floor that we should be checking. Which function is responsible for ultimately checking that T: 'static is really is a mess to keep track of, honestly.

I guess it's worthwhile nominating this for T-types discussion.

@compiler-errors compiler-errors added the I-types-nominated Nominated for discussion during a types team meeting. label Jun 15, 2022
@Dylan-DPC Dylan-DPC added P-high High priority and removed I-prioritize Issue: Indicates that prioritization has been requested for this issue. labels Jun 16, 2022
@Dylan-DPC
Copy link
Member

Marking this as p-high based on the discussion here

@jackh726
Copy link
Member

jackh726 commented Jul 29, 2022

Discussed in t-types meeting.

We think this will fall out of the ongoing work towards a-mir-formality. Namely here it's probably introducing WellFormed predicates for everything that is being proven. @lcnr is steadily making progress on this.

@jackh726 jackh726 removed the I-types-nominated Nominated for discussion during a types team meeting. label Jul 29, 2022
@steffahn

This comment was marked as resolved.

@jackh726
Copy link
Member

Discussed in t-types meeting.

This link points to the prioritization discussion @jackh726

Thanks, fixed.

@lcnr
Copy link
Contributor

lcnr commented Oct 28, 2022

@rustbot claim

already working in the area and want to take a closer look at this specific issue

matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Apr 23, 2023
…unsound-issues, r=jackh726

Add `known-bug` tests for 11 unsound issues

r? `@jackh726`

Should tests for other issues be in separate PRs?  Thanks.

Edit: Partially addresses rust-lang#105107.  This PR adds `known-bug` tests for 11 unsound issues:
- rust-lang#25860
- rust-lang#49206
- rust-lang#57893
- rust-lang#84366
- rust-lang#84533
- rust-lang#84591
- rust-lang#85099
- rust-lang#98117
- rust-lang#100041
- rust-lang#100051
- rust-lang#104005
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Apr 24, 2023
…unsound-issues, r=jackh726

Add `known-bug` tests for 11 unsound issues

r? ``@jackh726``

Should tests for other issues be in separate PRs?  Thanks.

Edit: Partially addresses rust-lang#105107.  This PR adds `known-bug` tests for 11 unsound issues:
- rust-lang#25860
- rust-lang#49206
- rust-lang#57893
- rust-lang#84366
- rust-lang#84533
- rust-lang#84591
- rust-lang#85099
- rust-lang#98117
- rust-lang#100041
- rust-lang#100051
- rust-lang#104005
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Apr 24, 2023
…unsound-issues, r=jackh726

Add `known-bug` tests for 11 unsound issues

r? `@jackh726`

Should tests for other issues be in separate PRs?  Thanks.

Edit: Partially addresses rust-lang#105107.  This PR adds `known-bug` tests for 11 unsound issues:
- rust-lang#25860
- rust-lang#49206
- rust-lang#57893
- rust-lang#84366
- rust-lang#84533
- rust-lang#84591
- rust-lang#85099
- rust-lang#98117
- rust-lang#100041
- rust-lang#100051
- rust-lang#104005
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Apr 24, 2023
…unsound-issues, r=jackh726

Add `known-bug` tests for 11 unsound issues

r? ``@jackh726``

Should tests for other issues be in separate PRs?  Thanks.

Edit: Partially addresses rust-lang#105107.  This PR adds `known-bug` tests for 11 unsound issues:
- rust-lang#25860
- rust-lang#49206
- rust-lang#57893
- rust-lang#84366
- rust-lang#84533
- rust-lang#84591
- rust-lang#85099
- rust-lang#98117
- rust-lang#100041
- rust-lang#100051
- rust-lang#104005
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Apr 24, 2023
…unsound-issues, r=jackh726

Add `known-bug` tests for 11 unsound issues

r? `@jackh726`

Should tests for other issues be in separate PRs?  Thanks.

Edit: Partially addresses rust-lang#105107.  This PR adds `known-bug` tests for 11 unsound issues:
- rust-lang#25860
- rust-lang#49206
- rust-lang#57893
- rust-lang#84366
- rust-lang#84533
- rust-lang#84591
- rust-lang#85099
- rust-lang#98117
- rust-lang#100041
- rust-lang#100051
- rust-lang#104005
JohnTitor added a commit to JohnTitor/rust that referenced this issue Apr 24, 2023
…unsound-issues, r=jackh726

Add `known-bug` tests for 11 unsound issues

r? ``@jackh726``

Should tests for other issues be in separate PRs?  Thanks.

Edit: Partially addresses rust-lang#105107.  This PR adds `known-bug` tests for 11 unsound issues:
- rust-lang#25860
- rust-lang#49206
- rust-lang#57893
- rust-lang#84366
- rust-lang#84533
- rust-lang#84591
- rust-lang#85099
- rust-lang#98117
- rust-lang#100041
- rust-lang#100051
- rust-lang#104005
@jackh726 jackh726 added the S-bug-has-test Status: This bug is tracked inside the repo by a `known-bug` test. label Apr 25, 2023
@lcnr lcnr removed their assignment Jul 3, 2023
@lcnr
Copy link
Contributor

lcnr commented Dec 13, 2023

Summarizing what's going wrong in the minimized example:

use std::fmt::Display;

trait Static: 'static {}
impl<T> Static for &'static T {}

fn foo<S: Display>(x: S) -> Box<dyn Display>
where
    &'static S: Static,
{
    Box::new(x)
}

fn main() {
    let s = foo(&String::from("blah blah blah"));
    println!("{}", s);
}

We check that where-clauses of items when wfchecking that item, we do not recheck the where-clauses when using it. We assume this to be sound as instantiating a binder should not remove WF.

We check that &'static S: Static is WF in the param_env of the function. After elaborating super trait bounds this environment contains a &'static S: 'static bound, which gets destructures to result in a S: 'static clause. When now checking whether &'static S is well-formed, we are able to use that bound.

When calling that function we never check that &'static &'a String is well-formed. When applying the impl we also assume that the trait_ref is well-formed, as that should have been checked by wfcheck of the function. However, wfcheck of the function relied on the elaborated S: 'static bound which never gets proven here.

I think this should generally be fixed by also proving super trait bounds when using an impl (which is already part of our coinduction approach).

@lcnr
Copy link
Contributor

lcnr commented Dec 13, 2023

actually: we can already elaborate any region constraints on traits when applying an impl. We can't check super traits because that requires coinduction, but adding a TypeOutlives constraint should already be possible.

bors added a commit to rust-lang-ci/rust that referenced this issue Apr 24, 2024
[crater] Enforce supertrait outlives obligations hold when confirming impl

r? `@lcnr`

Fixes rust-lang#98117
@bors bors closed this as completed in 2b78d92 Aug 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lifetimes Area: lifetime related C-bug Category: This is a bug. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness P-high High priority S-bug-has-test Status: This bug is tracked inside the repo by a `known-bug` test. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
Status: unblocked
Development

Successfully merging a pull request may close this issue.

7 participants