Skip to content

Commit

Permalink
Update ReadDir::next in std::sys::pal::unix::fs to use `&raw const (*…
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
zachs18 committed Jan 15, 2025
1 parent dd333ca commit 58d6301
Showing 1 changed file with 13 additions and 23 deletions.
36 changes: 13 additions & 23 deletions library/std/src/sys/pal/unix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -709,7 +709,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.
Expand All @@ -735,44 +735,34 @@ 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::<dirent64>()).$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) => {
&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;
}

#[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")]
Expand Down

0 comments on commit 58d6301

Please sign in to comment.