Skip to content

Commit df6c27d

Browse files
committed
Refactor return_read_bytes_and_count and return_written_byte_count_or_error
1 parent 8c0adc6 commit df6c27d

5 files changed

Lines changed: 76 additions & 67 deletions

File tree

‎src/tools/miri/src/helpers.rs‎

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::collections::BTreeSet;
22
use std::num::NonZero;
33
use std::sync::Mutex;
44
use std::time::Duration;
5-
use std::{cmp, iter};
5+
use std::{cmp,io,iter};
66

77
use rand::RngCore;
88
use rustc_apfloat::Float;
@@ -839,6 +839,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
839839
self.set_last_error(self.io_error_to_errnum(err)?)
840840
}
841841

842+
/// Sets the last OS error using a `std::io::ErrorKind` and writes -1 to dest place.
843+
fnset_last_error_and_return(
844+
&mutself,
845+
err:implInto<io::Error>,
846+
dest:&MPlaceTy<'tcx>,
847+
) -> InterpResult<'tcx>{
848+
self.set_last_error(self.io_error_to_errnum(err.into())?)?;
849+
self.write_int(-1, dest)?;
850+
Ok(())
851+
}
852+
842853
/// Helper function that consumes an `std::io::Result<T>` and returns an
843854
/// `InterpResult<'tcx,T>::Ok` instead. In case the result is an error, this function returns
844855
/// `Ok(-1)` and sets the last OS error accordingly.

‎src/tools/miri/src/shims/unix/fd.rs‎

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,10 @@ impl FileDescription for io::Stdin {
150150
helpers::isolation_abort_error("`read` from stdin")?;
151151
}
152152
let result = Read::read(&mut{self},&mut bytes);
153-
ecx.return_read_bytes_and_count(ptr,&bytes, result, dest)
153+
match result {
154+
Ok(read_size) => ecx.return_read_success(ptr,&bytes, read_size, dest),
155+
Err(e) => ecx.set_last_error_and_return(e, dest),
156+
}
154157
}
155158

156159
fnis_tty(&self,communicate_allowed:bool) -> bool{
@@ -181,7 +184,10 @@ impl FileDescription for io::Stdout {
181184
// the host -- there is no good in adding extra buffering
182185
// here.
183186
io::stdout().flush().unwrap();
184-
ecx.return_written_byte_count_or_error(result, dest)
187+
match result {
188+
Ok(write_size) => ecx.return_write_success(write_size, dest),
189+
Err(e) => ecx.set_last_error_and_return(e, dest),
190+
}
185191
}
186192

187193
fnis_tty(&self,communicate_allowed:bool) -> bool{
@@ -207,7 +213,10 @@ impl FileDescription for io::Stderr {
207213
// We allow writing to stderr even with isolation enabled.
208214
// No need to flush, stderr is not buffered.
209215
let result = Write::write(&mut{self}, bytes);
210-
ecx.return_written_byte_count_or_error(result, dest)
216+
match result {
217+
Ok(write_size) => ecx.return_write_success(write_size, dest),
218+
Err(e) => ecx.set_last_error_and_return(e, dest),
219+
}
211220
}
212221

213222
fnis_tty(&self,communicate_allowed:bool) -> bool{
@@ -234,8 +243,7 @@ impl FileDescription for NullOutput {
234243
ecx:&mutMiriInterpCx<'tcx>,
235244
) -> InterpResult<'tcx>{
236245
// We just don't write anything, but report to the user that we did.
237-
let result = Ok(len);
238-
ecx.return_written_byte_count_or_error(result, dest)
246+
ecx.return_write_success(len, dest)
239247
}
240248
}
241249

@@ -655,46 +663,39 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
655663
}
656664

657665
/// Helper to implement `FileDescription::read`:
658-
/// `result` should be the return value of some underlying `read` call that used `bytes` as its output buffer.
666+
/// This is only used when `read` is successful.
667+
/// `actual_read_size` should be the return value of some underlying `read` call that used
668+
/// `bytes` as its output buffer.
659669
/// The length of `bytes` must not exceed either the host's or the target's `isize`.
660-
/// If `Result` indicates success, `bytes` is written to `buf` and the size is written to `dest`.
661-
/// Otherwise, `-1` is written to `dest` and the last libc error is set appropriately.
662-
fnreturn_read_bytes_and_count(
670+
/// `bytes` is written to `buf` and the size is written to `dest`.
671+
fnreturn_read_success(
663672
&mutself,
664673
buf:Pointer,
665674
bytes:&[u8],
666-
result: io::Result<usize>,
675+
actual_read_size:usize,
667676
dest:&MPlaceTy<'tcx>,
668677
) -> InterpResult<'tcx>{
669678
let this = self.eval_context_mut();
670-
match result {
671-
Ok(read_bytes) => {
672-
// If reading to `bytes` did not fail, we write those bytes to the buffer.
673-
// Crucially, if fewer than `bytes.len()` bytes were read, only write
674-
// that much into the output buffer!
675-
this.write_bytes_ptr(buf, bytes[..read_bytes].iter().copied())?;
676-
// The actual read size is always less than what got originally requested so this cannot fail.
677-
this.write_int(u64::try_from(read_bytes).unwrap(), dest)?;
678-
Ok(())
679-
}
680-
Err(e) => {
681-
this.set_last_error_from_io_error(e)?;
682-
this.write_int(-1, dest)?;
683-
Ok(())
684-
}
685-
}
679+
// If reading to `bytes` did not fail, we write those bytes to the buffer.
680+
// Crucially, if fewer than `bytes.len()` bytes were read, only write
681+
// that much into the output buffer!
682+
this.write_bytes_ptr(buf, bytes[..actual_read_size].iter().copied())?;
683+
684+
// The actual read size is always less than what got originally requested so this cannot fail.
685+
this.write_int(u64::try_from(actual_read_size).unwrap(), dest)?;
686+
Ok(())
686687
}
687688

688-
/// This function writes the number of written bytes (given in `result`) to `dest`, or sets the
689-
/// last libc error and writes -1 to dest.
690-
fnreturn_written_byte_count_or_error(
689+
/// Helper to implement `FileDescription::write`:
690+
/// This function is only used when `write` is successful, and writes `actual_write_size` to `dest`
691+
fnreturn_write_success(
691692
&mutself,
692-
result: io::Result<usize>,
693+
actual_write_size:usize,
693694
dest:&MPlaceTy<'tcx>,
694695
) -> InterpResult<'tcx>{
695696
let this = self.eval_context_mut();
696-
let result = this.try_unwrap_io_result(result.map(|c| i64::try_from(c).unwrap()))?;
697-
this.write_int(result, dest)?;
697+
// The actual write size is always less than what got originally requested so this cannot fail.
698+
this.write_int(u64::try_from(actual_write_size).unwrap(), dest)?;
698699
Ok(())
699700
}
700701
}

‎src/tools/miri/src/shims/unix/fs.rs‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ impl FileDescription for FileHandle {
4141
assert!(communicate_allowed,"isolation should have prevented even opening a file");
4242
letmut bytes = vec![0; len];
4343
let result = (&mut&self.file).read(&mut bytes);
44-
ecx.return_read_bytes_and_count(ptr,&bytes, result, dest)
44+
match result {
45+
Ok(read_size) => ecx.return_read_success(ptr,&bytes, read_size, dest),
46+
Err(e) => ecx.set_last_error_and_return(e, dest),
47+
}
4548
}
4649

4750
fnwrite<'tcx>(
@@ -56,7 +59,10 @@ impl FileDescription for FileHandle {
5659
assert!(communicate_allowed,"isolation should have prevented even opening a file");
5760
let bytes = ecx.read_bytes_ptr_strip_provenance(ptr,Size::from_bytes(len))?;
5861
let result = (&mut&self.file).write(bytes);
59-
ecx.return_written_byte_count_or_error(result, dest)
62+
match result {
63+
Ok(write_size) => ecx.return_write_success(write_size, dest),
64+
Err(e) => ecx.set_last_error_and_return(e, dest),
65+
}
6066
}
6167

6268
fnpread<'tcx>(
@@ -84,7 +90,10 @@ impl FileDescription for FileHandle {
8490
res
8591
};
8692
let result = f();
87-
ecx.return_read_bytes_and_count(ptr,&bytes, result, dest)
93+
match result {
94+
Ok(read_size) => ecx.return_read_success(ptr,&bytes, read_size, dest),
95+
Err(e) => ecx.set_last_error_and_return(e, dest),
96+
}
8897
}
8998

9099
fnpwrite<'tcx>(
@@ -112,7 +121,10 @@ impl FileDescription for FileHandle {
112121
res
113122
};
114123
let result = f();
115-
ecx.return_written_byte_count_or_error(result, dest)
124+
match result {
125+
Ok(write_size) => ecx.return_write_success(write_size, dest),
126+
Err(e) => ecx.set_last_error_and_return(e, dest),
127+
}
116128
}
117129

118130
fnseek<'tcx>(

‎src/tools/miri/src/shims/unix/linux/eventfd.rs‎

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Linux `eventfd` implementation.
22
use std::cell::{Cell,RefCell};
33
use std::io;
4-
use std::io::{Error,ErrorKind};
4+
use std::io::ErrorKind;
55

66
usecrate::concurrency::VClock;
77
usecrate::shims::unix::fd::FileDescriptionRef;
@@ -66,9 +66,7 @@ impl FileDescription for Event {
6666
let ty = ecx.machine.layouts.u64;
6767
// Check the size of slice, and return error only if the size of the slice < 8.
6868
if len < ty.size.bytes_usize(){
69-
ecx.set_last_error_from_io_error(Error::from(ErrorKind::InvalidInput))?;
70-
ecx.write_int(-1, dest)?;
71-
returnOk(());
69+
return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
7270
}
7371

7472
// eventfd read at the size of u64.
@@ -78,9 +76,7 @@ impl FileDescription for Event {
7876
let counter = self.counter.get();
7977
if counter == 0{
8078
ifself.is_nonblock{
81-
ecx.set_last_error_from_io_error(Error::from(ErrorKind::WouldBlock))?;
82-
ecx.write_int(-1, dest)?;
83-
returnOk(());
79+
return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
8480
}
8581

8682
throw_unsup_format!("eventfd: blocking is unsupported");
@@ -128,8 +124,7 @@ impl FileDescription for Event {
128124
let ty = ecx.machine.layouts.u64;
129125
// Check the size of slice, and return error only if the size of the slice < 8.
130126
if len < ty.layout.size.bytes_usize(){
131-
let result = Err(Error::from(ErrorKind::InvalidInput));
132-
return ecx.return_written_byte_count_or_error(result, dest);
127+
return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
133128
}
134129

135130
// Read the user supplied value from the pointer.
@@ -138,8 +133,7 @@ impl FileDescription for Event {
138133

139134
// u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1.
140135
if num == u64::MAX{
141-
let result = Err(Error::from(ErrorKind::InvalidInput));
142-
return ecx.return_written_byte_count_or_error(result, dest);
136+
return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest);
143137
}
144138
// If the addition does not let the counter to exceed the maximum value, update the counter.
145139
// Else, block.
@@ -153,8 +147,7 @@ impl FileDescription for Event {
153147
}
154148
None | Some(u64::MAX) =>
155149
ifself.is_nonblock{
156-
let result = Err(Error::from(ErrorKind::WouldBlock));
157-
return ecx.return_written_byte_count_or_error(result, dest);
150+
return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
158151
}else{
159152
throw_unsup_format!("eventfd: blocking is unsupported");
160153
},

‎src/tools/miri/src/shims/unix/unnamed_socket.rs‎

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use std::cell::{Cell,OnceCell,RefCell};
66
use std::collections::VecDeque;
77
use std::io;
8-
use std::io::{Error,ErrorKind,Read};
8+
use std::io::{ErrorKind,Read};
99

1010
use rustc_target::abi::Size;
1111

@@ -138,8 +138,7 @@ impl FileDescription for AnonSocket {
138138

139139
// Always succeed on read size 0.
140140
if len == 0{
141-
let result = Ok(0);
142-
return ecx.return_read_bytes_and_count(ptr,&bytes, result, dest);
141+
return ecx.return_read_success(ptr,&bytes,0, dest);
143142
}
144143

145144
letSome(readbuf) = &self.readbufelse{
@@ -152,17 +151,15 @@ impl FileDescription for AnonSocket {
152151
ifself.peer_fd().upgrade().is_none(){
153152
// Socketpair with no peer and empty buffer.
154153
// 0 bytes successfully read indicates end-of-file.
155-
let result = Ok(0);
156-
return ecx.return_read_bytes_and_count(ptr,&bytes, result, dest);
154+
return ecx.return_read_success(ptr,&bytes,0, dest);
157155
}else{
158156
ifself.is_nonblock{
159157
// Non-blocking socketpair with writer and empty buffer.
160158
// https://linux.die.net/man/2/read
161159
// EAGAIN or EWOULDBLOCK can be returned for socket,
162160
// POSIX.1-2001 allows either error to be returned for this case.
163161
// Since there is no ErrorKind for EAGAIN, WouldBlock is used.
164-
let result = Err(Error::from(ErrorKind::WouldBlock));
165-
return ecx.return_read_bytes_and_count(ptr,&bytes, result, dest);
162+
return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
166163
}else{
167164
// Blocking socketpair with writer and empty buffer.
168165
// FIXME: blocking is currently not supported
@@ -194,8 +191,7 @@ impl FileDescription for AnonSocket {
194191
ecx.check_and_update_readiness(&peer_fd)?;
195192
}
196193

197-
let result = Ok(actual_read_size);
198-
ecx.return_read_bytes_and_count(ptr,&bytes, result, dest)
194+
ecx.return_read_success(ptr,&bytes, actual_read_size, dest)
199195
}
200196

201197
fnwrite<'tcx>(
@@ -210,16 +206,14 @@ impl FileDescription for AnonSocket {
210206
// Always succeed on write size 0.
211207
// ("If count is zero and fd refers to a file other than a regular file, the results are not specified.")
212208
if len == 0{
213-
let result = Ok(0);
214-
return ecx.return_written_byte_count_or_error(result, dest);
209+
return ecx.return_write_success(0, dest);
215210
}
216211

217212
// We are writing to our peer's readbuf.
218213
letSome(peer_fd) = self.peer_fd().upgrade()else{
219214
// If the upgrade from Weak to Rc fails, it indicates that all read ends have been
220215
// closed.
221-
let result = Err(Error::from(ErrorKind::BrokenPipe));
222-
return ecx.return_written_byte_count_or_error(result, dest);
216+
return ecx.set_last_error_and_return(ErrorKind::BrokenPipe, dest);
223217
};
224218

225219
letSome(writebuf) = &peer_fd.downcast::<AnonSocket>().unwrap().readbufelse{
@@ -233,8 +227,7 @@ impl FileDescription for AnonSocket {
233227
if available_space == 0{
234228
ifself.is_nonblock{
235229
// Non-blocking socketpair with a full buffer.
236-
let result = Err(Error::from(ErrorKind::WouldBlock));
237-
return ecx.return_written_byte_count_or_error(result, dest);
230+
return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
238231
}else{
239232
// Blocking socketpair with a full buffer.
240233
throw_unsup_format!("socketpair write: blocking isn't supported yet");
@@ -256,8 +249,7 @@ impl FileDescription for AnonSocket {
256249
// The kernel does this even if the fd was already readable before, so we follow suit.
257250
ecx.check_and_update_readiness(&peer_fd)?;
258251

259-
let result = Ok(actual_write_size);
260-
ecx.return_written_byte_count_or_error(result, dest)
252+
ecx.return_write_success(actual_write_size, dest)
261253
}
262254
}
263255

0 commit comments

Comments
 (0)