Skip to content

Commit 9c21fd4

Browse files
committed
make set_last_error directly callable on a bunch of ways to represent errors
1 parent 88c7452 commit 9c21fd4

File tree

10 files changed

+88
-80
lines changed

10 files changed

+88
-80
lines changed

src/tools/miri/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ pub use crate::range_map::RangeMap;
150150
pub use crate::shims::EmulateItemResult;
151151
pub use crate::shims::env::{EnvVars, EvalContextExt as _};
152152
pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _};
153-
pub use crate::shims::io_error::EvalContextExt as _;
153+
pub use crate::shims::io_error::{EvalContextExt as _, LibcError};
154154
pub use crate::shims::os_str::EvalContextExt as _;
155155
pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _};
156156
pub use crate::shims::time::EvalContextExt as _;

src/tools/miri/src/shims/io_error.rs

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,34 @@ use std::io;
22

33
use crate::*;
44

5+
/// A representation of an IO error: either a libc error name,
6+
/// or a host error.
7+
#[derive(Debug)]
8+
pub enum IoError {
9+
LibcError(&'static str),
10+
HostError(io::Error),
11+
Raw(Scalar),
12+
}
13+
pub use self::IoError::*;
14+
15+
impl From<io::Error> for IoError {
16+
fn from(value: io::Error) -> Self {
17+
IoError::HostError(value)
18+
}
19+
}
20+
21+
impl From<io::ErrorKind> for IoError {
22+
fn from(value: io::ErrorKind) -> Self {
23+
IoError::HostError(value.into())
24+
}
25+
}
26+
27+
impl From<Scalar> for IoError {
28+
fn from(value: Scalar) -> Self {
29+
IoError::Raw(value)
30+
}
31+
}
32+
533
// This mapping should match `decode_error_kind` in
634
// <https://github.com/rust-lang/rust/blob/master/library/std/src/sys/pal/unix/mod.rs>.
735
const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = {
@@ -80,10 +108,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
80108
}
81109

82110
/// Sets the last error variable.
83-
fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> {
111+
fn set_last_error(&mut self, err: impl Into<IoError>) -> InterpResult<'tcx> {
84112
let this = self.eval_context_mut();
113+
let errno = match err.into() {
114+
HostError(err) => this.io_error_to_errnum(err)?,
115+
LibcError(name) => this.eval_libc(name),
116+
Raw(val) => val,
117+
};
85118
let errno_place = this.last_error_place()?;
86-
this.write_scalar(scalar, &errno_place)
119+
this.write_scalar(errno, &errno_place)
87120
}
88121

89122
/// Gets the last error variable.
@@ -152,19 +185,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
152185
}
153186
}
154187

155-
/// Sets the last OS error using a `std::io::ErrorKind`.
156-
fn set_last_error_from_io_error(&mut self, err: std::io::Error) -> InterpResult<'tcx> {
157-
self.set_last_error(self.io_error_to_errnum(err)?)
158-
}
159-
160188
/// Sets the last OS error using a `std::io::ErrorKind` and writes -1 to dest place.
161189
fn set_last_error_and_return(
162190
&mut self,
163-
err: impl Into<io::Error>,
191+
err: impl Into<IoError>,
164192
dest: &MPlaceTy<'tcx>,
165193
) -> InterpResult<'tcx> {
166194
let this = self.eval_context_mut();
167-
this.set_last_error(this.io_error_to_errnum(err.into())?)?;
195+
this.set_last_error(err)?;
168196
this.write_int(-1, dest)?;
169197
Ok(())
170198
}
@@ -182,7 +210,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
182210
match result {
183211
Ok(ok) => Ok(ok),
184212
Err(e) => {
185-
self.eval_context_mut().set_last_error_from_io_error(e)?;
213+
self.eval_context_mut().set_last_error(e)?;
186214
Ok((-1).into())
187215
}
188216
}

src/tools/miri/src/shims/unix/env.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
177177
Ok(Scalar::from_i32(0)) // return zero on success
178178
} else {
179179
// name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
180-
let einval = this.eval_libc("EINVAL");
181-
this.set_last_error(einval)?;
180+
this.set_last_error(LibcError("EINVAL"))?;
182181
Ok(Scalar::from_i32(-1))
183182
}
184183
}
@@ -203,8 +202,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
203202
Ok(Scalar::from_i32(0))
204203
} else {
205204
// name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
206-
let einval = this.eval_libc("EINVAL");
207-
this.set_last_error(einval)?;
205+
this.set_last_error(LibcError("EINVAL"))?;
208206
Ok(Scalar::from_i32(-1))
209207
}
210208
}
@@ -218,7 +216,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
218216

219217
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
220218
this.reject_in_isolation("`getcwd`", reject_with)?;
221-
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
219+
this.set_last_error(ErrorKind::PermissionDenied)?;
222220
return Ok(Pointer::null());
223221
}
224222

@@ -228,10 +226,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
228226
if this.write_path_to_c_str(&cwd, buf, size)?.0 {
229227
return Ok(buf);
230228
}
231-
let erange = this.eval_libc("ERANGE");
232-
this.set_last_error(erange)?;
229+
this.set_last_error(LibcError("ERANGE"))?;
233230
}
234-
Err(e) => this.set_last_error_from_io_error(e)?,
231+
Err(e) => this.set_last_error(e)?,
235232
}
236233

237234
Ok(Pointer::null())
@@ -245,7 +242,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
245242

246243
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
247244
this.reject_in_isolation("`chdir`", reject_with)?;
248-
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
245+
this.set_last_error(ErrorKind::PermissionDenied)?;
249246

250247
return Ok(Scalar::from_i32(-1));
251248
}

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
524524
// Reject if isolation is enabled.
525525
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
526526
this.reject_in_isolation("`fcntl`", reject_with)?;
527-
this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
527+
this.set_last_error(ErrorKind::PermissionDenied)?;
528528
return Ok(Scalar::from_i32(-1));
529529
}
530530

@@ -606,8 +606,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
606606
None => fd.read(&fd, communicate, buf, count, dest, this)?,
607607
Some(offset) => {
608608
let Ok(offset) = u64::try_from(offset) else {
609-
let einval = this.eval_libc("EINVAL");
610-
this.set_last_error(einval)?;
609+
this.set_last_error(LibcError("EINVAL"))?;
611610
this.write_int(-1, dest)?;
612611
return Ok(());
613612
};
@@ -651,8 +650,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
651650
None => fd.write(&fd, communicate, buf, count, dest, this)?,
652651
Some(offset) => {
653652
let Ok(offset) = u64::try_from(offset) else {
654-
let einval = this.eval_libc("EINVAL");
655-
this.set_last_error(einval)?;
653+
this.set_last_error(LibcError("EINVAL"))?;
656654
this.write_int(-1, dest)?;
657655
return Ok(());
658656
};

src/tools/miri/src/shims/unix/foreign_items.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -355,8 +355,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
355355
// FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=reallocarray
356356
match this.compute_size_in_bytes(Size::from_bytes(size), nmemb) {
357357
None => {
358-
let einval = this.eval_libc("ENOMEM");
359-
this.set_last_error(einval)?;
358+
let enmem = this.eval_libc("ENOMEM");
359+
this.set_last_error(enmem)?;
360360
this.write_null(dest)?;
361361
}
362362
Some(len) => {
@@ -646,13 +646,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
646646
let chunk_size = CpuAffinityMask::chunk_size(this);
647647

648648
if this.ptr_is_null(mask)? {
649-
let einval = this.eval_libc("EFAULT");
650-
this.set_last_error(einval)?;
649+
let efault = this.eval_libc("EFAULT");
650+
this.set_last_error(efault)?;
651651
this.write_int(-1, dest)?;
652652
} else if cpusetsize == 0 || cpusetsize.checked_rem(chunk_size).unwrap() != 0 {
653653
// we only copy whole chunks of size_of::<c_ulong>()
654-
let einval = this.eval_libc("EINVAL");
655-
this.set_last_error(einval)?;
654+
this.set_last_error(LibcError("EINVAL"))?;
656655
this.write_int(-1, dest)?;
657656
} else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) {
658657
let cpuset = cpuset.clone();
@@ -662,8 +661,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
662661
this.write_null(dest)?;
663662
} else {
664663
// The thread whose ID is pid could not be found
665-
let einval = this.eval_libc("ESRCH");
666-
this.set_last_error(einval)?;
664+
let esrch = this.eval_libc("ESRCH");
665+
this.set_last_error(esrch)?;
667666
this.write_int(-1, dest)?;
668667
}
669668
}
@@ -689,8 +688,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
689688
};
690689

691690
if this.ptr_is_null(mask)? {
692-
let einval = this.eval_libc("EFAULT");
693-
this.set_last_error(einval)?;
691+
let efault = this.eval_libc("EFAULT");
692+
this.set_last_error(efault)?;
694693
this.write_int(-1, dest)?;
695694
} else {
696695
// NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`.
@@ -707,8 +706,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
707706
}
708707
None => {
709708
// The intersection between the mask and the available CPUs was empty.
710-
let einval = this.eval_libc("EINVAL");
711-
this.set_last_error(einval)?;
709+
this.set_last_error(LibcError("EINVAL"))?;
712710
this.write_int(-1, dest)?;
713711
}
714712
}

0 commit comments

Comments
 (0)