Skip to content

Fix the soundness bug in the representation of extern types - #5021

Merged
tgross35 merged 3 commits into
rust-lang:mainfrom
tgross35:extern-types
Jun 24, 2026
Merged

Fix the soundness bug in the representation of extern types#5021
tgross35 merged 3 commits into
rust-lang:mainfrom
tgross35:extern-types

Conversation

@tgross35

@tgross35 tgross35 commented Mar 16, 2026

Copy link
Copy Markdown
Contributor

Since the very first import dafaca9 ("Initial import of liblibc"), libc has used uninhabited enums to represent C's incomplete/opaque types. While this is, as far as I know, technically okay when working behind raw pointers, it means that using reference types like &FILE can lead to easy UB.

Resolve this by changing the representation to a !Sync + !Send + !Unpin ZST, as recommended by the nomicon 1. The loss of auto traits technically makes this user-visible, but it is unlikely that anybody who is doing sound things was relying on these.

I also used this as an opportunity to add a forward-compatibility note about intended use that should allow us to switch to real extern types once those are available.

Cc @RalfJung

@rustbot

rustbot commented Mar 16, 2026

Copy link
Copy Markdown
Collaborator

Some changes occurred in a NetBSD-like module

cc @semarie

Some changes occurred in a solarish module

cc @jclulow, @pfmooney

@tgross35
tgross35 requested a review from JohnTitor March 16, 2026 22:29
@rustbot rustbot added the A-CI Area: CI-related items label Mar 16, 2026
@tgross35

Copy link
Copy Markdown
Contributor Author

Looks like I need to skip these in tests, and the ZST flags improper_ctypes until 1.72 https://rust.godbolt.org/z/TrdqKa4Wb.

@tgross35
tgross35 marked this pull request as draft March 16, 2026 22:42
Comment thread src/macros.rs Outdated
// Representation based on the Nomicon:
// <https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs>.
//
// FIXME(1.0): the type is uninhabited so these traits are unreachable and could be

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.

The FIXME seems outdated now?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You're right; we should still remove the traits but the reason needs updating (will fix)

@JohnTitor JohnTitor 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.

I like the idea! LGTM as long as fixing the test and updating FIXME.

View changes since this review

@tgross35
tgross35 force-pushed the extern-types branch 3 times, most recently from bec3759 to 6be7f0b Compare June 24, 2026 04:16
@tgross35 tgross35 added the stable-nominated This PR should be considered for cherry-pick to libc's stable release branch label Jun 24, 2026
@tgross35
tgross35 force-pushed the extern-types branch 5 times, most recently from 0eb46ed to fd50378 Compare June 24, 2026 06:17
tgross35 added 3 commits June 24, 2026 02:25
Since the very first import dafaca9 ("Initial import of liblibc"),
`libc` has used uninhabited enums to represent C's incomplete/opaque
types. While this is, as far as I know, techincally okay when working
behind raw pointers, it means that using reference types like `&FILE`
can lead to easy UB.

Resolve this by changing the representation to a `!Sync + !Send +
!Unpin` ZST, as recommended by the nomicon [1]. The loss of auto traits
technically makes this user-visible, but it is unlikely that anybody who
is doing sound things was relying on these. 

I also used this as an opportunity to add a forward-compatibility note
about intended use that should allow us to switch to real extern types
once those are available.

[1]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
The new extern type representation raises the lint prior to 1.72 because
ZSTs behind pointers were not allowed.
@tgross35
tgross35 marked this pull request as ready for review June 24, 2026 06:26
@tgross35
tgross35 enabled auto-merge June 24, 2026 06:27
@tgross35
tgross35 added this pull request to the merge queue Jun 24, 2026
Merged via the queue into rust-lang:main with commit 96a27a4 Jun 24, 2026
54 checks passed
@rustbot rustbot mentioned this pull request Jun 24, 2026
3 tasks
@tgross35
tgross35 deleted the extern-types branch June 24, 2026 07:24
tgross35 added a commit to tgross35/rust-libc that referenced this pull request Jul 20, 2026
Since the very first import dafaca9 ("Initial import of liblibc"),
`libc` has used uninhabited enums to represent C's incomplete/opaque
types. While this is, as far as I know, techincally okay when working
behind raw pointers, it means that using reference types like `&FILE`
can lead to easy UB.

Resolve this by changing the representation to a `!Sync + !Send +
!Unpin` ZST, as recommended by the nomicon [1]. The loss of auto traits
technically makes this user-visible, but it is unlikely that anybody who
is doing sound things was relying on these.

I also used this as an opportunity to add a forward-compatibility note
about intended use that should allow us to switch to real extern types
once those are available.

[1]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs

(backport <rust-lang#5021>)
(cherry picked from commit 1cf49df)
tgross35 added a commit to tgross35/rust-libc that referenced this pull request Jul 20, 2026
(backport <rust-lang#5021>)
(cherry picked from commit fbaea87)
tgross35 added a commit to tgross35/rust-libc that referenced this pull request Jul 20, 2026
The new extern type representation raises the lint prior to 1.72 because
ZSTs behind pointers were not allowed.

(backport <rust-lang#5021>)
(cherry picked from commit 96a27a4)
This was referenced Jul 20, 2026
tgross35 added a commit to tgross35/rust-libc that referenced this pull request Jul 20, 2026
Since the very first import dafaca9 ("Initial import of liblibc"),
`libc` has used uninhabited enums to represent C's incomplete/opaque
types. While this is, as far as I know, techincally okay when working
behind raw pointers, it means that using reference types like `&FILE`
can lead to easy UB.

Resolve this by changing the representation to a `!Sync + !Send +
!Unpin` ZST, as recommended by the nomicon [1]. The loss of auto traits
technically makes this user-visible, but it is unlikely that anybody who
is doing sound things was relying on these.

I also used this as an opportunity to add a forward-compatibility note
about intended use that should allow us to switch to real extern types
once those are available.

[1]: https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs

(backport <rust-lang#5021>)
(cherry picked from commit 1cf49df)
tgross35 added a commit to tgross35/rust-libc that referenced this pull request Jul 20, 2026
(backport <rust-lang#5021>)
(cherry picked from commit fbaea87)
tgross35 added a commit to tgross35/rust-libc that referenced this pull request Jul 20, 2026
The new extern type representation raises the lint prior to 1.72 because
ZSTs behind pointers were not allowed.

(backport <rust-lang#5021>)
(cherry picked from commit 96a27a4)
@tgross35 tgross35 added stable-applied This PR has been cherry-picked to libc's stable release branch and removed stable-nominated This PR should be considered for cherry-pick to libc's stable release branch labels Jul 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-CI Area: CI-related items stable-applied This PR has been cherry-picked to libc's stable release branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants