Skip to content

Commit

Permalink
Fix the definition of sigevent on FreeBSD and Linux
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
asomers authored and JohnTitor committed Apr 26, 2024
1 parent bdc4282 commit 6de7d63
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 87 deletions.
7 changes: 5 additions & 2 deletions libc-test/build.rs
Expand Up @@ -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
Expand Down Expand Up @@ -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" ||
Expand Down
72 changes: 32 additions & 40 deletions src/unix/bsd/freebsdlike/freebsd/mod.rs
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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<H: ::hash::Hasher>(&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 {
Expand Down
39 changes: 21 additions & 18 deletions src/unix/linux_like/linux/gnu/mod.rs
Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down
46 changes: 19 additions & 27 deletions src/unix/linux_like/mod.rs
Expand Up @@ -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,
}
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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,
}
}

Expand Down Expand Up @@ -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<H: ::hash::Hasher>(&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);
}
}
}
}

Expand Down

0 comments on commit 6de7d63

Please sign in to comment.