mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-16 13:05:18 +03:00
Auto merge of #155321 - briansmith:b/bufwriter-conservative, r=Mark-Simulacrum
`BufWriter`: Make the soundness of `BorrowedBuf` usage clearer. The previous safety comment was outdated as it was written before `BorrowedBuf::set_init` was changed to be a boolean. It also failed to address the possibility that `flush_buf` invalidated the assumption.
This commit is contained in:
@@ -1784,6 +1784,9 @@ pub fn into_boxed_slice(mut self) -> Box<[T], A> {
|
||||
/// [`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 @@ pub const fn as_slice(&self) -> &[T] {
|
||||
#[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::<T>` <=
|
||||
|
||||
@@ -92,7 +92,7 @@ pub fn len(&self) -> usize {
|
||||
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 {
|
||||
|
||||
@@ -193,6 +193,10 @@ impl<W: ?Sized + Write> BufWriter<W> {
|
||||
/// `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: `<BufWriter as BufferedWriterSpec>::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 @@ fn done(&self) -> bool {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +221,8 @@ fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64> {
|
||||
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 @@ fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64> {
|
||||
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()?;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user