make write_at unsafe fn and add more safety comments

This commit is contained in:
Motoyuki Kimura 2025-09-06 02:03:10 +09:00
parent 901986c82d
commit 05c8c17e06
2 changed files with 17 additions and 4 deletions

View File

@ -56,7 +56,15 @@ async fn write_uring(path: &Path, contents: OwnedBuf) -> io::Result<()> {
let mut pos = 0;
let mut buf = contents.as_ref();
while !buf.is_empty() {
let n = Op::write_at(fd, buf, pos)?.await? as usize;
// SAFETY:
// If the operation completes successfully, `fd` and `buf` are still
// alive within the scope of this function, so remain valid.
//
// In the case of cancellation, local variables within the scope of
// this `async fn` are dropped in the reverse order of their declaration.
// Therefore, `Op` is dropped before `fd` and `buf`, ensuring that the
// operation finishes gracefully before these resources are dropped.
let n = unsafe { Op::write_at(fd, buf, pos) }?.await? as usize;
if n == 0 {
return Err(io::ErrorKind::WriteZero.into());
}

View File

@ -23,7 +23,12 @@ impl Cancellable for Write {
}
impl Op<Write> {
pub(crate) fn write_at(fd: BorrowedFd<'_>, buf: &[u8], offset: u64) -> io::Result<Self> {
/// # SAFETY
///
/// The caller must ensure that `fd` and `buf` remain valid until the
/// operation finishes (or gets cancelled) and the `Op::drop` completes.
/// Otherwise, the kernel could access freed memory, breaking soundness.
pub(crate) unsafe fn write_at(fd: BorrowedFd<'_>, buf: &[u8], offset: u64) -> io::Result<Self> {
// There is a cap on how many bytes we can write in a single uring write operation.
// ref: https://github.com/axboe/liburing/discussions/497
let len: u32 = cmp::min(buf.len(), u32::MAX as usize) as u32;
@ -32,8 +37,8 @@ impl Op<Write> {
.offset(offset)
.build();
// SAFETY: `fd` and `buf` are owned by caller function, ensuring these params are
// valid until operation completes.
// SAFETY: `fd` and `buf` valid until the operation completes or gets cancelled
// and the `Op::drop` completes.
let op = unsafe { Op::new(sqe, Write) };
Ok(op)
}