Skip to content

Commit 5e0fb23

Browse files
committed
Deprecate Read::initializer in favor of ptr::freeze
Read implementations should only write into the buffer passed to them, but have the ability to read from it. Access of uninitialized memory can easily cause UB, so there's then a question of what a user of a reader should do to initialize buffers. Previously, we allowed a Read implementation to promise it wouldn't look at the contents of the buffer, which allows the user to pass uninitialized memory to it. Instead, this PR adds a method to "freeze" undefined bytes into arbitrary-but-defined bytes. This is currently done via an inline assembly directive noting the address as an output, so LLVM no longer knows it's uninitialized. There is a proposed "freeze" operation in LLVM itself that would do this directly, but it hasn't been fully implemented. Some targets don't support inline assembly, so there we instead pass the pointer to an extern "C" function, which is similarly opaque to LLVM. The current approach is very low level. If we stabilize, we'll probably want to add something like `slice.freeze()` to make this easier to use.
1 parent c3d2490 commit 5e0fb23

File tree

14 files changed

+128
-15
lines changed

14 files changed

+128
-15
lines changed

src/libcore/ptr.rs

+50
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,56 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
946946
intrinsics::volatile_store(dst, src);
947947
}
948948

949+
/// Freezes `count * size_of::<T>()` bytes of memory, converting undefined data into
950+
/// defined-but-arbitrary data.
951+
///
952+
/// Uninitialized memory has undefined contents, and interation with that data
953+
/// can easily cause undefined behavior. This function "freezes" memory
954+
/// contents, converting uninitialized memory to initialized memory with
955+
/// arbitrary conents so that use of it is well defined.
956+
///
957+
/// This function has no runtime effect; it is purely an instruction to the
958+
/// compiler. In particular, it does not actually write anything to the memory.
959+
///
960+
/// # Safety
961+
///
962+
/// Behavior is undefined if any of the following conditions are violated:
963+
///
964+
/// * `dst` must be [valid] for reads.
965+
///
966+
/// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned.
967+
///
968+
/// [valid]: ../ptr/index.html#safety
969+
///
970+
/// # Examples
971+
///
972+
/// ```ignore (io-is-in-std)
973+
/// use std::io::{self, Read};
974+
/// use std::mem;
975+
/// use std::ptr;
976+
///
977+
/// pub fn read_le_u32<R>(reader: &mut R) -> io::Result<u32>
978+
/// where
979+
/// R: Read,
980+
/// {
981+
/// unsafe {
982+
/// // We're passing this buffer to an arbitrary reader and aren't
983+
/// // guaranteed they won't read from it, so freeze to avoid UB.
984+
/// let mut buf: [u8; 4] = mem::uninitialized();
985+
/// ptr::freeze(&mut buf, 1);
986+
/// reader.read_exact(&mut buf)?;
987+
///
988+
/// Ok(u32::from_le_bytes(buf))
989+
/// }
990+
/// }
991+
/// ```
992+
#[inline]
993+
#[unstable(feature = "ptr_freeze", issue = "0")]
994+
pub unsafe fn freeze<T>(dst: *mut T, count: usize) {
995+
let _ = count;
996+
asm!("" : "=*m"(dst) : );
997+
}
998+
949999
#[lang = "const_ptr"]
9501000
impl<T: ?Sized> *const T {
9511001
/// Returns `true` if the pointer is null.

src/libstd/fs.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99

1010
use fmt;
1111
use ffi::OsString;
12-
use io::{self, SeekFrom, Seek, Read, Initializer, Write};
12+
use io::{self, SeekFrom, Seek, Read, Write};
13+
#[allow(deprecated)]
14+
use io::Initializer;
1315
use path::{Path, PathBuf};
1416
use sys::fs as fs_imp;
1517
use sys_common::{AsInnerMut, FromInner, AsInner, IntoInner};
@@ -600,6 +602,7 @@ impl Read for File {
600602
}
601603

602604
#[inline]
605+
#[allow(deprecated)]
603606
unsafe fn initializer(&self) -> Initializer {
604607
Initializer::nop()
605608
}
@@ -624,6 +627,7 @@ impl<'a> Read for &'a File {
624627
}
625628

626629
#[inline]
630+
#[allow(deprecated)]
627631
unsafe fn initializer(&self) -> Initializer {
628632
Initializer::nop()
629633
}

src/libstd/io/buffered.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ use io::prelude::*;
55
use cmp;
66
use error;
77
use fmt;
8-
use io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom};
8+
use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom};
9+
#[allow(deprecated)]
10+
use io::Initializer;
911
use memchr;
12+
use ptr;
1013

1114
/// The `BufReader` struct adds buffering to any reader.
1215
///
@@ -92,7 +95,7 @@ impl<R: Read> BufReader<R> {
9295
unsafe {
9396
let mut buffer = Vec::with_capacity(cap);
9497
buffer.set_len(cap);
95-
inner.initializer().initialize(&mut buffer);
98+
ptr::freeze(buffer.as_mut_ptr(), cap);
9699
BufReader {
97100
inner,
98101
buf: buffer.into_boxed_slice(),
@@ -236,6 +239,7 @@ impl<R: Read> Read for BufReader<R> {
236239
}
237240

238241
// we can't skip unconditionally because of the large buffer case in read.
242+
#[allow(deprecated)]
239243
unsafe fn initializer(&self) -> Initializer {
240244
self.inner.initializer()
241245
}

src/libstd/io/cursor.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ use io::prelude::*;
22

33
use core::convert::TryInto;
44
use cmp;
5-
use io::{self, Initializer, SeekFrom, Error, ErrorKind};
5+
use io::{self, SeekFrom, Error, ErrorKind};
6+
#[allow(deprecated)]
7+
use io::Initializer;
68

79
/// A `Cursor` wraps an in-memory buffer and provides it with a
810
/// [`Seek`] implementation.
@@ -229,6 +231,7 @@ impl<T> Read for Cursor<T> where T: AsRef<[u8]> {
229231
}
230232

231233
#[inline]
234+
#[allow(deprecated)]
232235
unsafe fn initializer(&self) -> Initializer {
233236
Initializer::nop()
234237
}

src/libstd/io/impls.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use cmp;
2-
use io::{self, SeekFrom, Read, Initializer, Write, Seek, BufRead, Error, ErrorKind};
2+
use io::{self, SeekFrom, Read, Write, Seek, BufRead, Error, ErrorKind};
3+
#[allow(deprecated)]
4+
use io::Initializer;
35
use fmt;
46
use mem;
57

@@ -14,6 +16,7 @@ impl<'a, R: Read + ?Sized> Read for &'a mut R {
1416
}
1517

1618
#[inline]
19+
#[allow(deprecated)]
1720
unsafe fn initializer(&self) -> Initializer {
1821
(**self).initializer()
1922
}
@@ -83,6 +86,7 @@ impl<R: Read + ?Sized> Read for Box<R> {
8386
}
8487

8588
#[inline]
89+
#[allow(deprecated)]
8690
unsafe fn initializer(&self) -> Initializer {
8791
(**self).initializer()
8892
}
@@ -172,6 +176,7 @@ impl<'a> Read for &'a [u8] {
172176
}
173177

174178
#[inline]
179+
#[allow(deprecated)]
175180
unsafe fn initializer(&self) -> Initializer {
176181
Initializer::nop()
177182
}

src/libstd/io/mod.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ fn read_to_end_with_reservation<R: Read + ?Sized>(r: &mut R,
367367
g.buf.reserve(reservation_size);
368368
let capacity = g.buf.capacity();
369369
g.buf.set_len(capacity);
370-
r.initializer().initialize(&mut g.buf[g.len..]);
370+
ptr::freeze(g.buf.as_mut_ptr().add(g.len), g.buf.len() - g.len);
371371
}
372372
}
373373

@@ -543,6 +543,8 @@ pub trait Read {
543543
/// [`Initializer::nop()`]: ../../std/io/struct.Initializer.html#method.nop
544544
/// [`Initializer`]: ../../std/io/struct.Initializer.html
545545
#[unstable(feature = "read_initializer", issue = "42788")]
546+
#[rustc_deprecated(since = "1.33.0", reason = "use std::ptr::freeze instead")]
547+
#[allow(deprecated)]
546548
#[inline]
547549
unsafe fn initializer(&self) -> Initializer {
548550
Initializer::zeroing()
@@ -869,12 +871,22 @@ pub trait Read {
869871

870872
/// A type used to conditionally initialize buffers passed to `Read` methods.
871873
#[unstable(feature = "read_initializer", issue = "42788")]
872-
#[derive(Debug)]
874+
#[rustc_deprecated(since = "1.33.0", reason = "use std::ptr::freeze instead")]
873875
pub struct Initializer(bool);
874876

877+
#[allow(deprecated)]
878+
#[unstable(feature = "read_initializer", issue = "42788")]
879+
impl fmt::Debug for Initializer {
880+
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
881+
fmt.debug_tuple("Initializer").field(&self.0).finish()
882+
}
883+
}
884+
885+
#[allow(deprecated)]
875886
impl Initializer {
876887
/// Returns a new `Initializer` which will zero out buffers.
877888
#[unstable(feature = "read_initializer", issue = "42788")]
889+
#[rustc_deprecated(since = "1.33.0", reason = "use std::ptr::freeze instead")]
878890
#[inline]
879891
pub fn zeroing() -> Initializer {
880892
Initializer(true)
@@ -889,20 +901,23 @@ impl Initializer {
889901
/// the method accurately reflects the number of bytes that have been
890902
/// written to the head of the buffer.
891903
#[unstable(feature = "read_initializer", issue = "42788")]
904+
#[rustc_deprecated(since = "1.33.0", reason = "use std::ptr::freeze instead")]
892905
#[inline]
893906
pub unsafe fn nop() -> Initializer {
894907
Initializer(false)
895908
}
896909

897910
/// Indicates if a buffer should be initialized.
898911
#[unstable(feature = "read_initializer", issue = "42788")]
912+
#[rustc_deprecated(since = "1.33.0", reason = "use std::ptr::freeze instead")]
899913
#[inline]
900914
pub fn should_initialize(&self) -> bool {
901915
self.0
902916
}
903917

904918
/// Initializes a buffer if necessary.
905919
#[unstable(feature = "read_initializer", issue = "42788")]
920+
#[rustc_deprecated(since = "1.33.0", reason = "use std::ptr::freeze instead")]
906921
#[inline]
907922
pub fn initialize(&self, buf: &mut [u8]) {
908923
if self.should_initialize() {
@@ -1698,6 +1713,7 @@ impl<T: Read, U: Read> Read for Chain<T, U> {
16981713
self.second.read(buf)
16991714
}
17001715

1716+
#[allow(deprecated)]
17011717
unsafe fn initializer(&self) -> Initializer {
17021718
let initializer = self.first.initializer();
17031719
if initializer.should_initialize() {
@@ -1895,6 +1911,7 @@ impl<T: Read> Read for Take<T> {
18951911
Ok(n)
18961912
}
18971913

1914+
#[allow(deprecated)]
18981915
unsafe fn initializer(&self) -> Initializer {
18991916
self.inner.initializer()
19001917
}

src/libstd/io/stdio.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ use io::prelude::*;
33
use cell::RefCell;
44
use fmt;
55
use io::lazy::Lazy;
6-
use io::{self, Initializer, BufReader, LineWriter};
6+
use io::{self, BufReader, LineWriter};
7+
#[allow(deprecated)]
8+
use io::Initializer;
79
use sync::{Arc, Mutex, MutexGuard};
810
use sys::stdio;
911
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
@@ -67,6 +69,7 @@ impl Read for StdinRaw {
6769
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
6870

6971
#[inline]
72+
#[allow(deprecated)]
7073
unsafe fn initializer(&self) -> Initializer {
7174
Initializer::nop()
7275
}
@@ -297,6 +300,7 @@ impl Read for Stdin {
297300
self.lock().read(buf)
298301
}
299302
#[inline]
303+
#[allow(deprecated)]
300304
unsafe fn initializer(&self) -> Initializer {
301305
Initializer::nop()
302306
}
@@ -317,6 +321,7 @@ impl<'a> Read for StdinLock<'a> {
317321
self.inner.read(buf)
318322
}
319323
#[inline]
324+
#[allow(deprecated)]
320325
unsafe fn initializer(&self) -> Initializer {
321326
Initializer::nop()
322327
}

src/libstd/io/util.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
#![allow(missing_copy_implementations)]
22

33
use fmt;
4-
use io::{self, Read, Initializer, Write, ErrorKind, BufRead};
4+
use io::{self, Read, Write, ErrorKind, BufRead};
5+
#[allow(deprecated)]
6+
use io::Initializer;
57
use mem;
8+
use ptr;
69

710
/// Copies the entire contents of a reader into a writer.
811
///
@@ -45,7 +48,7 @@ pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<
4548
{
4649
let mut buf = unsafe {
4750
let mut buf: [u8; super::DEFAULT_BUF_SIZE] = mem::uninitialized();
48-
reader.initializer().initialize(&mut buf);
51+
ptr::freeze(&mut buf, 1);
4952
buf
5053
};
5154

@@ -97,6 +100,7 @@ impl Read for Empty {
97100
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> { Ok(0) }
98101

99102
#[inline]
103+
#[allow(deprecated)]
100104
unsafe fn initializer(&self) -> Initializer {
101105
Initializer::nop()
102106
}
@@ -153,6 +157,7 @@ impl Read for Repeat {
153157
}
154158

155159
#[inline]
160+
#[allow(deprecated)]
156161
unsafe fn initializer(&self) -> Initializer {
157162
Initializer::nop()
158163
}

src/libstd/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@
264264
#![feature(panic_unwind)]
265265
#![feature(prelude_import)]
266266
#![feature(ptr_internals)]
267+
#![feature(ptr_freeze)]
267268
#![feature(raw)]
268269
#![feature(hash_raw_entry)]
269270
#![feature(rustc_attrs)]

src/libstd/net/tcp.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use io::prelude::*;
22

33
use fmt;
4-
use io::{self, Initializer};
4+
use io;
5+
#[allow(deprecated)]
6+
use io::Initializer;
57
use net::{ToSocketAddrs, SocketAddr, Shutdown};
68
use sys_common::net as net_imp;
79
use sys_common::{AsInner, FromInner, IntoInner};
@@ -570,6 +572,7 @@ impl Read for TcpStream {
570572
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
571573

572574
#[inline]
575+
#[allow(deprecated)]
573576
unsafe fn initializer(&self) -> Initializer {
574577
Initializer::nop()
575578
}
@@ -584,6 +587,7 @@ impl<'a> Read for &'a TcpStream {
584587
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
585588

586589
#[inline]
590+
#[allow(deprecated)]
587591
unsafe fn initializer(&self) -> Initializer {
588592
Initializer::nop()
589593
}

src/libstd/process.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,9 @@ use io::prelude::*;
111111
use ffi::OsStr;
112112
use fmt;
113113
use fs;
114-
use io::{self, Initializer};
114+
use io;
115+
#[allow(deprecated)]
116+
use io::Initializer;
115117
use path::Path;
116118
use str;
117119
use sys::pipe::{read2, AnonPipe};
@@ -272,6 +274,7 @@ impl Read for ChildStdout {
272274
self.inner.read(buf)
273275
}
274276
#[inline]
277+
#[allow(deprecated)]
275278
unsafe fn initializer(&self) -> Initializer {
276279
Initializer::nop()
277280
}
@@ -319,6 +322,7 @@ impl Read for ChildStderr {
319322
self.inner.read(buf)
320323
}
321324
#[inline]
325+
#[allow(deprecated)]
322326
unsafe fn initializer(&self) -> Initializer {
323327
Initializer::nop()
324328
}

0 commit comments

Comments
 (0)