about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2025-07-19 13:16:42 +0200
committerRalf Jung <post@ralfj.de>2025-07-19 15:39:04 +0200
commit8acdee7bab65254f7cfc8f5e03ad180e65a45e9b (patch)
tree38f48adfd2b01d417280586112b3c5818f278214
parenteef454f89be3c48ba9ef3853054b16c800eabefc (diff)
downloadrust-8acdee7bab65254f7cfc8f5e03ad180e65a45e9b.tar.gz
rust-8acdee7bab65254f7cfc8f5e03ad180e65a45e9b.zip
don't halt execution when we write to a read-only file
-rw-r--r--src/tools/miri/src/shims/files.rs11
-rw-r--r--src/tools/miri/tests/pass/shims/fs.rs4
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();
 }