Skip to content

Commit 9ab80be

Browse files
committed
Fix soundness of FromBytes::read_from_io
See google#2319. Includes a Miri test confirming the previous unsoundness.
1 parent 17e7e4d commit 9ab80be

File tree

1 file changed

+25
-1
lines changed

1 file changed

+25
-1
lines changed

src/lib.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -4546,7 +4546,8 @@ pub unsafe trait FromBytes: FromZeros {
45464546
Self: Sized,
45474547
R: io::Read,
45484548
{
4549-
let mut buf = CoreMaybeUninit::<Self>::zeroed();
4549+
let mut buf = CoreMaybeUninit::<Self>::uninit();
4550+
buf.zero();
45504551
let ptr = Ptr::from_mut(&mut buf);
45514552
// SAFETY: `buf` consists entirely of initialized, zeroed bytes.
45524553
let ptr = unsafe { ptr.assume_validity::<invariant::Initialized>() };
@@ -5905,6 +5906,29 @@ mod tests {
59055906
assert_eq!(bytes, want);
59065907
}
59075908

5909+
#[test]
5910+
#[cfg(feature = "std")]
5911+
fn test_read_io_with_padding_soundness() {
5912+
#[derive(FromBytes)]
5913+
#[repr(C)]
5914+
struct WithPadding {
5915+
x: u8,
5916+
y: u16,
5917+
}
5918+
struct ReadsInRead;
5919+
impl std::io::Read for ReadsInRead {
5920+
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
5921+
if buf.iter().all(|&x| x == 0) {
5922+
Ok(buf.len())
5923+
} else {
5924+
buf.iter_mut().for_each(|x| *x = 0);
5925+
Ok(buf.len())
5926+
}
5927+
}
5928+
}
5929+
assert!(matches!(WithPadding::read_from_io(ReadsInRead), Ok(WithPadding { x: 0, y: 0 })));
5930+
}
5931+
59085932
#[test]
59095933
#[cfg(feature = "std")]
59105934
fn test_read_write_io() {

0 commit comments

Comments
 (0)