diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index b633beae89136..326da6ffb356a 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1784,6 +1784,9 @@ impl Vec { /// [`drain`]: Vec::drain #[stable(feature = "rust1", since = "1.0.0")] pub fn truncate(&mut self, len: usize) { + // SAFETY: `BufWriter::flush_buf` assumes that this will not + // de-initialize any elements of the spare capacity. + // This is safe because: // // * the slice passed to `drop_in_place` is valid; the `len > self.len` @@ -1857,6 +1860,9 @@ impl Vec { #[rustc_diagnostic_item = "vec_as_mut_slice"] #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")] pub const fn as_mut_slice(&mut self) -> &mut [T] { + // SAFETY: `BufWriter::flush_buf` assumes that this will not + // de-initialize any elements of the spare capacity. + // SAFETY: `slice::from_raw_parts_mut` requires pointee is a contiguous, aligned buffer of // size `len` containing properly-initialized `T`s. Data must not be accessed through any // other pointer for the returned lifetime. Further, `len * size_of::` <= diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs index 5a52a5df33ed7..6b85e89551b69 100644 --- a/library/core/src/io/borrowed_buf.rs +++ b/library/core/src/io/borrowed_buf.rs @@ -92,7 +92,7 @@ impl<'data> BorrowedBuf<'data> { self.filled } - /// Returns the length of the initialized part of the buffer. + /// Returns `true` if the buffer is initialized. #[unstable(feature = "borrowed_buf_init", issue = "78485")] #[inline] pub fn is_init(&self) -> bool { diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 1b34724e6ccdb..1a5cc911c0e43 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -193,6 +193,10 @@ impl BufWriter { /// `write`), any 0-length writes from `inner` must be reported as i/o /// errors from this method. pub(in crate::io) fn flush_buf(&mut self) -> io::Result<()> { + // SAFETY: `::copy_from` assumes that + // this will not de-initialize any elements of `self.buf`'s spare + // capacity. + /// Helper struct to ensure the buffer is updated after all the writes /// are complete. It tracks the number of written bytes and drains them /// all from the front of the buffer when dropped. @@ -225,7 +229,16 @@ impl BufWriter { impl Drop for BufGuard<'_> { fn drop(&mut self) { if self.written > 0 { - self.buffer.drain(..self.written); + // Like `self.buffer.drain(..self.written)` but more obviously + // preserving the spare capacity; see note above. + let new_len = self.buffer.len() - self.written; + // SAFETY: Assumes `Vec::as_mut_slice` will not + // de-initialize any elements of `self.buf`'s spare capacity, + // and that `<&mut [u8]>::copy_within` will not do so either. + self.buffer.as_mut_slice().copy_within(self.written.., 0); + // SAFETY: Assumes `Vec::truncate` will not de-initialize + // any elements of `self.buf`'s spare capacity, + self.buffer.truncate(new_len); } } } diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index 0f3f890a964ad..0feadf2b3f8bb 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -221,7 +221,8 @@ impl BufferedWriterSpec for BufWriter { let mut read_buf: BorrowedBuf<'_> = buf.spare_capacity_mut().into(); if init { - // SAFETY: init is either 0 or the init_len from the previous iteration. + // SAFETY: `init` is only true after `reader` initializes + // `read_buf`. See the comment about `flush_buf` below. unsafe { read_buf.set_init() }; } @@ -248,6 +249,8 @@ impl BufferedWriterSpec for BufWriter { Err(e) => return Err(e), } } else { + // SAFETY: `flush_buf` will not de-initialize any elements of + // the spare capacity so we can remember `init` across this. self.flush_buf()?; } }