Skip to content

Commit cbf6c86

Browse files
authored
Merge pull request rust-lang#3990 from RalfJung/errno-cleanup
Consistently use io error handlers
2 parents a21369f + 2350ba7 commit cbf6c86

File tree

6 files changed

+61
-85
lines changed

6 files changed

+61
-85
lines changed

src/tools/miri/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ pub use crate::range_map::RangeMap;
147147
pub use crate::shims::EmulateItemResult;
148148
pub use crate::shims::env::{EnvVars, EvalContextExt as _};
149149
pub use crate::shims::foreign_items::{DynSym, EvalContextExt as _};
150-
pub use crate::shims::io_error::{EvalContextExt as _, LibcError};
150+
pub use crate::shims::io_error::{EvalContextExt as _, IoError, LibcError};
151151
pub use crate::shims::os_str::EvalContextExt as _;
152152
pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _};
153153
pub use crate::shims::time::EvalContextExt as _;

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

+11-25
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
423423
let this = self.eval_context_mut();
424424

425425
let Some(fd) = this.machine.fds.get(old_fd_num) else {
426-
return interp_ok(Scalar::from_i32(this.fd_not_found()?));
426+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
427427
};
428428
interp_ok(Scalar::from_i32(this.machine.fds.insert(fd)))
429429
}
@@ -432,7 +432,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
432432
let this = self.eval_context_mut();
433433

434434
let Some(fd) = this.machine.fds.get(old_fd_num) else {
435-
return interp_ok(Scalar::from_i32(this.fd_not_found()?));
435+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
436436
};
437437
if new_fd_num != old_fd_num {
438438
// Close new_fd if it is previously opened.
@@ -448,7 +448,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
448448
fn flock(&mut self, fd_num: i32, op: i32) -> InterpResult<'tcx, Scalar> {
449449
let this = self.eval_context_mut();
450450
let Some(fd) = this.machine.fds.get(fd_num) else {
451-
return interp_ok(Scalar::from_i32(this.fd_not_found()?));
451+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
452452
};
453453

454454
// We need to check that there aren't unsupported options in `op`.
@@ -498,11 +498,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
498498
// `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
499499
// always sets this flag when opening a file. However we still need to check that the
500500
// file itself is open.
501-
interp_ok(Scalar::from_i32(if this.machine.fds.is_fd_num(fd_num) {
502-
this.eval_libc_i32("FD_CLOEXEC")
501+
if !this.machine.fds.is_fd_num(fd_num) {
502+
this.set_last_error_and_return_i32(LibcError("EBADF"))
503503
} else {
504-
this.fd_not_found()?
505-
}))
504+
interp_ok(this.eval_libc("FD_CLOEXEC"))
505+
}
506506
}
507507
cmd if cmd == f_dupfd || cmd == f_dupfd_cloexec => {
508508
// Note that we always assume the FD_CLOEXEC flag is set for every open file, in part
@@ -521,7 +521,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
521521
if let Some(fd) = this.machine.fds.get(fd_num) {
522522
interp_ok(Scalar::from_i32(this.machine.fds.insert_with_min_num(fd, start)))
523523
} else {
524-
interp_ok(Scalar::from_i32(this.fd_not_found()?))
524+
this.set_last_error_and_return_i32(LibcError("EBADF"))
525525
}
526526
}
527527
cmd if this.tcx.sess.target.os == "macos"
@@ -547,24 +547,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
547547
let fd_num = this.read_scalar(fd_op)?.to_i32()?;
548548

549549
let Some(fd) = this.machine.fds.remove(fd_num) else {
550-
return interp_ok(Scalar::from_i32(this.fd_not_found()?));
550+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
551551
};
552552
let result = fd.close(this.machine.communicate(), this)?;
553553
// return `0` if close is successful
554554
let result = result.map(|()| 0i32);
555555
interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?))
556556
}
557557

558-
/// Function used when a file descriptor does not exist. It returns `Ok(-1)`and sets
559-
/// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses
560-
/// `T: From<i32>` instead of `i32` directly because some fs functions return different integer
561-
/// types (like `read`, that returns an `i64`).
562-
fn fd_not_found<T: From<i32>>(&mut self) -> InterpResult<'tcx, T> {
563-
let this = self.eval_context_mut();
564-
this.set_last_error(LibcError("EBADF"))?;
565-
interp_ok((-1).into())
566-
}
567-
568558
/// Read data from `fd` into buffer specified by `buf` and `count`.
569559
///
570560
/// If `offset` is `None`, reads data from current cursor position associated with `fd`
@@ -598,9 +588,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
598588
// We temporarily dup the FD to be able to retain mutable access to `this`.
599589
let Some(fd) = this.machine.fds.get(fd_num) else {
600590
trace!("read: FD not found");
601-
let res: i32 = this.fd_not_found()?;
602-
this.write_int(res, dest)?;
603-
return interp_ok(());
591+
return this.set_last_error_and_return(LibcError("EBADF"), dest);
604592
};
605593

606594
trace!("read: FD mapped to {fd:?}");
@@ -645,9 +633,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
645633

646634
// We temporarily dup the FD to be able to retain mutable access to `this`.
647635
let Some(fd) = this.machine.fds.get(fd_num) else {
648-
let res: i32 = this.fd_not_found()?;
649-
this.write_int(res, dest)?;
650-
return interp_ok(());
636+
return this.set_last_error_and_return(LibcError("EBADF"), dest);
651637
};
652638

653639
match offset {

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

+39-40
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
595595
let communicate = this.machine.communicate();
596596

597597
let Some(fd) = this.machine.fds.get(fd_num) else {
598-
return interp_ok(Scalar::from_i64(this.fd_not_found()?));
598+
return this.set_last_error_and_return_i64(LibcError("EBADF"));
599599
};
600600
let result = fd.seek(communicate, seek_from)?.map(|offset| i64::try_from(offset).unwrap());
601601
drop(fd);
@@ -671,8 +671,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
671671

672672
// `stat` always follows symlinks.
673673
let metadata = match FileMetadata::from_path(this, &path, true)? {
674-
Some(metadata) => metadata,
675-
None => return interp_ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno
674+
Ok(metadata) => metadata,
675+
Err(err) => return this.set_last_error_and_return_i32(err),
676676
};
677677

678678
interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
@@ -700,8 +700,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
700700
}
701701

702702
let metadata = match FileMetadata::from_path(this, &path, false)? {
703-
Some(metadata) => metadata,
704-
None => return interp_ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno
703+
Ok(metadata) => metadata,
704+
Err(err) => return this.set_last_error_and_return_i32(err),
705705
};
706706

707707
interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
@@ -724,12 +724,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
724724
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
725725
this.reject_in_isolation("`fstat`", reject_with)?;
726726
// Set error code as "EBADF" (bad fd)
727-
return interp_ok(Scalar::from_i32(this.fd_not_found()?));
727+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
728728
}
729729

730730
let metadata = match FileMetadata::from_fd_num(this, fd)? {
731-
Some(metadata) => metadata,
732-
None => return interp_ok(Scalar::from_i32(-1)),
731+
Ok(metadata) => metadata,
732+
Err(err) => return this.set_last_error_and_return_i32(err),
733733
};
734734
interp_ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?))
735735
}
@@ -816,8 +816,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
816816
FileMetadata::from_path(this, &path, follow_symlink)?
817817
};
818818
let metadata = match metadata {
819-
Some(metadata) => metadata,
820-
None => return interp_ok(Scalar::from_i32(-1)),
819+
Ok(metadata) => metadata,
820+
Err(err) => return this.set_last_error_and_return_i32(err),
821821
};
822822

823823
// The `mode` field specifies the type of the file and the permissions over the file for
@@ -1131,7 +1131,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
11311131
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
11321132
this.reject_in_isolation("`readdir_r`", reject_with)?;
11331133
// Set error code as "EBADF" (bad fd)
1134-
return interp_ok(Scalar::from_i32(this.fd_not_found()?));
1134+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
11351135
}
11361136

11371137
let open_dir = this.machine.dirs.streams.get_mut(&dirp).ok_or_else(|| {
@@ -1242,20 +1242,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
12421242
let dirp = this.read_target_usize(dirp_op)?;
12431243

12441244
// Reject if isolation is enabled.
1245-
interp_ok(Scalar::from_i32(
1246-
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
1247-
this.reject_in_isolation("`closedir`", reject_with)?;
1248-
this.fd_not_found()?
1249-
} else if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) {
1250-
if let Some(entry) = open_dir.entry {
1251-
this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?;
1252-
}
1253-
drop(open_dir);
1254-
0
1255-
} else {
1256-
this.fd_not_found()?
1257-
},
1258-
))
1245+
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
1246+
this.reject_in_isolation("`closedir`", reject_with)?;
1247+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
1248+
}
1249+
1250+
let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) else {
1251+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
1252+
};
1253+
if let Some(entry) = open_dir.entry {
1254+
this.deallocate_ptr(entry, None, MiriMemoryKind::Runtime.into())?;
1255+
}
1256+
drop(open_dir);
1257+
1258+
interp_ok(Scalar::from_i32(0))
12591259
}
12601260

12611261
fn ftruncate64(&mut self, fd_num: i32, length: i128) -> InterpResult<'tcx, Scalar> {
@@ -1265,11 +1265,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
12651265
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
12661266
this.reject_in_isolation("`ftruncate64`", reject_with)?;
12671267
// Set error code as "EBADF" (bad fd)
1268-
return interp_ok(Scalar::from_i32(this.fd_not_found()?));
1268+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
12691269
}
12701270

12711271
let Some(fd) = this.machine.fds.get(fd_num) else {
1272-
return interp_ok(Scalar::from_i32(this.fd_not_found()?));
1272+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
12731273
};
12741274

12751275
// FIXME: Support ftruncate64 for all FDs
@@ -1308,7 +1308,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
13081308
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
13091309
this.reject_in_isolation("`fsync`", reject_with)?;
13101310
// Set error code as "EBADF" (bad fd)
1311-
return interp_ok(Scalar::from_i32(this.fd_not_found()?));
1311+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
13121312
}
13131313

13141314
self.ffullsync_fd(fd)
@@ -1317,7 +1317,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
13171317
fn ffullsync_fd(&mut self, fd_num: i32) -> InterpResult<'tcx, Scalar> {
13181318
let this = self.eval_context_mut();
13191319
let Some(fd) = this.machine.fds.get(fd_num) else {
1320-
return interp_ok(Scalar::from_i32(this.fd_not_found()?));
1320+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
13211321
};
13221322
// Only regular files support synchronization.
13231323
let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
@@ -1337,11 +1337,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
13371337
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
13381338
this.reject_in_isolation("`fdatasync`", reject_with)?;
13391339
// Set error code as "EBADF" (bad fd)
1340-
return interp_ok(Scalar::from_i32(this.fd_not_found()?));
1340+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
13411341
}
13421342

13431343
let Some(fd) = this.machine.fds.get(fd) else {
1344-
return interp_ok(Scalar::from_i32(this.fd_not_found()?));
1344+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
13451345
};
13461346
// Only regular files support synchronization.
13471347
let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
@@ -1380,11 +1380,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
13801380
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
13811381
this.reject_in_isolation("`sync_file_range`", reject_with)?;
13821382
// Set error code as "EBADF" (bad fd)
1383-
return interp_ok(Scalar::from_i32(this.fd_not_found()?));
1383+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
13841384
}
13851385

13861386
let Some(fd) = this.machine.fds.get(fd) else {
1387-
return interp_ok(Scalar::from_i32(this.fd_not_found()?));
1387+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
13881388
};
13891389
// Only regular files support synchronization.
13901390
let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| {
@@ -1667,7 +1667,7 @@ impl FileMetadata {
16671667
ecx: &mut MiriInterpCx<'tcx>,
16681668
path: &Path,
16691669
follow_symlink: bool,
1670-
) -> InterpResult<'tcx, Option<FileMetadata>> {
1670+
) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
16711671
let metadata =
16721672
if follow_symlink { std::fs::metadata(path) } else { std::fs::symlink_metadata(path) };
16731673

@@ -1677,9 +1677,9 @@ impl FileMetadata {
16771677
fn from_fd_num<'tcx>(
16781678
ecx: &mut MiriInterpCx<'tcx>,
16791679
fd_num: i32,
1680-
) -> InterpResult<'tcx, Option<FileMetadata>> {
1680+
) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
16811681
let Some(fd) = ecx.machine.fds.get(fd_num) else {
1682-
return ecx.fd_not_found().map(|_: i32| None);
1682+
return interp_ok(Err(LibcError("EBADF")));
16831683
};
16841684

16851685
let file = &fd
@@ -1699,12 +1699,11 @@ impl FileMetadata {
16991699
fn from_meta<'tcx>(
17001700
ecx: &mut MiriInterpCx<'tcx>,
17011701
metadata: Result<std::fs::Metadata, std::io::Error>,
1702-
) -> InterpResult<'tcx, Option<FileMetadata>> {
1702+
) -> InterpResult<'tcx, Result<FileMetadata, IoError>> {
17031703
let metadata = match metadata {
17041704
Ok(metadata) => metadata,
17051705
Err(e) => {
1706-
ecx.set_last_error(e)?;
1707-
return interp_ok(None);
1706+
return interp_ok(Err(e.into()));
17081707
}
17091708
};
17101709

@@ -1727,6 +1726,6 @@ impl FileMetadata {
17271726
let modified = extract_sec_and_nsec(metadata.modified())?;
17281727

17291728
// FIXME: Provide more fields using platform specific methods.
1730-
interp_ok(Some(FileMetadata { mode, size, created, accessed, modified }))
1729+
interp_ok(Ok(FileMetadata { mode, size, created, accessed, modified }))
17311730
}
17321731
}

src/tools/miri/src/shims/unix/linux/epoll.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
263263

264264
// Check if epfd is a valid epoll file descriptor.
265265
let Some(epfd) = this.machine.fds.get(epfd_value) else {
266-
return interp_ok(Scalar::from_i32(this.fd_not_found()?));
266+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
267267
};
268268
let epoll_file_description = epfd
269269
.downcast::<Epoll>()
@@ -273,7 +273,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
273273
let ready_list = &epoll_file_description.ready_list;
274274

275275
let Some(fd_ref) = this.machine.fds.get(fd) else {
276-
return interp_ok(Scalar::from_i32(this.fd_not_found()?));
276+
return this.set_last_error_and_return_i32(LibcError("EBADF"));
277277
};
278278
let id = fd_ref.get_id();
279279

@@ -433,9 +433,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
433433
let timeout = this.read_scalar(timeout)?.to_i32()?;
434434

435435
if epfd_value <= 0 || maxevents <= 0 {
436-
this.set_last_error(LibcError("EINVAL"))?;
437-
this.write_int(-1, dest)?;
438-
return interp_ok(());
436+
return this.set_last_error_and_return(LibcError("EINVAL"), dest);
439437
}
440438

441439
// This needs to come after the maxevents value check, or else maxevents.try_into().unwrap()
@@ -446,9 +444,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
446444
)?;
447445

448446
let Some(epfd) = this.machine.fds.get(epfd_value) else {
449-
let result_value: i32 = this.fd_not_found()?;
450-
this.write_int(result_value, dest)?;
451-
return interp_ok(());
447+
return this.set_last_error_and_return(LibcError("EBADF"), dest);
452448
};
453449
// Create a weak ref of epfd and pass it to callback so we will make sure that epfd
454450
// is not close after the thread unblocks.

0 commit comments

Comments
 (0)