diff options
| -rw-r--r-- | src/tools/miri/src/shims/files.rs | 11 | ||||
| -rw-r--r-- | src/tools/miri/tests/pass/shims/fs.rs | 4 |
2 files changed, 14 insertions, 1 deletions
diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs index 606d1ffbea6..f7419b6bca2 100644 --- a/src/tools/miri/src/shims/files.rs +++ b/src/tools/miri/src/shims/files.rs @@ -1,7 +1,7 @@ use std::any::Any; use std::collections::BTreeMap; use std::fs::{File, Metadata}; -use std::io::{IsTerminal, Seek, SeekFrom, Write}; +use std::io::{ErrorKind, IsTerminal, Seek, SeekFrom, Write}; use std::marker::CoercePointee; use std::ops::Deref; use std::rc::{Rc, Weak}; @@ -334,6 +334,15 @@ impl FileDescription for FileHandle { ) -> InterpResult<'tcx> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); + if !self.writable { + // Linux hosts return EBADF here which we can't translate via the platform-independent + // code since it does not map to any `io::ErrorKind` -- so if we don't do anything + // special, we'd throw an "unsupported error code" here. Windows returns something that + // gets translated to `PermissionDenied`. That seems like a good value so let's just use + // this everywhere, even if it means behavior on Unix targets does not match the real + // thing. + return finish.call(ecx, Err(ErrorKind::PermissionDenied.into())); + } let result = ecx.write_to_host(&self.file, len, ptr)?; finish.call(ecx, result) } diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 9d5725773e6..5e54cc38238 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -66,6 +66,10 @@ fn test_file() { assert!(!file.is_terminal()); + // Writing to a file opened for reading should error (and not stop interpretation). std does not + // categorize the error so we don't check for details. + file.write(&[]).unwrap_err(); + // Removing file should succeed. remove_file(&path).unwrap(); } |
