about summary refs log tree commit diff
diff options
context:
space:
mode:
authortiif <pekyuan@gmail.com>2024-03-23 00:22:57 +0800
committertiif <pekyuan@gmail.com>2024-03-24 22:00:16 +0800
commit04a69e4cf49d95a6c67af505673f1560ebad21d6 (patch)
tree2a03f0703436b027324118be78062d3004956a16
parent67966f3e80f9e5abd65f3fd98ff0fc3b861d06f3 (diff)
downloadrust-04a69e4cf49d95a6c67af505673f1560ebad21d6.tar.gz
rust-04a69e4cf49d95a6c67af505673f1560ebad21d6.zip
Add libc test for rename and ftruncate
-rw-r--r--src/tools/miri/CONTRIBUTING.md13
-rw-r--r--src/tools/miri/tests/pass-dep/shims/libc-fs.rs63
2 files changed, 71 insertions, 5 deletions
diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md
index f2f3a642e0a..f779c09b764 100644
--- a/src/tools/miri/CONTRIBUTING.md
+++ b/src/tools/miri/CONTRIBUTING.md
@@ -64,19 +64,22 @@ For example, you can (cross-)run the driver on a particular file by doing
 ./miri run tests/pass/hello.rs --target i686-unknown-linux-gnu
 ```
 
-and you can (cross-)run the entire test suite using:
+Tests in ``pass-dep`` need to be run using ``./miri run --dep <filename>``.  
+For example:
+```sh
+./miri run --dep tests/pass-dep/shims/libc-fs.rs
+```
+
+You can (cross-)run the entire test suite using:
 
 ```
 ./miri test
 MIRI_TEST_TARGET=i686-unknown-linux-gnu ./miri test
 ```
 
-If your target doesn't support libstd that should usually just work. However, if you are using a
-custom target file, you might have to set `MIRI_NO_STD=1`.
-
 `./miri test FILTER` only runs those tests that contain `FILTER` in their filename (including the
 base directory, e.g. `./miri test fail` will run all compile-fail tests). These filters are passed
-to `cargo test`, so for multiple filers you need to use `./miri test -- FILTER1 FILTER2`.
+to `cargo test`, so for multiple filters you need to use `./miri test -- FILTER1 FILTER2`.
 
 #### Fine grained logging
 
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs.rs b/src/tools/miri/tests/pass-dep/shims/libc-fs.rs
index fafeb9e0558..4cfc1843a7a 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-fs.rs
+++ b/src/tools/miri/tests/pass-dep/shims/libc-fs.rs
@@ -16,6 +16,10 @@ mod utils;
 fn main() {
     test_dup_stdout_stderr();
     test_canonicalize_too_long();
+    test_rename();
+    test_ftruncate::<libc::off_t>(libc::ftruncate);
+    #[cfg(target_os = "linux")]
+    test_ftruncate::<libc::off64_t>(libc::ftruncate64);
     test_readlink();
     test_file_open_unix_allow_two_args();
     test_file_open_unix_needs_three_args();
@@ -133,6 +137,65 @@ fn test_readlink() {
     assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound);
 }
 
+fn test_rename() {
+    let path1 = prepare("miri_test_libc_fs_source.txt");
+    let path2 = prepare("miri_test_libc_fs_rename_destination.txt");
+
+    let file = File::create(&path1).unwrap();
+    drop(file);
+
+    let c_path1 = CString::new(path1.as_os_str().as_bytes()).expect("CString::new failed");
+    let c_path2 = CString::new(path2.as_os_str().as_bytes()).expect("CString::new failed");
+
+    // Renaming should succeed
+    unsafe { libc::rename(c_path1.as_ptr(), c_path2.as_ptr()) };
+    // Check that old file path isn't present
+    assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind());
+    // Check that the file has moved successfully
+    assert!(path2.metadata().unwrap().is_file());
+
+    // Renaming a nonexistent file should fail
+    let res = unsafe { libc::rename(c_path1.as_ptr(), c_path2.as_ptr()) };
+    assert_eq!(res, -1);
+    assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound);
+
+    remove_file(&path2).unwrap();
+}
+
+fn test_ftruncate<T: From<i32>>(
+    ftruncate: unsafe extern "C" fn(fd: libc::c_int, length: T) -> libc::c_int,
+) {
+    // libc::off_t is i32 in target i686-unknown-linux-gnu
+    // https://docs.rs/libc/latest/i686-unknown-linux-gnu/libc/type.off_t.html
+
+    let bytes = b"hello";
+    let path = prepare("miri_test_libc_fs_ftruncate.txt");
+    let mut file = File::create(&path).unwrap();
+    file.write(bytes).unwrap();
+    file.sync_all().unwrap();
+    assert_eq!(file.metadata().unwrap().len(), 5);
+
+    let c_path = CString::new(path.as_os_str().as_bytes()).expect("CString::new failed");
+    let fd = unsafe { libc::open(c_path.as_ptr(), libc::O_RDWR) };
+
+    // Truncate to a bigger size
+    let mut res = unsafe { ftruncate(fd, T::from(10)) };
+    assert_eq!(res, 0);
+    assert_eq!(file.metadata().unwrap().len(), 10);
+
+    // Write after truncate
+    file.write(b"dup").unwrap();
+    file.sync_all().unwrap();
+    assert_eq!(file.metadata().unwrap().len(), 10);
+
+    // Truncate to smaller size
+    res = unsafe { ftruncate(fd, T::from(2)) };
+    assert_eq!(res, 0);
+    assert_eq!(file.metadata().unwrap().len(), 2);
+
+    remove_file(&path).unwrap();
+}
+
 #[cfg(target_os = "linux")]
 fn test_o_tmpfile_flag() {
     use std::fs::{create_dir, OpenOptions};