This commit is contained in:
Jeremy Soller
2025-11-08 20:59:05 -07:00
5 changed files with 93 additions and 9 deletions
+6 -4
View File
@@ -14,7 +14,7 @@ pub type sa_family_t = u16;
pub type socklen_t = u32;
#[repr(C)]
#[derive(Default)]
#[derive(Default, CheckVsLibcCrate)]
pub struct linger {
pub l_onoff: c_int,
pub l_linger: c_int,
@@ -24,7 +24,7 @@ pub struct linger {
pub extern "C" fn _cbindgen_export_linger(linger: linger) {}
#[repr(C)]
#[derive(Debug)]
#[derive(Debug, CheckVsLibcCrate)]
pub struct msghdr {
pub msg_name: *mut c_void,
pub msg_namelen: socklen_t,
@@ -36,7 +36,7 @@ pub struct msghdr {
}
#[repr(C)]
#[derive(Debug)]
#[derive(Debug, CheckVsLibcCrate)]
pub struct cmsghdr {
pub cmsg_len: size_t,
pub cmsg_level: c_int,
@@ -45,6 +45,7 @@ pub struct cmsghdr {
#[repr(C)]
#[derive(Clone, Copy, Debug)]
// FIXME: CheckVsLibcCrate
pub struct ucred {
pub pid: pid_t,
pub uid: uid_t,
@@ -55,7 +56,7 @@ pub struct ucred {
pub extern "C" fn _cbindgen_export_cmsghdr(cmsghdr: cmsghdr) {}
#[repr(C)]
#[derive(Default)]
#[derive(Default, CheckVsLibcCrate)]
pub struct sockaddr {
pub sa_family: sa_family_t,
pub sa_data: [c_char; 14],
@@ -75,6 +76,7 @@ const _SS_PADDING: usize = _SS_MAXSIZE - mem::size_of::<sa_family_t>() - mem::si
/// * The order of the fields is important because the bytes in the padding will be cast to and
/// from protocol structs in C
#[repr(C)]
//#[derive(CheckVsLibcCrate)] FIXME: can't ignore private fields yet
pub struct sockaddr_storage {
pub ss_family: sa_family_t,
__ss_pad2: [u8; _SS_PADDING],
+1 -1
View File
@@ -55,7 +55,7 @@ impl LogSink for LogFile {
connect(
log_fd,
&raw const log_addr as *const sockaddr,
size_of::<sockaddr_un>(),
size_of::<sockaddr_un>() as u32,
) < 0
} {
// In case close sets ERRNO.
+1 -1
View File
@@ -11,7 +11,7 @@ use crate::{
pub const IOV_MAX: c_int = 1024;
#[repr(C)]
#[derive(Debug)]
#[derive(Debug, CheckVsLibcCrate)]
pub struct iovec {
pub iov_base: *mut c_void,
pub iov_len: size_t,
+83
View File
@@ -410,3 +410,86 @@ macro_rules! OutProject {
unsafe impl $crate::out::OutProject for $name {}
}
}
#[macro_export]
#[cfg(not(feature = "check_against_libc_crate"))]
macro_rules! CheckVsLibcCrate {
derive() { $(#[$($attrs:meta),*])* $v:vis struct $name:ident {
$(
$(#[$($fa:meta),*])* $fv:vis $field:ident : $type:ty
),*$(,)?
} } => {
}
}
// TODO: probably exists nice nightly features that allow conflicting impls. Then we wouldn't need
// much of this redundant code just to say A == B -> B == A and say A == B -> *mut A == *mut B.
pub trait LibcTypeEquals<A, B> {}
//impl<A, B> LibcTypeEquals<A, B> for () {}
impl<A, B> LibcTypeEquals<*mut A, *mut B> for () where (): LibcTypeEquals<A, B> {}
impl<A, B> LibcTypeEquals<*const A, *const B> for () where (): LibcTypeEquals<A, B> {}
impl<A, B, const N: usize> LibcTypeEquals<[A; N], [B; N]> for () where (): LibcTypeEquals<A, B> {}
macro_rules! for_primitive_int(
($i:ident) => {
impl LibcTypeEquals<$i, $i> for () {}
}
);
for_primitive_int!(u8);
for_primitive_int!(u16);
for_primitive_int!(u32);
for_primitive_int!(u64);
for_primitive_int!(u128);
for_primitive_int!(usize);
for_primitive_int!(i8);
for_primitive_int!(i16);
for_primitive_int!(i32);
for_primitive_int!(i64);
for_primitive_int!(i128);
for_primitive_int!(isize);
impl LibcTypeEquals<crate::platform::types::c_void, crate::platform::types::c_void> for () {}
impl LibcTypeEquals<__libc_only_for_layout_checks::c_void, crate::platform::types::c_void> for () {}
impl LibcTypeEquals<crate::platform::types::c_void, __libc_only_for_layout_checks::c_void> for () {}
//impl LibcTypeEquals<__libc_only_for_layout_checks::c_void>
/// Derive macro which checks that structs here are defined the same as in the libc crate. Perhaps
/// not sufficiently rigorous to soundly cast between the types, but should catch most mistakes.
#[macro_export]
#[cfg(feature = "check_against_libc_crate")]
macro_rules! CheckVsLibcCrate {
// XXX: not sure we can have the name be different from libc::$name without parameters to the
// derive macro
derive() { $(#[$($attrs:meta),*])* $v:vis struct $name:ident {
$(
$(#[$($fa:meta),*])* $fv:vis $field:ident : $type:ty
),*$(,)?
} } => {
// TODO: check repr(C)? probably possible to match on $attrs
#[allow(dead_code)]
const _: () = {
if ::core::mem::size_of::<$name>() != ::core::mem::size_of::<::__libc_only_for_layout_checks::$name>() {
panic!("struct size mismatch");
}
if ::core::mem::align_of::<$name>() != ::core::mem::align_of::<::__libc_only_for_layout_checks::$name>() {
panic!("struct alignment mismatch");
}
$(
if ::core::mem::offset_of!($name, $field) != ::core::mem::offset_of!(__libc_only_for_layout_checks::$name, $field) {
panic!("struct field offset mismatch");
}
)*
};
$(
// check all field types are equivalent
#[allow(dead_code)]
const _: () = {
fn ensure_ty<A, B>(a: A, b: B) where (): $crate::macros::LibcTypeEquals::<A, B> {}
fn for_libc(a: $name, b: __libc_only_for_layout_checks::$name) {
let a: $type = panic!("never called");
ensure_ty(a, b.$field);
}
};
)*
impl $crate::macros::LibcTypeEquals<$name, __libc_only_for_layout_checks::$name> for () {}
impl $crate::macros::LibcTypeEquals<__libc_only_for_layout_checks::$name, $name> for () {}
}
}
+2 -3
View File
@@ -716,8 +716,7 @@ impl PalSocket for Sys {
}
_ => {
let metadata = [SocketCall::GetSockOpt as u64, option_name as u64];
let payload =
slice::from_raw_parts_mut(option_value as *mut u8, option_len);
let payload = slice::from_raw_parts_mut(option_value as *mut u8, option_len);
let call_flags = CallFlags::empty();
*option_len_ptr = redox_rt::sys::sys_call(
socket as usize,
@@ -810,7 +809,7 @@ impl PalSocket for Sys {
+ mem::size_of::<usize>() // payload_len
+ whole_iov_size // payload_data_buffer
+ mem::size_of::<usize>() // control_len
+ mhdr.msg_controllen as usize // ancillary_stream_buffer
+ mhdr.msg_controllen as usize // ancillary_stream_buffer
};
msg_stream
.try_reserve_exact(expected_stream_size)