about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBen Kimock <kimockb@gmail.com>2024-07-12 13:49:41 -0400
committerBen Kimock <kimockb@gmail.com>2024-07-12 17:15:50 -0400
commit7fc69436a1226b254b3b6f9ed8c6d54965e0cfbf (patch)
tree244ad61687ec005be4cdb1516b2435f66fcdeab5
parent5d76a13bbedebd773b4960432bff14f40acf3840 (diff)
downloadrust-7fc69436a1226b254b3b6f9ed8c6d54965e0cfbf.tar.gz
rust-7fc69436a1226b254b3b6f9ed8c6d54965e0cfbf.zip
Use ManuallyDrop in BufWriter::into_parts
-rw-r--r--library/std/src/io/buffered/bufwriter.rs14
-rw-r--r--library/std/src/io/buffered/tests.rs10
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();
+}