Skip to content

Commit 284a8e7

Browse files
committed
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.
1 parent 908af5b commit 284a8e7

File tree

1 file changed

+15
-22
lines changed
  • library/std/src/sys/pal/unix

1 file changed

+15
-22
lines changed

library/std/src/sys/pal/unix/fs.rs

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ impl Iterator for ReadDir {
713713
// thread safety for readdir() as long an individual DIR* is not accessed
714714
// concurrently, which is sufficient for Rust.
715715
super::os::set_errno(0);
716-
let entry_ptr = readdir64(self.inner.dirp.0);
716+
let entry_ptr: *const dirent64 = readdir64(self.inner.dirp.0);
717717
if entry_ptr.is_null() {
718718
// We either encountered an error, or reached the end. Either way,
719719
// the next call to next() should return None.
@@ -739,44 +739,37 @@ impl Iterator for ReadDir {
739739
// contents were "simply" partially initialized data.
740740
//
741741
// Like for uninitialized contents, converting entry_ptr to `&dirent64`
742-
// would not be legal. However, unique to dirent64 is that we don't even
743-
// get to use `&raw const (*entry_ptr).d_name` because that operation
744-
// requires the full extent of *entry_ptr to be in bounds of the same
745-
// allocation, which is not necessarily the case here.
746-
//
747-
// Instead we must access fields individually through their offsets.
748-
macro_rules! offset_ptr {
749-
($entry_ptr:expr, $field:ident) => {{
750-
const OFFSET: isize = mem::offset_of!(dirent64, $field) as isize;
751-
if true {
752-
// Cast to the same type determined by the else branch.
753-
$entry_ptr.byte_offset(OFFSET).cast::<_>()
754-
} else {
755-
#[allow(deref_nullptr)]
756-
{
757-
&raw const (*ptr::null::<dirent64>()).$field
758-
}
759-
}
742+
// would not be legal. However, we can use `&raw const (*entry_ptr).d_name`
743+
// to refer the fields individually, because that operation is equivalent
744+
// to `byte_offset` and thus does not require the full extent of `*entry_ptr`
745+
// to be in bounds of the same allocation, only the offset of the field
746+
// being referenced.
747+
macro_rules! entry_field_ptr {
748+
($field:ident) => {{
749+
// To make sure the field actually exists and is visible,
750+
// and we aren't silently doing any Deref coercion.
751+
const _: usize = mem::offset_of!(dirent64, $field);
752+
&raw const (*entry_ptr).$field
760753
}};
761754
}
762755

763756
// d_name is guaranteed to be null-terminated.
764-
let name = CStr::from_ptr(offset_ptr!(entry_ptr, d_name).cast());
757+
let name = CStr::from_ptr(entry_field_ptr!(d_name).cast());
765758
let name_bytes = name.to_bytes();
766759
if name_bytes == b"." || name_bytes == b".." {
767760
continue;
768761
}
769762

770763
#[cfg(not(target_os = "vita"))]
771764
let entry = dirent64_min {
772-
d_ino: *offset_ptr!(entry_ptr, d_ino) as u64,
765+
d_ino: *entry_field_ptr!(d_ino) as u64,
773766
#[cfg(not(any(
774767
target_os = "solaris",
775768
target_os = "illumos",
776769
target_os = "aix",
777770
target_os = "nto",
778771
)))]
779-
d_type: *offset_ptr!(entry_ptr, d_type) as u8,
772+
d_type: *entry_field_ptr!(d_type) as u8,
780773
};
781774

782775
#[cfg(target_os = "vita")]

0 commit comments

Comments
 (0)