-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
A Pin
unsoundness involving an impl DerefMut for Pin<&dyn LocalTrait>
#85099
Comments
impl DerefMut for Pin<&dyn LocalTrait>
Pin
unsoundness involving an impl DerefMut for Pin<&dyn LocalTrait>
This is related to #68015 even though I didn’t really know much about that issue while finding this one. #68015 was summarized as
In relation to that summary, this issue (#85099) demonstrates that it is in fact possible to abuse existing I’ve also made an explanation of this issue (#85099) (which also relates it to the summary of #68015 quoted above). This explanation is reproduced below: ExplanationThe type More concretely: Since Methods on |
And just to be clear (I was confused for a moment), this works on stable even though the example in the other linked issue doesn't. |
@khoek Thanks, I’ve put in some clarification. |
Error: Label P-high can only be set by Rust team members Please let |
Assigning priority as discussed in the Zulip thread of the Prioritization Working Group. @rustbot label -I-prioritize +P-high |
Hi, I am new to rust development and not really sure where to post this, so i figured here would be fine. I found this issue and took interest in fixing it. I looked through related issues and the Zulip thread, but did not find any newer contributions. If I understand the crux of this problem correctly, then it lies within the conversion from
The issue lies with step 3 and in this case there are several possibilites to fixing the behaviour:
Footnotes
|
@y86-dev Thanks for the excellent write-up! I believe that @steffahn: If I understand correctly, this issue is only possible because of the blanket If use std::marker::PhantomPinned;
use std::pin::Pin;
fn main() {
let val: Pin<Pin<&PhantomPinned>> = Pin::new(Pin::new(&PhantomPinned));
} produces:
To obtain a With that in mind, I think we can eliminate the problem by replacing the blanket Since impl<P, U> CoerceUnsized<Pin<Box<U>>> for Pin<Box<P>> where P: CoerceUnsized<U> {}
impl<P, U> CoerceUnsized<Pin<Box<U>>> for Pin<Box<P>> where P: CoerceUnsized<U> {}
impl<P, U> CoerceUnsized<Pin<Cell<U>>> for Pin<Cell<P>> where P: CoerceUnsized<U> {}
... This would allow users to continue relying on 'useful' coercions (e.g. |
@Aaron1011 I tried to implement your approach, impl<P, U> CoerceUnsized<Pin<U>> for Pin<P> where P: CoerceUnsized<U> {} from impl<P, U, A> CoerceUnsized<Pin<Box<U, A>>> for Pin<Box<P, A>>
where
P: ?Sized + Unsize<U>,
U: ?Sized,
A: Allocator
{}
Edit: I made a mistake compiling the stdlib and ended up not using the freshly compiled version, so scrap all the above. |
While @Aaron1011's approach works, I would prefer not to modify the behaviour of
|
We're assuming that T-types is taking ownership of finding a path to a solution here. (My instinct is that a negative impl is the right long term solution, and we just need to decide whether to slowly ease that in via a future-incompatibility lint of the form suggested by @y86-dev ) |
(NOT A CONTRIBUTION) I've only just now seen this issue, but I want to say that I think adding a negative impl of DerefMut is the correct approach. The soundness of the Pin APIs rests on std types not implementing DerefMut or Clone, which is broken by fundamental tricks. As I argued when we fixed the previous issue in 2020, I think library writers should be able to rely on basic, seemingly obvious assumptions like "shared references (including pinned shared references) do not implement DerefMut" without having to think about the nuances of the fundamental attribute. I don't believe the impls you'd be excluding have any valid use cases, and I think its bad for Rust that I even think it might be a good idea to exempt DerefMut and Clone from
I assume the recursive impl is necessary because if just the impl for (As another aside, I would guess there's might be a way to get the unsound behaviour through an impl of |
Visiting for P-high 2023 Q1 review . I'd like to hear what T-types has to say about @withoutboats 's suggestion in the previous comment that we should, at minimum, add a negative impl of (It sounds like something we might need to tie to the 2024 edition? Or maybe we justify it as a soundness fix.) @rustbot label: +I-types-nominated |
This issue didn't get any types input over the last few months 😅 I haven't thought about this too deeply, but my feelings here are:
will try to get to this in the next t-types planning meeting. Would also mentor experimentation with either of these 2 options. Please open a thread in t-types if you're interested. |
…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
…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
…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
talked about this in the t-types triage meeting: https://rust-lang.zulipchat.com/#narrow/stream/326132-t-types.2Fmeetings/topic/2023-05-08.20triage.20meeting/near/356721636 the consensus was to go ahead with removing the special behavior for fundamental types for We also quickly touched on extending the "disable fundamental types behavior" to more traits and would like to experiment with that. We did not reach a conclusion for this however. |
I am available to mentor an implementation of disabling the fundamental type behavior for
if you get stuck, please open a thread on zulip in the t-types stream. |
Is the idea that this is a stopgap solution until the negative impl can be used? I agree with all the voices above who said that that is clearly the right solution: What is not clear to me yet is where exactly this assumption is made for |
(NOT A CONTRIBUTION) Just want to reiterate that this is probably also breakable with |
At least for me "disabling the fundamental ty behavior for some traits" is the final solution. The negative impl for We would therefore need the impl People would still be allowed to implement
This is complex enough that I tend to forget the details again after a while, but in general the issue is that
we have to assume that each of these transitions does not change whether the pointee is the first step is trivially correct, going from |
I think this is exactly the argument we need to make a formal proof of
I think writing negative impls is the best way to make this argument local. Then one can directly point at another piece of code in the local crate which ensures that the invariant is maintained. In contrast, anything based on fundamental/coherence relies on the global invariant of coherence -- worse, it relies on how exactly the compiler ensures coherence (i.e., just knowing "the entire crate graph is coherent wrt trait impls" is insufficient, we need to argue based on how the compiler reasons about coherence in a compositional way -- things that I consider details of the orphan rules, not something I would like to see unsafe code based on). |
coherence allows you to say that "this type will certainly not implement that trait" 😁
to me this feels similar to reasoning about |
(NOT A CONTRIBUTION) I would tend to agree with both @lcnr and @RalfJung. Ideally, we would move to explicit negative impls as the basis for soundness proofs (so yes, there should be an explicit |
I don't see how. Coherence is first and foremost a consistency property: for any given type and trait, there will be at most one impl of the trait for the type. This does not help in the slightest to make statements of the form "this type will certainly not implement that trait". The way rustc ensures coherence is through some form of "orphan rules" (using Haskell terminology since I don't know if we have a Rust term for this). Those rules are subtle and subject to change. Only with those rules is it possible to make statements of the form "no other crate can impl this trait for this type". For people that have internalized these rules, that might seem like a natural way of expressing constraints to the compiler, but really it is not -- I would not be able to do it, since despite having worked on Rust for a long time I don't know the orphan rules well enough. Furthermore, if we make this an acceptable soundness argument then it becomes a lot harder to evolve the orphan rules over time.
Well IMO we really should have I'm not objecting to adjusting how |
@lcnr Hey! Is it possible to get assigned to the issue? I would be interested in working on implementing this in the upcoming weeks to get more insight into the compiler. |
(@lambinoo I've assigned you; tip: you can use |
WIP WIP fix for rust-lang#85099, will write up a description w/ `@lcnr` when I'm at my computer r? lcnr
Being able to implement |
Haven’t got the time to do any more explaining right now, but here’s the code (Edit: I added a few inline comments anyways):
(playground)
segfaults in debug build due to an
async
-block future being moved after the first.poll()
call@rustbot label C-bug, A-pin, T-compiler, T-libs, T-lang
and someone please add I-unsound 💥
The text was updated successfully, but these errors were encountered: