Skip to content

Conversation

Darksonn
Copy link
Contributor

@Darksonn Darksonn commented Aug 19, 2025

The safety requirements for PinCoerceUnsized are essentially that the type does not have a malicious Deref or DerefMut impl. However, the Pin type is fundamental, so the end-user can provide their own implementation of DerefMut for Pin<&SomeLocalType>, so it's possible for Pin to have a malicious DerefMut impl. This unsoundness is known as #85099.

Unfortunately, this means that the implementation of PinCoerceUnsized for Pin is currently unsound. To fix that, modify the impl so that it becomes impossible for downstream crates to provide their own implementation of DerefMut for Pin by abusing a hidden struct that is not fundamental.

This PR is a breaking change, but it fixes #85099. The PR supersedes #144896.

r? lcnr

@Darksonn Darksonn added T-lang Relevant to the language team A-pin Area: Pin T-types Relevant to the types team, which will review and decide on the PR/issue. labels Aug 19, 2025
@Darksonn Darksonn requested a review from lcnr August 19, 2025 14:53
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Aug 19, 2025
@Darksonn
Copy link
Contributor Author

It doesn't immediately look like error messages have regressed, but the docs have:

image

I'm going to push another commit to improve the docs to this:

image

I think it's reasonable in this case since the impls really are equivalent except for the orphan rules treatment.

@lcnr
Copy link
Contributor

lcnr commented Aug 19, 2025

I want to make sure I properly understand #85099 before merging this. I do think it's a very nice solution and gj for coming up with it!

I personally dislike "lying in the impl", even if it doesn't matter in practice. Gonna throw that question to @rust-lang/libs-api.

Let's crater

@bors try

rust-bors bot added a commit that referenced this pull request Aug 19, 2025
Prevent downstream impl DerefMut for Pin
@rust-bors

This comment has been minimized.

@dtolnay dtolnay added the I-libs-api-nominated Nominated for discussion during a libs-api team meeting. label Aug 19, 2025
@traviscross traviscross added I-lang-nominated Nominated for discussion during a lang team meeting. I-lang-radar Items that are on lang's radar and will need eventual work or consideration. P-lang-drag-1 Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang labels Aug 19, 2025
@dtolnay
Copy link
Member

dtolnay commented Aug 19, 2025

We discussed this PR in today's standard library API meeting. Those present were on board with the approach, but it will be important to see a reasonably clean crater result and send PRs for any breakage, because not all downstream impls of DerefMut for Pin are necessarily unsound. The new implementation rules out correct as well as incorrect impls.

Once crater is finished, we would like to do a libs-api FCP to surface this to the rest of the team.

We noticed that the new pin::hidden::PinHelper type is now going to appear in diagnostics such as the pin-unsound-issue-85099-derefmut.stderr in this PR, but hopefully this mostly only happens when someone is doing funny business like writing their own DerefMut impl, and not for more typical use of Pin's methods and impls.

@dtolnay dtolnay removed the I-libs-api-nominated Nominated for discussion during a libs-api team meeting. label Aug 19, 2025
@Darksonn
Copy link
Contributor Author

Ok, let's see what crater says. But I don't think there are any valid use-cases for impl DerefMut for Pin<P> for pointer types that aren't DerefMut.

@rust-bors
Copy link

rust-bors bot commented Aug 19, 2025

☀️ Try build successful (CI)
Build commit: c659ee1 (c659ee110de67e82444e4b6c8407c1a9af9c2cf6, parent: 8c32e313cccf7df531e2d49ffb8227bb92304aee)

@lcnr
Copy link
Contributor

lcnr commented Aug 19, 2025

@craterbot check

@craterbot
Copy link
Collaborator

👌 Experiment pr-145608 created and queued.
🤖 Automatically detected try build c659ee1
🔍 You can check out the queue and this experiment's details.

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot craterbot added S-waiting-on-crater Status: Waiting on a crater run to be completed. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 19, 2025
@Darksonn
Copy link
Contributor Author

Darksonn commented Aug 19, 2025

Updating this with some additional tests for error messages. I'm not worried about PinHelper showing up in pin-unsound-issue-85099-derefmut.stderr, but that it also shows up in tests/ui/deref/pin-impl-deref.stderr is unfortunate.

(See individual commits for how the error messages change.)

@Darksonn
Copy link
Contributor Author

Darksonn commented Aug 19, 2025

A slightly different implementation seems to give somewhat better errors:

Darksonn@5e4d49a

But let's wait for crater before we think about that further.

@Darksonn Darksonn changed the title Prevent downstream impl DerefMut for Pin Prevent downstream impl DerefMut for Pin<LocalType> Aug 19, 2025
@traviscross traviscross added P-lang-drag-2 Lang team prioritization drag level 2.https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang. and removed P-lang-drag-1 Lang team prioritization drag level 1. https://rust-lang.zulipchat.com/#narrow/channel/410516-t-lang labels Aug 20, 2025
@craterbot
Copy link
Collaborator

🚧 Experiment pr-145608 is now running

ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@craterbot
Copy link
Collaborator

🎉 Experiment pr-145608 is completed!
📊 6 regressed and 8 fixed (685389 total)
📰 Open the summary report.

⚠️ If you notice any spurious failure please add them to the denylist!
ℹ️ Crater is a tool to run experiments across parts of the Rust ecosystem. Learn more

@rust-rfcbot rust-rfcbot removed the proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. label Sep 24, 2025
@rust-rfcbot
Copy link
Collaborator

🔔 This is now entering its final comment period, as per the review above. 🔔

@Darksonn
Copy link
Contributor Author

Darksonn commented Sep 24, 2025

I think excluding certain traits from fundamental makes sense as what could be missing.

@traviscross
Copy link
Contributor

traviscross commented Sep 25, 2025

@rustbot labels +S-waiting-on-documentation

@Darksonn, could you perhaps make a Reference PR here? We do cover fundamental in the Reference and discuss e.g. how the type T in Box<T>, Pin<T>, etc. is not considered "covered". We should add the needed caveats.

cc @rust-lang/lang-docs @tshepang @PLeVasseur

@rustbot rustbot added the S-waiting-on-documentation Status: Waiting on approved PRs to documentation before merging label Sep 25, 2025
@lcnr
Copy link
Contributor

lcnr commented Sep 25, 2025

What are the expected changes to the reference here? This does not change anything about fundamental types in the language. The most I can think of would be "note: the standard library sometimes works around this by 'sealing' traits for fundamental types via indirection, e.g. Pin: DerefMut...".

But I feel like given the way it is implemented as an ordinary trait implementation, I would expect us to document this in the standard library on the impl, if at all. If we think this exception to the coherence rules for fundamental types is worth documenting, imo we should add a comment to the DerefMut impl and potentially remove the #[cfg(docs)] version to always show the 'correct' trait bounds

@traviscross
Copy link
Contributor

traviscross commented Sep 25, 2025

In my view, we should answer somewhere why impl DerefMut for Pin<LocalTy> doesn't work, because otherwise the extrapolation from the visible documentation in the standard library and the text in the Reference about the fact that Pin is fundamental and what that means suggests, as far as I can tell on a quick read, that it should work.

As for where that should go, we've discussed recently that somewhat more in the way of details about lang-item types may need to live in the Reference, so I can see this here from that perspective. I could see the core library docs saying something about this too, of course. It's OK if both say something about it. The key point, though, is that we should say this clearly and normatively somewhere in our documentation.

@Darksonn
Copy link
Contributor Author

There are already a bunch of other examples of preventing downstream crates from implement traits on #[fundamental] things. One example is DerefMut for &T, which is prevented using an impl<T> !DerefMut for &T clause. This one isn't really so different from that.

@traviscross
Copy link
Contributor

traviscross commented Sep 26, 2025

...which is prevented using an impl<T> !DerefMut for &T clause...

We document that. In this case, we're suppressing any documentation which would explain the behavior.

@BoxyUwU
Copy link
Member

BoxyUwU commented Sep 26, 2025

I don't think whether we have rustdoc hacks to avoid showing how an impl is written should have any bearing on whether something goes in the reference or not. This PR doesn't change language semantics in any way.

I do think it could possibly be confusing that people get errors that they "shouldn't" but the right place for that documentation to live would be the impl in std not the reference.

The fact that Pin is a Lang item is somewhat besides the point IMO. it may be special to the language but this behaviour is not a special Pin thing.

@traviscross
Copy link
Contributor

As mentioned, I'm happy as long as we document it somewhere.

As for where that should go, we've discussed recently that somewhat more in the way of details about lang-item types may need to live in the Reference, so I can see this here from that perspective. I could see the core library docs saying something about this too, of course. It's OK if both say something about it. The key point, though, is that we should say this clearly and normatively somewhere in our documentation.

@Darksonn
Copy link
Contributor Author

I looked at what the reference says about fundamental types, and I don't think this fits there. I added this to the docs:

image

@Darksonn Darksonn removed the S-waiting-on-documentation Status: Waiting on approved PRs to documentation before merging label Sep 29, 2025
@traviscross
Copy link
Contributor

Thanks for adding the doc comment. Left some editorial notes.

@Darksonn
Copy link
Contributor Author

Darksonn commented Sep 29, 2025

Suggestions applied. I checked that the link is working.

image

Copy link
Contributor

@traviscross traviscross left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks; all looks great to me.

View changes since this review

@rustbot
Copy link
Collaborator

rustbot commented Oct 1, 2025

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@bors
Copy link
Collaborator

bors commented Oct 3, 2025

☔ The latest upstream changes (presumably #142771) made this pull request unmergeable. Please resolve the merge conflicts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-pin Area: Pin disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. I-lang-radar Items that are on lang's radar and will need eventual work or consideration. S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). T-lang Relevant to the language team T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

A Pin unsoundness involving an impl DerefMut for Pin<&dyn LocalTrait>