diff options
Diffstat (limited to '')
-rw-r--r-- | vendor/memmap2/src/lib.rs | 149 |
1 files changed, 131 insertions, 18 deletions
diff --git a/vendor/memmap2/src/lib.rs b/vendor/memmap2/src/lib.rs index b90d1bcf6..0b92ea0e1 100644 --- a/vendor/memmap2/src/lib.rs +++ b/vendor/memmap2/src/lib.rs @@ -51,13 +51,14 @@ use std::fmt; #[cfg(not(any(unix, windows)))] use std::fs::File; use std::io::{Error, ErrorKind, Result}; +use std::isize; +use std::mem; use std::ops::{Deref, DerefMut}; #[cfg(unix)] use std::os::unix::io::{AsRawFd, RawFd}; #[cfg(windows)] use std::os::windows::io::{AsRawHandle, RawHandle}; use std::slice; -use std::usize; #[cfg(not(any(unix, windows)))] pub struct MmapRawDescriptor<'a>(&'a File); @@ -237,15 +238,20 @@ impl MmapOptions { } let len = file_len - self.offset; - // This check it not relevant on 64bit targets, because usize == u64 - #[cfg(not(target_pointer_width = "64"))] - { - if len > (usize::MAX as u64) { - return Err(Error::new( - ErrorKind::InvalidData, - "memory map length overflows usize", - )); - } + // Rust's slice cannot be larger than isize::MAX. + // See https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html + // + // This is not a problem on 64-bit targets, but on 32-bit one + // having a file or an anonymous mapping larger than 2GB is quite normal + // and we have to prevent it. + // + // The code below is essentially the same as in Rust's std: + // https://github.com/rust-lang/rust/blob/db78ab70a88a0a5e89031d7ee4eccec835dcdbde/library/alloc/src/raw_vec.rs#L495 + if mem::size_of::<usize>() < 8 && len > isize::MAX as u64 { + return Err(Error::new( + ErrorKind::InvalidData, + "memory map length overflows isize", + )); } Ok(len as usize) @@ -457,14 +463,26 @@ impl MmapOptions { /// Creates an anonymous memory map. /// - /// Note: the memory map length must be configured to be greater than 0 before creating an - /// anonymous memory map using `MmapOptions::len()`. + /// The memory map length should be configured using [`MmapOptions::len()`] + /// before creating an anonymous memory map, otherwise a zero-length mapping + /// will be crated. /// /// # Errors /// - /// This method returns an error when the underlying system call fails. + /// This method returns an error when the underlying system call fails or + /// when `len > isize::MAX`. pub fn map_anon(&self) -> Result<MmapMut> { - MmapInner::map_anon(self.len.unwrap_or(0), self.stack).map(|inner| MmapMut { inner }) + let len = self.len.unwrap_or(0); + + // See get_len() for details. + if mem::size_of::<usize>() < 8 && len > isize::MAX as usize { + return Err(Error::new( + ErrorKind::InvalidData, + "memory map length overflows isize", + )); + } + + MmapInner::map_anon(len, self.stack).map(|inner| MmapMut { inner }) } /// Creates a raw memory map. @@ -611,6 +629,22 @@ impl Mmap { pub fn advise(&self, advice: Advice) -> Result<()> { self.inner.advise(advice) } + + /// Lock the whole memory map into RAM. Only supported on Unix. + /// + /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page. + #[cfg(unix)] + pub fn lock(&mut self) -> Result<()> { + self.inner.lock() + } + + /// Unlock the whole memory map. Only supported on Unix. + /// + /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page. + #[cfg(unix)] + pub fn unlock(&mut self) -> Result<()> { + self.inner.unlock() + } } #[cfg(feature = "stable_deref_trait")] @@ -856,7 +890,8 @@ impl MmapMut { /// /// # Errors /// - /// This method returns an error when the underlying system call fails. + /// This method returns an error when the underlying system call fails or + /// when `len > isize::MAX`. pub fn map_anon(length: usize) -> Result<MmapMut> { MmapOptions::new().len(length).map_anon() } @@ -987,6 +1022,22 @@ impl MmapMut { pub fn advise(&self, advice: Advice) -> Result<()> { self.inner.advise(advice) } + + /// Lock the whole memory map into RAM. Only supported on Unix. + /// + /// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page. + #[cfg(unix)] + pub fn lock(&mut self) -> Result<()> { + self.inner.lock() + } + + /// Unlock the whole memory map. Only supported on Unix. + /// + /// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page. + #[cfg(unix)] + pub fn unlock(&mut self) -> Result<()> { + self.inner.unlock() + } } #[cfg(feature = "stable_deref_trait")] @@ -1037,7 +1088,7 @@ mod test { #[cfg(unix)] use crate::advice::Advice; - use std::fs::OpenOptions; + use std::fs::{self, OpenOptions}; use std::io::{Read, Write}; #[cfg(unix)] use std::os::unix::io::AsRawFd; @@ -1158,6 +1209,17 @@ mod test { } #[test] + #[cfg(target_pointer_width = "32")] + fn map_anon_len_overflow() { + let res = MmapMut::map_anon(0x80000000); + + assert_eq!( + res.unwrap_err().to_string(), + "memory map length overflows isize" + ); + } + + #[test] fn file_write() { let tempdir = tempfile::tempdir().unwrap(); let path = tempdir.path().join("mmap"); @@ -1333,7 +1395,6 @@ mod test { #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn jit_x86(mut mmap: MmapMut) { - use std::mem; mmap[0] = 0xB8; // mov eax, 0xAB mmap[1] = 0xAB; mmap[2] = 0x00; @@ -1343,7 +1404,7 @@ mod test { let mmap = mmap.make_exec().expect("make_exec"); - let jitfn: extern "C" fn() -> u8 = unsafe { mem::transmute(mmap.as_ptr()) }; + let jitfn: extern "C" fn() -> u8 = unsafe { std::mem::transmute(mmap.as_ptr()) }; assert_eq!(jitfn(), 0xab); } @@ -1557,4 +1618,56 @@ mod test { // read values back assert_eq!(&incr[..], &mmap[..]); } + + /// Returns true if a non-zero amount of memory is locked. + #[cfg(target_os = "linux")] + fn is_locked() -> bool { + let status = &fs::read_to_string("/proc/self/status") + .expect("/proc/self/status should be available"); + for line in status.lines() { + if line.starts_with("VmLck:") { + let numbers = line.replace(|c: char| !c.is_ascii_digit(), ""); + return numbers != "0"; + } + } + panic!("cannot get VmLck information") + } + + #[test] + #[cfg(unix)] + fn lock() { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("mmap_lock"); + + let file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .open(&path) + .unwrap(); + file.set_len(128).unwrap(); + + let mut mmap = unsafe { Mmap::map(&file).unwrap() }; + #[cfg(target_os = "linux")] + assert!(!is_locked()); + + mmap.lock().expect("mmap lock should be supported on unix"); + #[cfg(target_os = "linux")] + assert!(is_locked()); + + mmap.lock() + .expect("mmap lock again should not cause problems"); + #[cfg(target_os = "linux")] + assert!(is_locked()); + + mmap.unlock() + .expect("mmap unlock should be supported on unix"); + #[cfg(target_os = "linux")] + assert!(!is_locked()); + + mmap.unlock() + .expect("mmap unlock again should not cause problems"); + #[cfg(target_os = "linux")] + assert!(!is_locked()); + } } |