Skip to content

std: avoid aliasing violations when wrapping opaque C types - #160848

Merged
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
joboet:opaque_c_alias
Aug 28, 2026
Merged

std: avoid aliasing violations when wrapping opaque C types#160848
rust-bors[bot] merged 1 commit into
rust-lang:mainfrom
joboet:opaque_c_alias

Conversation

@joboet

@joboet joboet commented Aug 10, 2026

Copy link
Copy Markdown
Member

Fixes #160815 (and some other instances of the same problem)

See the new documentation of COpaque for a detailed description of the kinds of issues solved by this. In short: creating mutable references to the opaque types from pthread is unsound since some platforms (at least AIX) store an intrinsically list of these types and the creation of the mutable reference (e.g. in the drop glue) invalidates the other pointers to the type.

This doesn't just apply to the internal pthread Condvar and Mutex abstraction as described in the issue, but also to all other opaque types – nobody is promising us that these are not internally aliased. Hence this PR adds an internal COpaque helper type which uses a combination of UnsafePinned and MaybeUninit to relax all relevant requirements added by Rust's operational semantics.

CC @RalfJung I'd love to hear your opinion on this
r? libs

@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 10, 2026
@rust-log-analyzer

This comment has been minimized.

@joboet
joboet force-pushed the opaque_c_alias branch 2 times, most recently from feb6204 to 086a6d2 Compare August 10, 2026 11:42
@rust-log-analyzer

This comment has been minimized.

@ais523

ais523 commented Aug 11, 2026

Copy link
Copy Markdown

I noticed something interesting while working on the opsem of this, and it might make sense to call it out in the documentation in order to help make the safety proofs easier to understand.

Normally in Rust, if you convert a reference into a pointer, you cannot use the pointer outside the lifetime of the reference without causing aliasing violations. It's as though raw pointers have lifetimes, and copy them from the reference they're created from (but you get UB rather than a borrow checker error if you violate them). This is the root cause behind #160815; a reference was converted to a pointer, but the pointer outlived the reference. (Although UnsafeCell often helps with this, because all the &UnsafeCell can often be inferred to have the same lifetime and thus the pointers can often last as long as the UnsafeCell does, this mechanism fails in situations where an &mut is created, like in drop.)

With UnsafePinned, and wrappers for it like COpaque, this is no longer true: if you convert a reference to it into a pointer, the pointer is opsem-usable for as long as the containing memory is not used via anything other than UnsafePinned types, and that's the reason why code like Condvar is sound after the change.

In addition to mentioning this in COpaque's documentation, it should probably be mentioned in the safety comments of the uses of the variables (i.e. "this is sound because a pointer obtained via a COpaque lasts until the memory is repurposed, we ask the OS to stop using the memory in our destructor, and because self is Pin our destructor is guaranteed to run before the memory is repurposed"). It took me a long time to understand why this is sound, so having it in a code comment would likely help other people to figure out why it is sound.

@RalfJung

Copy link
Copy Markdown
Member

With UnsafePinned, and wrappers for it like COpaque, this is no longer true: if you convert a reference to it into a pointer, the pointer is opsem-usable for as long as the containing memory is not used via anything other than UnsafePinned types, and that's the reason why code like Condvar is sound after the change.

Yeah, this is the exact same thing that already happens with UnsafeCell for shared references.

@RalfJung

Copy link
Copy Markdown
Member

CC @RalfJung I'd love to hear your opinion on this

Using UnsafePinned here makes a lot of sense.
I am not sure if MaybeUninit is needed, but it can't hurt.

@joboet

joboet commented Aug 16, 2026

Copy link
Copy Markdown
Member Author

I am not sure if MaybeUninit is needed, but it can't hurt.

I just checked, POSIX actually says that:

The pthread_mutex_destroy() function shall destroy the mutex object referenced by mutex; the mutex object becomes, in effect, uninitialized. An implementation may cause pthread_mutex_destroy() to set the object referenced by mutex to an invalid value.

so the current Mutex and Condvar abstractions are of questionable soundness (though as the destruction happens in Drop and there are no further loads of the pthread_mutex_t/pthread_cond_t this is sound under rust-lang/unsafe-code-guidelines#414).

Comment thread library/std/src/sys/helpers/c_opaque.rs Outdated
Comment on lines +8 to +9
/// operational semantics are much stricter when it comes to e.g. the initiali-
/// zation state of data types and pointer aliasing. For instance, a function

@tbu- tbu- Aug 24, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hyphenated things in doc blocks probably don't work correctly.

View changes since the review

@nia-e

nia-e commented Aug 25, 2026

Copy link
Copy Markdown
Member

This looks correct to me. I worry slightly that there's a lot of other similar patterns in std that we're not looking at, but this is basically just a line-by-line change to the more relaxed semantics, so there's little to get wrong here ^^ r=me once the doc nit above is addressed

@nia-e nia-e 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 25, 2026
@joboet

joboet commented Aug 27, 2026

Copy link
Copy Markdown
Member Author

@bors r=@nia-e

@rust-bors

rust-bors Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

📌 Commit 3b2afd1 has been approved by nia-e

It is now in the queue for this repository.

@rust-bors rust-bors Bot 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-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 27, 2026
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Aug 27, 2026
std: avoid aliasing violations when wrapping opaque C types

Fixes rust-lang#160815 (and some other instances of the same problem)

See the new documentation of `COpaque` for a detailed description of the kinds of issues solved by this. In short: creating mutable references to the opaque types from pthread is unsound since some platforms (at least AIX) store an intrinsically list of these types and the creation of the mutable reference (e.g. in the drop glue) invalidates the other pointers to the type.

This doesn't just apply to the internal pthread `Condvar` and `Mutex` abstraction as described in the issue, but also to all other opaque types – nobody is promising us that these are not internally aliased. Hence this PR adds an internal `COpaque` helper type which uses a combination of `UnsafePinned` and `MaybeUninit` to relax all relevant requirements added by Rust's operational semantics.

CC @RalfJung I'd love to hear your opinion on this
r? libs
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 27, 2026
std: avoid aliasing violations when wrapping opaque C types

Fixes rust-lang#160815 (and some other instances of the same problem)

See the new documentation of `COpaque` for a detailed description of the kinds of issues solved by this. In short: creating mutable references to the opaque types from pthread is unsound since some platforms (at least AIX) store an intrinsically list of these types and the creation of the mutable reference (e.g. in the drop glue) invalidates the other pointers to the type.

This doesn't just apply to the internal pthread `Condvar` and `Mutex` abstraction as described in the issue, but also to all other opaque types – nobody is promising us that these are not internally aliased. Hence this PR adds an internal `COpaque` helper type which uses a combination of `UnsafePinned` and `MaybeUninit` to relax all relevant requirements added by Rust's operational semantics.

CC @RalfJung I'd love to hear your opinion on this
r? libs
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 27, 2026
std: avoid aliasing violations when wrapping opaque C types

Fixes rust-lang#160815 (and some other instances of the same problem)

See the new documentation of `COpaque` for a detailed description of the kinds of issues solved by this. In short: creating mutable references to the opaque types from pthread is unsound since some platforms (at least AIX) store an intrinsically list of these types and the creation of the mutable reference (e.g. in the drop glue) invalidates the other pointers to the type.

This doesn't just apply to the internal pthread `Condvar` and `Mutex` abstraction as described in the issue, but also to all other opaque types – nobody is promising us that these are not internally aliased. Hence this PR adds an internal `COpaque` helper type which uses a combination of `UnsafePinned` and `MaybeUninit` to relax all relevant requirements added by Rust's operational semantics.

CC @RalfJung I'd love to hear your opinion on this
r? libs
GuillaumeGomez added a commit to GuillaumeGomez/rust that referenced this pull request Aug 27, 2026
std: avoid aliasing violations when wrapping opaque C types

Fixes rust-lang#160815 (and some other instances of the same problem)

See the new documentation of `COpaque` for a detailed description of the kinds of issues solved by this. In short: creating mutable references to the opaque types from pthread is unsound since some platforms (at least AIX) store an intrinsically list of these types and the creation of the mutable reference (e.g. in the drop glue) invalidates the other pointers to the type.

This doesn't just apply to the internal pthread `Condvar` and `Mutex` abstraction as described in the issue, but also to all other opaque types – nobody is promising us that these are not internally aliased. Hence this PR adds an internal `COpaque` helper type which uses a combination of `UnsafePinned` and `MaybeUninit` to relax all relevant requirements added by Rust's operational semantics.

CC @RalfJung I'd love to hear your opinion on this
r? libs
rust-bors Bot pushed a commit that referenced this pull request Aug 28, 2026
Rollup of 14 pull requests

Successful merges:

 - #150075 (Implement clamp_to)
 - #159103 (fix(reborrow): recursive implementation)
 - #160848 (std: avoid aliasing violations when wrapping opaque C types)
 - #161421 (Include startup crt objects on WASI for more outputs)
 - #161805 (Prefer ambiguous candidates when deduplicating traits in scope, so `ambiguous_glob_imported_traits` doesn't depend on import order)
 - #161862 (Put data segment in specified section with link_section on wasm)
 - #161866 (delegation: add tests fixating behavior of delegating to default trait implementations)
 - #161456 (reduce perf impact of scalar size checks)
 - #161666 (Print vendor instructions in `x vendor`)
 - #161730 (Improve type mismatch annotation for lets with block-wrapped initializers)
 - #161828 (Never type after-stabilization cleanup)
 - #161860 (atomicptr.rs test: remove unused import)
 - #161870 (bind to [::1] instead of 127.0.0.1 in documentation examples for v6 UDP methods)
 - #161876 (rustdoc: Correctly handle when a macro generates multiple items in `--generate-macro-expansion`)
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 28, 2026
std: avoid aliasing violations when wrapping opaque C types

Fixes rust-lang#160815 (and some other instances of the same problem)

See the new documentation of `COpaque` for a detailed description of the kinds of issues solved by this. In short: creating mutable references to the opaque types from pthread is unsound since some platforms (at least AIX) store an intrinsically list of these types and the creation of the mutable reference (e.g. in the drop glue) invalidates the other pointers to the type.

This doesn't just apply to the internal pthread `Condvar` and `Mutex` abstraction as described in the issue, but also to all other opaque types – nobody is promising us that these are not internally aliased. Hence this PR adds an internal `COpaque` helper type which uses a combination of `UnsafePinned` and `MaybeUninit` to relax all relevant requirements added by Rust's operational semantics.

CC @RalfJung I'd love to hear your opinion on this
r? libs
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 28, 2026
std: avoid aliasing violations when wrapping opaque C types

Fixes rust-lang#160815 (and some other instances of the same problem)

See the new documentation of `COpaque` for a detailed description of the kinds of issues solved by this. In short: creating mutable references to the opaque types from pthread is unsound since some platforms (at least AIX) store an intrinsically list of these types and the creation of the mutable reference (e.g. in the drop glue) invalidates the other pointers to the type.

This doesn't just apply to the internal pthread `Condvar` and `Mutex` abstraction as described in the issue, but also to all other opaque types – nobody is promising us that these are not internally aliased. Hence this PR adds an internal `COpaque` helper type which uses a combination of `UnsafePinned` and `MaybeUninit` to relax all relevant requirements added by Rust's operational semantics.

CC @RalfJung I'd love to hear your opinion on this
r? libs
rust-bors Bot pushed a commit that referenced this pull request Aug 28, 2026
…uwer

Rollup of 21 pull requests

Successful merges:

 - #158609 (Update sccache to 0.16.0)
 - #150075 (Implement clamp_to)
 - #159103 (fix(reborrow): recursive implementation)
 - #160562 (add target feature ABI checks for SPARC)
 - #160848 (std: avoid aliasing violations when wrapping opaque C types)
 - #161421 (Include startup crt objects on WASI for more outputs)
 - #161805 (Prefer ambiguous candidates when deduplicating traits in scope, so `ambiguous_glob_imported_traits` doesn't depend on import order)
 - #161862 (Put data segment in specified section with link_section on wasm)
 - #161866 (delegation: add tests fixating behavior of delegating to default trait implementations)
 - #161456 (reduce perf impact of scalar size checks)
 - #161528 (Add regression test to ensure optimal compilation)
 - #161666 (Print vendor instructions in `x vendor`)
 - #161730 (Improve type mismatch annotation for lets with block-wrapped initializers)
 - #161828 (Never type after-stabilization cleanup)
 - #161859 (Do not optimize MIR for comptime ConstFns)
 - #161860 (atomicptr.rs test: remove unused import)
 - #161870 (bind to [::1] instead of 127.0.0.1 in documentation examples for v6 UDP methods)
 - #161876 (rustdoc: Correctly handle when a macro generates multiple items in `--generate-macro-expansion`)
 - #161889 (Add link to ownership section in ptr::read docs)
 - #161890 (rustdoc: some clarifying comments)
 - #161891 (Mark `extern_item_impls` feature as incomplete)

Failed merges:

 - #161702 (Use `drop_guard` in some places in {core,alloc,std})
rust-bors Bot pushed a commit that referenced this pull request Aug 28, 2026
…uwer

Rollup of 21 pull requests

Successful merges:

 - #150075 (Implement clamp_to)
 - #159103 (fix(reborrow): recursive implementation)
 - #160562 (add target feature ABI checks for SPARC)
 - #160848 (std: avoid aliasing violations when wrapping opaque C types)
 - #161421 (Include startup crt objects on WASI for more outputs)
 - #161805 (Prefer ambiguous candidates when deduplicating traits in scope, so `ambiguous_glob_imported_traits` doesn't depend on import order)
 - #161862 (Put data segment in specified section with link_section on wasm)
 - #161866 (delegation: add tests fixating behavior of delegating to default trait implementations)
 - #157218 (Track items behind `cfg_select` in the same way we do for `cfg`)
 - #161456 (reduce perf impact of scalar size checks)
 - #161528 (Add regression test to ensure optimal compilation)
 - #161666 (Print vendor instructions in `x vendor`)
 - #161730 (Improve type mismatch annotation for lets with block-wrapped initializers)
 - #161828 (Never type after-stabilization cleanup)
 - #161859 (Do not optimize MIR for comptime ConstFns)
 - #161860 (atomicptr.rs test: remove unused import)
 - #161870 (bind to [::1] instead of 127.0.0.1 in documentation examples for v6 UDP methods)
 - #161876 (rustdoc: Correctly handle when a macro generates multiple items in `--generate-macro-expansion`)
 - #161889 (Add link to ownership section in ptr::read docs)
 - #161890 (rustdoc: some clarifying comments)
 - #161891 (Mark `extern_item_impls` feature as incomplete)

Failed merges:

 - #161702 (Use `drop_guard` in some places in {core,alloc,std})
@rust-bors
rust-bors Bot merged commit 0bca179 into rust-lang:main Aug 28, 2026
13 checks passed
@rustbot rustbot added this to the 1.100.0 milestone Aug 28, 2026
rust-bors Bot pushed a commit that referenced this pull request Aug 28, 2026
Rollup merge of #160848 - joboet:opaque_c_alias, r=nia-e

std: avoid aliasing violations when wrapping opaque C types

Fixes #160815 (and some other instances of the same problem)

See the new documentation of `COpaque` for a detailed description of the kinds of issues solved by this. In short: creating mutable references to the opaque types from pthread is unsound since some platforms (at least AIX) store an intrinsically list of these types and the creation of the mutable reference (e.g. in the drop glue) invalidates the other pointers to the type.

This doesn't just apply to the internal pthread `Condvar` and `Mutex` abstraction as described in the issue, but also to all other opaque types – nobody is promising us that these are not internally aliased. Hence this PR adds an internal `COpaque` helper type which uses a combination of `UnsafePinned` and `MaybeUninit` to relax all relevant requirements added by Rust's operational semantics.

CC @RalfJung I'd love to hear your opinion on this
r? libs
pacak added a commit to pacak/rust that referenced this pull request Aug 28, 2026
It was added rust-lang#160848

I'm not sure why was it made private.
pacak added a commit to pacak/rust that referenced this pull request Aug 29, 2026
It was added rust-lang#160848

I'm not sure why was it made private.
pacak added a commit to pacak/rust that referenced this pull request Aug 29, 2026
It was added rust-lang#160848

I'm not sure why was it made private.
pacak added a commit to pacak/rust that referenced this pull request Aug 30, 2026
It was added rust-lang#160848

I'm not sure why was it made private.
Zalathar added a commit to Zalathar/rust that referenced this pull request Aug 31, 2026
…ize, r=joboet

Fix a compile error on the ESP-IDF target

PR rust-lang#160848 accidentally broke the Tier-3 ESP-IDF target by leaving out one reference to `attr.as_ptr()` which should've been changed to `attr.get()`.

This PR does the absolute minimum to restore correct behavior for the ESP-IDF target (and Nuttx).

CC
@joboet
@nia-e
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 31, 2026
…ize, r=joboet

Fix a compile error on the ESP-IDF target

PR rust-lang#160848 accidentally broke the Tier-3 ESP-IDF target by leaving out one reference to `attr.as_ptr()` which should've been changed to `attr.get()`.

This PR does the absolute minimum to restore correct behavior for the ESP-IDF target (and Nuttx).

CC
@joboet
@nia-e
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 31, 2026
…ize, r=joboet

Fix a compile error on the ESP-IDF target

PR rust-lang#160848 accidentally broke the Tier-3 ESP-IDF target by leaving out one reference to `attr.as_ptr()` which should've been changed to `attr.get()`.

This PR does the absolute minimum to restore correct behavior for the ESP-IDF target (and Nuttx).

CC
@joboet
@nia-e
rust-bors Bot pushed a commit that referenced this pull request Aug 31, 2026
Rollup merge of #162049 - ivmarkov:fix-espidf-thread-stack-size, r=joboet

Fix a compile error on the ESP-IDF target

PR #160848 accidentally broke the Tier-3 ESP-IDF target by leaving out one reference to `attr.as_ptr()` which should've been changed to `attr.get()`.

This PR does the absolute minimum to restore correct behavior for the ESP-IDF target (and Nuttx).

CC
@joboet
@nia-e
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-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. 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.

Condvar and Mutex in std::sys::pal::unix::sync violate aliasing rules

8 participants