Skip to content

Fix UB from &mut-derived pointer in Thread::new - #160817

Open
im-lunex wants to merge 1 commit into
rust-lang:mainfrom
im-lunex:fix_#160815
Open

Fix UB from &mut-derived pointer in Thread::new#160817
im-lunex wants to merge 1 commit into
rust-lang:mainfrom
im-lunex:fix_#160815

Conversation

@im-lunex

@im-lunex im-lunex commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

fix_approach: Take the pointer from the raw allocation (Arc::as_ptr) instead of from a &mut,
and pass libc the address straight from the allocation (addr_of_mut). It stays
valid no matter how the thread is used later.

@rustbot rustbot added O-unix Operating system: Unix-like S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Aug 9, 2026
@rustbot

rustbot commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

r? @nia-e

rustbot has assigned @nia-e.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @ChrisDenton, libs
  • @ChrisDenton, libs expanded to 13 candidates
  • Random selection from JohnTitor, Mark-Simulacrum, clarfonthey, nia-e

@rust-log-analyzer

This comment has been minimized.

@nia-e nia-e left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks - see my notes. I'll also wait for some of the folks involved in discovering the issue to chime in; you may want to @rustbot claim it to make it apparent you're working on this, though

View changes since this review

assert_eq!(r, 0);
let r = libc::pthread_cond_init(self.raw(), attr.0.as_ptr());
let r =
libc::pthread_cond_init(ptr::addr_of_mut!((*this).inner).cast(), attr.0.as_ptr());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

uses of addr_of_mut! should be replaced with &raw mut

Comment thread library/std/src/thread/thread.rs Outdated
@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Aug 9, 2026
@rustbot

rustbot commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

@maxdexh

maxdexh commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

We have some more concerns about the &mut created for the Drop impl. If that is an issue, I think we might need a more intrusive redesign...

@ais523

ais523 commented Aug 9, 2026

Copy link
Copy Markdown

To follow up from the other thread, it turns out that the Drop implementation of sys::Condvar is unsound and can't be fixed without changing the definition of Condvar.

Most likely, the fix will involve wrapping the field that gets aliased by the OS in UnsafePinned. That's likely to have an effect on what this PR needs to look like (or whether this PR is needed at all), because &mut UnsafePinned<T> has aliasing rules that are significantly different from those of typical &mut references and thus a change like this might end up being unnecessary.

@maxdexh

maxdexh commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

If you want, you can check out the discussion over at #160815 and rewrite the fix using UnsafePinned (the Pin<&mut Self> params can stay, I think). I'll hold off on writing my own PR if you want to do this :)

@im-lunex

im-lunex commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

I'll hold off on writing my own PR if you want to do this :)

Thanks that would be Great. I will follow-up on this soon...

The pthread implementations of `Mutex` and `Condvar` may store the
address of the object during `init` (e.g. AIX keeps condition variables
in an intrusive list) and write through it later. Wrapping the object in
`UnsafeCell` is not sufficient for that: creating an exclusive reference
to the `UnsafeCell` (as `Drop::drop` does) invalidates pointers that
were derived from it earlier, so a write performed by the implementation
while `drop` runs violates the aliasing rules.

`UnsafePinned` is designed exactly for this situation: it opts out of
the uniqueness guarantee of `&mut`, so the state aliased by the OS may
be written at any time.

Fixes rust-lang#160815

Co-Authored-By: ʟᴜɴᴇx <thisissamir04@gmail.com>
@rustbot

rustbot commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

⚠️ Warning ⚠️

  • There are issue links (such as #123) in the commit messages of the following commits.
    Please move them to the PR description, to avoid spamming the issues with references to the commit, and so this bot can automatically canonicalize them to avoid issues with subtree.

@nia-e

nia-e commented Aug 10, 2026

Copy link
Copy Markdown
Member

hi - it seems like you're using an LLM to write part of this PR. that's not explicitly disallowed, but please read our AI policy - this particular PR touches on sensitive soundness-relevant code, so all of those parts should be human-authored in full. feel free to head over to #llm-mentoring on Zulip if you'd like to arrange mentoring for an LLM-assisted PR. thanks!

let attr = AttrGuard(&mut attr);
let r = libc::pthread_condattr_setclock(attr.0.as_mut_ptr(), Self::CLOCK);
assert_eq!(r, 0);
let r = libc::pthread_cond_init(self.raw(), attr.0.as_ptr());

@ais523 ais523 Aug 10, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The soundness of thls line is much more subtle than it might appear simply by looking at the code, so it isn't reasonable to have it in an unsafe block with no safety comment.

In particular, the raw pointer self.raw() outlives the reference it was created from. There are two ways this can be unsound (aliasing model violations, and the memory mistakenly being used for other purposes while the pointer to it is still in use), and these likely both need a detailed explanation of why they are not a problem in this case.

View changes since the review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

O-unix Operating system: Unix-like S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants