block: replace as <pointer> casts with safer alternatives

`as` casts can change mutability, which quickly leads to undefined
behavior.

Signed-off-by: Julian Schindel <mail@arctic-alpaca.de>
This commit is contained in:
Julian Schindel
2026-04-29 21:55:06 +02:00
committed by Rob Bradford
parent 7455ff1ea4
commit 2b6e9df4e3
8 changed files with 37 additions and 47 deletions

View File

@@ -931,8 +931,7 @@ mod unit_tests {
unsafe { ptr::write_bytes(buf, 0xAB, alignment) };
// SAFETY: buf is aligned and sized for O_DIRECT; fd is valid.
let written =
unsafe { libc::pwrite(f.as_raw_fd(), buf as *const libc::c_void, alignment, 0) };
let written = unsafe { libc::pwrite(f.as_raw_fd(), buf.cast(), alignment, 0) };
assert_eq!(
written as usize,
alignment,
@@ -943,7 +942,7 @@ mod unit_tests {
// SAFETY: buf is valid for `alignment` bytes.
unsafe { ptr::write_bytes(buf, 0x00, alignment) };
// SAFETY: buf is aligned and sized for O_DIRECT; fd is valid.
let read = unsafe { libc::pread(f.as_raw_fd(), buf as *mut libc::c_void, alignment, 0) };
let read = unsafe { libc::pread(f.as_raw_fd(), buf.cast(), alignment, 0) };
assert_eq!(
read as usize,
alignment,

View File

@@ -15,7 +15,6 @@ use std::os::fd::{AsFd, BorrowedFd};
use std::os::unix::io::{AsRawFd, RawFd};
use std::slice;
use libc::c_void;
use vmm_sys_util::file_traits::FileSync;
use vmm_sys_util::seek_hole::SeekHole;
use vmm_sys_util::write_zeroes::{PunchHole, WriteZeroesAt};
@@ -39,14 +38,7 @@ fn is_valid_alignment(fd: RawFd, alignment: usize) -> bool {
assert!(!ptr.is_null());
// SAFETY: FFI call
let ret = unsafe {
::libc::pread(
fd,
ptr as *mut c_void,
alignment,
alignment.try_into().unwrap(),
)
};
let ret = unsafe { ::libc::pread(fd, ptr.cast(), alignment, alignment.try_into().unwrap()) };
// SAFETY: ptr was allocated by alloc_zeroed with layout
unsafe { dealloc(ptr, layout) };
@@ -187,7 +179,7 @@ impl Read for RawFile {
let ret = unsafe {
::libc::pread64(
self.file.as_raw_fd(),
tmp_buf.as_mut_ptr() as *mut c_void,
tmp_buf.as_mut_ptr().cast(),
tmp_buf.len(),
rounded_pos.try_into().unwrap(),
)
@@ -267,7 +259,7 @@ impl Write for RawFile {
let ret = unsafe {
::libc::pread64(
self.file.as_raw_fd(),
tmp_buf.as_mut_ptr() as *mut c_void,
tmp_buf.as_mut_ptr().cast(),
tmp_buf.len(),
rounded_pos.try_into().unwrap(),
)
@@ -286,7 +278,7 @@ impl Write for RawFile {
let ret = unsafe {
::libc::pwrite64(
self.file.as_raw_fd(),
tmp_buf.as_ptr() as *const c_void,
tmp_buf.as_ptr().cast(),
tmp_buf.len(),
rounded_pos.try_into().unwrap(),
)

View File

@@ -597,7 +597,7 @@ mod unit_tests {
let mut val = 0u64;
// SAFETY: reading 8 bytes from a valid eventfd.
unsafe {
libc::read(fd, &mut val as *mut u64 as *mut libc::c_void, 8);
libc::read(fd, (&raw mut val).cast(), 8);
}
}
}
@@ -605,7 +605,7 @@ mod unit_tests {
fn async_write(disk: &QcowDisk, offset: u64, data: &[u8]) {
let mut async_io = disk.create_async_io(1).unwrap();
let iovec = libc::iovec {
iov_base: data.as_ptr() as *mut libc::c_void,
iov_base: data.as_ptr().cast::<libc::c_void>().cast_mut(),
iov_len: data.len(),
};
async_io
@@ -624,7 +624,7 @@ mod unit_tests {
let mut async_io = disk.create_async_io(1).unwrap();
let mut buf = vec![0xFFu8; len];
let iovec = libc::iovec {
iov_base: buf.as_mut_ptr() as *mut libc::c_void,
iov_base: buf.as_mut_ptr().cast(),
iov_len: buf.len(),
};
async_io
@@ -755,11 +755,11 @@ mod unit_tests {
let offset_b: u64 = 65536;
let iov_a = libc::iovec {
iov_base: write_a.as_ptr() as *mut libc::c_void,
iov_base: write_a.as_ptr().cast::<libc::c_void>().cast_mut(),
iov_len: write_a.len(),
};
let iov_b = libc::iovec {
iov_base: write_b.as_ptr() as *mut libc::c_void,
iov_base: write_b.as_ptr().cast::<libc::c_void>().cast_mut(),
iov_len: write_b.len(),
};
@@ -793,11 +793,11 @@ mod unit_tests {
let mut read_a = vec![0u8; 4096];
let mut read_b = vec![0u8; 4096];
let riov_a = libc::iovec {
iov_base: read_a.as_mut_ptr() as *mut libc::c_void,
iov_base: read_a.as_mut_ptr().cast(),
iov_len: read_a.len(),
};
let riov_b = libc::iovec {
iov_base: read_b.as_mut_ptr() as *mut libc::c_void,
iov_base: read_b.as_mut_ptr().cast(),
iov_len: read_b.len(),
};
@@ -1068,7 +1068,7 @@ mod unit_tests {
let mut async_io = disk.create_async_io(1).unwrap();
let mut buf = vec![0xFFu8; cluster_size];
let iovec = libc::iovec {
iov_base: buf.as_mut_ptr() as *mut libc::c_void,
iov_base: buf.as_mut_ptr().cast(),
iov_len: buf.len(),
};
async_io.read_vectored(0, &[iovec], 1).unwrap();

View File

@@ -30,7 +30,7 @@ pub fn pread_exact(fd: RawFd, buf: &mut [u8], offset: u64) -> io::Result<()> {
let ret = unsafe {
libc::pread64(
fd,
buf[total..].as_mut_ptr() as *mut libc::c_void,
buf[total..].as_mut_ptr().cast(),
buf.len() - total,
(offset + total as u64) as libc::off_t,
)
@@ -81,7 +81,7 @@ pub fn pwrite_all(fd: RawFd, buf: &[u8], offset: u64) -> io::Result<()> {
let ret = unsafe {
libc::pwrite64(
fd,
buf[total..].as_ptr() as *const libc::c_void,
buf[total..].as_ptr().cast(),
buf.len() - total,
(offset + total as u64) as libc::off_t,
)
@@ -211,7 +211,7 @@ pub unsafe fn scatter_to_iovecs(iovecs: &[libc::iovec], start: usize, data: &[u8
let count = min(available, remaining.len());
// SAFETY: iov_base is valid for iov_len bytes per caller contract.
unsafe {
let dst = (iov.iov_base as *mut u8).add(iov_start);
let dst = iov.iov_base.cast::<u8>().add(iov_start);
ptr::copy_nonoverlapping(remaining.as_ptr(), dst, count);
}
remaining = &remaining[count..];
@@ -240,7 +240,7 @@ pub unsafe fn zero_fill_iovecs(iovecs: &[libc::iovec], start: usize, len: usize)
let count = min(available, remaining);
// SAFETY: iov_base is valid for iov_len bytes per caller contract.
unsafe {
let dst = (iov.iov_base as *mut u8).add(iov_start);
let dst = iov.iov_base.cast::<u8>().add(iov_start);
ptr::write_bytes(dst, 0, count);
}
remaining -= count;
@@ -270,7 +270,7 @@ pub unsafe fn gather_from_iovecs_into(iovecs: &[libc::iovec], start: usize, dst:
let count = min(available, len - written);
// SAFETY: iov_base is valid for iov_len bytes per caller contract.
unsafe {
let src = (iov.iov_base as *const u8).add(iov_start);
let src = iov.iov_base.cast::<u8>().add(iov_start);
ptr::copy_nonoverlapping(src, dst.as_mut_ptr().add(written), count);
}
written += count;

View File

@@ -353,7 +353,7 @@ mod unit_tests {
let mut async_io = disk.create_async_io(1).unwrap();
let mut buf = vec![0xFFu8; len];
let iovec = libc::iovec {
iov_base: buf.as_mut_ptr() as *mut libc::c_void,
iov_base: buf.as_mut_ptr().cast(),
iov_len: buf.len(),
};
async_io
@@ -368,7 +368,7 @@ mod unit_tests {
fn async_write(disk: &QcowDisk, offset: u64, data: &[u8]) {
let mut async_io = disk.create_async_io(1).unwrap();
let iovec = libc::iovec {
iov_base: data.as_ptr() as *mut libc::c_void,
iov_base: data.as_ptr().cast::<libc::c_void>().cast_mut(),
iov_len: data.len(),
};
async_io
@@ -1550,15 +1550,15 @@ mod unit_tests {
let c = vec![0xCCu8; 16 * 1024];
let iovecs_w = [
libc::iovec {
iov_base: a.as_ptr() as *mut libc::c_void,
iov_base: a.as_ptr().cast::<libc::c_void>().cast_mut(),
iov_len: a.len(),
},
libc::iovec {
iov_base: b.as_ptr() as *mut libc::c_void,
iov_base: b.as_ptr().cast::<libc::c_void>().cast_mut(),
iov_len: b.len(),
},
libc::iovec {
iov_base: c.as_ptr() as *mut libc::c_void,
iov_base: c.as_ptr().cast::<libc::c_void>().cast_mut(),
iov_len: c.len(),
},
];
@@ -1578,15 +1578,15 @@ mod unit_tests {
let mut r3 = vec![0u8; 8 * 1024];
let iovecs_r = [
libc::iovec {
iov_base: r1.as_mut_ptr() as *mut libc::c_void,
iov_base: r1.as_mut_ptr().cast(),
iov_len: r1.len(),
},
libc::iovec {
iov_base: r2.as_mut_ptr() as *mut libc::c_void,
iov_base: r2.as_mut_ptr().cast(),
iov_len: r2.len(),
},
libc::iovec {
iov_base: r3.as_mut_ptr() as *mut libc::c_void,
iov_base: r3.as_mut_ptr().cast(),
iov_len: r3.len(),
},
];

View File

@@ -291,7 +291,7 @@ impl Request {
.get_slice(data_addr, data_len)
.map_err(ExecuteError::GetHostAddress)?;
assert!(origin_ptr.len() >= data_len);
let origin_ptr = origin_ptr.ptr_guard();
let origin_ptr = origin_ptr.ptr_guard_mut();
// O_DIRECT requires buffer addresses to be aligned to the
// backend device's logical block size. In case it's not properly
@@ -299,7 +299,7 @@ impl Request {
// alignment, and a copy from/to the origin buffer is performed,
// depending on the type of operation.
let iov_base = if (origin_ptr.as_ptr() as u64).is_multiple_of(alignment) {
origin_ptr.as_ptr() as *mut libc::c_void
origin_ptr.as_ptr().cast()
} else {
let layout = Layout::from_size_align(data_len, alignment as usize).unwrap();
// SAFETY: layout has non-zero size
@@ -327,7 +327,7 @@ impl Request {
layout,
});
aligned_ptr as *mut libc::c_void
aligned_ptr.cast()
};
let iovec = libc::iovec {

View File

@@ -135,7 +135,7 @@ impl Header {
.map_err(VhdxHeaderError::ReadHeader)?;
// SAFETY: buffer is of correct size and has been successfully filled.
let header = unsafe { *(buffer.as_ptr() as *mut Header) };
let header: Header = unsafe { *(buffer.as_ptr().cast()) };
if header.signature != HEADER_SIGN {
return Err(VhdxHeaderError::InvalidHeaderSign);
}
@@ -151,9 +151,8 @@ impl Header {
/// Converts the header structure into a buffer
fn write_to_buffer(&self, buffer: &mut [u8; HEADER_SIZE as usize]) {
// SAFETY: self is a valid header.
let reference = unsafe {
std::slice::from_raw_parts(self as *const Header as *const u8, HEADER_SIZE as usize)
};
let reference =
unsafe { std::slice::from_raw_parts((&raw const *self).cast(), HEADER_SIZE as usize) };
*buffer = reference.try_into().unwrap();
}
@@ -222,7 +221,7 @@ impl RegionTableHeader {
.map_err(VhdxHeaderError::ReadRegionTableHeader)?;
// SAFETY: buffer is of correct size and has been successfully filled.
let region_table_header = unsafe { *(buffer.as_ptr() as *mut RegionTableHeader) };
let region_table_header: RegionTableHeader = unsafe { *(buffer.as_ptr().cast()) };
if region_table_header.signature != REGION_SIGN {
return Err(VhdxHeaderError::InvalidRegionSign);
}
@@ -340,7 +339,7 @@ impl RegionTableEntry {
pub fn new(buffer: &[u8]) -> Result<RegionTableEntry> {
assert!(buffer.len() == std::mem::size_of::<RegionTableEntry>());
// SAFETY: the assertion above makes sure the buffer size is correct.
let mut region_table_entry = unsafe { *(buffer.as_ptr() as *mut RegionTableEntry) };
let mut region_table_entry: RegionTableEntry = unsafe { *(buffer.as_ptr().cast()) };
let uuid = crate::vhdx::uuid_from_guid(buffer);
region_table_entry.guid = uuid;

View File

@@ -280,7 +280,7 @@ impl MetadataTableHeader {
pub fn new(buffer: &[u8]) -> Result<MetadataTableHeader> {
assert!(buffer.len() == std::mem::size_of::<MetadataTableHeader>());
// SAFETY: the assertion above makes sure the buffer size is correct.
let metadata_table_header = unsafe { *(buffer.as_ptr() as *mut MetadataTableHeader) };
let metadata_table_header: MetadataTableHeader = unsafe { *(buffer.as_ptr().cast()) };
if metadata_table_header.signature != METADATA_SIGN {
return Err(VhdxMetadataError::InvalidMetadataSign);
@@ -313,7 +313,7 @@ impl MetadataTableEntry {
fn new(buffer: &[u8]) -> Result<MetadataTableEntry> {
assert!(buffer.len() == std::mem::size_of::<MetadataTableEntry>());
// SAFETY: the assertion above makes sure the buffer size is correct.
let mut metadata_table_entry = unsafe { *(buffer.as_ptr() as *mut MetadataTableEntry) };
let mut metadata_table_entry: MetadataTableEntry = unsafe { *(buffer.as_ptr().cast()) };
let uuid = crate::vhdx::uuid_from_guid(buffer);
metadata_table_entry.item_id = uuid;