From 284a8e7ef77e3c62a63453a17553ebb3af7fe396 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Mon, 23 Dec 2024 00:33:10 -0600 Subject: [PATCH 1/2] Update ReadDir::next in std::sys::pal::unix::fs to use `&raw const (*ptr).field` instead of `ptr.offset(...).cast()`. Also, the macro is only called three times, and all with the same local variable entry_ptr, so just use the local variable directly, and rename the macro to entry_field_ptr. --- library/std/src/sys/pal/unix/fs.rs | 37 ++++++++++++------------------ 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 37029bcd36e30..a57f7865f3ff9 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -713,7 +713,7 @@ impl Iterator for ReadDir { // thread safety for readdir() as long an individual DIR* is not accessed // concurrently, which is sufficient for Rust. super::os::set_errno(0); - let entry_ptr = readdir64(self.inner.dirp.0); + let entry_ptr: *const dirent64 = readdir64(self.inner.dirp.0); if entry_ptr.is_null() { // We either encountered an error, or reached the end. Either way, // the next call to next() should return None. @@ -739,29 +739,22 @@ impl Iterator for ReadDir { // contents were "simply" partially initialized data. // // Like for uninitialized contents, converting entry_ptr to `&dirent64` - // would not be legal. However, unique to dirent64 is that we don't even - // get to use `&raw const (*entry_ptr).d_name` because that operation - // requires the full extent of *entry_ptr to be in bounds of the same - // allocation, which is not necessarily the case here. - // - // Instead we must access fields individually through their offsets. - macro_rules! offset_ptr { - ($entry_ptr:expr, $field:ident) => {{ - const OFFSET: isize = mem::offset_of!(dirent64, $field) as isize; - if true { - // Cast to the same type determined by the else branch. - $entry_ptr.byte_offset(OFFSET).cast::<_>() - } else { - #[allow(deref_nullptr)] - { - &raw const (*ptr::null::()).$field - } - } + // would not be legal. However, we can use `&raw const (*entry_ptr).d_name` + // to refer the fields individually, because that operation is equivalent + // to `byte_offset` and thus does not require the full extent of `*entry_ptr` + // to be in bounds of the same allocation, only the offset of the field + // being referenced. + macro_rules! entry_field_ptr { + ($field:ident) => {{ + // To make sure the field actually exists and is visible, + // and we aren't silently doing any Deref coercion. + const _: usize = mem::offset_of!(dirent64, $field); + &raw const (*entry_ptr).$field }}; } // d_name is guaranteed to be null-terminated. - let name = CStr::from_ptr(offset_ptr!(entry_ptr, d_name).cast()); + let name = CStr::from_ptr(entry_field_ptr!(d_name).cast()); let name_bytes = name.to_bytes(); if name_bytes == b"." || name_bytes == b".." { continue; @@ -769,14 +762,14 @@ impl Iterator for ReadDir { #[cfg(not(target_os = "vita"))] let entry = dirent64_min { - d_ino: *offset_ptr!(entry_ptr, d_ino) as u64, + d_ino: *entry_field_ptr!(d_ino) as u64, #[cfg(not(any( target_os = "solaris", target_os = "illumos", target_os = "aix", target_os = "nto", )))] - d_type: *offset_ptr!(entry_ptr, d_type) as u8, + d_type: *entry_field_ptr!(d_type) as u8, }; #[cfg(target_os = "vita")] From f010518b331cb6207c6359ed81308a9c5d731286 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Mon, 23 Dec 2024 02:41:18 -0600 Subject: [PATCH 2/2] Update comment on field check --- library/std/src/sys/pal/unix/fs.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index a57f7865f3ff9..865db9374502c 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -746,8 +746,7 @@ impl Iterator for ReadDir { // being referenced. macro_rules! entry_field_ptr { ($field:ident) => {{ - // To make sure the field actually exists and is visible, - // and we aren't silently doing any Deref coercion. + // To make sure we aren't silently doing any Deref coercion. const _: usize = mem::offset_of!(dirent64, $field); &raw const (*entry_ptr).$field }};