about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDan Gohman <dev@sunfishcode.online>2024-01-30 08:28:12 -0500
committerDan Gohman <dev@sunfishcode.online>2024-01-30 09:00:13 -0500
commita6f1dbac79be41db8042920dd723f56d2c2e3154 (patch)
tree7da38332e1f03c5c9d53afe11489272705d6a78d
parent71f8f4949eb2bde39c88d6d5e4571d0415f59119 (diff)
downloadrust-a6f1dbac79be41db8042920dd723f56d2c2e3154.tar.gz
rust-a6f1dbac79be41db8042920dd723f56d2c2e3154.zip
Implement the `mmap64` foreign item.
`mmap64` is like `mmap` but uses a 64-bit integer instead of `off_t` for
the offset parameter.
-rw-r--r--src/tools/miri/src/shims/unix/foreign_items.rs7
-rw-r--r--src/tools/miri/src/shims/unix/mem.rs3
-rw-r--r--src/tools/miri/tests/pass-dep/shims/mmap.rs114
3 files changed, 122 insertions, 2 deletions
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 35036ce078d..0f992e957c2 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -262,9 +262,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
 
             "mmap" => {
                 let [addr, length, prot, flags, fd, offset] = this.check_shim(abi, Abi::C {unwind: false}, link_name, args)?;
+                let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
                 let ptr = this.mmap(addr, length, prot, flags, fd, offset)?;
                 this.write_scalar(ptr, dest)?;
             }
+            "mmap64" => {
+                let [addr, length, prot, flags, fd, offset] = this.check_shim(abi, Abi::C {unwind: false}, link_name, args)?;
+                let offset = this.read_scalar(offset)?.to_i64()?;
+                let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?;
+                this.write_scalar(ptr, dest)?;
+            }
             "munmap" => {
                 let [addr, length] = this.check_shim(abi, Abi::C {unwind: false}, link_name, args)?;
                 let result = this.munmap(addr, length)?;
diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs
index d7dc17fa89f..d3470893dbb 100644
--- a/src/tools/miri/src/shims/unix/mem.rs
+++ b/src/tools/miri/src/shims/unix/mem.rs
@@ -26,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         prot: &OpTy<'tcx, Provenance>,
         flags: &OpTy<'tcx, Provenance>,
         fd: &OpTy<'tcx, Provenance>,
-        offset: &OpTy<'tcx, Provenance>,
+        offset: i128,
     ) -> InterpResult<'tcx, Scalar<Provenance>> {
         let this = self.eval_context_mut();
 
@@ -36,7 +36,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let prot = this.read_scalar(prot)?.to_i32()?;
         let flags = this.read_scalar(flags)?.to_i32()?;
         let fd = this.read_scalar(fd)?.to_i32()?;
-        let offset = this.read_target_usize(offset)?;
 
         let map_private = this.eval_libc_i32("MAP_PRIVATE");
         let map_anonymous = this.eval_libc_i32("MAP_ANONYMOUS");
diff --git a/src/tools/miri/tests/pass-dep/shims/mmap.rs b/src/tools/miri/tests/pass-dep/shims/mmap.rs
index e19f54d0687..08faf76c00d 100644
--- a/src/tools/miri/tests/pass-dep/shims/mmap.rs
+++ b/src/tools/miri/tests/pass-dep/shims/mmap.rs
@@ -117,6 +117,118 @@ fn test_mmap() {
 }
 
 #[cfg(target_os = "linux")]
+fn test_mmap64() {
+    let page_size = page_size::get();
+    let ptr = unsafe {
+        libc::mmap64(
+            ptr::null_mut(),
+            page_size,
+            libc::PROT_READ | libc::PROT_WRITE,
+            libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
+            -1,
+            0,
+        )
+    };
+    assert!(!ptr.is_null());
+
+    // Ensure that freshly mapped allocations are zeroed
+    let slice = unsafe { slice::from_raw_parts_mut(ptr as *mut u8, page_size) };
+    assert!(slice.iter().all(|b| *b == 0));
+
+    // Do some writes, make sure they worked
+    for b in slice.iter_mut() {
+        *b = 1;
+    }
+    assert!(slice.iter().all(|b| *b == 1));
+
+    // Ensure that we can munmap
+    let res = unsafe { libc::munmap(ptr, page_size) };
+    assert_eq!(res, 0i32);
+
+    // Test all of our error conditions
+    let ptr = unsafe {
+        libc::mmap64(
+            ptr::null_mut(),
+            page_size,
+            libc::PROT_READ | libc::PROT_WRITE,
+            libc::MAP_PRIVATE | libc::MAP_SHARED, // Can't be both private and shared
+            -1,
+            0,
+        )
+    };
+    assert_eq!(ptr, libc::MAP_FAILED);
+    assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
+
+    let ptr = unsafe {
+        libc::mmap64(
+            ptr::null_mut(),
+            0, // Can't map no memory
+            libc::PROT_READ | libc::PROT_WRITE,
+            libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
+            -1,
+            0,
+        )
+    };
+    assert_eq!(ptr, libc::MAP_FAILED);
+    assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
+
+    let ptr = unsafe {
+        libc::mmap64(
+            ptr::invalid_mut(page_size * 64),
+            page_size,
+            libc::PROT_READ | libc::PROT_WRITE,
+            // We don't support MAP_FIXED
+            libc::MAP_PRIVATE | libc::MAP_ANONYMOUS | libc::MAP_FIXED,
+            -1,
+            0,
+        )
+    };
+    assert_eq!(ptr, libc::MAP_FAILED);
+    assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::ENOTSUP);
+
+    // We don't support protections other than read+write
+    for prot in [libc::PROT_NONE, libc::PROT_EXEC, libc::PROT_READ, libc::PROT_WRITE] {
+        let ptr = unsafe {
+            libc::mmap64(
+                ptr::null_mut(),
+                page_size,
+                prot,
+                libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
+                -1,
+                0,
+            )
+        };
+        assert_eq!(ptr, libc::MAP_FAILED);
+        assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::ENOTSUP);
+    }
+
+    // We report an error for mappings whose length cannot be rounded up to a multiple of
+    // the page size.
+    let ptr = unsafe {
+        libc::mmap64(
+            ptr::null_mut(),
+            usize::MAX - 1,
+            libc::PROT_READ | libc::PROT_WRITE,
+            libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
+            -1,
+            0,
+        )
+    };
+    assert_eq!(ptr, libc::MAP_FAILED);
+
+    // We report an error when trying to munmap an address which is not a multiple of the page size
+    let res = unsafe { libc::munmap(ptr::invalid_mut(1), page_size) };
+    assert_eq!(res, -1);
+    assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
+
+    // We report an error when trying to munmap a length that cannot be rounded up to a multiple of
+    // the page size.
+    let res = unsafe { libc::munmap(ptr::invalid_mut(page_size), usize::MAX - 1) };
+    assert_eq!(res, -1);
+    assert_eq!(Error::last_os_error().raw_os_error().unwrap(), libc::EINVAL);
+}
+
+#[cfg(target_os = "linux")]
 fn test_mremap() {
     let page_size = page_size::get();
     let ptr = unsafe {
@@ -165,5 +277,7 @@ fn test_mremap() {
 fn main() {
     test_mmap();
     #[cfg(target_os = "linux")]
+    test_mmap64();
+    #[cfg(target_os = "linux")]
     test_mremap();
 }