diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index bbda40def62..e0ad0d8d411 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -1,4 +1,5 @@ use std::convert::TryFrom; +use std::io::{self, Read, Write}; use log::trace; @@ -67,7 +68,37 @@ fn emulate_foreign_item_by_name( let buf = this.read_scalar(buf)?.not_undef()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let result = if fd == 0 { - throw_unsup_format!("reading from stdin is not implemented") + + this.check_no_isolation("read")?; + + // We cap the number of read bytes to the largest + // value that we are able to fit in both the + // host's and target's `isize`. This saves us from + // having to handle overflows later. + let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); + + // We want to read at most `count` bytes. We are + // sure that `count` is not negative because it + // was a target's `usize`. Also we are sure that + // its smaller than `usize::MAX` because it is a + // host's `isize`. + let mut buffer = vec![0; count as usize]; + let res = io::stdin() + .read(&mut buffer) + // `Stdin::read` never returns a value larger + // than `count`, so this cannot fail. + .map(|c| i64::try_from(c).unwrap()); + + match res { + Ok(bytes) => { + this.memory.write_bytes(buf, buffer)?; + i64::try_from(bytes).unwrap() + }, + Err(e) => { + this.set_last_error_from_io_error(e)?; + -1 + }, + } } else if fd == 1 || fd == 2 { throw_unsup_format!("cannot read from stdout/stderr") } else { @@ -85,7 +116,6 @@ fn emulate_foreign_item_by_name( throw_unsup_format!("cannot write to stdin") } else if fd == 1 || fd == 2 { // stdout/stderr - use std::io::{self, Write}; let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(count))?; // We need to flush to make sure this actually appears on the screen @@ -103,6 +133,7 @@ fn emulate_foreign_item_by_name( }; match res { Ok(n) => i64::try_from(n).unwrap(), + // FIXME: set errno to appropriate value Err(_) => -1, } } else {