Skip to content

Commit b021209

Browse files
committed
Auto merge of #1436 - samrat:support-stdin-read, r=RalfJung
Handle `read`s on STDIN Closes #1434
2 parents 515287f + f4d1841 commit b021209

File tree

1 file changed

+33
-2
lines changed

1 file changed

+33
-2
lines changed

src/shims/posix/foreign_items.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::convert::TryFrom;
2+
use std::io::{self, Read, Write};
23

34
use log::trace;
45

@@ -67,7 +68,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
6768
let buf = this.read_scalar(buf)?.not_undef()?;
6869
let count = this.read_scalar(count)?.to_machine_usize(this)?;
6970
let result = if fd == 0 {
70-
throw_unsup_format!("reading from stdin is not implemented")
71+
72+
this.check_no_isolation("read")?;
73+
74+
// We cap the number of read bytes to the largest
75+
// value that we are able to fit in both the
76+
// host's and target's `isize`. This saves us from
77+
// having to handle overflows later.
78+
let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64);
79+
80+
// We want to read at most `count` bytes. We are
81+
// sure that `count` is not negative because it
82+
// was a target's `usize`. Also we are sure that
83+
// its smaller than `usize::MAX` because it is a
84+
// host's `isize`.
85+
let mut buffer = vec![0; count as usize];
86+
let res = io::stdin()
87+
.read(&mut buffer)
88+
// `Stdin::read` never returns a value larger
89+
// than `count`, so this cannot fail.
90+
.map(|c| i64::try_from(c).unwrap());
91+
92+
match res {
93+
Ok(bytes) => {
94+
this.memory.write_bytes(buf, buffer)?;
95+
i64::try_from(bytes).unwrap()
96+
},
97+
Err(e) => {
98+
this.set_last_error_from_io_error(e)?;
99+
-1
100+
},
101+
}
71102
} else if fd == 1 || fd == 2 {
72103
throw_unsup_format!("cannot read from stdout/stderr")
73104
} else {
@@ -85,7 +116,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
85116
throw_unsup_format!("cannot write to stdin")
86117
} else if fd == 1 || fd == 2 {
87118
// stdout/stderr
88-
use std::io::{self, Write};
89119

90120
let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(count))?;
91121
// We need to flush to make sure this actually appears on the screen
@@ -103,6 +133,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
103133
};
104134
match res {
105135
Ok(n) => i64::try_from(n).unwrap(),
136+
// FIXME: set errno to appropriate value
106137
Err(_) => -1,
107138
}
108139
} else {

0 commit comments

Comments
 (0)