better error when reading from stdin

This commit is contained in:
Ralf Jung 2020-05-25 10:39:37 +02:00
parent f280e7e2d7
commit a95f754a9c
2 changed files with 29 additions and 19 deletions

View File

@ -62,20 +62,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
} }
"read" => { "read" => {
let &[fd, buf, count] = check_arg_count(args)?; let &[fd, buf, count] = check_arg_count(args)?;
let result = this.read(fd, buf, count)?; let fd = this.read_scalar(fd)?.to_i32()?;
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")
} else if fd == 1 || fd == 2 {
throw_unsup_format!("cannot read from stdout/stderr")
} else {
this.read(fd, buf, count)?
};
this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?;
} }
"write" => { "write" => {
let &[fd, buf, n] = check_arg_count(args)?; let &[fd, buf, n] = check_arg_count(args)?;
let fd = this.read_scalar(fd)?.to_i32()?; let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_scalar(buf)?.not_undef()?; let buf = this.read_scalar(buf)?.not_undef()?;
let n = this.read_scalar(n)?.to_machine_usize(this)?; let count = this.read_scalar(n)?.to_machine_usize(this)?;
trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); trace!("Called write({:?}, {:?}, {:?})", fd, buf, count);
let result = if fd == 1 || fd == 2 { let result = if fd == 0 {
throw_unsup_format!("cannot write to stdin")
} else if fd == 1 || fd == 2 {
// stdout/stderr // stdout/stderr
use std::io::{self, Write}; use std::io::{self, Write};
let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(n))?; 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 // We need to flush to make sure this actually appears on the screen
let res = if fd == 1 { let res = if fd == 1 {
// Stdout is buffered, flush to make sure it appears on the screen. // Stdout is buffered, flush to make sure it appears on the screen.
@ -94,7 +105,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
Err(_) => -1, Err(_) => -1,
} }
} else { } else {
let &[fd, buf, count] = check_arg_count(args)?;
this.write(fd, buf, count)? this.write(fd, buf, count)?
}; };
// Now, `result` is the value we return back to the program. // Now, `result` is the value we return back to the program.

View File

@ -5,6 +5,8 @@ use std::io::{Read, Seek, SeekFrom, Write};
use std::path::Path; use std::path::Path;
use std::time::SystemTime; use std::time::SystemTime;
use log::trace;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_target::abi::{Align, LayoutOf, Size};
@ -413,17 +415,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
fn read( fn read(
&mut self, &mut self,
fd_op: OpTy<'tcx, Tag>, fd: i32,
buf_op: OpTy<'tcx, Tag>, buf: Scalar<Tag>,
count_op: OpTy<'tcx, Tag>, count: u64,
) -> InterpResult<'tcx, i64> { ) -> InterpResult<'tcx, i64> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
this.check_no_isolation("read")?; this.check_no_isolation("read")?;
assert!(fd >= 3);
let fd = this.read_scalar(fd_op)?.to_i32()?; trace!("Reading from FD {}, size {}", fd, count);
let buf = this.read_scalar(buf_op)?.not_undef()?;
let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?;
// Check that the *entire* buffer is actually valid memory. // Check that the *entire* buffer is actually valid memory.
this.memory.check_ptr_access( this.memory.check_ptr_access(
@ -437,6 +438,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64);
if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) {
trace!("read: FD mapped to {:?}", file);
// This can never fail because `count` was capped to be smaller than // This can never fail because `count` was capped to be smaller than
// `isize::MAX`. // `isize::MAX`.
let count = isize::try_from(count).unwrap(); let count = isize::try_from(count).unwrap();
@ -461,23 +463,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
} }
} }
} else { } else {
trace!("read: FD not found");
this.handle_not_found() this.handle_not_found()
} }
} }
fn write( fn write(
&mut self, &mut self,
fd_op: OpTy<'tcx, Tag>, fd: i32,
buf_op: OpTy<'tcx, Tag>, buf: Scalar<Tag>,
count_op: OpTy<'tcx, Tag>, count: u64,
) -> InterpResult<'tcx, i64> { ) -> InterpResult<'tcx, i64> {
let this = self.eval_context_mut(); let this = self.eval_context_mut();
this.check_no_isolation("write")?; this.check_no_isolation("write")?;
assert!(fd >= 3);
let fd = this.read_scalar(fd_op)?.to_i32()?;
let buf = this.read_scalar(buf_op)?.not_undef()?;
let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?;
// Check that the *entire* buffer is actually valid memory. // Check that the *entire* buffer is actually valid memory.
this.memory.check_ptr_access( this.memory.check_ptr_access(