Skip to content

Commit 452521f

Browse files
committed
Fix the soundness bug in the representation of extern types
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
1 parent bc30895 commit 452521f

File tree

23 files changed

+64
-48
lines changed

23 files changed

+64
-48
lines changed

src/fuchsia/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ pub type fsfilcnt_t = c_ulonglong;
7979
pub type rlim_t = c_ulonglong;
8080

8181
extern_ty! {
82-
pub enum timezone {}
83-
pub enum DIR {}
84-
pub enum fpos64_t {} // FIXME(fuchsia): fill this out with a struct
82+
pub type timezone;
83+
pub type DIR;
84+
pub type fpos64_t; // FIXME(fuchsia): fill this out with a struct
8585
}
8686

8787
// PUB_STRUCT
@@ -3192,8 +3192,8 @@ fn __MHDR_END(mhdr: *const msghdr) -> *mut c_uchar {
31923192
extern "C" {}
31933193

31943194
extern_ty! {
3195-
pub enum FILE {}
3196-
pub enum fpos_t {} // FIXME(fuchsia): fill this out with a struct
3195+
pub type FILE;
3196+
pub type fpos_t; // FIXME(fuchsia): fill this out with a struct
31973197
}
31983198

31993199
extern "C" {

src/macros.rs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,17 +246,37 @@ macro_rules! s_no_extra_traits {
246246
macro_rules! extern_ty {
247247
($(
248248
$(#[$attr:meta])*
249-
pub enum $i:ident {}
249+
pub type $i:ident;
250250
)*) => ($(
251251
$(#[$attr])*
252+
/// This is an extern type ("opaque" or "incomplete" type in C).
253+
///
254+
/// <div class="warning">
255+
/// This type's current representation allows inspecting some properties, such as via
256+
/// <code>size_of</code>, and it is technically possible to construct the type within
257+
/// <code>MaybeUninit</code>, However, this <strong>MUST NOT</strong> be relied upon
258+
/// because a future version of <code>libc</code> may switch to a proper
259+
/// <a href="https://rust-lang.github.io/rfcs/1861-extern-types.html">extern type</a>
260+
/// representation when available.
261+
/// </div>
262+
// ^ unfortunately warning blocks currently don't render markdown so we need to
263+
// use raw HTML.
264+
//
265+
// Representation based on the Nomicon:
266+
// <https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs>.
267+
//
252268
// FIXME(1.0): the type is uninhabited so these traits are unreachable and could be
253269
// removed.
254270
#[::core::prelude::v1::derive(
255271
::core::clone::Clone,
256272
::core::marker::Copy,
257273
::core::fmt::Debug,
258274
)]
259-
pub enum $i { }
275+
#[repr(C)]
276+
pub struct $i {
277+
_data: (),
278+
_marker: ::core::marker::PhantomData<(*mut u8, ::core::marker::PhantomPinned)>,
279+
}
260280
)*);
261281
}
262282

src/new/qurt/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub type fd_set = c_ulong;
6060

6161
// Standard C library types
6262
extern_ty! {
63-
pub enum FILE {}
63+
pub type FILE;
6464
}
6565
pub type fpos_t = c_long;
6666
pub type clock_t = c_long;

src/solid/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,8 +397,8 @@ pub const SIGUSR2: c_int = 31;
397397
pub const SIGPWR: c_int = 32;
398398

399399
extern_ty! {
400-
pub enum FILE {}
401-
pub enum fpos_t {}
400+
pub type FILE;
401+
pub type fpos_t;
402402
}
403403

404404
extern "C" {

src/unix/aix/powerpc64.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::prelude::*;
33

44
// Define lock_data_instrumented as an empty enum
55
extern_ty! {
6-
pub enum lock_data_instrumented {}
6+
pub type lock_data_instrumented;
77
}
88

99
s! {

src/unix/bsd/apple/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ pub type attrgroup_t = u32;
176176
pub type vol_capabilities_set_t = [u32; 4];
177177

178178
extern_ty! {
179-
pub enum timezone {}
179+
pub type timezone;
180180
}
181181

182182
c_enum! {

src/unix/bsd/freebsdlike/dragonfly/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ pub type vm_map_entry_t = *mut vm_map_entry;
4949
pub type pmap = __c_anonymous_pmap;
5050

5151
extern_ty! {
52-
pub enum sem {}
52+
pub type sem;
5353
}
5454

5555
c_enum! {

src/unix/bsd/freebsdlike/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ cfg_if! {
6060
// link.h
6161

6262
extern_ty! {
63-
pub enum timezone {}
63+
pub type timezone;
6464
}
6565

6666
impl siginfo_t {

src/unix/bsd/netbsdlike/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ pub type sem_t = *mut sem;
1717
pub type key_t = c_long;
1818

1919
extern_ty! {
20-
pub enum timezone {}
21-
pub enum sem {}
20+
pub type timezone;
21+
pub type sem;
2222
}
2323

2424
s! {

src/unix/bsd/netbsdlike/netbsd/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ c_enum! {
4545
}
4646

4747
extern_ty! {
48-
pub enum _cpuset {}
48+
pub type _cpuset;
4949
}
5050

5151
cfg_if! {

0 commit comments

Comments
 (0)