diff options
| author | Jubilee <46493976+workingjubilee@users.noreply.github.com> | 2024-07-13 20:19:47 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-13 20:19:47 -0700 |
| commit | 2d8493bb5f5e154aeec07f6c81c65dd0d4242e70 (patch) | |
| tree | 253701c28a0e1184ae03bb266c42a38b3a668f28 | |
| parent | 125343e7abbef6717996cceef6d56479318f6032 (diff) | |
| parent | 7fc69436a1226b254b3b6f9ed8c6d54965e0cfbf (diff) | |
| download | rust-2d8493bb5f5e154aeec07f6c81c65dd0d4242e70.tar.gz rust-2d8493bb5f5e154aeec07f6c81c65dd0d4242e70.zip | |
Rollup merge of #127659 - saethlin:manually-drop-bufwriter, r=joboet
Use ManuallyDrop in BufWriter::into_parts The fact that `mem::forget` takes by value means that it interacts very poorly with Stacked Borrows; generally users think of calling it as a no-op, but in Stacked Borrows, the field retagging tends to cause surprise tag invalidation.
| -rw-r--r-- | library/std/src/io/buffered/bufwriter.rs | 14 | ||||
| -rw-r--r-- | library/std/src/io/buffered/tests.rs | 10 |
2 files changed, 17 insertions, 7 deletions
diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs index 2d13230ffba..1768bb05ddb 100644 --- a/library/std/src/io/buffered/bufwriter.rs +++ b/library/std/src/io/buffered/bufwriter.rs @@ -3,7 +3,7 @@ use crate::fmt; use crate::io::{ self, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE, }; -use crate::mem; +use crate::mem::{self, ManuallyDrop}; use crate::ptr; /// Wraps a writer and buffers its output. @@ -164,13 +164,13 @@ impl<W: Write> BufWriter<W> { /// assert_eq!(&buffered_data.unwrap(), b"ata"); /// ``` #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] - pub fn into_parts(mut self) -> (W, Result<Vec<u8>, WriterPanicked>) { - let buf = mem::take(&mut self.buf); - let buf = if !self.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) }; + pub fn into_parts(self) -> (W, Result<Vec<u8>, WriterPanicked>) { + let mut this = ManuallyDrop::new(self); + let buf = mem::take(&mut this.buf); + let buf = if !this.panicked { Ok(buf) } else { Err(WriterPanicked { buf }) }; - // SAFETY: forget(self) prevents double dropping inner - let inner = unsafe { ptr::read(&self.inner) }; - mem::forget(self); + // SAFETY: double-drops are prevented by putting `this` in a ManuallyDrop that is never dropped + let inner = unsafe { ptr::read(&this.inner) }; (inner, buf) } diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs index ee0db30e22c..ab66deaf31d 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/std/src/io/buffered/tests.rs @@ -1067,3 +1067,13 @@ fn bufreader_full_initialize() { // But we initialized the whole buffer! assert_eq!(reader.initialized(), reader.capacity()); } + +/// This is a regression test for https://github.com/rust-lang/rust/issues/127584. +#[test] +fn bufwriter_aliasing() { + use crate::io::{BufWriter, Cursor}; + let mut v = vec![0; 1024]; + let c = Cursor::new(&mut v); + let w = BufWriter::new(Box::new(c)); + let _ = w.into_parts(); +} |
