Replace AlignedAs with a more specific Align8 type

This commit is contained in:
Thom Chiovoloni 2022-08-30 01:15:59 -07:00
parent d9c760db43
commit 5c3490c901
No known key found for this signature in database
GPG key ID: D7733D1D7A775F0A
3 changed files with 20 additions and 52 deletions

View file

@ -11,7 +11,7 @@ use crate::slice;
use crate::sync::Arc;
use crate::sys::handle::Handle;
use crate::sys::time::SystemTime;
use crate::sys::{c, cvt, AlignedAs};
use crate::sys::{c, cvt, Align8};
use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::thread;
@ -47,9 +47,6 @@ pub struct ReadDir {
first: Option<c::WIN32_FIND_DATAW>,
}
type AlignedReparseBuf =
AlignedAs<c::REPARSE_DATA_BUFFER, [u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]>;
struct FindNextFileHandle(c::HANDLE);
unsafe impl Send for FindNextFileHandle {}
@ -329,7 +326,7 @@ impl File {
cvt(c::GetFileInformationByHandle(self.handle.as_raw_handle(), &mut info))?;
let mut reparse_tag = 0;
if info.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 {
let mut b = AlignedReparseBuf::new([0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
let mut b = Align8([0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
if let Ok((_, buf)) = self.reparse_point(&mut b) {
reparse_tag = (*buf).ReparseTag;
}
@ -392,7 +389,7 @@ impl File {
attr.file_size = info.AllocationSize as u64;
attr.number_of_links = Some(info.NumberOfLinks);
if attr.file_type().is_reparse_point() {
let mut b = AlignedReparseBuf::new([0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
let mut b = Align8([0; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
if let Ok((_, buf)) = self.reparse_point(&mut b) {
attr.reparse_tag = (*buf).ReparseTag;
}
@ -466,28 +463,32 @@ impl File {
// avoid narrowing provenance to the actual `REPARSE_DATA_BUFFER`.
fn reparse_point(
&self,
space: &mut AlignedReparseBuf,
space: &mut Align8<[u8]>,
) -> io::Result<(c::DWORD, *const c::REPARSE_DATA_BUFFER)> {
unsafe {
let mut bytes = 0;
cvt({
// Grab this in advance to avoid it invalidating the pointer
// we get from `space.0.as_mut_ptr()`.
let len = space.0.len();
c::DeviceIoControl(
self.handle.as_raw_handle(),
c::FSCTL_GET_REPARSE_POINT,
ptr::null_mut(),
0,
space.value.as_mut_ptr() as *mut _,
space.value.len() as c::DWORD,
space.0.as_mut_ptr().cast(),
len as c::DWORD,
&mut bytes,
ptr::null_mut(),
)
})?;
Ok((bytes, space.value.as_ptr().cast::<c::REPARSE_DATA_BUFFER>()))
const _: () = assert!(core::mem::align_of::<c::REPARSE_DATA_BUFFER>() <= 8);
Ok((bytes, space.0.as_ptr().cast::<c::REPARSE_DATA_BUFFER>()))
}
}
fn readlink(&self) -> io::Result<PathBuf> {
let mut space = AlignedReparseBuf::new([0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
let mut space = Align8([0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
let (_bytes, buf) = self.reparse_point(&mut space)?;
unsafe {
let (path_buffer, subst_off, subst_len, relative) = match (*buf).ReparseTag {
@ -1345,8 +1346,8 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
let h = f.as_inner().as_raw_handle();
unsafe {
let mut data = AlignedReparseBuf::new([0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
let data_ptr = data.value.as_mut_ptr();
let mut data = Align8([0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
let data_ptr = data.0.as_mut_ptr();
let db = data_ptr.cast::<c::REPARSE_MOUNTPOINT_DATA_BUFFER>();
let buf = ptr::addr_of_mut!((*db).ReparseTarget).cast::<c::WCHAR>();
let mut i = 0;

View file

@ -330,25 +330,10 @@ pub fn abort_internal() -> ! {
crate::intrinsics::abort();
}
/// Used for some win32 buffers which are stack allocated, for example:
/// `AlignedAs<c::REPARSE_DATA_BUFFER, [u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]>`
#[repr(C)]
/// Align the inner value to 8 bytes.
///
/// This is enough for almost all of the buffers we're likely to work with in
/// the Windows APIs we use.
#[repr(C, align(8))]
#[derive(Copy, Clone)]
pub struct AlignedAs<Aligner, Alignee: ?Sized> {
/// Use `[Aligner; 0]` as a sort of `PhantomAlignNextField<Aligner>`. This
/// is a bit of a hack, and could break (in a way that's caught by tests) if
/// #81996 is fixed.
aligner: [Aligner; 0],
/// The aligned value. Public rather than exposed via accessors so that if
/// needed it can be used with `addr_of` and such (also, this is less code).
pub value: Alignee,
}
impl<Aligner, Alignee> AlignedAs<Aligner, Alignee> {
// This is frequently used with large stack buffers, so force-inline to
// try and avoid using 2x as much stack space in debug builds.
#[inline(always)]
pub const fn new(value: Alignee) -> Self {
Self { aligner: [], value }
}
}
pub(crate) struct Align8<T: ?Sized>(pub T);

View file

@ -11,21 +11,3 @@ fn ntstatus_error() {
.contains("FormatMessageW() returned error")
);
}
#[test]
fn smoketest_aligned_as() {
use crate::{
mem::{align_of, size_of},
ptr::addr_of,
sys::{c, AlignedAs},
};
type AlignedReparseBuf =
AlignedAs<c::REPARSE_DATA_BUFFER, [u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]>;
assert!(size_of::<AlignedReparseBuf>() >= c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
assert_eq!(align_of::<AlignedReparseBuf>(), align_of::<c::REPARSE_DATA_BUFFER>());
let a = AlignedReparseBuf::new([0u8; c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
// Quick and dirty offsetof check.
assert_eq!(addr_of!(a).cast::<u8>(), addr_of!(a.value).cast::<u8>());
// Smoke check that it's actually aligned.
assert!(addr_of!(a.value).is_aligned_to(align_of::<c::REPARSE_DATA_BUFFER>()));
}