Skip to content

Commit 6c36a8c

Browse files
committed
Return earlier when reading/writing 0 bytes
1 parent f5022b1 commit 6c36a8c

File tree

2 files changed

+22
-18
lines changed

2 files changed

+22
-18
lines changed

src/shims/io.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -149,25 +149,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
149149

150150
let tcx = &{ this.tcx.tcx };
151151

152+
let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?;
153+
// Reading zero bytes should not change `buf`
154+
if count == 0 {
155+
return Ok(0);
156+
}
152157
let fd = this.read_scalar(fd_op)?.to_i32()?;
153158
let buf_scalar = this.read_scalar(buf_op)?.not_undef()?;
154-
let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?;
155159

156160
// Remove the file handle to avoid borrowing issues
157161
this.remove_handle_and(fd, |mut handle, this| {
158162
// Don't use `?` to avoid returning before reinserting the handle
159-
let bytes =
160-
if count == 0 {
161-
Ok(handle.file.read(&mut []))
162-
} else {
163-
this.force_ptr(buf_scalar).and_then(|buf| this
164-
.memory_mut()
165-
.get_mut(buf.alloc_id).and_then(|alloc|
166-
alloc.get_bytes_mut(tcx, buf, Size::from_bytes(count))
167-
.map(|buffer| handle.file.read(buffer))
168-
))
169-
170-
};
163+
let bytes = this.force_ptr(buf_scalar).and_then(|buf| {
164+
this.memory_mut()
165+
.get_mut(buf.alloc_id)?
166+
.get_bytes_mut(tcx, buf, Size::from_bytes(count))
167+
.map(|buffer| handle.file.read(buffer))
168+
});
171169
// Reinsert the file handle
172170
this.machine.file_handler.handles.insert(fd, handle);
173171
this.consume_result(bytes?.map(|bytes| bytes as i64))
@@ -188,9 +186,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
188186

189187
let tcx = &{ this.tcx.tcx };
190188

189+
let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?;
190+
// Writing zero bytes should not change `buf`
191+
if count == 0 {
192+
return Ok(0);
193+
}
191194
let fd = this.read_scalar(fd_op)?.to_i32()?;
192195
let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?;
193-
let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?;
194196

195197
this.remove_handle_and(fd, |mut handle, this| {
196198
let bytes = this.memory().get(buf.alloc_id).and_then(|alloc| {

tests/run-pass/file_read.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,23 @@
22
// compile-flags: -Zmiri-disable-isolation
33

44
use std::fs::File;
5-
use std::io::{ Read, Write };
5+
use std::io::{Read, Write};
66

77
fn main() {
88
// FIXME: remove the file and delete it when `rm` is implemented.
99
let path = "./tests/hello.txt";
1010
let bytes = b"Hello, World!\n";
1111
// Test creating, writing and closing a file (closing is tested when `file` is dropped).
1212
let mut file = File::create(path).unwrap();
13+
// Writing 0 bytes should not change the file contents.
14+
file.write(&mut []).unwrap();
15+
1316
file.write(bytes).unwrap();
1417
// Test opening, reading and closing a file.
1518
let mut file = File::open(path).unwrap();
1619
let mut contents = Vec::new();
17-
// Reading 0 bytes should not fill `contents`.
18-
file.read(&mut contents).unwrap();
19-
assert!(contents.is_empty());
20+
// Reading 0 bytes should not move the file pointer.
21+
file.read(&mut []).unwrap();
2022
// Reading until EOF should get the whole text.
2123
file.read_to_end(&mut contents).unwrap();
2224
assert_eq!(bytes, contents.as_slice());

0 commit comments

Comments
 (0)