From 3c21a9fdcfc903646a5c7c68f453f0970188e839 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 31 May 2022 18:42:58 -0600 Subject: [PATCH 1/6] Fix the definition of sigevent It was originally defined back before rust could represent C unions. So instead of defining the union field correctly, it simply defined that union's most useful field. Define it correctly now. Include a backwards-compatibility mechanism: Rename sigevent's old definition and hide it. Implement Deref and DerefMut from sigevent to the old definition, so consumers will still be able to use the old field name. --- libc-test/build.rs | 32 ++++++- src/unix/bsd/freebsdlike/freebsd/mod.rs | 107 +++++++++++++++++---- src/unix/linux_like/mod.rs | 118 ++++++++++++++++++++---- 3 files changed, 219 insertions(+), 38 deletions(-) diff --git a/libc-test/build.rs b/libc-test/build.rs index 23134e0f56609..e8340d02d3606 100644 --- a/libc-test/build.rs +++ b/libc-test/build.rs @@ -1477,7 +1477,7 @@ fn test_dragonflybsd(target: &str) { // just insert some padding. (struct_ == "siginfo_t" && field == "_pad") || // sigev_notify_thread_id is actually part of a sigev_un union - (struct_ == "sigevent" && field == "sigev_notify_thread_id") + (struct_ == "sigevent_0_2_126" && field == "sigev_notify_thread_id") }); cfg.generate("../src/lib.rs", "main.rs"); @@ -1724,6 +1724,8 @@ fn test_android(target: &str) { // sigval is a struct in Rust, but a union in C: "sigval" => format!("union sigval"), + "sigevent_0_2_126" => "struct sigevent".to_string(), + // put `struct` in front of all structs:. t if is_struct => format!("struct {}", t), @@ -1970,6 +1972,8 @@ fn test_android(target: &str) { (struct_ == "sigevent" && field == "sigev_value") || // this one is an anonymous union (struct_ == "ff_effect" && field == "u") || + (struct_ == "sigevent_0_2_126" && field == "sigev_value") || + (struct_ == "sigevent" && field == "_sigev_un") || // FIXME: `sa_sigaction` has type `sighandler_t` but that type is // incorrect, see: https://github.com/rust-lang/libc/issues/1359 (struct_ == "sigaction" && field == "sa_sigaction") || @@ -2163,6 +2167,8 @@ fn test_freebsd(target: &str) { // FIXME: https://github.com/rust-lang/libc/issues/1273 "sighandler_t" => "sig_t".to_string(), + "sigevent_0_2_126" => "struct sigevent".to_string(), + t if is_union => format!("union {}", t), t if t.ends_with("_t") => t.to_string(), @@ -2574,6 +2580,7 @@ fn test_freebsd(target: &str) { ("if_data", "__ifi_lastchange") => true, ("ifreq", "ifr_ifru") => true, ("ifconf", "ifc_ifcu") => true, + ("sigevent", "_sigev_un") => true, // anonymous struct ("devstat", "dev_links") => true, @@ -2722,6 +2729,8 @@ fn test_emscripten(target: &str) { // typedefs don't need any keywords t if t.ends_with("_t") => t.to_string(), + "sigevent_0_2_126" => "struct sigevent".to_string(), + // put `struct` in front of all structs:. t if is_struct => format!("struct {}", t), @@ -2761,6 +2770,9 @@ fn test_emscripten(target: &str) { }); cfg.skip_struct(move |ty| { + if ty.starts_with("__c_anonymous_") { + return true; + } match ty { // This is actually a union, not a struct // FIXME: is this necessary? @@ -2847,6 +2859,7 @@ fn test_emscripten(target: &str) { // sigval is actually a union, but we pretend it's a struct // FIXME: is this necessary? (struct_ == "sigevent" && field == "sigev_value") || + (struct_ == "sigevent_0_2_126" && field == "sigev_value") || // aio_buf is "volatile void*" and Rust doesn't understand volatile // FIXME: is this necessary? (struct_ == "aiocb" && field == "aio_buf") @@ -2863,8 +2876,10 @@ fn test_emscripten(target: &str) { // musl seems to define this as an *anonymous* bitfield // FIXME: is this necessary? (struct_ == "statvfs" && field == "__f_unused") || - // sigev_notify_thread_id is actually part of a sigev_un union - (struct_ == "sigevent" && field == "sigev_notify_thread_id") || + // union field + (struct_ == "sigevent" && field == "_sigev_un") || + // union field on the backwards-compat struct definition + (struct_ == "sigevent_0_2_126" && field == "sigev_notify_thread_id") || // signalfd had SIGSYS fields added in Linux 4.18, but no libc release has them yet. (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || field == "_pad2" || @@ -3486,6 +3501,9 @@ fn test_linux(target: &str) { // typedefs don't need any keywords t if t.ends_with("_t") => t.to_string(), + + "sigevent_0_2_126" => "struct sigevent".to_string(), + // put `struct` in front of all structs:. t if is_struct => format!("struct {}", t), // put `union` in front of all unions: @@ -4178,6 +4196,7 @@ fn test_linux(target: &str) { (struct_ == "utmpx" && field == "ut_tv") || // sigval is actually a union, but we pretend it's a struct (struct_ == "sigevent" && field == "sigev_value") || + (struct_ == "sigevent_0_2_126" && field == "sigev_value") || // this one is an anonymous union (struct_ == "ff_effect" && field == "u") || // `__exit_status` type is a patch which is absent in musl @@ -4204,8 +4223,10 @@ fn test_linux(target: &str) { (musl && struct_ == "glob_t" && field == "gl_flags") || // musl seems to define this as an *anonymous* bitfield (musl && struct_ == "statvfs" && field == "__f_unused") || - // sigev_notify_thread_id is actually part of a sigev_un union - (struct_ == "sigevent" && field == "sigev_notify_thread_id") || + // union field + (struct_ == "sigevent" && field == "_sigev_un") || + // union field on the backwards-compat struct definition + (struct_ == "sigevent_0_2_126" && field == "sigev_notify_thread_id") || // signalfd had SIGSYS fields added in Linux 4.18, but no libc release // has them yet. (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || @@ -4717,6 +4738,7 @@ fn test_haiku(target: &str) { ("sem_t", "named_sem_id") => true, ("sigaction", "sa_sigaction") => true, ("sigevent", "sigev_value") => true, + ("sigevent_0_2_126", "sigev_value") => true, ("fpu_state", "_fpreg") => true, ("cpu_topology_node_info", "data") => true, // these fields have a simplified data definition in libc diff --git a/src/unix/bsd/freebsdlike/freebsd/mod.rs b/src/unix/bsd/freebsdlike/freebsd/mod.rs index 799e3811ed44c..463637fc6a105 100644 --- a/src/unix/bsd/freebsdlike/freebsd/mod.rs +++ b/src/unix/bsd/freebsdlike/freebsd/mod.rs @@ -888,6 +888,12 @@ s! { pub profhz: ::c_int, } + #[cfg(libc_union)] + pub struct __c_anonymous_sigev_thread { + pub _function: *mut ::c_void, // Actually a function pointer + pub _attribute: *mut ::pthread_attr_t, + } + pub struct __c_anonymous_stailq_entry_devstat { pub stqe_next: *mut devstat, } @@ -1343,6 +1349,21 @@ s! { pub strchange_instrms: u16, pub strchange_outstrms: u16, } + + // When sigevent was first added to libc, Rust still didn't support unions. + // So the definition only included one of the union's member. This + // structure exists for backwards-compatibility with consumers that still + // try to access that one member. + #[doc(hidden)] + pub struct sigevent_0_2_126 { + pub sigev_notify: ::c_int, + pub sigev_signo: ::c_int, + pub sigev_value: ::sigval, + pub sigev_notify_thread_id: ::lwpid_t, + #[cfg(target_pointer_width = "64")] + __unused1: ::c_int, + __unused2: [::c_long; 7] + } } s_no_extra_traits! { @@ -1393,16 +1414,22 @@ s_no_extra_traits! { __reserved: [::c_long; 4] } + // Can't correctly impl Debug for unions + #[allow(missing_debug_implementations)] + #[cfg(libc_union)] + pub union __c_anonymous_sigev_un { + pub _threadid: ::__lwpid_t, + pub _sigev_thread: __c_anonymous_sigev_thread, + pub _kevent_flags: ::c_ushort, + __spare__: [::c_long; 8], + } + + #[cfg(libc_union)] pub struct sigevent { pub sigev_notify: ::c_int, pub sigev_signo: ::c_int, pub sigev_value: ::sigval, - //The rest of the structure is actually a union. We expose only - //sigev_notify_thread_id because it's the most useful union member. - pub sigev_notify_thread_id: ::lwpid_t, - #[cfg(target_pointer_width = "64")] - __unused1: ::c_int, - __unused2: [::c_long; 7] + pub _sigev_un: __c_anonymous_sigev_un, } pub struct ptsstat { @@ -1637,6 +1664,20 @@ s_no_extra_traits! { } } +impl ::core::ops::Deref for sigevent { + type Target = sigevent_0_2_126; + + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self as *const sigevent_0_2_126) } + } +} + +impl ::core::ops::DerefMut for sigevent { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self as *mut sigevent_0_2_126) } + } +} + cfg_if! { if #[cfg(feature = "extra_traits")] { impl PartialEq for utmpx { @@ -1831,20 +1872,46 @@ cfg_if! { self.sigev_notify == other.sigev_notify && self.sigev_signo == other.sigev_signo && self.sigev_value == other.sigev_value - && self.sigev_notify_thread_id - == other.sigev_notify_thread_id + // sigev_notify indicates which union fields are valid + && match self.sigev_notify { + ::SIGEV_NONE => true, + ::SIGEV_SIGNAL => true, + ::SIGEV_THREAD => unsafe { + self._sigev_un._sigev_thread + == other._sigev_un._sigev_thread + }, + ::SIGEV_KEVENT => unsafe { + self._sigev_un._kevent_flags + == other._sigev_un._kevent_flags + }, + ::SIGEV_THREAD_ID => unsafe { + self._sigev_un._threadid + == other._sigev_un._threadid + }, + _ => false + } } } impl Eq for sigevent {} impl ::fmt::Debug for sigevent { fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { - f.debug_struct("sigevent") - .field("sigev_notify", &self.sigev_notify) - .field("sigev_signo", &self.sigev_signo) - .field("sigev_value", &self.sigev_value) - .field("sigev_notify_thread_id", - &self.sigev_notify_thread_id) - .finish() + let mut ds = f.debug_struct("sigevent"); + ds.field("sigev_notify", &self.sigev_notify); + ds.field("sigev_signo", &self.sigev_signo); + ds.field("sigev_value", &self.sigev_value); + // The sigev_notify field indicates which union fields are valid + unsafe { + match self.sigev_notify { + ::SIGEV_THREAD => ds.field("_sigev_thread", + &self._sigev_un._sigev_thread), + ::SIGEV_KEVENT => ds.field("_kevent_flags", + &self._sigev_un._kevent_flags), + ::SIGEV_THREAD_ID => ds.field("_threadid", + &self._sigev_un._threadid), + _ => &mut ds + } + }; + ds.finish() } } impl ::hash::Hash for sigevent { @@ -1852,7 +1919,15 @@ cfg_if! { self.sigev_notify.hash(state); self.sigev_signo.hash(state); self.sigev_value.hash(state); - self.sigev_notify_thread_id.hash(state); + // The sigev_notify field indicates which union fields are valid + unsafe { + match self.sigev_notify { + ::SIGEV_THREAD => self._sigev_un._sigev_thread.hash(state), + ::SIGEV_KEVENT => self._sigev_un._kevent_flags.hash(state), + ::SIGEV_THREAD_ID => self._sigev_un._threadid.hash(state), + _ => () + }; + } } } diff --git a/src/unix/linux_like/mod.rs b/src/unix/linux_like/mod.rs index 35c7598c911d8..0985f2d8a9f73 100644 --- a/src/unix/linux_like/mod.rs +++ b/src/unix/linux_like/mod.rs @@ -12,6 +12,12 @@ missing! { } s! { + #[cfg(libc_union)] + pub struct __c_anonymous_sigev_thread { + pub _function: *mut ::c_void, // Actually a function pointer + pub _attribute: *mut ::pthread_attr_t, + } + pub struct in_addr { pub s_addr: ::in_addr_t, } @@ -204,6 +210,22 @@ s! { pub msg_hdr: ::msghdr, pub msg_len: ::c_uint, } + + // When sigevent was first added to libc, Rust still didn't support unions. + // So the definition only included one of the union's member. This + // structure exists for backwards-compatibility with consumers that still + // try to access that one member. + #[doc(hidden)] + pub struct sigevent_0_2_126 { + pub sigev_value: ::sigval, + pub sigev_signo: ::c_int, + pub sigev_notify: ::c_int, + pub sigev_notify_thread_id: ::c_int, + #[cfg(target_pointer_width = "64")] + __unused1: [::c_int; 11], + #[cfg(target_pointer_width = "32")] + __unused1: [::c_int; 12] + } } s_no_extra_traits! { @@ -243,17 +265,38 @@ s_no_extra_traits! { pub domainname: [::c_char; 65] } + // Can't correctly impl Debug for unions + #[allow(missing_debug_implementations)] + #[cfg(libc_union)] + pub union __c_anonymous_sigev_un { + #[cfg(target_pointer_width = "64")] + _pad: [::c_int; (64 - 2 * 4 - 8) / 4], + #[cfg(target_pointer_width = "32")] + _pad: [::c_int; (64 - 2 * 4 - 4) / 4], + pub _tid: ::c_int, + pub _sigev_thread: __c_anonymous_sigev_thread, + } + + #[cfg(libc_union)] pub struct sigevent { pub sigev_value: ::sigval, pub sigev_signo: ::c_int, pub sigev_notify: ::c_int, - // Actually a union. We only expose sigev_notify_thread_id because it's - // the most useful member - pub sigev_notify_thread_id: ::c_int, - #[cfg(target_pointer_width = "64")] - __unused1: [::c_int; 11], - #[cfg(target_pointer_width = "32")] - __unused1: [::c_int; 12] + pub _sigev_un: __c_anonymous_sigev_un, + } +} + +impl ::core::ops::Deref for sigevent { + type Target = sigevent_0_2_126; + + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const Self as *const sigevent_0_2_126) } + } +} + +impl ::core::ops::DerefMut for sigevent { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *(self as *mut Self as *mut sigevent_0_2_126) } } } @@ -406,20 +449,49 @@ cfg_if! { self.sigev_value == other.sigev_value && self.sigev_signo == other.sigev_signo && self.sigev_notify == other.sigev_notify - && self.sigev_notify_thread_id - == other.sigev_notify_thread_id + // sigev_notify indicates which union fields are valid + && match self.sigev_notify { + ::SIGEV_NONE => true, + ::SIGEV_SIGNAL => true, + ::SIGEV_THREAD => unsafe { + self._sigev_un._sigev_thread + == other._sigev_un._sigev_thread + }, + #[cfg(any( + target_os = "android", + target_env = "gnu", + target_env = "uclibc", + ))] + ::SIGEV_THREAD_ID => unsafe { + self._sigev_un._tid == other._sigev_un._tid + }, + _ => false + } } } impl Eq for sigevent {} impl ::fmt::Debug for sigevent { fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { - f.debug_struct("sigevent") - .field("sigev_value", &self.sigev_value) - .field("sigev_signo", &self.sigev_signo) - .field("sigev_notify", &self.sigev_notify) - .field("sigev_notify_thread_id", - &self.sigev_notify_thread_id) - .finish() + let mut ds = f.debug_struct("sigevent"); + ds.field("sigev_value", &self.sigev_value); + ds.field("sigev_signo", &self.sigev_signo); + ds.field("sigev_notify", &self.sigev_notify); + // The sigev_notify field indicates which union fields are valid + unsafe { + match self.sigev_notify { + ::SIGEV_THREAD => ds.field("_sigev_thread", + &self._sigev_un._sigev_thread), + #[cfg(any( + target_os = "android", + target_env = "gnu", + target_env = "uclibc", + ))] + ::SIGEV_THREAD_ID => ds.field("_tid", + &self._sigev_un._tid), + _ => &mut ds + } + }; + ds.finish() } } impl ::hash::Hash for sigevent { @@ -427,7 +499,19 @@ cfg_if! { self.sigev_value.hash(state); self.sigev_signo.hash(state); self.sigev_notify.hash(state); - self.sigev_notify_thread_id.hash(state); + // The sigev_notify field indicates which union fields are valid + unsafe { + match self.sigev_notify { + ::SIGEV_THREAD => self._sigev_un._sigev_thread.hash(state), + #[cfg(any( + target_os = "android", + target_env = "gnu", + target_env = "uclibc", + ))] + ::SIGEV_THREAD_ID => self._sigev_un._tid.hash(state), + _ => () + }; + } } } } From c77fdd68f49fe4311e6bbad0b9df9d2e3d15c95a Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 24 Jun 2022 08:45:45 -0600 Subject: [PATCH 2/6] Deprecate the sigevent_0_2_126 structures --- src/unix/bsd/freebsdlike/freebsd/mod.rs | 6 ++++++ src/unix/linux_like/mod.rs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/unix/bsd/freebsdlike/freebsd/mod.rs b/src/unix/bsd/freebsdlike/freebsd/mod.rs index 463637fc6a105..2836a99e79720 100644 --- a/src/unix/bsd/freebsdlike/freebsd/mod.rs +++ b/src/unix/bsd/freebsdlike/freebsd/mod.rs @@ -1355,6 +1355,10 @@ s! { // structure exists for backwards-compatibility with consumers that still // try to access that one member. #[doc(hidden)] + #[deprecated( + since = "0.2.127", + note = "Use sigevent instead" + )] pub struct sigevent_0_2_126 { pub sigev_notify: ::c_int, pub sigev_signo: ::c_int, @@ -1664,6 +1668,7 @@ s_no_extra_traits! { } } +#[allow(deprecated)] impl ::core::ops::Deref for sigevent { type Target = sigevent_0_2_126; @@ -1672,6 +1677,7 @@ impl ::core::ops::Deref for sigevent { } } +#[allow(deprecated)] impl ::core::ops::DerefMut for sigevent { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut *(self as *mut Self as *mut sigevent_0_2_126) } diff --git a/src/unix/linux_like/mod.rs b/src/unix/linux_like/mod.rs index 0985f2d8a9f73..fc51fb3f8123a 100644 --- a/src/unix/linux_like/mod.rs +++ b/src/unix/linux_like/mod.rs @@ -216,6 +216,10 @@ s! { // structure exists for backwards-compatibility with consumers that still // try to access that one member. #[doc(hidden)] + #[deprecated( + since = "0.2.127", + note = "Use sigevent instead" + )] pub struct sigevent_0_2_126 { pub sigev_value: ::sigval, pub sigev_signo: ::c_int, @@ -286,6 +290,7 @@ s_no_extra_traits! { } } +#[allow(deprecated)] impl ::core::ops::Deref for sigevent { type Target = sigevent_0_2_126; @@ -294,6 +299,7 @@ impl ::core::ops::Deref for sigevent { } } +#[allow(deprecated)] impl ::core::ops::DerefMut for sigevent { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut *(self as *mut Self as *mut sigevent_0_2_126) } From 84057ced598e7e2759d90811f97f840103c50fc5 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 24 Jun 2022 12:04:30 -0600 Subject: [PATCH 3/6] Prevent safe construction of struct sigevent sigevent's Debug, PartialEq, and Hash trait impls might read union fields that could be potentially uninitialized by a standard initializer. Those trait impls shouldn't be present (see https://github.com/rust-lang/libc/issues/2816), but can't easily be removed. Until they get removed, the constructor must be `unsafe` to force the user to zero all fields. The same issue applies to the Deref trait impl, which exists only for backwards compatibility. --- src/unix/bsd/freebsdlike/freebsd/mod.rs | 6 ++++++ src/unix/linux_like/mod.rs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/unix/bsd/freebsdlike/freebsd/mod.rs b/src/unix/bsd/freebsdlike/freebsd/mod.rs index 2836a99e79720..bd4fca18203d7 100644 --- a/src/unix/bsd/freebsdlike/freebsd/mod.rs +++ b/src/unix/bsd/freebsdlike/freebsd/mod.rs @@ -1434,6 +1434,12 @@ s_no_extra_traits! { pub sigev_signo: ::c_int, pub sigev_value: ::sigval, pub _sigev_un: __c_anonymous_sigev_un, + /// Exists just to prevent the struct from being safely constructed, + /// because the Debug, Hash, PartialImpl, and + /// Deref trait impls might read uninitialized + /// fields of _sigev_un. This field may be removed once those trait + /// impls are. + _private: () } pub struct ptsstat { diff --git a/src/unix/linux_like/mod.rs b/src/unix/linux_like/mod.rs index fc51fb3f8123a..670ed0bb5babc 100644 --- a/src/unix/linux_like/mod.rs +++ b/src/unix/linux_like/mod.rs @@ -287,6 +287,12 @@ s_no_extra_traits! { pub sigev_signo: ::c_int, pub sigev_notify: ::c_int, pub _sigev_un: __c_anonymous_sigev_un, + /// Exists just to prevent the struct from being safely constructed, + /// because the Debug, Hash, PartialImpl, and + /// Deref trait impls might read uninitialized + /// fields of _sigev_un. This field may be removed once those trait + /// impls are. + _private: () } } From 70646307f39b7ca6e24136a1ed5440a8cb4005e7 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Fri, 24 Jun 2022 14:54:59 -0600 Subject: [PATCH 4/6] Fix the build with Rust 1.14.0 --- src/unix/bsd/freebsdlike/freebsd/mod.rs | 133 +++++++++++++++--------- src/unix/linux_like/mod.rs | 95 ++++++++++++----- 2 files changed, 151 insertions(+), 77 deletions(-) diff --git a/src/unix/bsd/freebsdlike/freebsd/mod.rs b/src/unix/bsd/freebsdlike/freebsd/mod.rs index bd4fca18203d7..ae2132949ff52 100644 --- a/src/unix/bsd/freebsdlike/freebsd/mod.rs +++ b/src/unix/bsd/freebsdlike/freebsd/mod.rs @@ -888,12 +888,6 @@ s! { pub profhz: ::c_int, } - #[cfg(libc_union)] - pub struct __c_anonymous_sigev_thread { - pub _function: *mut ::c_void, // Actually a function pointer - pub _attribute: *mut ::pthread_attr_t, - } - pub struct __c_anonymous_stailq_entry_devstat { pub stqe_next: *mut devstat, } @@ -1349,25 +1343,6 @@ s! { pub strchange_instrms: u16, pub strchange_outstrms: u16, } - - // When sigevent was first added to libc, Rust still didn't support unions. - // So the definition only included one of the union's member. This - // structure exists for backwards-compatibility with consumers that still - // try to access that one member. - #[doc(hidden)] - #[deprecated( - since = "0.2.127", - note = "Use sigevent instead" - )] - pub struct sigevent_0_2_126 { - pub sigev_notify: ::c_int, - pub sigev_signo: ::c_int, - pub sigev_value: ::sigval, - pub sigev_notify_thread_id: ::lwpid_t, - #[cfg(target_pointer_width = "64")] - __unused1: ::c_int, - __unused2: [::c_long; 7] - } } s_no_extra_traits! { @@ -1418,30 +1393,6 @@ s_no_extra_traits! { __reserved: [::c_long; 4] } - // Can't correctly impl Debug for unions - #[allow(missing_debug_implementations)] - #[cfg(libc_union)] - pub union __c_anonymous_sigev_un { - pub _threadid: ::__lwpid_t, - pub _sigev_thread: __c_anonymous_sigev_thread, - pub _kevent_flags: ::c_ushort, - __spare__: [::c_long; 8], - } - - #[cfg(libc_union)] - pub struct sigevent { - pub sigev_notify: ::c_int, - pub sigev_signo: ::c_int, - pub sigev_value: ::sigval, - pub _sigev_un: __c_anonymous_sigev_un, - /// Exists just to prevent the struct from being safely constructed, - /// because the Debug, Hash, PartialImpl, and - /// Deref trait impls might read uninitialized - /// fields of _sigev_un. This field may be removed once those trait - /// impls are. - _private: () - } - pub struct ptsstat { #[cfg(any(freebsd12, freebsd13, freebsd14))] pub dev: u64, @@ -1674,7 +1625,79 @@ s_no_extra_traits! { } } +#[cfg(libc_union)] +s! { + pub struct __c_anonymous_sigev_thread { + pub _function: *mut ::c_void, // Actually a function pointer + pub _attribute: *mut ::pthread_attr_t, + } + + // When sigevent was first added to libc, Rust still didn't support unions. + // So the definition only included one of the union's member. This + // structure exists for backwards-compatibility with consumers that still + // try to access that one member. + #[doc(hidden)] + #[deprecated( + since = "0.2.147", + note = "Use sigevent instead" + )] + pub struct sigevent_0_2_126 { + pub sigev_notify: ::c_int, + pub sigev_signo: ::c_int, + pub sigev_value: ::sigval, + pub sigev_notify_thread_id: ::lwpid_t, + #[cfg(target_pointer_width = "64")] + __unused1: ::c_int, + __unused2: [::c_long; 7] + } +} + +#[cfg(libc_union)] +s_no_extra_traits! { + // Can't correctly impl Debug for unions + #[allow(missing_debug_implementations)] + pub union __c_anonymous_sigev_un { + pub _threadid: ::__lwpid_t, + pub _sigev_thread: __c_anonymous_sigev_thread, + pub _kevent_flags: ::c_ushort, + __spare__: [::c_long; 8], + } + + pub struct sigevent { + pub sigev_notify: ::c_int, + pub sigev_signo: ::c_int, + pub sigev_value: ::sigval, + pub _sigev_un: __c_anonymous_sigev_un, + /// Exists just to prevent the struct from being safely constructed, + /// because the Debug, Hash, PartialImpl, and + /// Deref trait impls might read uninitialized + /// fields of _sigev_un. This field may be removed once those trait + /// impls are. + _private: () + } +} + +#[cfg(not(libc_union))] +s_no_extra_traits! { + pub struct sigevent { + pub sigev_notify: ::c_int, + pub sigev_signo: ::c_int, + pub sigev_value: ::sigval, + pub _unused0: ::lwpid_t, + #[cfg(target_pointer_width = "64")] + __unused1: ::c_int, + __unused2: [::c_long; 7], + /// Exists just to prevent the struct from being safely constructed, + /// because the Debug, Hash, PartialImpl, and + /// Deref trait impls might read uninitialized + /// fields of _sigev_un. This field may be removed once those trait + /// impls are. + _private: () + } +} + #[allow(deprecated)] +#[cfg(libc_union)] impl ::core::ops::Deref for sigevent { type Target = sigevent_0_2_126; @@ -1684,6 +1707,7 @@ impl ::core::ops::Deref for sigevent { } #[allow(deprecated)] +#[cfg(libc_union)] impl ::core::ops::DerefMut for sigevent { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut *(self as *mut Self as *mut sigevent_0_2_126) } @@ -1879,6 +1903,7 @@ cfg_if! { } } + #[cfg(libc_union)] impl PartialEq for sigevent { fn eq(&self, other: &sigevent) -> bool { self.sigev_notify == other.sigev_notify @@ -1904,6 +1929,14 @@ cfg_if! { } } } + #[cfg(not(libc_union))] + impl PartialEq for sigevent { + fn eq(&self, other: &sigevent) -> bool { + self.sigev_notify == other.sigev_notify + && self.sigev_signo == other.sigev_signo + && self.sigev_value == other.sigev_value + } + } impl Eq for sigevent {} impl ::fmt::Debug for sigevent { fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { @@ -1911,6 +1944,7 @@ cfg_if! { ds.field("sigev_notify", &self.sigev_notify); ds.field("sigev_signo", &self.sigev_signo); ds.field("sigev_value", &self.sigev_value); + #[cfg(libc_union)] // The sigev_notify field indicates which union fields are valid unsafe { match self.sigev_notify { @@ -1931,6 +1965,7 @@ cfg_if! { self.sigev_notify.hash(state); self.sigev_signo.hash(state); self.sigev_value.hash(state); + #[cfg(libc_union)] // The sigev_notify field indicates which union fields are valid unsafe { match self.sigev_notify { diff --git a/src/unix/linux_like/mod.rs b/src/unix/linux_like/mod.rs index 670ed0bb5babc..4b3f28b774f7d 100644 --- a/src/unix/linux_like/mod.rs +++ b/src/unix/linux_like/mod.rs @@ -12,12 +12,6 @@ missing! { } s! { - #[cfg(libc_union)] - pub struct __c_anonymous_sigev_thread { - pub _function: *mut ::c_void, // Actually a function pointer - pub _attribute: *mut ::pthread_attr_t, - } - pub struct in_addr { pub s_addr: ::in_addr_t, } @@ -210,26 +204,6 @@ s! { pub msg_hdr: ::msghdr, pub msg_len: ::c_uint, } - - // When sigevent was first added to libc, Rust still didn't support unions. - // So the definition only included one of the union's member. This - // structure exists for backwards-compatibility with consumers that still - // try to access that one member. - #[doc(hidden)] - #[deprecated( - since = "0.2.127", - note = "Use sigevent instead" - )] - pub struct sigevent_0_2_126 { - pub sigev_value: ::sigval, - pub sigev_signo: ::c_int, - pub sigev_notify: ::c_int, - pub sigev_notify_thread_id: ::c_int, - #[cfg(target_pointer_width = "64")] - __unused1: [::c_int; 11], - #[cfg(target_pointer_width = "32")] - __unused1: [::c_int; 12] - } } s_no_extra_traits! { @@ -269,6 +243,39 @@ s_no_extra_traits! { pub domainname: [::c_char; 65] } +} + +#[cfg(libc_union)] +s! { + pub struct __c_anonymous_sigev_thread { + pub _function: *mut ::c_void, // Actually a function pointer + pub _attribute: *mut ::pthread_attr_t, + } + + // When sigevent was first added to libc, Rust still didn't support unions. + // So the definition only included one of the union's member. This + // structure exists for backwards-compatibility with consumers that still + // try to access that one member. + #[doc(hidden)] + #[deprecated( + since = "0.2.127", + note = "Use sigevent instead" + )] + #[cfg(libc_union)] + pub struct sigevent_0_2_126 { + pub sigev_value: ::sigval, + pub sigev_signo: ::c_int, + pub sigev_notify: ::c_int, + pub sigev_notify_thread_id: ::c_int, + #[cfg(target_pointer_width = "64")] + __unused1: [::c_int; 11], + #[cfg(target_pointer_width = "32")] + __unused1: [::c_int; 12] + } +} + +#[cfg(libc_union)] +s_no_extra_traits!{ // Can't correctly impl Debug for unions #[allow(missing_debug_implementations)] #[cfg(libc_union)] @@ -281,7 +288,6 @@ s_no_extra_traits! { pub _sigev_thread: __c_anonymous_sigev_thread, } - #[cfg(libc_union)] pub struct sigevent { pub sigev_value: ::sigval, pub sigev_signo: ::c_int, @@ -289,7 +295,27 @@ s_no_extra_traits! { pub _sigev_un: __c_anonymous_sigev_un, /// Exists just to prevent the struct from being safely constructed, /// because the Debug, Hash, PartialImpl, and - /// Deref trait impls might read uninitialized + /// Deref trait impls might read uninitialized + /// fields of _sigev_un. This field may be removed once those trait + /// impls are. + _private: () + } +} + +#[cfg(not(libc_union))] +s_no_extra_traits!{ + pub struct sigevent { + pub sigev_value: ::sigval, + pub sigev_signo: ::c_int, + pub sigev_notify: ::c_int, + __unused0: ::c_int, + #[cfg(target_pointer_width = "64")] + __unused1: [::c_int; 11], + #[cfg(target_pointer_width = "32")] + __unused1: [::c_int; 12], + /// Exists just to prevent the struct from being safely constructed, + /// because the Debug, Hash, PartialImpl, and + /// Deref trait impls might read uninitialized /// fields of _sigev_un. This field may be removed once those trait /// impls are. _private: () @@ -297,6 +323,7 @@ s_no_extra_traits! { } #[allow(deprecated)] +#[cfg(libc_union)] impl ::core::ops::Deref for sigevent { type Target = sigevent_0_2_126; @@ -306,6 +333,7 @@ impl ::core::ops::Deref for sigevent { } #[allow(deprecated)] +#[cfg(libc_union)] impl ::core::ops::DerefMut for sigevent { fn deref_mut(&mut self) -> &mut Self::Target { unsafe { &mut *(self as *mut Self as *mut sigevent_0_2_126) } @@ -456,6 +484,7 @@ cfg_if! { } } + #[cfg(libc_union)] impl PartialEq for sigevent { fn eq(&self, other: &sigevent) -> bool { self.sigev_value == other.sigev_value @@ -481,6 +510,14 @@ cfg_if! { } } } + #[cfg(not(libc_union))] + impl PartialEq for sigevent { + fn eq(&self, other: &sigevent) -> bool { + self.sigev_value == other.sigev_value + && self.sigev_signo == other.sigev_signo + && self.sigev_notify == other.sigev_notify + } + } impl Eq for sigevent {} impl ::fmt::Debug for sigevent { fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result { @@ -488,6 +525,7 @@ cfg_if! { ds.field("sigev_value", &self.sigev_value); ds.field("sigev_signo", &self.sigev_signo); ds.field("sigev_notify", &self.sigev_notify); + #[cfg(libc_union)] // The sigev_notify field indicates which union fields are valid unsafe { match self.sigev_notify { @@ -511,6 +549,7 @@ cfg_if! { self.sigev_value.hash(state); self.sigev_signo.hash(state); self.sigev_notify.hash(state); + #[cfg(libc_union)] // The sigev_notify field indicates which union fields are valid unsafe { match self.sigev_notify { From c72e45ff4285239bfa3eb5a9d637be3ac4788b79 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 10 Jul 2022 09:44:39 -0600 Subject: [PATCH 5/6] Disable the 1-s!-macro-per-file style rule Rust 1.14.0 and earlier don't correctly expand #[cfg()] attributes within the macro, sometimes necessitating multiple s! macros per file. --- ci/style.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ci/style.rs b/ci/style.rs index 31adeae4fbde7..b50189a6966df 100644 --- a/ci/style.rs +++ b/ci/style.rs @@ -177,7 +177,15 @@ fn check_style(file: &str, path: &Path, err: &mut Errors) { } if s_macros == 2 { s_macros += 1; - err.error(path, i, "multiple s! macros in one module"); + // Can't enforce this rule until after raising the MSRV to 1.19.0 or + // later. It seems that earlier Rust versions ignore #[cfg()] + // attributes within the macro. As a result, it's sometimes + // necessary to have multiple s!{} macros in a single file. It's + // hard to debug, because cargo-expand doesn't work with such + // old versions. + // See also https://github.com/rust-lang/libc/pull/2813 + + // err.error(path, i, "multiple s! macros in one module"); } state = line_state; From 62d6477763f312b426906bfbb47cf017873325ed Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sun, 10 Jul 2022 09:48:10 -0600 Subject: [PATCH 6/6] style --- src/unix/linux_like/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unix/linux_like/mod.rs b/src/unix/linux_like/mod.rs index 4b3f28b774f7d..dd7b099c051f8 100644 --- a/src/unix/linux_like/mod.rs +++ b/src/unix/linux_like/mod.rs @@ -275,7 +275,7 @@ s! { } #[cfg(libc_union)] -s_no_extra_traits!{ +s_no_extra_traits! { // Can't correctly impl Debug for unions #[allow(missing_debug_implementations)] #[cfg(libc_union)] @@ -303,7 +303,7 @@ s_no_extra_traits!{ } #[cfg(not(libc_union))] -s_no_extra_traits!{ +s_no_extra_traits! { pub struct sigevent { pub sigev_value: ::sigval, pub sigev_signo: ::c_int,