Auto merge of #2857 - RalfJung:endian, r=RalfJung
fix endianess handling in eventfd::write Fixes https://github.com/rust-lang/miri/issues/2800
This commit is contained in:
commit
db73863c42
2 changed files with 26 additions and 8 deletions
|
|
@ -11,6 +11,7 @@ use std::time::SystemTime;
|
|||
use log::trace;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_target::abi::{Align, Size};
|
||||
|
||||
use crate::shims::os_str::bytes_to_os_str;
|
||||
|
|
@ -31,6 +32,7 @@ pub trait FileDescriptor: std::fmt::Debug + helpers::AsAny {
|
|||
&mut self,
|
||||
_communicate_allowed: bool,
|
||||
_bytes: &mut [u8],
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
) -> InterpResult<'tcx, io::Result<usize>> {
|
||||
throw_unsup_format!("cannot read from {}", self.name());
|
||||
}
|
||||
|
|
@ -39,6 +41,7 @@ pub trait FileDescriptor: std::fmt::Debug + helpers::AsAny {
|
|||
&self,
|
||||
_communicate_allowed: bool,
|
||||
_bytes: &[u8],
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
) -> InterpResult<'tcx, io::Result<usize>> {
|
||||
throw_unsup_format!("cannot write to {}", self.name());
|
||||
}
|
||||
|
|
@ -79,6 +82,7 @@ impl FileDescriptor for FileHandle {
|
|||
&mut self,
|
||||
communicate_allowed: bool,
|
||||
bytes: &mut [u8],
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
) -> InterpResult<'tcx, io::Result<usize>> {
|
||||
assert!(communicate_allowed, "isolation should have prevented even opening a file");
|
||||
Ok(self.file.read(bytes))
|
||||
|
|
@ -88,6 +92,7 @@ impl FileDescriptor for FileHandle {
|
|||
&self,
|
||||
communicate_allowed: bool,
|
||||
bytes: &[u8],
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
) -> InterpResult<'tcx, io::Result<usize>> {
|
||||
assert!(communicate_allowed, "isolation should have prevented even opening a file");
|
||||
Ok((&mut &self.file).write(bytes))
|
||||
|
|
@ -153,6 +158,7 @@ impl FileDescriptor for io::Stdin {
|
|||
&mut self,
|
||||
communicate_allowed: bool,
|
||||
bytes: &mut [u8],
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
) -> InterpResult<'tcx, io::Result<usize>> {
|
||||
if !communicate_allowed {
|
||||
// We want isolation mode to be deterministic, so we have to disallow all reads, even stdin.
|
||||
|
|
@ -184,6 +190,7 @@ impl FileDescriptor for io::Stdout {
|
|||
&self,
|
||||
_communicate_allowed: bool,
|
||||
bytes: &[u8],
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
) -> InterpResult<'tcx, io::Result<usize>> {
|
||||
// We allow writing to stderr even with isolation enabled.
|
||||
let result = Write::write(&mut { self }, bytes);
|
||||
|
|
@ -220,6 +227,7 @@ impl FileDescriptor for io::Stderr {
|
|||
&self,
|
||||
_communicate_allowed: bool,
|
||||
bytes: &[u8],
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
) -> InterpResult<'tcx, io::Result<usize>> {
|
||||
// We allow writing to stderr even with isolation enabled.
|
||||
// No need to flush, stderr is not buffered.
|
||||
|
|
@ -252,6 +260,7 @@ impl FileDescriptor for NullOutput {
|
|||
&self,
|
||||
_communicate_allowed: bool,
|
||||
bytes: &[u8],
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
) -> InterpResult<'tcx, io::Result<usize>> {
|
||||
// We just don't write anything, but report to the user that we did.
|
||||
Ok(Ok(bytes.len()))
|
||||
|
|
@ -756,8 +765,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let mut bytes = vec![0; usize::try_from(count).unwrap()];
|
||||
// `File::read` never returns a value larger than `count`,
|
||||
// so this cannot fail.
|
||||
let result =
|
||||
file_descriptor.read(communicate, &mut bytes)?.map(|c| i64::try_from(c).unwrap());
|
||||
let result = file_descriptor
|
||||
.read(communicate, &mut bytes, *this.tcx)?
|
||||
.map(|c| i64::try_from(c).unwrap());
|
||||
|
||||
match result {
|
||||
Ok(read_bytes) => {
|
||||
|
|
@ -803,8 +813,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) {
|
||||
let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?;
|
||||
let result =
|
||||
file_descriptor.write(communicate, bytes)?.map(|c| i64::try_from(c).unwrap());
|
||||
let result = file_descriptor
|
||||
.write(communicate, bytes, *this.tcx)?
|
||||
.map(|c| i64::try_from(c).unwrap());
|
||||
this.try_unwrap_io_result(result)
|
||||
} else {
|
||||
this.handle_not_found()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use crate::shims::unix::fs::FileDescriptor;
|
||||
|
||||
use rustc_const_eval::interpret::InterpResult;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_target::abi::Endian;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::io;
|
||||
|
|
@ -36,7 +38,7 @@ impl FileDescriptor for Event {
|
|||
}
|
||||
|
||||
/// A write call adds the 8-byte integer value supplied in
|
||||
/// its buffer to the counter. The maximum value that may be
|
||||
/// its buffer (in native endianess) to the counter. The maximum value that may be
|
||||
/// stored in the counter is the largest unsigned 64-bit value
|
||||
/// minus 1 (i.e., 0xfffffffffffffffe). If the addition would
|
||||
/// cause the counter's value to exceed the maximum, then the
|
||||
|
|
@ -47,17 +49,22 @@ impl FileDescriptor for Event {
|
|||
/// A write fails with the error EINVAL if the size of the
|
||||
/// supplied buffer is less than 8 bytes, or if an attempt is
|
||||
/// made to write the value 0xffffffffffffffff.
|
||||
///
|
||||
/// FIXME: use endianness
|
||||
fn write<'tcx>(
|
||||
&self,
|
||||
_communicate_allowed: bool,
|
||||
bytes: &[u8],
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> InterpResult<'tcx, io::Result<usize>> {
|
||||
let v1 = self.val.get();
|
||||
let bytes: [u8; 8] = bytes.try_into().unwrap(); // FIXME fail gracefully when this has the wrong size
|
||||
// Convert from target endianess to host endianess.
|
||||
let num = match tcx.sess.target.endian {
|
||||
Endian::Little => u64::from_le_bytes(bytes),
|
||||
Endian::Big => u64::from_be_bytes(bytes),
|
||||
};
|
||||
// FIXME handle blocking when addition results in exceeding the max u64 value
|
||||
// or fail with EAGAIN if the file descriptor is nonblocking.
|
||||
let v2 = v1.checked_add(u64::from_be_bytes(bytes.try_into().unwrap())).unwrap();
|
||||
let v2 = v1.checked_add(num).unwrap();
|
||||
self.val.set(v2);
|
||||
assert_eq!(8, bytes.len());
|
||||
Ok(Ok(8))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue