diff --git a/src/buffer.rs b/src/buffer.rs index 3584c5b39..4f05ef036 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -173,6 +173,8 @@ impl<'a, T> private::Sealed for &'a mut [MaybeUninit] { #[inline] unsafe fn assume_init(self, len: usize) -> Self::Output { + // The syscall may report more than the buffer holds, as in an xattr size query. + let len = len.min(self.len()); let (init, uninit) = self.split_at_mut(len); // SAFETY: The user asserts that the slice is now initialized. @@ -192,6 +194,8 @@ impl<'a, T, const N: usize> private::Sealed for &'a mut [MaybeUninit; N] { #[inline] unsafe fn assume_init(self, len: usize) -> Self::Output { + // The syscall may report more than the buffer holds, as in an xattr size query. + let len = len.min(self.len()); let (init, uninit) = self.split_at_mut(len); // SAFETY: The user asserts that the slice is now initialized. @@ -212,6 +216,8 @@ impl<'a, T> private::Sealed for &'a mut Vec> { #[inline] unsafe fn assume_init(self, len: usize) -> Self::Output { + // The syscall may report more than the buffer holds, as in an xattr size query. + let len = len.min(self.len()); let (init, uninit) = self.split_at_mut(len); // SAFETY: The user asserts that the slice is now initialized. @@ -316,7 +322,8 @@ mod private { /// /// # Safety /// - /// At least `len` elements of the buffer must now be initialized. + /// At least `len` elements of the buffer, or the whole buffer if `len` is + /// larger, must now be initialized. #[must_use] unsafe fn assume_init(self, len: usize) -> Self::Output; } diff --git a/tests/fs/xattr.rs b/tests/fs/xattr.rs index ba2ff17aa..767f54590 100644 --- a/tests/fs/xattr.rs +++ b/tests/fs/xattr.rs @@ -131,6 +131,27 @@ fn xattr_basic() { ); } +#[test] +fn xattr_size_query_uninit() { + use rustix::fs::XattrFlags; + use std::mem::MaybeUninit; + + let tmp = tempfile::tempdir().unwrap(); + let path = tmp.path().join("file"); + std::fs::write(&path, b"").unwrap(); + rustix::fs::setxattr(&path, "user.test", b"hello", XattrFlags::empty()).unwrap(); + + let empty: &mut [MaybeUninit] = &mut []; + let (init, uninit) = rustix::fs::getxattr(&path, "user.test", empty).unwrap(); + assert!(init.is_empty()); + assert!(uninit.is_empty()); + + let empty: &mut [MaybeUninit] = &mut []; + let (init, uninit) = rustix::fs::listxattr(&path, empty).unwrap(); + assert!(init.is_empty()); + assert!(uninit.is_empty()); +} + /// To check the correctness of the tested implementations of *listxattr(), their output can be /// compared to an external implementation, in this case listxattr() from the libc crate. fn libc_listxattr(path: &str) -> usize {