From 6de7d63d2ec3bc9c0652ed880cb666a825b5b9c3 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Sat, 23 Mar 2024 09:23:24 -0600 Subject: [PATCH] Fix the definition of sigevent on FreeBSD and Linux 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. Remove traits that can't be safely implemented on a union: PartialEq, Eq, and Hash. Define Debug, but exclude the union field. --- libc-test/build.rs | 7 ++- src/unix/bsd/freebsdlike/freebsd/mod.rs | 72 +++++++++++-------------- src/unix/linux_like/linux/gnu/mod.rs | 39 +++++++------- src/unix/linux_like/mod.rs | 46 +++++++--------- 4 files changed, 77 insertions(+), 87 deletions(-) diff --git a/libc-test/build.rs b/libc-test/build.rs index 3e443bb86e932..ed186b00c79ba 100644 --- a/libc-test/build.rs +++ b/libc-test/build.rs @@ -2543,6 +2543,9 @@ fn test_freebsd(target: &str) { // not available until FreeBSD 12, and is an anonymous union there. ("xucred", "cr_pid__c_anonymous_union") => true, + // Anonymous union + ("sigevent", "_sigev_un") => true, + // m_owner field is a volatile __lwpid_t ("umutex", "m_owner") => true, // c_has_waiters field is a volatile int32_t @@ -4281,8 +4284,8 @@ 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") || + // _sigev_un is an anonymous union + (struct_ == "sigevent" && field == "_sigev_un") || // signalfd had SIGSYS fields added in Linux 4.18, but no libc release // has them yet. (struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" || diff --git a/src/unix/bsd/freebsdlike/freebsd/mod.rs b/src/unix/bsd/freebsdlike/freebsd/mod.rs index 4363b143d2027..7c1f9512cabf1 100644 --- a/src/unix/bsd/freebsdlike/freebsd/mod.rs +++ b/src/unix/bsd/freebsdlike/freebsd/mod.rs @@ -237,20 +237,9 @@ impl ::Clone for devstat_select_mode { } s! { - pub struct aiocb { - pub aio_fildes: ::c_int, - pub aio_offset: ::off_t, - pub aio_buf: *mut ::c_void, - pub aio_nbytes: ::size_t, - __unused1: [::c_int; 2], - __unused2: *mut ::c_void, - pub aio_lio_opcode: ::c_int, - pub aio_reqprio: ::c_int, - // unused 3 through 5 are the __aiocb_private structure - __unused3: ::c_long, - __unused4: ::c_long, - __unused5: *mut ::c_void, - pub aio_sigevent: sigevent + pub struct __c_anonymous_sigev_thread { + pub _function: *mut ::c_void, // Actually a function pointer + pub _attribute: *mut ::pthread_attr_t, } pub struct jail { @@ -1345,6 +1334,32 @@ s! { } s_no_extra_traits! { + #[cfg_attr(feature = "extra_traits", derive(Debug))] + pub struct aiocb { + pub aio_fildes: ::c_int, + pub aio_offset: ::off_t, + pub aio_buf: *mut ::c_void, + pub aio_nbytes: ::size_t, + __unused1: [::c_int; 2], + __unused2: *mut ::c_void, + pub aio_lio_opcode: ::c_int, + pub aio_reqprio: ::c_int, + // unused 3 through 5 are the __aiocb_private structure + __unused3: ::c_long, + __unused4: ::c_long, + __unused5: *mut ::c_void, + pub aio_sigevent: sigevent + } + + // 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 utmpx { pub ut_type: ::c_short, pub ut_tv: ::timeval, @@ -1392,12 +1407,7 @@ s_no_extra_traits! { 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 { @@ -1791,35 +1801,17 @@ cfg_if! { } } - 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 - && self.sigev_notify_thread_id - == other.sigev_notify_thread_id - } - } - 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) + // Skip _sigev_un, since we can't guarantee that it will be + // properly initialized. .finish() } } - impl ::hash::Hash for sigevent { - fn hash(&self, state: &mut H) { - self.sigev_notify.hash(state); - self.sigev_signo.hash(state); - self.sigev_value.hash(state); - self.sigev_notify_thread_id.hash(state); - } - } impl PartialEq for ptsstat { fn eq(&self, other: &ptsstat) -> bool { diff --git a/src/unix/linux_like/linux/gnu/mod.rs b/src/unix/linux_like/linux/gnu/mod.rs index 4d235ba0ad951..82afe7a0d8faa 100644 --- a/src/unix/linux_like/linux/gnu/mod.rs +++ b/src/unix/linux_like/linux/gnu/mod.rs @@ -49,24 +49,6 @@ s! { pub __statx_timestamp_pad1: [i32; 1], } - pub struct aiocb { - pub aio_fildes: ::c_int, - pub aio_lio_opcode: ::c_int, - pub aio_reqprio: ::c_int, - pub aio_buf: *mut ::c_void, - pub aio_nbytes: ::size_t, - pub aio_sigevent: ::sigevent, - __next_prio: *mut aiocb, - __abs_prio: ::c_int, - __policy: ::c_int, - __error_code: ::c_int, - __return_value: ::ssize_t, - pub aio_offset: off_t, - #[cfg(all(not(target_arch = "x86_64"), target_pointer_width = "32"))] - __unused1: [::c_char; 4], - __glibc_reserved: [::c_char; 32] - } - pub struct __exit_status { pub e_termination: ::c_short, pub e_exit: ::c_short, @@ -481,6 +463,27 @@ impl siginfo_t { } } +s_no_extra_traits! { + #[cfg_attr(feature = "extra_traits", derive(Debug))] + pub struct aiocb { + pub aio_fildes: ::c_int, + pub aio_lio_opcode: ::c_int, + pub aio_reqprio: ::c_int, + pub aio_buf: *mut ::c_void, + pub aio_nbytes: ::size_t, + pub aio_sigevent: ::sigevent, + __next_prio: *mut aiocb, + __abs_prio: ::c_int, + __policy: ::c_int, + __error_code: ::c_int, + __return_value: ::ssize_t, + pub aio_offset: off_t, + #[cfg(all(not(target_arch = "x86_64"), target_pointer_width = "32"))] + __unused1: [::c_char; 4], + __glibc_reserved: [::c_char; 32] + } +} + // Internal, for casts to access union fields #[repr(C)] struct sifields_sigchld { diff --git a/src/unix/linux_like/mod.rs b/src/unix/linux_like/mod.rs index 26a552101e4ca..564383fe3e690 100644 --- a/src/unix/linux_like/mod.rs +++ b/src/unix/linux_like/mod.rs @@ -12,6 +12,11 @@ missing! { } s! { + 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, } @@ -220,6 +225,17 @@ s_no_extra_traits! { pub u64: u64, } + // Can't correctly impl Debug for unions + #[allow(missing_debug_implementations)] + 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, + } + pub struct sockaddr_un { pub sun_family: sa_family_t, pub sun_path: [::c_char; 108] @@ -247,13 +263,7 @@ s_no_extra_traits! { 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, } } @@ -401,35 +411,17 @@ cfg_if! { } } - 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 - && self.sigev_notify_thread_id - == other.sigev_notify_thread_id - } - } - 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) + // Skip _sigev_un, since we can't guarantee that it will be + // properly initialized. .finish() } } - impl ::hash::Hash for sigevent { - fn hash(&self, state: &mut H) { - self.sigev_value.hash(state); - self.sigev_signo.hash(state); - self.sigev_notify.hash(state); - self.sigev_notify_thread_id.hash(state); - } - } } }