summaryrefslogtreecommitdiffstats
path: root/vendor/memmap2/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/memmap2/src/lib.rs')
-rw-r--r--vendor/memmap2/src/lib.rs280
1 files changed, 270 insertions, 10 deletions
diff --git a/vendor/memmap2/src/lib.rs b/vendor/memmap2/src/lib.rs
index 2d730ae90..dd99ba12e 100644
--- a/vendor/memmap2/src/lib.rs
+++ b/vendor/memmap2/src/lib.rs
@@ -4,7 +4,7 @@
//! which correspond to mapping a [`File`] to a [`&[u8]`](https://doc.rust-lang.org/std/primitive.slice.html)
//! or [`&mut [u8]`](https://doc.rust-lang.org/std/primitive.slice.html)
//! respectively. Both function by dereferencing to a slice, allowing the
-//! [`Mmap`]/[`MmapMut`] to be used in the same way you would the equivelant slice
+//! [`Mmap`]/[`MmapMut`] to be used in the same way you would the equivalent slice
//! types.
//!
//! [`File`]: std::fs::File
@@ -497,6 +497,21 @@ impl MmapOptions {
MmapInner::map_mut(self.get_len(&file)?, desc.0, self.offset, self.populate)
.map(|inner| MmapRaw { inner })
}
+
+ /// Creates a read-only raw memory map
+ ///
+ /// This is primarily useful to avoid intermediate `Mmap` instances when
+ /// read-only access to files modified elsewhere are required.
+ ///
+ /// # Errors
+ ///
+ /// This method returns an error when the underlying system call fails
+ pub fn map_raw_read_only<T: MmapAsRawDesc>(&self, file: T) -> Result<MmapRaw> {
+ let desc = file.as_raw_desc();
+
+ MmapInner::map(self.get_len(&file)?, desc.0, self.offset, self.populate)
+ .map(|inner| MmapRaw { inner })
+ }
}
/// A handle to an immutable memory mapped buffer.
@@ -646,7 +661,7 @@ impl Mmap {
///
/// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page.
#[cfg(unix)]
- pub fn lock(&mut self) -> Result<()> {
+ pub fn lock(&self) -> Result<()> {
self.inner.lock()
}
@@ -654,9 +669,31 @@ impl Mmap {
///
/// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page.
#[cfg(unix)]
- pub fn unlock(&mut self) -> Result<()> {
+ pub fn unlock(&self) -> Result<()> {
self.inner.unlock()
}
+
+ /// Adjust the size of the memory mapping.
+ ///
+ /// This will try to resize the memory mapping in place. If
+ /// [`RemapOptions::may_move`] is specified it will move the mapping if it
+ /// could not resize in place, otherwise it will error.
+ ///
+ /// Only supported on Linux.
+ ///
+ /// See the [`mremap(2)`] man page.
+ ///
+ /// # Safety
+ ///
+ /// Resizing the memory mapping beyond the end of the mapped file will
+ /// result in UB should you happen to access memory beyond the end of the
+ /// file.
+ ///
+ /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html
+ #[cfg(target_os = "linux")]
+ pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()> {
+ self.inner.remap(new_len, options)
+ }
}
#[cfg(feature = "stable_deref_trait")]
@@ -837,7 +874,7 @@ impl MmapRaw {
///
/// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page.
#[cfg(unix)]
- pub fn lock(&mut self) -> Result<()> {
+ pub fn lock(&self) -> Result<()> {
self.inner.lock()
}
@@ -845,9 +882,31 @@ impl MmapRaw {
///
/// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page.
#[cfg(unix)]
- pub fn unlock(&mut self) -> Result<()> {
+ pub fn unlock(&self) -> Result<()> {
self.inner.unlock()
}
+
+ /// Adjust the size of the memory mapping.
+ ///
+ /// This will try to resize the memory mapping in place. If
+ /// [`RemapOptions::may_move`] is specified it will move the mapping if it
+ /// could not resize in place, otherwise it will error.
+ ///
+ /// Only supported on Linux.
+ ///
+ /// See the [`mremap(2)`] man page.
+ ///
+ /// # Safety
+ ///
+ /// Resizing the memory mapping beyond the end of the mapped file will
+ /// result in UB should you happen to access memory beyond the end of the
+ /// file.
+ ///
+ /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html
+ #[cfg(target_os = "linux")]
+ pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()> {
+ self.inner.remap(new_len, options)
+ }
}
impl fmt::Debug for MmapRaw {
@@ -1105,7 +1164,7 @@ impl MmapMut {
///
/// See [mlock()](https://man7.org/linux/man-pages/man2/mlock.2.html) map page.
#[cfg(unix)]
- pub fn lock(&mut self) -> Result<()> {
+ pub fn lock(&self) -> Result<()> {
self.inner.lock()
}
@@ -1113,9 +1172,31 @@ impl MmapMut {
///
/// See [munlock()](https://man7.org/linux/man-pages/man2/munlock.2.html) map page.
#[cfg(unix)]
- pub fn unlock(&mut self) -> Result<()> {
+ pub fn unlock(&self) -> Result<()> {
self.inner.unlock()
}
+
+ /// Adjust the size of the memory mapping.
+ ///
+ /// This will try to resize the memory mapping in place. If
+ /// [`RemapOptions::may_move`] is specified it will move the mapping if it
+ /// could not resize in place, otherwise it will error.
+ ///
+ /// Only supported on Linux.
+ ///
+ /// See the [`mremap(2)`] man page.
+ ///
+ /// # Safety
+ ///
+ /// Resizing the memory mapping beyond the end of the mapped file will
+ /// result in UB should you happen to access memory beyond the end of the
+ /// file.
+ ///
+ /// [`mremap(2)`]: https://man7.org/linux/man-pages/man2/mremap.2.html
+ #[cfg(target_os = "linux")]
+ pub unsafe fn remap(&mut self, new_len: usize, options: RemapOptions) -> Result<()> {
+ self.inner.remap(new_len, options)
+ }
}
#[cfg(feature = "stable_deref_trait")]
@@ -1160,14 +1241,60 @@ impl fmt::Debug for MmapMut {
}
}
+/// Options for [`Mmap::remap`] and [`MmapMut::remap`].
+#[derive(Copy, Clone, Default, Debug)]
+#[cfg(target_os = "linux")]
+pub struct RemapOptions {
+ may_move: bool,
+}
+
+#[cfg(target_os = "linux")]
+impl RemapOptions {
+ /// Creates a mew set of options for resizing a memory map.
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Controls whether the memory map can be moved if it is not possible to
+ /// resize it in place.
+ ///
+ /// If false then the memory map is guaranteed to remain at the same
+ /// address when being resized but attempting to resize will return an
+ /// error if the new memory map would overlap with something else in the
+ /// current process' memory.
+ ///
+ /// By default this is false.
+ ///
+ /// # `may_move` and `StableDeref`
+ /// If the `stable_deref_trait` feature is enabled then [`Mmap`] and
+ /// [`MmapMut`] implement `StableDeref`. `StableDeref` promises that the
+ /// memory map dereferences to a fixed address, however, calling `remap`
+ /// with `may_move` set may result in the backing memory of the mapping
+ /// being moved to a new address. This may cause UB in other code
+ /// depending on the `StableDeref` guarantees.
+ pub fn may_move(mut self, may_move: bool) -> Self {
+ self.may_move = may_move;
+ self
+ }
+
+ pub(crate) fn into_flags(self) -> libc::c_int {
+ if self.may_move {
+ libc::MREMAP_MAYMOVE
+ } else {
+ 0
+ }
+ }
+}
+
#[cfg(test)]
mod test {
extern crate tempfile;
#[cfg(unix)]
use crate::advice::Advice;
- use std::fs::OpenOptions;
+ use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
+ use std::mem;
#[cfg(unix)]
use std::os::unix::io::AsRawFd;
#[cfg(windows)]
@@ -1257,8 +1384,10 @@ mod test {
.unwrap();
let mmap = unsafe { Mmap::map(&file).unwrap() };
assert!(mmap.is_empty());
+ assert_eq!(mmap.as_ptr().align_offset(mem::size_of::<usize>()), 0);
let mmap = unsafe { MmapMut::map_mut(&file).unwrap() };
assert!(mmap.is_empty());
+ assert_eq!(mmap.as_ptr().align_offset(mem::size_of::<usize>()), 0);
}
#[test]
@@ -1482,7 +1611,7 @@ mod test {
let mmap = mmap.make_exec().expect("make_exec");
- let jitfn: extern "C" fn() -> u8 = unsafe { std::mem::transmute(mmap.as_ptr()) };
+ let jitfn: extern "C" fn() -> u8 = unsafe { mem::transmute(mmap.as_ptr()) };
assert_eq!(jitfn(), 0xab);
}
@@ -1633,6 +1762,22 @@ mod test {
assert_eq!(unsafe { std::ptr::read(mmap.as_ptr()) }, b'a');
}
+ #[test]
+ fn raw_read_only() {
+ let tempdir = tempfile::tempdir().unwrap();
+ let path = tempdir.path().join("mmaprawro");
+
+ File::create(&path).unwrap().write_all(b"abc123").unwrap();
+
+ let mmap = MmapOptions::new()
+ .map_raw_read_only(&File::open(&path).unwrap())
+ .unwrap();
+
+ assert_eq!(mmap.len(), 6);
+ assert!(!mmap.as_ptr().is_null());
+ assert_eq!(unsafe { std::ptr::read(mmap.as_ptr()) }, b'a');
+ }
+
/// Something that relies on StableDeref
#[test]
#[cfg(feature = "stable_deref_trait")]
@@ -1728,7 +1873,7 @@ mod test {
.unwrap();
file.set_len(128).unwrap();
- let mut mmap = unsafe { Mmap::map(&file).unwrap() };
+ let mmap = unsafe { Mmap::map(&file).unwrap() };
#[cfg(target_os = "linux")]
assert!(!is_locked());
@@ -1751,4 +1896,119 @@ mod test {
#[cfg(target_os = "linux")]
assert!(!is_locked());
}
+
+ #[test]
+ #[cfg(target_os = "linux")]
+ fn remap_grow() {
+ use crate::RemapOptions;
+
+ let initial_len = 128;
+ let final_len = 2000;
+
+ let zeros = vec![0u8; final_len];
+ let incr: Vec<u8> = (0..final_len).map(|v| v as u8).collect();
+
+ let file = tempfile::tempfile().unwrap();
+ file.set_len(final_len as u64).unwrap();
+
+ let mut mmap = unsafe { MmapOptions::new().len(initial_len).map_mut(&file).unwrap() };
+ assert_eq!(mmap.len(), initial_len);
+ assert_eq!(&mmap[..], &zeros[..initial_len]);
+
+ unsafe {
+ mmap.remap(final_len, RemapOptions::new().may_move(true))
+ .unwrap()
+ };
+
+ // The size should have been updated
+ assert_eq!(mmap.len(), final_len);
+
+ // Should still be all zeros
+ assert_eq!(&mmap[..], &zeros);
+
+ // Write out to the whole expanded slice.
+ mmap.copy_from_slice(&incr);
+ }
+
+ #[test]
+ #[cfg(target_os = "linux")]
+ fn remap_shrink() {
+ use crate::RemapOptions;
+
+ let initial_len = 20000;
+ let final_len = 400;
+
+ let incr: Vec<u8> = (0..final_len).map(|v| v as u8).collect();
+
+ let file = tempfile::tempfile().unwrap();
+ file.set_len(initial_len as u64).unwrap();
+
+ let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() };
+ assert_eq!(mmap.len(), initial_len);
+
+ unsafe { mmap.remap(final_len, RemapOptions::new()).unwrap() };
+ assert_eq!(mmap.len(), final_len);
+
+ // Check that the mmap is still writable along the slice length
+ mmap.copy_from_slice(&incr);
+ }
+
+ #[test]
+ #[cfg(target_os = "linux")]
+ #[cfg(target_pointer_width = "32")]
+ fn remap_len_overflow() {
+ use crate::RemapOptions;
+
+ let file = tempfile::tempfile().unwrap();
+ file.set_len(1024).unwrap();
+ let mut mmap = unsafe { MmapOptions::new().len(1024).map(&file).unwrap() };
+
+ let res = unsafe { mmap.remap(0x80000000, RemapOptions::new().may_move(true)) };
+ assert_eq!(
+ res.unwrap_err().to_string(),
+ "memory map length overflows isize"
+ );
+
+ assert_eq!(mmap.len(), 1024);
+ }
+
+ #[test]
+ #[cfg(target_os = "linux")]
+ fn remap_with_offset() {
+ use crate::RemapOptions;
+
+ let offset = 77;
+ let initial_len = 128;
+ let final_len = 2000;
+
+ let zeros = vec![0u8; final_len];
+ let incr: Vec<u8> = (0..final_len).map(|v| v as u8).collect();
+
+ let file = tempfile::tempfile().unwrap();
+ file.set_len(final_len as u64 + offset).unwrap();
+
+ let mut mmap = unsafe {
+ MmapOptions::new()
+ .len(initial_len)
+ .offset(offset)
+ .map_mut(&file)
+ .unwrap()
+ };
+ assert_eq!(mmap.len(), initial_len);
+ assert_eq!(&mmap[..], &zeros[..initial_len]);
+
+ unsafe {
+ mmap.remap(final_len, RemapOptions::new().may_move(true))
+ .unwrap()
+ };
+
+ // The size should have been updated
+ assert_eq!(mmap.len(), final_len);
+
+ // Should still be all zeros
+ assert_eq!(&mmap[..], &zeros);
+
+ // Write out to the whole expanded slice.
+ mmap.copy_from_slice(&incr);
+ }
}