Skip to content
/ rust Public
forked from rust-lang/rust

Commit 56eb7bd

Browse files
authored
Rollup merge of rust-lang#134678 - zachs18:offset-ptr-update, r=tgross35
Update `ReadDir::next` in `std::sys::pal::unix::fs` to use `&raw const (*p).field` instead of `p.byte_offset().cast()` Since rust-lang/reference#1387 and rust-lang#117572, `&raw mut (*p).field`/`addr_of!((*p).field)` is defined to have the same inbounds preconditions as `ptr::offset`/`ptr::byte_offset`. I.e. `&raw const (*p).field` does not require that `p: *const T` point to a full `size_of::<T>()` bytes of memory, only that `p.byte_add(offset_of!(T, field))` is defined. The old comment "[...] 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 [...]" is now outdated, and the code can be simplified to use `&raw const (*entry_ptr).field`. ------- There should be no behavior differences from this PR. The `: *const dirent64` on line 716 and the `const _: usize = mem::offset_of!(dirent64, $field);` and comment on lines 749-751 are just sanity checks and should not affect semantics. Since the `offset_ptr!` macro is only called three times, and all with the same local variable entry_ptr, I just used the local variable directly in the macro instead of taking it as an input, and renamed the macro to `entry_field_ptr!`. The whole macro could also be removed and replaced with just using `&raw const (*entry_ptr).field` in the three places, but the comments on the macro seemed worthwhile to keep.
2 parents bf4aeeb + 58d6301 commit 56eb7bd

File tree

1 file changed

+13
-23
lines changed
  • library/std/src/sys/pal/unix

1 file changed

+13
-23
lines changed

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

+13-23
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@ impl Iterator for ReadDir {
709709
// thread safety for readdir() as long an individual DIR* is not accessed
710710
// concurrently, which is sufficient for Rust.
711711
super::os::set_errno(0);
712-
let entry_ptr = readdir64(self.inner.dirp.0);
712+
let entry_ptr: *const dirent64 = readdir64(self.inner.dirp.0);
713713
if entry_ptr.is_null() {
714714
// We either encountered an error, or reached the end. Either way,
715715
// the next call to next() should return None.
@@ -735,44 +735,34 @@ impl Iterator for ReadDir {
735735
// contents were "simply" partially initialized data.
736736
//
737737
// Like for uninitialized contents, converting entry_ptr to `&dirent64`
738-
// would not be legal. However, unique to dirent64 is that we don't even
739-
// get to use `&raw const (*entry_ptr).d_name` because that operation
740-
// requires the full extent of *entry_ptr to be in bounds of the same
741-
// allocation, which is not necessarily the case here.
742-
//
743-
// Instead we must access fields individually through their offsets.
744-
macro_rules! offset_ptr {
745-
($entry_ptr:expr, $field:ident) => {{
746-
const OFFSET: isize = mem::offset_of!(dirent64, $field) as isize;
747-
if true {
748-
// Cast to the same type determined by the else branch.
749-
$entry_ptr.byte_offset(OFFSET).cast::<_>()
750-
} else {
751-
#[allow(deref_nullptr)]
752-
{
753-
&raw const (*ptr::null::<dirent64>()).$field
754-
}
755-
}
756-
}};
738+
// would not be legal. However, we can use `&raw const (*entry_ptr).d_name`
739+
// to refer the fields individually, because that operation is equivalent
740+
// to `byte_offset` and thus does not require the full extent of `*entry_ptr`
741+
// to be in bounds of the same allocation, only the offset of the field
742+
// being referenced.
743+
macro_rules! entry_field_ptr {
744+
($field:ident) => {
745+
&raw const (*entry_ptr).$field
746+
};
757747
}
758748

759749
// d_name is guaranteed to be null-terminated.
760-
let name = CStr::from_ptr(offset_ptr!(entry_ptr, d_name).cast());
750+
let name = CStr::from_ptr(entry_field_ptr!(d_name).cast());
761751
let name_bytes = name.to_bytes();
762752
if name_bytes == b"." || name_bytes == b".." {
763753
continue;
764754
}
765755

766756
#[cfg(not(target_os = "vita"))]
767757
let entry = dirent64_min {
768-
d_ino: *offset_ptr!(entry_ptr, d_ino) as u64,
758+
d_ino: *entry_field_ptr!(d_ino) as u64,
769759
#[cfg(not(any(
770760
target_os = "solaris",
771761
target_os = "illumos",
772762
target_os = "aix",
773763
target_os = "nto",
774764
)))]
775-
d_type: *offset_ptr!(entry_ptr, d_type) as u8,
765+
d_type: *entry_field_ptr!(d_type) as u8,
776766
};
777767

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

0 commit comments

Comments
 (0)